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