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