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