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