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