xref: /trunk/main/sw/source/core/text/frmform.cxx (revision ca62e2c2083b5d0995f1245bad6c2edfb455fbec)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #include <hintids.hxx>
29 #include <editeng/keepitem.hxx>
30 #include <editeng/hyznitem.hxx>
31 #include <pagefrm.hxx>      // ChangeFtnRef
32 #include <ndtxt.hxx>        // MakeFrm()
33 #include <dcontact.hxx>     // SwDrawContact
34 #include <dflyobj.hxx>      // SwVirtFlyDrawObj
35 #include <flyfrm.hxx>
36 #include <ftnfrm.hxx>       // SwFtnFrm
37 #include <txtftn.hxx>
38 #include <fmtftn.hxx>
39 #include <paratr.hxx>
40 #include <viewopt.hxx>      // SwViewOptions
41 #include <viewsh.hxx>       // ViewShell
42 #include <frmatr.hxx>
43 #include <pam.hxx>
44 #include <flyfrms.hxx>
45 #include <fmtanchr.hxx>
46 #include <txtcfg.hxx>
47 #include <itrform2.hxx>     // SwTxtFormatter
48 #include <widorp.hxx>       // Widows and Orphans
49 #include <txtcache.hxx>
50 #include <porrst.hxx>       // SwEmptyPortion
51 #include <blink.hxx>        // pBlink
52 #include <porfld.hxx>       // SwFldPortion
53 #include <sectfrm.hxx>      // SwSectionFrm
54 #include <pormulti.hxx>     // SwMultiPortion
55 
56 #include <rootfrm.hxx>
57 #include <frmfmt.hxx>       // SwFrmFmt
58 // OD 2004-05-24 #i28701#
59 #include <sortedobjs.hxx>
60 //IAccessibility2 Implementation 2009-----
61 #include <portab.hxx>
62 #include <editeng/lrspitem.hxx>
63 #include <editeng/tstpitem.hxx>
64 //-----IAccessibility2 Implementation 2009
65 
66 class FormatLevel
67 {
68     static MSHORT nLevel;
69 public:
70     inline FormatLevel()  { ++nLevel; }
71     inline ~FormatLevel() { --nLevel; }
72     inline MSHORT GetLevel() const { return nLevel; }
73     static sal_Bool LastLevel() { return 10 < nLevel; }
74 };
75 MSHORT FormatLevel::nLevel = 0;
76 
77 /*************************************************************************
78  *                          ValidateTxt/Frm()
79  *************************************************************************/
80 
81 void ValidateTxt( SwFrm *pFrm )     // Freund vom Frame
82 {
83     if ( ( ! pFrm->IsVertical() &&
84              pFrm->Frm().Width() == pFrm->GetUpper()->Prt().Width() ) ||
85          (   pFrm->IsVertical() &&
86              pFrm->Frm().Height() == pFrm->GetUpper()->Prt().Height() ) )
87         pFrm->bValidSize = sal_True;
88 /*
89     pFrm->bValidPrtArea = sal_True;
90     //Die Position validieren um nicht unnoetige (Test-)Moves zu provozieren.
91     //Dabei darf allerdings nicht eine tatsaechlich falsche Coordinate
92     //validiert werden.
93     if ( !pFrm->bValidPos )
94     {
95         //Leider muessen wir dazu die korrekte Position berechnen.
96         Point aOld( pFrm->Frm().Pos() );
97         pFrm->MakePos();
98         if ( aOld != pFrm->Pos() )
99         {
100             pFrm->Frm().Pos( aOld );
101             pFrm->bValidPos = sal_False;
102         }
103     }
104 */
105 }
106 
107 void SwTxtFrm::ValidateFrm()
108 {
109     // Umgebung validieren, um Oszillationen zu verhindern.
110     SWAP_IF_SWAPPED( this )
111 
112     if ( !IsInFly() && !IsInTab() )
113     {   //Innerhalb eines Flys nur this validieren, der Rest sollte eigentlich
114         //nur fuer Fussnoten notwendig sein und die gibt es innerhalb von
115         //Flys nicht. Fix fuer 5544
116         SwSectionFrm* pSct = FindSctFrm();
117         if( pSct )
118         {
119             if( !pSct->IsColLocked() )
120                 pSct->ColLock();
121             else
122                 pSct = NULL;
123         }
124 
125         SwFrm *pUp = GetUpper();
126         pUp->Calc();
127         if( pSct )
128             pSct->ColUnlock();
129     }
130     ValidateTxt( this );
131 
132     //MA: mindestens das MustFit-Flag muessen wir retten!
133     ASSERT( HasPara(), "ResetPreps(), missing ParaPortion." );
134     SwParaPortion *pPara = GetPara();
135     const sal_Bool bMustFit = pPara->IsPrepMustFit();
136     ResetPreps();
137     pPara->SetPrepMustFit( bMustFit );
138 
139     UNDO_SWAP( this )
140 }
141 
142 /*************************************************************************
143  *                          ValidateBodyFrm()
144  *************************************************************************/
145 
146 // nach einem RemoveFtn muss der BodyFrm und alle innenliegenden kalkuliert
147 // werden, damit die DeadLine richtig sitzt.
148 // Erst wird nach aussen hin gesucht, beim Rueckweg werden alle kalkuliert.
149 
150 void _ValidateBodyFrm( SwFrm *pFrm )
151 {
152     if( pFrm && !pFrm->IsCellFrm() )
153     {
154         if( !pFrm->IsBodyFrm() && pFrm->GetUpper() )
155             _ValidateBodyFrm( pFrm->GetUpper() );
156         if( !pFrm->IsSctFrm() )
157             pFrm->Calc();
158         else
159         {
160             sal_Bool bOld = ((SwSectionFrm*)pFrm)->IsCntntLocked();
161             ((SwSectionFrm*)pFrm)->SetCntntLock( sal_True );
162             pFrm->Calc();
163             if( !bOld )
164                 ((SwSectionFrm*)pFrm)->SetCntntLock( sal_False );
165         }
166     }
167 }
168 
169 void SwTxtFrm::ValidateBodyFrm()
170 {
171     SWAP_IF_SWAPPED( this )
172 
173      //siehe Kommtar in ValidateFrm()
174     if ( !IsInFly() && !IsInTab() &&
175          !( IsInSct() && FindSctFrm()->Lower()->IsColumnFrm() ) )
176         _ValidateBodyFrm( GetUpper() );
177 
178     UNDO_SWAP( this )
179 }
180 
181 /*************************************************************************
182  *                      SwTxtFrm::FindBodyFrm()
183  *************************************************************************/
184 
185 sal_Bool SwTxtFrm::_GetDropRect( SwRect &rRect ) const
186 {
187     SWAP_IF_NOT_SWAPPED( this )
188 
189     ASSERT( HasPara(), "SwTxtFrm::_GetDropRect: try again next year." );
190     SwTxtSizeInfo aInf( (SwTxtFrm*)this );
191     SwTxtMargin aLine( (SwTxtFrm*)this, &aInf );
192     if( aLine.GetDropLines() )
193     {
194         rRect.Top( aLine.Y() );
195         rRect.Left( aLine.GetLineStart() );
196         rRect.Height( aLine.GetDropHeight() );
197         rRect.Width( aLine.GetDropLeft() );
198 
199         if ( IsRightToLeft() )
200             SwitchLTRtoRTL( rRect );
201 
202         if ( IsVertical() )
203             SwitchHorizontalToVertical( rRect );
204         UNDO_SWAP( this )
205         return sal_True;
206     }
207 
208     UNDO_SWAP( this )
209 
210     return sal_False;
211 }
212 
213 /*************************************************************************
214  *                      SwTxtFrm::FindBodyFrm()
215  *************************************************************************/
216 
217 const SwBodyFrm *SwTxtFrm::FindBodyFrm() const
218 {
219     if ( IsInDocBody() )
220     {
221         const SwFrm *pFrm = GetUpper();
222         while( pFrm && !pFrm->IsBodyFrm() )
223             pFrm = pFrm->GetUpper();
224         return (const SwBodyFrm*)pFrm;
225     }
226     return 0;
227 }
228 
229 /*************************************************************************
230  *                      SwTxtFrm::CalcFollow()
231  *************************************************************************/
232 
233 sal_Bool SwTxtFrm::CalcFollow( const xub_StrLen nTxtOfst )
234 {
235     SWAP_IF_SWAPPED( this )
236 
237     ASSERT( HasFollow(), "CalcFollow: missing Follow." );
238 
239     SwTxtFrm* pMyFollow = GetFollow();
240 
241     SwParaPortion *pPara = GetPara();
242     sal_Bool bFollowFld = pPara ? pPara->IsFollowField() : sal_False;
243 
244     if( !pMyFollow->GetOfst() || pMyFollow->GetOfst() != nTxtOfst ||
245         bFollowFld || pMyFollow->IsFieldFollow() ||
246         ( pMyFollow->IsVertical() && !pMyFollow->Prt().Width() ) ||
247         ( ! pMyFollow->IsVertical() && !pMyFollow->Prt().Height() ) )
248     {
249 #ifdef DBG_UTIL
250         const SwFrm *pOldUp = GetUpper();
251 #endif
252 
253         SWRECTFN ( this )
254         SwTwips nOldBottom = (GetUpper()->Frm().*fnRect->fnGetBottom)();
255         SwTwips nMyPos = (Frm().*fnRect->fnGetTop)();
256 
257         const SwPageFrm *pPage = 0;
258         sal_Bool  bOldInvaCntnt = sal_True;
259         if ( !IsInFly() && GetNext() )
260         {
261             pPage = FindPageFrm();
262             //Minimieren - sprich ggf. zuruecksetzen - der Invalidierungen s.u.
263             bOldInvaCntnt  = pPage->IsInvalidCntnt();
264         }
265 
266         pMyFollow->_SetOfst( nTxtOfst );
267         pMyFollow->SetFieldFollow( bFollowFld );
268         if( HasFtn() || pMyFollow->HasFtn() )
269         {
270             ValidateFrm();
271             ValidateBodyFrm();
272             if( pPara )
273             {
274                 *(pPara->GetReformat()) = SwCharRange();
275                 *(pPara->GetDelta()) = 0;
276             }
277         }
278 
279         //Der Fussnotenbereich darf sich keinesfalls vergrossern.
280         SwSaveFtnHeight aSave( FindFtnBossFrm( sal_True ), LONG_MAX );
281 
282         pMyFollow->CalcFtnFlag();
283         if ( !pMyFollow->GetNext() && !pMyFollow->HasFtn() )
284             nOldBottom = bVert ? 0 : LONG_MAX;
285 
286         while( sal_True )
287         {
288             if( !FormatLevel::LastLevel() )
289             {
290                 // Weenn der Follow in einem spaltigen Bereich oder einem
291                 // spaltigen Rahmen steckt, muss zunaechst dieser kalkuliert
292                 // werden, da das FormatWidthCols() nicht funktioniert, wenn
293                 // es aus dem MakeAll des _gelockten_ Follows heraus gerufen
294                 // wird.
295                 SwSectionFrm* pSct = pMyFollow->FindSctFrm();
296                 if( pSct && !pSct->IsAnLower( this ) )
297                 {
298                     if( pSct->GetFollow() )
299                         pSct->SimpleFormat();
300                     else if( ( pSct->IsVertical() && !pSct->Frm().Width() ) ||
301                              ( ! pSct->IsVertical() && !pSct->Frm().Height() ) )
302                         break;
303                 }
304                 // OD 14.03.2003 #i11760# - intrinsic format of follow is controlled.
305                 if ( FollowFormatAllowed() )
306                 {
307                     // OD 14.03.2003 #i11760# - no nested format of follows, if
308                     // text frame is contained in a column frame.
309                     // Thus, forbid intrinsic format of follow.
310                     {
311                         bool bIsFollowInColumn = false;
312                         SwFrm* pFollowUpper = pMyFollow->GetUpper();
313                         while ( pFollowUpper )
314                         {
315                             if ( pFollowUpper->IsColumnFrm() )
316                             {
317                                 bIsFollowInColumn = true;
318                                 break;
319                             }
320                             if ( pFollowUpper->IsPageFrm() ||
321                                  pFollowUpper->IsFlyFrm() )
322                             {
323                                 break;
324                             }
325                             pFollowUpper = pFollowUpper->GetUpper();
326                         }
327                         if ( bIsFollowInColumn )
328                         {
329                             pMyFollow->ForbidFollowFormat();
330                         }
331                     }
332 
333                     pMyFollow->Calc();
334                     // Der Follow merkt anhand seiner Frm().Height(), dass was schief
335                     // gelaufen ist.
336                     ASSERT( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: cheesy follow" );
337                     if( pMyFollow->GetPrev() )
338                     {
339                         pMyFollow->Prepare( PREP_CLEAR );
340                         pMyFollow->Calc();
341                         ASSERT( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: very cheesy follow" );
342                     }
343 
344                     // OD 14.03.2003 #i11760# - reset control flag for follow format.
345                     pMyFollow->AllowFollowFormat();
346                 }
347 
348                 //Sicherstellen, dass der Follow gepaintet wird.
349                 pMyFollow->SetCompletePaint();
350             }
351 
352             pPara = GetPara();
353             //Solange der Follow wg. Orphans Zeilen angefordert, bekommt er
354             //diese und wird erneut formatiert, falls moeglich.
355             if( pPara && pPara->IsPrepWidows() )
356                 CalcPreps();
357             else
358                 break;
359         }
360 
361         if( HasFtn() || pMyFollow->HasFtn() )
362         {
363             ValidateBodyFrm();
364             ValidateFrm();
365             if( pPara )
366             {
367                 *(pPara->GetReformat()) = SwCharRange();
368                 *(pPara->GetDelta()) = 0;
369             }
370         }
371 
372         if ( pPage )
373         {
374             if ( !bOldInvaCntnt )
375                 pPage->ValidateCntnt();
376         }
377 
378 #ifdef DBG_UTIL
379         ASSERT( pOldUp == GetUpper(), "SwTxtFrm::CalcFollow: heavy follow" );
380 #endif
381 
382         const long nRemaining =
383                  - (GetUpper()->Frm().*fnRect->fnBottomDist)( nOldBottom );
384         if (  nRemaining > 0 && !GetUpper()->IsSctFrm() &&
385               nRemaining != ( bVert ?
386                               nMyPos - Frm().Right() :
387                               Frm().Top() - nMyPos ) )
388         {
389             UNDO_SWAP( this )
390             return sal_True;
391         }
392     }
393 
394     UNDO_SWAP( this )
395 
396     return sal_False;
397 }
398 
399 /*************************************************************************
400  *                      SwTxtFrm::AdjustFrm()
401  *************************************************************************/
402 
403 void SwTxtFrm::AdjustFrm( const SwTwips nChgHght, sal_Bool bHasToFit )
404 {
405     if( IsUndersized() )
406     {
407         if( GetOfst() && !IsFollow() ) // ein gescrollter Absatz (undersized)
408             return;
409         SetUndersized( nChgHght == 0 || bHasToFit );
410     }
411 
412     // AdjustFrm is called with a swapped frame during
413     // formatting but the frame is not swapped during FormatEmpty
414     SWAP_IF_SWAPPED( this )
415     SWRECTFN ( this )
416 
417     // Die Size-Variable des Frames wird durch Grow inkrementiert
418     // oder durch Shrink dekrementiert. Wenn die Groesse
419     // unveraendert ist, soll nichts passieren!
420     if( nChgHght >= 0)
421     {
422         SwTwips nChgHeight = nChgHght;
423         if( nChgHght && !bHasToFit )
424         {
425             if( IsInFtn() && !IsInSct() )
426             {
427                 SwTwips nReal = Grow( nChgHght, sal_True );
428                 if( nReal < nChgHght )
429                 {
430                     SwTwips nBot = (*fnRect->fnYInc)( (Frm().*fnRect->fnGetBottom)(),
431                                                       nChgHght - nReal );
432                     SwFrm* pCont = FindFtnFrm()->GetUpper();
433 
434                     if( (pCont->Frm().*fnRect->fnBottomDist)( nBot ) > 0 )
435                     {
436                         (Frm().*fnRect->fnAddBottom)( nChgHght );
437                         if( bVert )
438                             Prt().SSize().Width() += nChgHght;
439                         else
440                         Prt().SSize().Height() += nChgHght;
441                         UNDO_SWAP( this )
442                         return;
443                     }
444                 }
445             }
446 
447             Grow( nChgHght );
448 
449             if ( IsInFly() )
450             {
451                 //MA 06. May. 93: Wenn einer der Upper ein Fly ist, so ist es
452                 //sehr wahrscheinlich, dass dieser Fly durch das Grow seine
453                 //Position veraendert - also muss auch meine Position korrigiert
454                 //werden (sonst ist die Pruefung s.u. nicht aussagekraeftig).
455                 //Die Vorgaenger muessen berechnet werden, damit die Position
456                 //korrekt berechnet werden kann.
457                 if ( GetPrev() )
458                 {
459                     SwFrm *pPre = GetUpper()->Lower();
460                     do
461                     {   pPre->Calc();
462                         pPre = pPre->GetNext();
463                     } while ( pPre && pPre != this );
464                 }
465                 const Point aOldPos( Frm().Pos() );
466                 MakePos();
467                 if ( aOldPos != Frm().Pos() )
468                 {
469                     // OD 2004-07-01 #i28701# - use new method <SwFrm::InvalidateObjs(..)>
470                     // No format is performed for the floating screen objects.
471                     InvalidateObjs( true );
472                 }
473             }
474             nChgHeight = 0;
475         }
476         // Ein Grow() wird von der Layout-Seite immer akzeptiert,
477         // also auch, wenn die FixSize des umgebenden Layoutframes
478         // dies nicht zulassen sollte. Wir ueberpruefen diesen
479         // Fall und korrigieren die Werte.
480         // MA 06. May. 93: Der Frm darf allerdings auch im Notfall nicht
481         // weiter geschrumpft werden als es seine Groesse zulaesst.
482         SwTwips nRstHeight;
483         if ( IsVertical() )
484         {
485             ASSERT( ! IsSwapped(),"Swapped frame while calculating nRstHeight" );
486 
487             //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
488             if ( IsVertLR() )
489                     nRstHeight = GetUpper()->Frm().Left()
490                             + GetUpper()->Prt().Left()
491                             + GetUpper()->Prt().Width()
492                             - Frm().Left();
493             else
494                 nRstHeight = Frm().Left() + Frm().Width() -
495                             ( GetUpper()->Frm().Left() + GetUpper()->Prt().Left() );
496          }
497         else
498             nRstHeight = GetUpper()->Frm().Top()
499                        + GetUpper()->Prt().Top()
500                        + GetUpper()->Prt().Height()
501                        - Frm().Top();
502 
503         //In Tabellenzellen kann ich mir evtl. noch ein wenig dazuholen, weil
504         //durch eine vertikale Ausrichtung auch oben noch Raum sein kann.
505         // --> OD 2004-11-25 #115759# - assure, that first lower in upper
506         // is the current one or is valid.
507         if ( IsInTab() &&
508              ( GetUpper()->Lower() == this ||
509                GetUpper()->Lower()->IsValid() ) )
510         // <--
511         {
512             long nAdd = (*fnRect->fnYDiff)( (GetUpper()->Lower()->Frm().*fnRect->fnGetTop)(),
513                                             (GetUpper()->*fnRect->fnGetPrtTop)() );
514             ASSERT( nAdd >= 0, "Ey" );
515             nRstHeight += nAdd;
516         }
517 
518 /* ------------------------------------
519  * #50964#: nRstHeight < 0 bedeutet, dass der TxtFrm komplett ausserhalb seines
520  * Upper liegt. Dies kann passieren, wenn er innerhalb eines FlyAtCntFrm liegt, der
521  * durch das Grow() die Seite gewechselt hat. In so einem Fall ist es falsch, der
522  * folgenden Grow-Versuch durchzufuehren. Im Bugfall fuehrte dies sogar zur
523  * Endlosschleife.
524  * -----------------------------------*/
525         SwTwips nFrmHeight = (Frm().*fnRect->fnGetHeight)();
526         SwTwips nPrtHeight = (Prt().*fnRect->fnGetHeight)();
527 
528         if( nRstHeight < nFrmHeight )
529         {
530             //Kann sein, dass ich die richtige Grosse habe, der Upper aber zu
531             //klein ist und der Upper noch Platz schaffen kann.
532             if( ( nRstHeight >= 0 || ( IsInFtn() && IsInSct() ) ) && !bHasToFit )
533                 nRstHeight += GetUpper()->Grow( nFrmHeight - nRstHeight );
534             // In spaltigen Bereichen wollen wir moeglichst nicht zu gross werden, damit
535             // nicht ueber GetNextSctLeaf weitere Bereiche angelegt werden. Stattdessen
536             // schrumpfen wir und notieren bUndersized, damit FormatWidthCols die richtige
537             // Spaltengroesse ermitteln kann.
538             if ( nRstHeight < nFrmHeight )
539             {
540                 if( bHasToFit || !IsMoveable() ||
541                     ( IsInSct() && !FindSctFrm()->MoveAllowed(this) ) )
542                 {
543                     SetUndersized( sal_True );
544                     Shrink( Min( ( nFrmHeight - nRstHeight), nPrtHeight ) );
545                 }
546                 else
547                     SetUndersized( sal_False );
548             }
549         }
550         else if( nChgHeight )
551         {
552             if( nRstHeight - nFrmHeight < nChgHeight )
553                 nChgHeight = nRstHeight - nFrmHeight;
554             if( nChgHeight )
555                 Grow( nChgHeight );
556         }
557     }
558     else
559         Shrink( -nChgHght );
560 
561     UNDO_SWAP( this )
562 }
563 
564 //IAccessibility2 Implementation 2009-----
565 com::sun::star::uno::Sequence< ::com::sun::star::style::TabStop > SwTxtFrm::GetTabStopInfo( SwTwips CurrentPos )
566 {
567     com::sun::star::uno::Sequence< ::com::sun::star::style::TabStop > tabs(1);
568     ::com::sun::star::style::TabStop ts;
569 
570     SwTxtFormatInfo     aInf( this );
571     SwTxtFormatter      aLine( this, &aInf );
572     SwTxtCursor         TxtCursor( this, &aInf );
573     const Point aCharPos( TxtCursor.GetTopLeft() );
574 
575 
576     SwTwips nRight = aLine.Right();
577     CurrentPos -= aCharPos.X();
578 
579     // get current tab stop information stored in the Frm
580     const SvxTabStop *pTS = aLine.GetLineInfo().GetTabStop( CurrentPos, nRight );
581 
582     if( !pTS )
583     {
584         return com::sun::star::uno::Sequence< ::com::sun::star::style::TabStop >();
585     }
586 
587     // copy tab stop information into a Sequence, which only contains one element.
588     ts.Position = pTS->GetTabPos();
589     ts.DecimalChar = pTS->GetDecimal();
590     ts.FillChar = pTS->GetFill();
591     switch( pTS->GetAdjustment() )
592     {
593     case SVX_TAB_ADJUST_LEFT   : ts.Alignment = ::com::sun::star::style::TabAlign_LEFT; break;
594     case SVX_TAB_ADJUST_CENTER : ts.Alignment = ::com::sun::star::style::TabAlign_CENTER; break;
595     case SVX_TAB_ADJUST_RIGHT  : ts.Alignment = ::com::sun::star::style::TabAlign_RIGHT; break;
596     case SVX_TAB_ADJUST_DECIMAL: ts.Alignment = ::com::sun::star::style::TabAlign_DECIMAL; break;
597     case SVX_TAB_ADJUST_DEFAULT: ts.Alignment = ::com::sun::star::style::TabAlign_DEFAULT; break;
598     default: break; // prevent warning
599     }
600 
601     tabs[0] = ts;
602     return tabs;
603 }
604 //-----IAccessibility2 Implementation 2009
605 /*************************************************************************
606  *                      SwTxtFrm::AdjustFollow()
607  *************************************************************************/
608 
609 /* AdjustFollow erwartet folgende Situation:
610  * Der SwTxtIter steht am unteren Ende des Masters, der Offset wird
611  * im Follow eingestellt.
612  * nOffset haelt den Offset im Textstring, ab dem der Master abschliesst
613  * und der Follow beginnt. Wenn er 0 ist, wird der FolgeFrame geloescht.
614  */
615 
616 void SwTxtFrm::_AdjustFollow( SwTxtFormatter &rLine,
617                              const xub_StrLen nOffset, const xub_StrLen nEnd,
618                              const sal_uInt8 nMode )
619 {
620     SwFrmSwapper aSwapper( this, sal_False );
621 
622     // Wir haben den Rest der Textmasse: alle Follows loeschen
623     // Sonderfall sind DummyPortions()
624     // - special cases are controlled by parameter <nMode>.
625     if( HasFollow() && !(nMode & 1) && nOffset == nEnd )
626     {
627         while( GetFollow() )
628         {
629             if( ((SwTxtFrm*)GetFollow())->IsLocked() )
630             {
631                 ASSERT( sal_False, "+SwTxtFrm::JoinFrm: Follow ist locked." );
632                 return;
633             }
634             JoinFrm();
635         }
636 
637         return;
638     }
639 
640     // Tanz auf dem Vulkan: Wir formatieren eben schnell noch einmal
641     // die letzte Zeile fuer das QuoVadis-Geraffel. Selbstverstaendlich
642     // kann sich dadurch auch der Offset verschieben:
643     const xub_StrLen nNewOfst = ( IsInFtn() && ( !GetIndNext() || HasFollow() ) ) ?
644                             rLine.FormatQuoVadis(nOffset) : nOffset;
645 
646     if( !(nMode & 1) )
647     {
648         // Wir klauen unseren Follows Textmasse, dabei kann es passieren,
649         // dass wir einige Follows Joinen muessen.
650         while( GetFollow() && GetFollow()->GetFollow() &&
651                nNewOfst >= GetFollow()->GetFollow()->GetOfst() )
652         {
653             DBG_LOOP;
654             JoinFrm();
655         }
656     }
657 
658     // Der Ofst hat sich verschoben.
659     if( GetFollow() )
660     {
661 #if OSL_DEBUG_LEVEL > 1
662         static sal_Bool bTest = sal_False;
663         if( !bTest || ( nMode & 1 ) )
664 #endif
665         if ( nMode )
666             GetFollow()->ManipOfst( 0 );
667 
668         if ( CalcFollow( nNewOfst ) )   // CalcFollow erst zum Schluss, dort erfolgt ein SetOfst
669             rLine.SetOnceMore( sal_True );
670     }
671 }
672 
673 /*************************************************************************
674  *                      SwTxtFrm::JoinFrm()
675  *************************************************************************/
676 
677 SwCntntFrm *SwTxtFrm::JoinFrm()
678 {
679     ASSERT( GetFollow(), "+SwTxtFrm::JoinFrm: no follow" );
680     SwTxtFrm  *pFoll = GetFollow();
681 
682     SwTxtFrm *pNxt = pFoll->GetFollow();
683 
684     // Alle Fussnoten des zu zerstoerenden Follows werden auf uns
685     // umgehaengt.
686     xub_StrLen nStart = pFoll->GetOfst();
687     if ( pFoll->HasFtn() )
688     {
689         const SwpHints *pHints = pFoll->GetTxtNode()->GetpSwpHints();
690         if( pHints )
691         {
692             SwFtnBossFrm *pFtnBoss = 0;
693             SwFtnBossFrm *pEndBoss = 0;
694             for ( sal_uInt16 i = 0; i < pHints->Count(); ++i )
695             {
696                 const SwTxtAttr *pHt = (*pHints)[i];
697                 if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nStart )
698                 {
699                     if( pHt->GetFtn().IsEndNote() )
700                     {
701                         if( !pEndBoss )
702                             pEndBoss = pFoll->FindFtnBossFrm();
703                         pEndBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this );
704                     }
705                     else
706                     {
707                         if( !pFtnBoss )
708                             pFtnBoss = pFoll->FindFtnBossFrm( sal_True );
709                         pFtnBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this );
710                     }
711                     SetFtn( sal_True );
712                 }
713             }
714         }
715     }
716 
717 #ifdef DBG_UTIL
718     else if ( pFoll->GetValidPrtAreaFlag() ||
719               pFoll->GetValidSizeFlag() )
720     {
721         pFoll->CalcFtnFlag();
722         ASSERT( !pFoll->HasFtn(), "Missing FtnFlag." );
723     }
724 #endif
725 
726     pFoll->MoveFlyInCnt( this, nStart, STRING_LEN );
727     pFoll->SetFtn( sal_False );
728     // --> OD 2005-12-01 #i27138#
729     // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
730     // Relation CONTENT_FLOWS_FROM for current next paragraph will change
731     // and relation CONTENT_FLOWS_TO for current previous paragraph, which
732     // is <this>, will change.
733     {
734         ViewShell* pViewShell( pFoll->getRootFrm()->GetCurrShell() );
735         if ( pViewShell && pViewShell->GetLayout() &&
736              pViewShell->GetLayout()->IsAnyShellAccessible() )
737         {
738             pViewShell->InvalidateAccessibleParaFlowRelation(
739                             dynamic_cast<SwTxtFrm*>(pFoll->FindNextCnt( true )),
740                             this );
741         }
742     }
743     // <--
744     pFoll->Cut();
745     delete pFoll;
746     pFollow = pNxt;
747     return pNxt;
748 }
749 
750 /*************************************************************************
751  *                      SwTxtFrm::SplitFrm()
752  *************************************************************************/
753 
754 SwCntntFrm *SwTxtFrm::SplitFrm( const xub_StrLen nTxtPos )
755 {
756     SWAP_IF_SWAPPED( this )
757 
758     // Durch das Paste wird ein Modify() an mich verschickt.
759     // Damit meine Daten nicht verschwinden, locke ich mich.
760     SwTxtFrmLocker aLock( this );
761     SwTxtFrm *pNew = (SwTxtFrm *)(GetTxtNode()->MakeFrm( this ));
762     pNew->bIsFollow = sal_True;
763 
764     pNew->SetFollow( GetFollow() );
765     SetFollow( pNew );
766 
767     pNew->Paste( GetUpper(), GetNext() );
768     // --> OD 2005-12-01 #i27138#
769     // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
770     // Relation CONTENT_FLOWS_FROM for current next paragraph will change
771     // and relation CONTENT_FLOWS_TO for current previous paragraph, which
772     // is <this>, will change.
773     {
774         ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() );
775         if ( pViewShell && pViewShell->GetLayout() &&
776              pViewShell->GetLayout()->IsAnyShellAccessible() )
777         {
778             pViewShell->InvalidateAccessibleParaFlowRelation(
779                             dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )),
780                             this );
781         }
782     }
783     // <--
784 
785     // Wenn durch unsere Aktionen Fussnoten in pNew landen,
786     // so muessen sie umgemeldet werden.
787     if ( HasFtn() )
788     {
789         const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
790         if( pHints )
791         {
792             SwFtnBossFrm *pFtnBoss = 0;
793             SwFtnBossFrm *pEndBoss = 0;
794             for ( sal_uInt16 i = 0; i < pHints->Count(); ++i )
795             {
796                 const SwTxtAttr *pHt = (*pHints)[i];
797                 if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nTxtPos )
798                 {
799                     if( pHt->GetFtn().IsEndNote() )
800                     {
801                         if( !pEndBoss )
802                             pEndBoss = FindFtnBossFrm();
803                         pEndBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew );
804                     }
805                     else
806                     {
807                         if( !pFtnBoss )
808                             pFtnBoss = FindFtnBossFrm( sal_True );
809                         pFtnBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew );
810                     }
811                     pNew->SetFtn( sal_True );
812                 }
813             }
814         }
815     }
816 
817 #ifdef DBG_UTIL
818     else
819     {
820         CalcFtnFlag( nTxtPos-1 );
821         ASSERT( !HasFtn(), "Missing FtnFlag." );
822     }
823 #endif
824 
825     MoveFlyInCnt( pNew, nTxtPos, STRING_LEN );
826 
827     // Kein SetOfst oder CalcFollow, weil gleich ohnehin ein AdjustFollow folgt.
828 
829     pNew->ManipOfst( nTxtPos );
830 
831     UNDO_SWAP( this )
832     return pNew;
833 }
834 
835 
836 /*************************************************************************
837  *                      virtual SwTxtFrm::SetOfst()
838  *************************************************************************/
839 
840 void SwTxtFrm::_SetOfst( const xub_StrLen nNewOfst )
841 {
842 #ifdef DBGTXT
843     // Es gibt tatsaechlich einen Sonderfall, in dem ein SetOfst(0)
844     // zulaessig ist: bug 3496
845     ASSERT( nNewOfst, "!SwTxtFrm::SetOfst: missing JoinFrm()." );
846 #endif
847 
848     // Die Invalidierung unseres Follows ist nicht noetig.
849     // Wir sind ein Follow, werden gleich formatiert und
850     // rufen von dort aus das SetOfst() !
851     nOfst = nNewOfst;
852     SwParaPortion *pPara = GetPara();
853     if( pPara )
854     {
855         SwCharRange &rReformat = *(pPara->GetReformat());
856         rReformat.Start() = 0;
857         rReformat.Len() = GetTxt().Len();
858         *(pPara->GetDelta()) = rReformat.Len();
859     }
860     InvalidateSize();
861 }
862 
863 /*************************************************************************
864  *                      SwTxtFrm::CalcPreps
865  *************************************************************************/
866 
867 sal_Bool SwTxtFrm::CalcPreps()
868 {
869     ASSERT( ! IsVertical() || ! IsSwapped(), "SwTxtFrm::CalcPreps with swapped frame" );
870     SWRECTFN( this );
871 
872     SwParaPortion *pPara = GetPara();
873     if ( !pPara )
874         return sal_False;
875     sal_Bool bPrep = pPara->IsPrep();
876     sal_Bool bPrepWidows = pPara->IsPrepWidows();
877     sal_Bool bPrepAdjust = pPara->IsPrepAdjust();
878     sal_Bool bPrepMustFit = pPara->IsPrepMustFit();
879     ResetPreps();
880 
881     sal_Bool bRet = sal_False;
882     if( bPrep && !pPara->GetReformat()->Len() )
883     {
884         // PREP_WIDOWS bedeutet, dass im Follow die Orphans-Regel
885         // zuschlug.
886         // Es kann in unguenstigen Faellen vorkommen, dass auch ein
887         // PrepAdjust vorliegt (3680)!
888         if( bPrepWidows )
889         {
890             if( !GetFollow() )
891             {
892                 ASSERT( GetFollow(), "+SwTxtFrm::CalcPreps: no credits" );
893                 return sal_False;
894             }
895 
896             // Wir muessen uns auf zwei Faelle einstellen:
897             // Wir konnten dem Follow noch ein paar Zeilen abgeben,
898             // -> dann muessen wir schrumpfen
899             // oder wir muessen auf die naechste Seite
900             // -> dann lassen wir unseren Frame zu gross werden.
901 
902             SwTwips nChgHeight = GetParHeight();
903             if( nChgHeight >= (Prt().*fnRect->fnGetHeight)() )
904             {
905                 if( bPrepMustFit )
906                 {
907                     GetFollow()->SetJustWidow( sal_True );
908                     GetFollow()->Prepare( PREP_CLEAR );
909                 }
910                 else if ( bVert )
911                 {
912                     Frm().Width( Frm().Width() + Frm().Left() );
913                     Prt().Width( Prt().Width() + Frm().Left() );
914                     Frm().Left( 0 );
915                     SetWidow( sal_True );
916                 }
917                 else
918                 {
919                     SwTwips nTmp  = LONG_MAX - (Frm().Top()+10000);
920                     SwTwips nDiff = nTmp - Frm().Height();
921                     Frm().Height( nTmp );
922                     Prt().Height( Prt().Height() + nDiff );
923                     SetWidow( sal_True );
924                 }
925             }
926             else
927             {
928                 ASSERT( nChgHeight < (Prt().*fnRect->fnGetHeight)(),
929                         "+SwTxtFrm::CalcPrep: wanna shrink" );
930 
931                 nChgHeight = (Prt().*fnRect->fnGetHeight)() - nChgHeight;
932 
933                 GetFollow()->SetJustWidow( sal_True );
934                 GetFollow()->Prepare( PREP_CLEAR );
935                 Shrink( nChgHeight );
936                 SwRect &rRepaint = *(pPara->GetRepaint());
937 
938                 if ( bVert )
939                 {
940                     SwRect aRepaint( Frm().Pos() + Prt().Pos(), Prt().SSize() );
941                     SwitchVerticalToHorizontal( aRepaint );
942                     rRepaint.Chg( aRepaint.Pos(), aRepaint.SSize() );
943                 }
944                 else
945                     rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() );
946 
947                 // 6792: Rrand < LRand und Repaint
948                 if( 0 >= rRepaint.Width() )
949                     rRepaint.Width(1);
950             }
951             bRet = sal_True;
952         }
953 
954         else if ( bPrepAdjust )
955         {
956             if ( HasFtn() )
957             {
958                 if( !CalcPrepFtnAdjust() )
959                 {
960                     if( bPrepMustFit )
961                     {
962                         SwTxtLineAccess aAccess( this );
963                         aAccess.GetPara()->SetPrepMustFit( sal_True );
964                     }
965                     return sal_False;
966                 }
967             }
968 
969             SWAP_IF_NOT_SWAPPED( this )
970 
971             SwTxtFormatInfo aInf( this );
972             SwTxtFormatter aLine( this, &aInf );
973 
974             WidowsAndOrphans aFrmBreak( this );
975             // Egal was die Attribute meinen, bei MustFit wird
976             // der Absatz im Notfall trotzdem gesplittet...
977             if( bPrepMustFit )
978             {
979                 aFrmBreak.SetKeep( sal_False );
980                 aFrmBreak.ClrOrphLines();
981             }
982             // Bevor wir FormatAdjust aufrufen muessen wir dafuer
983             // sorgen, dass die Zeilen, die unten raushaengen
984             // auch tatsaechlich abgeschnitten werden.
985             // OD 2004-02-25 #i16128# - method renamed
986             sal_Bool bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine );
987             bRet = sal_True;
988             while( !bBreak && aLine.Next() )
989             {
990                 // OD 2004-02-25 #i16128# - method renamed
991                 bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine );
992             }
993             if( bBreak )
994             {
995                 // Es gibt Komplikationen: wenn TruncLines gerufen wird,
996                 // veraendern sich ploetzlich die Bedingungen in
997                 // IsInside, so dass IsBreakNow andere Ergebnisse
998                 // liefern kann. Aus diesem Grund wird rFrmBreak bekannt
999                 // gegeben, dass da wo rLine steht, das Ende erreicht
1000                 // ist. Mal sehen, ob's klappt ...
1001                 aLine.TruncLines();
1002                 aFrmBreak.SetRstHeight( aLine );
1003                 FormatAdjust( aLine, aFrmBreak, aInf.GetTxt().Len(), aInf.IsStop() );
1004             }
1005             else
1006             {
1007                 if( !GetFollow() )
1008                 {
1009                     FormatAdjust( aLine, aFrmBreak,
1010                                   aInf.GetTxt().Len(), aInf.IsStop() );
1011                 }
1012                 else if ( !aFrmBreak.IsKeepAlways() )
1013                 {
1014                     // Siehe Bug: 2320
1015                     // Vor dem Master wird eine Zeile geloescht, der Follow
1016                     // koennte eine Zeile abgeben.
1017                     const SwCharRange aFollowRg( GetFollow()->GetOfst(), 1 );
1018                     *(pPara->GetReformat()) += aFollowRg;
1019                     // Es soll weitergehen!
1020                     bRet = sal_False;
1021                 }
1022             }
1023 
1024             UNDO_SWAP( this )
1025             // Eine letzte Ueberpruefung, falls das FormatAdjust() nichts
1026             // brachte, muessen wir amputieren.
1027             if( bPrepMustFit )
1028             {
1029                 const SwTwips nMust = (GetUpper()->*fnRect->fnGetPrtBottom)();
1030                 const SwTwips nIs   = (Frm().*fnRect->fnGetBottom)();
1031 
1032                 if( bVert && nIs < nMust )
1033                 {
1034                     Shrink( nMust - nIs );
1035                     if( Prt().Width() < 0 )
1036                         Prt().Width( 0 );
1037                     SetUndersized( sal_True );
1038                 }
1039                 else if ( ! bVert && nIs > nMust )
1040                 {
1041                     Shrink( nIs - nMust );
1042                     if( Prt().Height() < 0 )
1043                         Prt().Height( 0 );
1044                     SetUndersized( sal_True );
1045                 }
1046             }
1047         }
1048     }
1049     pPara->SetPrepMustFit( bPrepMustFit );
1050     return bRet;
1051 }
1052 
1053 
1054 /*************************************************************************
1055  *                      SwTxtFrm::FormatAdjust()
1056  *************************************************************************/
1057 
1058 // Hier werden die Fussnoten und "als Zeichen"-gebundenen Objekte umgehaengt
1059 #define CHG_OFFSET( pFrm, nNew )\
1060     {\
1061         if( pFrm->GetOfst() < nNew )\
1062             pFrm->MoveFlyInCnt( this, 0, nNew );\
1063         else if( pFrm->GetOfst() > nNew )\
1064             MoveFlyInCnt( pFrm, nNew, STRING_LEN );\
1065     }
1066 
1067 void SwTxtFrm::FormatAdjust( SwTxtFormatter &rLine,
1068                              WidowsAndOrphans &rFrmBreak,
1069                              const xub_StrLen nStrLen,
1070                              const sal_Bool bDummy )
1071 {
1072     SWAP_IF_NOT_SWAPPED( this )
1073 
1074     SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1075 
1076     xub_StrLen nEnd = rLine.GetStart();
1077 
1078     sal_Bool bHasToFit = pPara->IsPrepMustFit();
1079 
1080     // Das StopFlag wird durch Fussnoten gesetzt,
1081     // die auf die naechste Seite wollen.
1082     // OD, FME 2004-03-03 - call base class method <SwTxtFrmBreak::IsBreakNow(..)>
1083     // instead of method <WidowsAndOrphans::IsBreakNow(..)> to get a break,
1084     // even if due to widow rule no enough lines exists.
1085     sal_uInt8 nNew = ( !GetFollow() &&
1086                        nEnd < nStrLen &&
1087                        ( rLine.IsStop() ||
1088                          ( bHasToFit
1089                            ? ( rLine.GetLineNr() > 1 &&
1090                                !rFrmBreak.IsInside( rLine ) )
1091                            : rFrmBreak.IsBreakNow( rLine ) ) ) )
1092                      ? 1 : 0;
1093     // --> OD #i84870#
1094     // no split of text frame, which only contains a as-character anchored object
1095     const bool bOnlyContainsAsCharAnchoredObj =
1096             !IsFollow() && nStrLen == 1 &&
1097             GetDrawObjs() && GetDrawObjs()->Count() == 1 &&
1098             (*GetDrawObjs())[0]->GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AS_CHAR;
1099     if ( nNew && bOnlyContainsAsCharAnchoredObj )
1100     {
1101         nNew = 0;
1102     }
1103     // <--
1104     if ( nNew )
1105     {
1106         SplitFrm( nEnd );
1107     }
1108 
1109     const SwFrm *pBodyFrm = (const SwFrm*)(FindBodyFrm());
1110 
1111     const long nBodyHeight = pBodyFrm ? ( IsVertical() ?
1112                                           pBodyFrm->Frm().Width() :
1113                                           pBodyFrm->Frm().Height() ) : 0;
1114 
1115     // Wenn die aktuellen Werte berechnet wurden, anzeigen, dass
1116     // sie jetzt gueltig sind.
1117     *(pPara->GetReformat()) = SwCharRange();
1118     sal_Bool bDelta = *pPara->GetDelta() != 0;
1119     *(pPara->GetDelta()) = 0;
1120 
1121     if( rLine.IsStop() )
1122     {
1123         rLine.TruncLines( sal_True );
1124         nNew = 1;
1125     }
1126 
1127     // FindBreak schneidet die letzte Zeile ab.
1128     if( !rFrmBreak.FindBreak( this, rLine, bHasToFit ) )
1129     {
1130         // Wenn wir bis zum Ende durchformatiert haben, wird nEnd auf das Ende
1131         // gesetzt. In AdjustFollow wird dadurch ggf. JoinFrm() ausgefuehrt.
1132         // Ansonsten ist nEnd das Ende der letzten Zeile im Master.
1133         xub_StrLen nOld = nEnd;
1134         nEnd = rLine.GetEnd();
1135         if( GetFollow() )
1136         {
1137             if( nNew && nOld < nEnd )
1138                 RemoveFtn( nOld, nEnd - nOld );
1139             CHG_OFFSET( GetFollow(), nEnd )
1140             if( !bDelta )
1141                 GetFollow()->ManipOfst( nEnd );
1142         }
1143     }
1144     else
1145     {   // Wenn wir Zeilen abgeben, darf kein Join auf den Folows gerufen werden,
1146         // im Gegenteil, es muss ggf. sogar ein Follow erzeugt werden.
1147         // Dies muss auch geschehen, wenn die Textmasse komplett im Master
1148         // bleibt, denn es k???nnte ja ein harter Zeilenumbruch noch eine weitere
1149         // Zeile (ohne Textmassse) notwendig machen!
1150         nEnd = rLine.GetEnd();
1151         if( GetFollow() )
1152         {
1153             // OD 21.03.2003 #108121# - Another case for not joining the follow:
1154             // Text frame has no content, but a numbering. Then, do *not* join.
1155             // Example of this case: When an empty, but numbered paragraph
1156             // at the end of page is completely displaced by a fly frame.
1157             // Thus, the text frame introduced a follow by a
1158             // <SwTxtFrm::SplitFrm(..)> - see below. The follow then shows
1159             // the numbering and must stay.
1160             if ( GetFollow()->GetOfst() != nEnd ||
1161                  GetFollow()->IsFieldFollow() ||
1162                  ( nStrLen == 0 && GetTxtNode()->GetNumRule() ) )
1163             {
1164                 nNew |= 3;
1165             }
1166             CHG_OFFSET( GetFollow(), nEnd )
1167             GetFollow()->ManipOfst( nEnd );
1168         }
1169         else
1170         {
1171             // OD 21.03.2003 #108121# - Only split frame, if the frame contains
1172             // content or contains no content, but has a numbering.
1173             // OD #i84870# - no split, if text frame only contains one
1174             // as-character anchored object.
1175             if ( !bOnlyContainsAsCharAnchoredObj &&
1176                  ( nStrLen > 0 ||
1177                    ( nStrLen == 0 && GetTxtNode()->GetNumRule() ) )
1178                )
1179             {
1180                 SplitFrm( nEnd );
1181                 nNew |= 3;
1182             }
1183         }
1184         // Wenn sich die Resthoehe geaendert hat, z.B. durch RemoveFtn()
1185         // dann muessen wir auffuellen, um Oszillationen zu vermeiden!
1186         if( bDummy && pBodyFrm &&
1187            nBodyHeight < ( IsVertical() ?
1188                            pBodyFrm->Frm().Width() :
1189                            pBodyFrm->Frm().Height() ) )
1190             rLine.MakeDummyLine();
1191     }
1192 
1193     // In AdjustFrm() stellen wir uns selbst per Grow/Shrink ein,
1194     // in AdjustFollow() stellen wir unseren FolgeFrame ein.
1195 
1196     const SwTwips nDocPrtTop = Frm().Top() + Prt().Top();
1197     const SwTwips nOldHeight = Prt().SSize().Height();
1198     SwTwips nChg = rLine.CalcBottomLine() - nDocPrtTop - nOldHeight;
1199     // --> OD #i84870# - no shrink of text frame, if it only contains one
1200     // as-character anchored object.
1201     if ( nChg < 0 &&
1202          bOnlyContainsAsCharAnchoredObj )
1203     {
1204         nChg = 0;
1205     }
1206     // <--
1207 
1208     // Vertical Formatting:
1209     // The (rotated) repaint rectangle's x coordinate referes to the frame.
1210     // If the frame grows (or shirks) the repaint rectangle cannot simply
1211     // be rotated back after formatting, because we use the upper left point
1212     // of the frame for rotation. This point changes when growing/shrinking.
1213 
1214     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
1215     if ( IsVertical() && !IsVertLR() && nChg )
1216     {
1217         SwRect &rRepaint = *(pPara->GetRepaint());
1218         rRepaint.Left( rRepaint.Left() - nChg );
1219         rRepaint.Width( rRepaint.Width() - nChg );
1220     }
1221 
1222     AdjustFrm( nChg, bHasToFit );
1223 
1224 /*
1225     // FME 16.07.2003 #i16930# - removed this code because it did not
1226     // work correctly. In SwCntntFrm::MakeAll, the frame did not move to the
1227     // next page, instead the print area was recalculated and
1228     // Prepare( PREP_POS_CHGD, (const void*)&bFormatted, sal_False ) invalidated
1229     // the other flags => loop
1230 
1231     // OD 04.04.2003 #108446# - handle special case:
1232     // If text frame contains no content and just has split, because of a
1233     // line stop, it has to move forward. To force this forward move without
1234     // unnecessary formatting of its footnotes and its follow, especially in
1235     // columned sections, adjust frame height to zero (0) and do not perform
1236     // the intrinsic format of the follow.
1237     // The formating method <SwCntntFrm::MakeAll()> will initiate the move forward.
1238     sal_Bool bForcedNoIntrinsicFollowCalc = sal_False;
1239     if ( nEnd == 0 &&
1240          rLine.IsStop() && HasFollow() && nNew == 1
1241        )
1242     {
1243         AdjustFrm( -Frm().SSize().Height(), bHasToFit );
1244         Prt().Pos().Y() = 0;
1245         Prt().Height( Frm().Height() );
1246         if ( FollowFormatAllowed() )
1247         {
1248             bForcedNoIntrinsicFollowCalc = sal_True;
1249             ForbidFollowFormat();
1250         }
1251     }
1252     else
1253     {
1254         AdjustFrm( nChg, bHasToFit );
1255     }
1256  */
1257 
1258     if( HasFollow() || IsInFtn() )
1259         _AdjustFollow( rLine, nEnd, nStrLen, nNew );
1260 
1261     // FME 16.07.2003 #i16930# - removed this code because it did not work
1262     // correctly
1263     // OD 04.04.2003 #108446# - allow intrinsic format of follow, if above
1264     // special case has forbit it.
1265 /*    if ( bForcedNoIntrinsicFollowCalc )
1266     {
1267         AllowFollowFormat();
1268     }
1269  */
1270 
1271     pPara->SetPrepMustFit( sal_False );
1272 
1273     UNDO_SWAP( this )
1274 }
1275 
1276 /*************************************************************************
1277  *                      SwTxtFrm::FormatLine()
1278  *************************************************************************/
1279 
1280 // bPrev zeigt an, ob Reformat.Start() wegen Prev() vorgezogen wurde.
1281 // Man weiss sonst nicht, ob man Repaint weiter einschraenken kann oder nicht.
1282 
1283 
1284 sal_Bool SwTxtFrm::FormatLine( SwTxtFormatter &rLine, const sal_Bool bPrev )
1285 {
1286     ASSERT( ! IsVertical() || IsSwapped(),
1287             "SwTxtFrm::FormatLine( rLine, bPrev) with unswapped frame" );
1288     SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1289     // Nach rLine.FormatLine() haelt nStart den neuen Wert,
1290     // waehrend in pOldStart der alte Offset gepflegt wird.
1291     // Ueber diesen Weg soll das nDelta ersetzt werden.
1292     // *pOldStart += rLine.GetCurr()->GetLen();
1293     const SwLineLayout *pOldCur = rLine.GetCurr();
1294     const xub_StrLen nOldLen    = pOldCur->GetLen();
1295     const KSHORT nOldAscent = pOldCur->GetAscent();
1296     const KSHORT nOldHeight = pOldCur->Height();
1297     const SwTwips nOldWidth = pOldCur->Width() + pOldCur->GetHangingMargin();
1298     const sal_Bool bOldHyph = pOldCur->IsEndHyph();
1299     SwTwips nOldTop = 0;
1300     SwTwips nOldBottom = 0;
1301     if( rLine.GetCurr()->IsClipping() )
1302         rLine.CalcUnclipped( nOldTop, nOldBottom );
1303 
1304     const xub_StrLen nNewStart = rLine.FormatLine( rLine.GetStart() );
1305 
1306     ASSERT( Frm().Pos().Y() + Prt().Pos().Y() == rLine.GetFirstPos(),
1307             "SwTxtFrm::FormatLine: frame leaves orbit." );
1308     ASSERT( rLine.GetCurr()->Height(),
1309             "SwTxtFrm::FormatLine: line height is zero" );
1310 
1311     // Das aktuelle Zeilenumbruchobjekt.
1312     const SwLineLayout *pNew = rLine.GetCurr();
1313 
1314     sal_Bool bUnChg = nOldLen == pNew->GetLen() &&
1315                   bOldHyph == pNew->IsEndHyph();
1316     if ( bUnChg && !bPrev )
1317     {
1318         // 6672: Toleranz von SLOPPY_TWIPS (5 Twips); vgl. 6922
1319         const long nWidthDiff = nOldWidth > pNew->Width()
1320                                 ? nOldWidth - pNew->Width()
1321                                 : pNew->Width() - nOldWidth;
1322 
1323         // we only declare a line as unchanged, if its main values have not
1324         // changed and it is not the last line (!paragraph end symbol!)
1325         bUnChg = nOldHeight == pNew->Height() &&
1326                  nOldAscent == pNew->GetAscent() &&
1327                  nWidthDiff <= SLOPPY_TWIPS &&
1328                  pOldCur->GetNext();
1329     }
1330 
1331     // rRepaint wird berechnet:
1332     const SwTwips nBottom = rLine.Y() + rLine.GetLineHeight();
1333     SwRepaint &rRepaint = *(pPara->GetRepaint());
1334     if( bUnChg && rRepaint.Top() == rLine.Y()
1335                && (bPrev || nNewStart <= pPara->GetReformat()->Start())
1336                && ( nNewStart < GetTxtNode()->GetTxt().Len() ) )
1337     {
1338         rRepaint.Top( nBottom );
1339         rRepaint.Height( 0 );
1340     }
1341     else
1342     {
1343         if( nOldTop )
1344         {
1345             if( nOldTop < rRepaint.Top() )
1346                 rRepaint.Top( nOldTop );
1347             if( !rLine.IsUnclipped() || nOldBottom > rRepaint.Bottom() )
1348             {
1349                 rRepaint.Bottom( nOldBottom - 1 );
1350                 rLine.SetUnclipped( sal_True );
1351             }
1352         }
1353         if( rLine.GetCurr()->IsClipping() && rLine.IsFlyInCntBase() )
1354         {
1355             SwTwips nTmpTop, nTmpBottom;
1356             rLine.CalcUnclipped( nTmpTop, nTmpBottom );
1357             if( nTmpTop < rRepaint.Top() )
1358                 rRepaint.Top( nTmpTop );
1359             if( !rLine.IsUnclipped() || nTmpBottom > rRepaint.Bottom() )
1360             {
1361                 rRepaint.Bottom( nTmpBottom - 1 );
1362                 rLine.SetUnclipped( sal_True );
1363             }
1364         }
1365         else
1366         {
1367             if( !rLine.IsUnclipped() || nBottom > rRepaint.Bottom() )
1368             {
1369                 rRepaint.Bottom( nBottom - 1 );
1370                 rLine.SetUnclipped( sal_False );
1371             }
1372         }
1373         SwTwips nRght = Max( nOldWidth, pNew->Width() +
1374                              pNew->GetHangingMargin() );
1375         ViewShell *pSh = getRootFrm()->GetCurrShell();
1376         const SwViewOption *pOpt = pSh ? pSh->GetViewOptions() : 0;
1377         if( pOpt && (pOpt->IsParagraph() || pOpt->IsLineBreak()) )
1378             nRght += ( Max( nOldAscent, pNew->GetAscent() ) );
1379         else
1380             nRght += ( Max( nOldAscent, pNew->GetAscent() ) / 4);
1381         nRght += rLine.GetLeftMargin();
1382         if( rRepaint.GetOfst() || rRepaint.GetRightOfst() < nRght )
1383             rRepaint.SetRightOfst( nRght );
1384 
1385         // Finally we enlarge the repaint rectangle if we found an underscore
1386         // within our line. 40 Twips should be enough
1387         const sal_Bool bHasUnderscore =
1388                 ( rLine.GetInfo().GetUnderScorePos() < nNewStart );
1389         if ( bHasUnderscore || rLine.GetCurr()->HasUnderscore() )
1390             rRepaint.Bottom( rRepaint.Bottom() + 40 );
1391 
1392         ((SwLineLayout*)rLine.GetCurr())->SetUnderscore( bHasUnderscore );
1393     }
1394     if( !bUnChg )
1395         rLine.SetChanges();
1396 
1397     // Die gute, alte nDelta-Berechnung:
1398     *(pPara->GetDelta()) -= long(pNew->GetLen()) - long(nOldLen);
1399 
1400     // Stop!
1401     if( rLine.IsStop() )
1402         return sal_False;
1403 
1404     // Unbedingt noch eine Zeile
1405     if( rLine.IsNewLine() )
1406         return sal_True;
1407 
1408     // bis zum Ende des Strings ?
1409     if( nNewStart >= GetTxtNode()->GetTxt().Len() )
1410         return sal_False;
1411 
1412     if( rLine.GetInfo().IsShift() )
1413         return sal_True;
1414 
1415     // Ende des Reformats erreicht ?
1416     const xub_StrLen nEnd = pPara->GetReformat()->Start() +
1417                         pPara->GetReformat()->Len();
1418 
1419     if( nNewStart <= nEnd )
1420         return sal_True;
1421 
1422     return 0 != *(pPara->GetDelta());
1423 }
1424 
1425 /*************************************************************************
1426  *                      SwTxtFrm::_Format()
1427  *************************************************************************/
1428 
1429 void SwTxtFrm::_Format( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf,
1430                         const sal_Bool bAdjust )
1431 {
1432     ASSERT( ! IsVertical() || IsSwapped(),"SwTxtFrm::_Format with unswapped frame" );
1433 
1434     SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1435     rLine.SetUnclipped( sal_False );
1436 
1437     // Das war dem C30 zu kompliziert: aString( GetTxt() );
1438     const XubString &rString = GetTxtNode()->GetTxt();
1439     const xub_StrLen nStrLen = rString.Len();
1440 
1441     SwCharRange &rReformat = *(pPara->GetReformat());
1442     SwRepaint   &rRepaint = *(pPara->GetRepaint());
1443     SwRepaint *pFreeze = NULL;
1444 
1445     // Aus Performancegruenden wird in Init() rReformat auf STRING_LEN gesetzt.
1446     // Fuer diesen Fall wird rReformat angepasst.
1447     if( rReformat.Len() > nStrLen )
1448         rReformat.Len() = nStrLen;
1449 
1450     // Optimiert:
1451     xub_StrLen nEnd = rReformat.Start() + rReformat.Len();
1452     if( nEnd > nStrLen )
1453     {
1454         rReformat.Len() = nStrLen - rReformat.Start();
1455         nEnd = nStrLen;
1456     }
1457 
1458     SwTwips nOldBottom;
1459     if( GetOfst() && !IsFollow() )
1460     {
1461         rLine.Bottom();
1462         nOldBottom = rLine.Y();
1463         rLine.Top();
1464     }
1465     else
1466         nOldBottom = 0;
1467     rLine.CharToLine( rReformat.Start() );
1468 
1469     // Worte koennen durch Fortfall oder Einfuegen eines Space
1470     // auf die Zeile vor der editierten hinausgezogen werden,
1471     // deshalb muss diese ebenfalls formatiert werden.
1472     // Optimierung: Wenn rReformat erst hinter dem ersten Wort der
1473     // Zeile beginnt, so kann diese Zeile die vorige nicht mehr beeinflussen.
1474     // AMA: Leider doch, Textgroessenaenderungen + FlyFrames, die Rueckwirkung
1475     // kann im Extremfall mehrere Zeilen (Frames!!!) betreffen!
1476 
1477     // --> FME 2005-04-18 #i46560#
1478     // FME: Yes, consider this case: (word ) has to go to the next line
1479     // because ) is a forbidden character at the beginning of a line although
1480     // (word would still fit on the previous line. Adding text right in front
1481     // of ) would not trigger a reformatting of the previous line. Adding 1
1482     // to the result of FindBrk() does not solve the problem in all cases,
1483     // nevertheless it should be sufficient.
1484     // <--
1485     sal_Bool bPrev = rLine.GetPrev() &&
1486                      ( FindBrk( rString, rLine.GetStart(), rReformat.Start() + 1 )
1487                        // --> FME 2005-04-18 #i46560#
1488                        + 1
1489                        // <--
1490                        >= rReformat.Start() ||
1491                        rLine.GetCurr()->IsRest() );
1492     if( bPrev )
1493     {
1494         while( rLine.Prev() )
1495             if( rLine.GetCurr()->GetLen() && !rLine.GetCurr()->IsRest() )
1496             {
1497                 if( !rLine.GetStart() )
1498                     rLine.Top(); // damit NumDone nicht durcheinander kommt
1499                 break;
1500             }
1501         xub_StrLen nNew = rLine.GetStart() + rLine.GetLength();
1502         if( nNew )
1503         {
1504             --nNew;
1505             if( CH_BREAK == rString.GetChar( nNew ) )
1506             {
1507                 ++nNew;
1508                 rLine.Next();
1509                 bPrev = sal_False;
1510             }
1511         }
1512         rReformat.Len()  += rReformat.Start() - nNew;
1513         rReformat.Start() = nNew;
1514     }
1515 
1516     rRepaint.SetOfst( 0 );
1517     rRepaint.SetRightOfst( 0 );
1518     rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() );
1519     if( pPara->IsMargin() )
1520         rRepaint.Width( rRepaint.Width() + pPara->GetHangingMargin() );
1521     rRepaint.Top( rLine.Y() );
1522     // 6792: Rrand < LRand und Repaint
1523     if( 0 >= rRepaint.Width() )
1524         rRepaint.Width(1);
1525     WidowsAndOrphans aFrmBreak( this, rInf.IsTest() ? 1 : 0 );
1526 
1527     // rLine steht jetzt auf der ersten Zeile, die formatiert werden
1528     // muss. Das Flag bFirst sorgt dafuer, dass nicht Next() gerufen wird.
1529     // Das ganze sieht verdreht aus, aber es muss sichergestellt werden,
1530     // dass bei IsBreakNow rLine auf der Zeile zum stehen kommt, die
1531     // nicht mehr passt.
1532     sal_Bool bFirst  = sal_True;
1533     sal_Bool bFormat = sal_True;
1534 
1535     // 5383: Das CharToLine() kann uns auch in den roten Bereich fuehren.
1536     // In diesem Fall muessen wir zurueckwandern, bis die Zeile, die
1537     // nicht mehr passt in rLine eingestellt ist. Ansonsten geht Textmasse
1538     // verloren, weil der Ofst im Follow falsch eingestellt wird.
1539 
1540     // OD 2004-02-25 #i16128# - method renamed
1541     sal_Bool bBreak = ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 )
1542                     && aFrmBreak.IsBreakNowWidAndOrp( rLine );
1543     if( bBreak )
1544     {
1545         sal_Bool bPrevDone = 0 != rLine.Prev();
1546         // OD 2004-02-25 #i16128# - method renamed
1547         while( bPrevDone && aFrmBreak.IsBreakNowWidAndOrp(rLine) )
1548             bPrevDone = 0 != rLine.Prev();
1549         if( bPrevDone )
1550         {
1551             aFrmBreak.SetKeep( sal_False );
1552             rLine.Next();
1553         }
1554         rLine.TruncLines();
1555 
1556         // auf Nummer sicher:
1557         // OD 2004-02-25 #i16128# - method renamed
1558         bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine) &&
1559                   ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 );
1560     }
1561 
1562  /* Bedeutung der folgenden Flags:
1563     Ist das Watch(End/Mid)Hyph-Flag gesetzt, so muss formatiert werden, wenn
1564     eine Trennung am (Zeilenende/Fly) vorliegt, sofern MaxHyph erreicht ist.
1565     Das Jump(End/Mid)Flag bedeutet, dass die naechste Zeile, bei der keine
1566     Trennung (Zeilenende/Fly) vorliegt, formatiert werden muss, da jetzt
1567     umgebrochen werden koennte, was vorher moeglicherweise durch MaxHyph
1568     verboten war.
1569     Watch(End/Mid)Hyph wird gesetzt, wenn die letzte formatierte Zeile eine
1570     Trennstelle erhalten hat, vorher aber keine hatte,
1571     Jump(End/Mid)Hyph, wenn eine Trennstelle verschwindet.
1572  */
1573     sal_Bool bJumpEndHyph  = sal_False,
1574          bWatchEndHyph = sal_False,
1575          bJumpMidHyph  = sal_False,
1576          bWatchMidHyph = sal_False;
1577 
1578     const SwAttrSet& rAttrSet = GetTxtNode()->GetSwAttrSet();
1579     sal_Bool bMaxHyph = ( 0 !=
1580         ( rInf.MaxHyph() = rAttrSet.GetHyphenZone().GetMaxHyphens() ) );
1581     if ( bMaxHyph )
1582         rLine.InitCntHyph();
1583 
1584     if( IsFollow() && IsFieldFollow() && rLine.GetStart() == GetOfst() )
1585     {
1586         const SwLineLayout* pLine;
1587         {
1588             SwTxtFrm *pMaster = FindMaster();
1589             ASSERT( pMaster, "SwTxtFrm::Format: homeless follow" );
1590             if( !pMaster->HasPara() )
1591                 pMaster->GetFormatted();
1592             SwTxtSizeInfo aInf( pMaster );
1593             SwTxtIter aMasterLine( pMaster, &aInf );
1594             aMasterLine.Bottom();
1595             pLine = aMasterLine.GetCurr();
1596         }
1597         SwLinePortion* pRest =
1598             rLine.MakeRestPortion( pLine, GetOfst() );
1599         if( pRest )
1600             rInf.SetRest( pRest );
1601         else
1602             SetFieldFollow( sal_False );
1603     }
1604 
1605     /* Zum Abbruchkriterium:
1606      * Um zu erkennen, dass eine Zeile nicht mehr auf die Seite passt,
1607      * muss sie formatiert werden. Dieser Ueberhang wird z.B. in AdjustFollow
1608      * wieder entfernt.
1609      * Eine weitere Komplikation: wenn wir der Master sind, so muessen
1610      * wir die Zeilen durchgehen, da es ja sein kann, dass eine Zeile
1611      * vom Follow in den Master rutschen kann.
1612      */
1613     do
1614     {
1615         DBG_LOOP;
1616         if( bFirst )
1617             bFirst = sal_False;
1618         else
1619         {
1620             if ( bMaxHyph )
1621             {
1622                 if ( rLine.GetCurr()->IsEndHyph() )
1623                     rLine.CntEndHyph()++;
1624                 else
1625                     rLine.CntEndHyph() = 0;
1626                 if ( rLine.GetCurr()->IsMidHyph() )
1627                     rLine.CntMidHyph()++;
1628                 else
1629                     rLine.CntMidHyph() = 0;
1630             }
1631             if( !rLine.Next() )
1632             {
1633                 if( !bFormat )
1634                 {
1635                     SwLinePortion* pRest =
1636                         rLine.MakeRestPortion( rLine.GetCurr(), rLine.GetEnd() );
1637                     if( pRest )
1638                         rInf.SetRest( pRest );
1639                 }
1640                 rLine.Insert( new SwLineLayout() );
1641                 rLine.Next();
1642                 bFormat = sal_True;
1643             }
1644         }
1645         if ( !bFormat && bMaxHyph &&
1646               (bWatchEndHyph || bJumpEndHyph || bWatchMidHyph || bJumpMidHyph) )
1647         {
1648             if ( rLine.GetCurr()->IsEndHyph() )
1649             {
1650                 if ( bWatchEndHyph )
1651                     bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() );
1652             }
1653             else
1654             {
1655                 bFormat = bJumpEndHyph;
1656                 bWatchEndHyph = sal_False;
1657                 bJumpEndHyph = sal_False;
1658             }
1659             if ( rLine.GetCurr()->IsMidHyph() )
1660             {
1661                 if ( bWatchMidHyph && !bFormat )
1662                     bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() );
1663             }
1664             else
1665             {
1666                 bFormat = bFormat || bJumpMidHyph;
1667                 bWatchMidHyph = sal_False;
1668                 bJumpMidHyph = sal_False;
1669             }
1670         }
1671         if( bFormat )
1672         {
1673             sal_Bool bOldEndHyph = rLine.GetCurr()->IsEndHyph();
1674             sal_Bool bOldMidHyph = rLine.GetCurr()->IsMidHyph();
1675             bFormat = FormatLine( rLine, bPrev );
1676             //9334: Es kann nur ein bPrev geben... (???)
1677             bPrev = sal_False;
1678             if ( bMaxHyph )
1679             {
1680                 if ( rLine.GetCurr()->IsEndHyph() != bOldEndHyph )
1681                 {
1682                     bWatchEndHyph = !bOldEndHyph;
1683                     bJumpEndHyph = bOldEndHyph;
1684                 }
1685                 if ( rLine.GetCurr()->IsMidHyph() != bOldMidHyph )
1686                 {
1687                     bWatchMidHyph = !bOldMidHyph;
1688                     bJumpMidHyph = bOldMidHyph;
1689                 }
1690             }
1691         }
1692 
1693         if( !rInf.IsNewLine() )
1694         {
1695             if( !bFormat )
1696                  bFormat = 0 != rInf.GetRest();
1697             if( rInf.IsStop() || rInf.GetIdx() >= nStrLen )
1698                 break;
1699             if( !bFormat && ( !bMaxHyph || ( !bWatchEndHyph &&
1700                     !bJumpEndHyph && !bWatchMidHyph && !bJumpMidHyph ) ) )
1701             {
1702                 if( GetFollow() )
1703                 {
1704                     while( rLine.Next() )
1705                         ; //Nothing
1706                     pFreeze = new SwRepaint( rRepaint ); // to minimize painting
1707                 }
1708                 else
1709                     break;
1710             }
1711         }
1712         // OD 2004-02-25 #i16128# - method renamed
1713         bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine);
1714     }while( !bBreak );
1715 
1716     if( pFreeze )
1717     {
1718         rRepaint = *pFreeze;
1719         delete pFreeze;
1720     }
1721 
1722     if( !rLine.IsStop() )
1723     {
1724         // Wurde aller Text formatiert und gibt es noch weitere
1725         // Zeilenobjekte, dann sind diese jetzt ueberfluessig,
1726         // weil der Text kuerzer geworden ist.
1727         if( rLine.GetStart() + rLine.GetLength() >= nStrLen &&
1728             rLine.GetCurr()->GetNext() )
1729         {
1730             rLine.TruncLines();
1731             rLine.SetTruncLines( sal_True );
1732         }
1733     }
1734 
1735     if( !rInf.IsTest() )
1736     {
1737         // Bei OnceMore lohnt sich kein FormatAdjust
1738         if( bAdjust || !rLine.GetDropFmt() || !rLine.CalcOnceMore() )
1739         {
1740             FormatAdjust( rLine, aFrmBreak, nStrLen, rInf.IsStop() );
1741         }
1742         if( rRepaint.HasArea() )
1743             SetRepaint();
1744         rLine.SetTruncLines( sal_False );
1745         if( nOldBottom )                    // Bei "gescollten" Absaetzen wird
1746         {                                   // noch ueberprueft, ob durch Schrumpfen
1747             rLine.Bottom();                 // das Scrolling ueberfluessig wurde.
1748             SwTwips nNewBottom = rLine.Y();
1749             if( nNewBottom < nOldBottom )
1750                 _SetOfst( 0 );
1751         }
1752     }
1753 }
1754 
1755 /*************************************************************************
1756  *                      SwTxtFrm::Format()
1757  *************************************************************************/
1758 
1759 void SwTxtFrm::FormatOnceMore( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf )
1760 {
1761     ASSERT( ! IsVertical() || IsSwapped(),
1762             "A frame is not swapped in SwTxtFrm::FormatOnceMore" );
1763 
1764     SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1765     if( !pPara )
1766         return;
1767 
1768     // ggf gegen pPara
1769     KSHORT nOld  = ((const SwTxtMargin&)rLine).GetDropHeight();
1770     sal_Bool bShrink = sal_False,
1771          bGrow   = sal_False,
1772          bGoOn   = rLine.IsOnceMore();
1773     sal_uInt8 nGo    = 0;
1774     while( bGoOn )
1775     {
1776 #ifdef DBGTXT
1777         aDbstream << "OnceMore!" << endl;
1778 #endif
1779         ++nGo;
1780         rInf.Init();
1781         rLine.Top();
1782         if( !rLine.GetDropFmt() )
1783             rLine.SetOnceMore( sal_False );
1784         SwCharRange aRange( 0, rInf.GetTxt().Len() );
1785         *(pPara->GetReformat()) = aRange;
1786         _Format( rLine, rInf );
1787 
1788         bGoOn = rLine.IsOnceMore();
1789         if( bGoOn )
1790         {
1791             const KSHORT nNew = ((const SwTxtMargin&)rLine).GetDropHeight();
1792             if( nOld == nNew )
1793                 bGoOn = sal_False;
1794             else
1795             {
1796                 if( nOld > nNew )
1797                     bShrink = sal_True;
1798                 else
1799                     bGrow = sal_True;
1800 
1801                 if( bShrink == bGrow || 5 < nGo )
1802                     bGoOn = sal_False;
1803 
1804                 nOld = nNew;
1805             }
1806 
1807             // 6107: Wenn was schief ging, muss noch einmal formatiert werden.
1808             if( !bGoOn )
1809             {
1810                 rInf.CtorInitTxtFormatInfo( this );
1811                 rLine.CtorInitTxtFormatter( this, &rInf );
1812                 rLine.SetDropLines( 1 );
1813                 rLine.CalcDropHeight( 1 );
1814                 SwCharRange aTmpRange( 0, rInf.GetTxt().Len() );
1815                 *(pPara->GetReformat()) = aTmpRange;
1816                 _Format( rLine, rInf, sal_True );
1817                 // 8047: Wir painten alles...
1818                 SetCompletePaint();
1819             }
1820         }
1821     }
1822 }
1823 
1824 /*************************************************************************
1825  *                      SwTxtFrm::_Format()
1826  *************************************************************************/
1827 
1828 
1829 void SwTxtFrm::_Format( SwParaPortion *pPara )
1830 {
1831     const xub_StrLen nStrLen = GetTxt().Len();
1832 
1833     // AMA: Wozu soll das gut sein? Scheint mir zuoft zu einem kompletten
1834     // Formatieren und Repainten zu fuehren???
1835 //  if ( !(*pPara->GetDelta()) )
1836 //      *(pPara->GetDelta()) = nStrLen;
1837 //  else
1838     if ( !nStrLen )
1839     {
1840         // Leere Zeilen werden nicht lange gequaelt:
1841         // pPara wird blank geputzt
1842         // entspricht *pPara = SwParaPortion;
1843         sal_Bool bMustFit = pPara->IsPrepMustFit();
1844         pPara->Truncate();
1845         pPara->FormatReset();
1846         if( pBlink && pPara->IsBlinking() )
1847             pBlink->Delete( pPara );
1848 
1849         // delete pSpaceAdd und pKanaComp
1850         pPara->FinishSpaceAdd();
1851         pPara->FinishKanaComp();
1852         pPara->ResetFlags();
1853         pPara->SetPrepMustFit( bMustFit );
1854     }
1855 
1856     ASSERT( ! IsSwapped(), "A frame is swapped before _Format" );
1857 
1858     if ( IsVertical() )
1859         SwapWidthAndHeight();
1860 
1861     SwTxtFormatInfo aInf( this );
1862     SwTxtFormatter  aLine( this, &aInf );
1863 
1864     // OD 2004-01-15 #110582#
1865     HideAndShowObjects();
1866 
1867     _Format( aLine, aInf );
1868 
1869     if( aLine.IsOnceMore() )
1870         FormatOnceMore( aLine, aInf );
1871 
1872     if ( IsVertical() )
1873         SwapWidthAndHeight();
1874 
1875     ASSERT( ! IsSwapped(), "A frame is swapped after _Format" );
1876 
1877     if( 1 < aLine.GetDropLines() )
1878     {
1879         if( SVX_ADJUST_LEFT != aLine.GetAdjust() &&
1880             SVX_ADJUST_BLOCK != aLine.GetAdjust() )
1881         {
1882             aLine.CalcDropAdjust();
1883             aLine.SetPaintDrop( sal_True );
1884         }
1885 
1886         if( aLine.IsPaintDrop() )
1887         {
1888             aLine.CalcDropRepaint();
1889             aLine.SetPaintDrop( sal_False );
1890         }
1891     }
1892 }
1893 
1894 /*************************************************************************
1895  *                      SwTxtFrm::Format()
1896  *************************************************************************/
1897 
1898 /*
1899  * Format berechnet die Groesse des Textframes und ruft, wenn
1900  * diese feststeht, Shrink() oder Grow(), um die Framegroesse dem
1901  * evtl. veraenderten Platzbedarf anzupassen.
1902  */
1903 
1904 void SwTxtFrm::Format( const SwBorderAttrs * )
1905 {
1906     DBG_LOOP;
1907 #if OSL_DEBUG_LEVEL > 1
1908     const XubString aXXX = GetTxtNode()->GetTxt();
1909     const SwTwips nDbgY = Frm().Top();
1910     (void)nDbgY;
1911     const SwPageFrm *pDbgPage = FindPageFrm();
1912     const MSHORT nDbgPageNr = pDbgPage->GetPhyPageNum();
1913     (void)nDbgPageNr;
1914     // Um zu gucken, ob es einen Ftn-Bereich gibt.
1915     const SwFrm *pDbgFtnCont = (const SwFrm*)(FindPageFrm()->FindFtnCont());
1916     (void)pDbgFtnCont;
1917 
1918 #ifdef DBG_UTIL
1919     // nStopAt laesst sich vom CV bearbeiten.
1920     static MSHORT nStopAt = 0;
1921     if( nStopAt == GetFrmId() )
1922     {
1923         int i = GetFrmId();
1924         (void)i;
1925     }
1926 #endif
1927 #endif
1928 
1929 #ifdef DEBUG_FTN
1930     //Fussnote darf nicht auf einer Seite vor ihrer Referenz stehen.
1931     if( IsInFtn() )
1932     {
1933         const SwFtnFrm *pFtn = (SwFtnFrm*)GetUpper();
1934         const SwPageFrm *pFtnPage = pFtn->GetRef()->FindPageFrm();
1935         const MSHORT nFtnPageNr = pFtnPage->GetPhyPageNum();
1936         if( !IsLocked() )
1937         {
1938             if( nFtnPageNr > nDbgPageNr )
1939             {
1940                 SwTxtFrmLocker aLock(this);
1941                 ASSERT( nFtnPageNr <= nDbgPageNr, "!Ftn steht vor der Referenz." );
1942                 MSHORT i = 0;
1943             }
1944         }
1945     }
1946 #endif
1947 
1948     SWRECTFN( this )
1949 
1950     // --> OD 2008-01-31 #newlistlevelattrs#
1951     CalcAdditionalFirstLineOffset();
1952     // <--
1953 
1954     // Vom Berichtsautopiloten oder ueber die BASIC-Schnittstelle kommen
1955     // gelegentlich TxtFrms mit einer Breite <=0.
1956     if( (Prt().*fnRect->fnGetWidth)() <= 0 )
1957     {
1958         // Wenn MustFit gesetzt ist, schrumpfen wir ggf. auf die Unterkante
1959         // des Uppers, ansonsten nehmen wir einfach eine Standardgroesse
1960         // von 12 Pt. ein (240 Twip).
1961         SwTxtLineAccess aAccess( this );
1962         long nFrmHeight = (Frm().*fnRect->fnGetHeight)();
1963         if( aAccess.GetPara()->IsPrepMustFit() )
1964         {
1965             const SwTwips nLimit = (GetUpper()->*fnRect->fnGetPrtBottom)();
1966             const SwTwips nDiff = - (Frm().*fnRect->fnBottomDist)( nLimit );
1967             if( nDiff > 0 )
1968                 Shrink( nDiff );
1969         }
1970         else if( 240 < nFrmHeight )
1971             Shrink( nFrmHeight - 240 );
1972         else if( 240 > nFrmHeight )
1973             Grow( 240 - nFrmHeight );
1974         nFrmHeight = (Frm().*fnRect->fnGetHeight)();
1975 
1976         long nTop = (this->*fnRect->fnGetTopMargin)();
1977         if( nTop > nFrmHeight )
1978             (this->*fnRect->fnSetYMargins)( nFrmHeight, 0 );
1979         else if( (Prt().*fnRect->fnGetHeight)() < 0 )
1980             (Prt().*fnRect->fnSetHeight)( 0 );
1981         return;
1982     }
1983 
1984     const xub_StrLen nStrLen = GetTxtNode()->GetTxt().Len();
1985     if ( nStrLen || !FormatEmpty() )
1986     {
1987 
1988         SetEmpty( sal_False );
1989         // Um nicht durch verschachtelte Formats irritiert zu werden.
1990         FormatLevel aLevel;
1991         if( 12 == aLevel.GetLevel() )
1992             return;
1993 
1994         // Die Formatinformationen duerfen u.U. nicht veraendert werden.
1995         if( IsLocked() )
1996             return;
1997 
1998         // 8708: Vorsicht, das Format() kann auch durch GetFormatted()
1999         // angestossen werden.
2000         if( IsHiddenNow() )
2001         {
2002             long nPrtHeight = (Prt().*fnRect->fnGetHeight)();
2003             if( nPrtHeight )
2004             {
2005                 HideHidden();
2006                 Shrink( nPrtHeight );
2007             }
2008             else
2009             {
2010                 // OD 2004-01-20 #110582# - assure that objects anchored
2011                 // at paragraph resp. at/as character inside paragraph
2012                 // are hidden.
2013                 HideAndShowObjects();
2014             }
2015             ChgThisLines();
2016             return;
2017         }
2018 
2019         // Waehrend wir formatieren, wollen wir nicht gestoert werden.
2020         SwTxtFrmLocker aLock(this);
2021         SwTxtLineAccess aAccess( this );
2022         const sal_Bool bNew = !aAccess.SwTxtLineAccess::IsAvailable();
2023         const sal_Bool bSetOfst = ( GetOfst() && GetOfst() > GetTxtNode()->GetTxt().Len() );
2024 
2025         if( CalcPreps() )
2026             ; // nothing
2027         // Wir returnen, wenn schon formatiert wurde, nicht aber, wenn
2028         // der TxtFrm gerade erzeugt wurde und ueberhaupt keine Format-
2029         // informationen vorliegen.
2030         else if( !bNew && !aAccess.GetPara()->GetReformat()->Len() )
2031         {
2032             if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
2033             {
2034                 aAccess.GetPara()->SetPrepAdjust( sal_True );
2035                 aAccess.GetPara()->SetPrep( sal_True );
2036                 CalcPreps();
2037             }
2038             SetWidow( sal_False );
2039         }
2040         else if( bSetOfst && IsFollow() )
2041         {
2042             SwTxtFrm *pMaster = FindMaster();
2043             ASSERT( pMaster, "SwTxtFrm::Format: homeless follow" );
2044             if( pMaster )
2045                 pMaster->Prepare( PREP_FOLLOW_FOLLOWS );
2046             SwTwips nMaxY = (GetUpper()->*fnRect->fnGetPrtBottom)();
2047             if( (Frm().*fnRect->fnOverStep)( nMaxY  ) )
2048                 (this->*fnRect->fnSetLimit)( nMaxY );
2049             else if( (Frm().*fnRect->fnBottomDist)( nMaxY  ) < 0 )
2050                 (Frm().*fnRect->fnAddBottom)( -(Frm().*fnRect->fnGetHeight)() );
2051         }
2052         else
2053         {
2054             // bSetOfst here means that we have the "red arrow situation"
2055             if ( bSetOfst )
2056                 _SetOfst( 0 );
2057 
2058             const sal_Bool bOrphan = IsWidow();
2059             const SwFtnBossFrm* pFtnBoss = HasFtn() ? FindFtnBossFrm() : 0;
2060             SwTwips nFtnHeight = 0;
2061             if( pFtnBoss )
2062             {
2063                 const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont();
2064                 nFtnHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0;
2065             }
2066             do
2067             {
2068                 _Format( aAccess.GetPara() );
2069                 if( pFtnBoss && nFtnHeight )
2070                 {
2071                     const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont();
2072                     SwTwips nNewHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0;
2073                     // If we lost some footnotes, we may have more space
2074                     // for our main text, so we have to format again ...
2075                     if( nNewHeight < nFtnHeight )
2076                         nFtnHeight = nNewHeight;
2077                     else
2078                         break;
2079                 }
2080                 else
2081                     break;
2082             } while ( pFtnBoss );
2083             if( bOrphan )
2084             {
2085                 ValidateFrm();
2086                 SetWidow( sal_False );
2087             }
2088         }
2089         if( IsEmptyMaster() )
2090         {
2091             SwFrm* pPre = GetPrev();
2092             if( pPre &&
2093                 // --> FME 2004-07-22 #i10826# It's the first, it cannot keep!
2094                 pPre->GetIndPrev() &&
2095                 // <--
2096                 pPre->GetAttrSet()->GetKeep().GetValue() )
2097             {
2098                 pPre->InvalidatePos();
2099             }
2100         }
2101     }
2102 
2103     ChgThisLines();
2104 
2105     // the PrepMustFit should not survive a Format operation
2106     SwParaPortion *pPara = GetPara();
2107     if ( pPara )
2108         pPara->SetPrepMustFit( sal_False );
2109 
2110 #if OSL_DEBUG_LEVEL > 1
2111     // Hier ein Instrumentarium, um ungewoehnlichen Master/Follow-Kombinationen,
2112     // insbesondere bei Fussnoten, auf die Schliche zu kommen
2113     if( IsFollow() || GetFollow() )
2114     {
2115         SwTxtFrm *pTmpFrm = IsFollow() ? FindMaster() : this;
2116         const SwPageFrm *pTmpPage = pTmpFrm->FindPageFrm();
2117         MSHORT nPgNr = pTmpPage->GetPhyPageNum();
2118         MSHORT nLast;
2119         MSHORT nDummy = 0; // nur zum Breakpoint setzen
2120         while( pTmpFrm->GetFollow() )
2121         {
2122             pTmpFrm = pTmpFrm->GetFollow();
2123             nLast = nPgNr;
2124             pTmpPage = pTmpFrm->FindPageFrm();
2125             nPgNr = pTmpPage->GetPhyPageNum();
2126             if( nLast > nPgNr )
2127                 ++nDummy; // schon fast eine Assertion wert
2128             else if( nLast == nPgNr )
2129                 ++nDummy; // bei Spalten voellig normal, aber sonst!?
2130             else if( nLast < nPgNr - 1 )
2131                 ++nDummy; // kann schon mal temporaer vorkommen
2132         }
2133     }
2134 #endif
2135 
2136     CalcBaseOfstForFly();
2137     // OD 2004-03-17 #i11860#
2138     _CalcHeightOfLastLine();
2139 }
2140 
2141 /*************************************************************************
2142  *                      SwTxtFrm::FormatQuick()
2143  *
2144  * bForceQuickFormat is set if GetFormatted() has been called during the
2145  * painting process. Actually I cannot imagine a situation which requires
2146  * a full formatting of the paragraph during painting, on the other hand
2147  * a full formatting can cause the invalidation of other layout frames,
2148  * e.g., if there are footnotes in this paragraph, and invalid layout
2149  * frames will not calculated during the painting. So I actually want to
2150  * avoid a formatting during painting, but since I'm a coward, I'll only
2151  * force the quick formatting in the situation of issue i29062.
2152  *************************************************************************/
2153 
2154 sal_Bool SwTxtFrm::FormatQuick( bool bForceQuickFormat )
2155 {
2156     ASSERT( ! IsVertical() || ! IsSwapped(),
2157             "SwTxtFrm::FormatQuick with swapped frame" );
2158 
2159     DBG_LOOP;
2160 #if OSL_DEBUG_LEVEL > 1
2161     const XubString aXXX = GetTxtNode()->GetTxt();
2162     const SwTwips nDbgY = Frm().Top();
2163     (void)nDbgY;
2164 #ifdef DBG_UTIL
2165     // nStopAt laesst sich vom CV bearbeiten.
2166     static MSHORT nStopAt = 0;
2167     if( nStopAt == GetFrmId() )
2168     {
2169         int i = GetFrmId();
2170         (void)i;
2171     }
2172 #endif
2173 #endif
2174 
2175     if( IsEmpty() && FormatEmpty() )
2176         return sal_True;
2177 
2178     // Wir sind sehr waehlerisch:
2179     if( HasPara() || IsWidow() || IsLocked()
2180         || !GetValidSizeFlag() ||
2181         ( ( IsVertical() ? Prt().Width() : Prt().Height() ) && IsHiddenNow() ) )
2182         return sal_False;
2183 
2184     SwTxtLineAccess aAccess( this );
2185     SwParaPortion *pPara = aAccess.GetPara();
2186     if( !pPara )
2187         return sal_False;
2188 
2189     SwFrmSwapper aSwapper( this, sal_True );
2190 
2191     SwTxtFrmLocker aLock(this);
2192     SwTxtFormatInfo aInf( this, sal_False, sal_True );
2193     if( 0 != aInf.MaxHyph() )   // 27483: MaxHyphen beachten!
2194         return sal_False;
2195 
2196     SwTxtFormatter  aLine( this, &aInf );
2197 
2198     // DropCaps sind zu kompliziert...
2199     if( aLine.GetDropFmt() )
2200         return sal_False;
2201 
2202     xub_StrLen nStart = GetOfst();
2203     const xub_StrLen nEnd = GetFollow()
2204                       ? GetFollow()->GetOfst() : aInf.GetTxt().Len();
2205     do
2206     {
2207         //DBG_LOOP; shadows declaration above.
2208         //resolved into:
2209 #if OSL_DEBUG_LEVEL > 1
2210 #ifdef DBG_UTIL
2211         DbgLoop aDbgLoop2( (const void*) this );
2212 #endif
2213 #endif
2214         nStart = aLine.FormatLine( nStart );
2215         if( aInf.IsNewLine() || (!aInf.IsStop() && nStart < nEnd) )
2216             aLine.Insert( new SwLineLayout() );
2217     } while( aLine.Next() );
2218 
2219     // Last exit: die Hoehen muessen uebereinstimmen.
2220     Point aTopLeft( Frm().Pos() );
2221     aTopLeft += Prt().Pos();
2222     const SwTwips nNewHeight = aLine.Y() + aLine.GetLineHeight();
2223     const SwTwips nOldHeight = aTopLeft.Y() + Prt().Height();
2224 
2225     if( !bForceQuickFormat && nNewHeight != nOldHeight && !IsUndersized() )
2226     {
2227         // Achtung: Durch FormatLevel==12 kann diese Situation auftreten, don't panic!
2228         // ASSERT( nNewHeight == nOldHeight, "!FormatQuick: rosebud" );
2229         const xub_StrLen nStrt = GetOfst();
2230         _InvalidateRange( SwCharRange( nStrt, nEnd - nStrt) );
2231         return sal_False;
2232     }
2233 
2234     if( pFollow && nStart != ((SwTxtFrm*)pFollow)->GetOfst() )
2235         return sal_False; // kann z.B. durch Orphans auftreten (35083,35081)
2236 
2237     // Geschafft, wir sind durch ...
2238 
2239     // Repaint setzen
2240     pPara->GetRepaint()->Pos( aTopLeft );
2241     pPara->GetRepaint()->SSize( Prt().SSize() );
2242 
2243     // Reformat loeschen
2244     *(pPara->GetReformat()) = SwCharRange();
2245     *(pPara->GetDelta()) = 0;
2246 
2247     return sal_True;
2248 }
2249