xref: /AOO41X/main/sw/source/core/text/widorp.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include "hintids.hxx"
33 
34 #include "layfrm.hxx"
35 #include "ftnboss.hxx"
36 #include "ndtxt.hxx"
37 #include "paratr.hxx"
38 #include <editeng/orphitem.hxx>
39 #include <editeng/widwitem.hxx>
40 #include <editeng/keepitem.hxx>
41 #include <editeng/spltitem.hxx>
42 #include <frmatr.hxx>
43 #include <txtftn.hxx>
44 #include <fmtftn.hxx>
45 #include <rowfrm.hxx>
46 
47 #include "txtcfg.hxx"
48 #include "widorp.hxx"
49 #include "txtfrm.hxx"
50 #include "itrtxt.hxx"
51 #include "sectfrm.hxx"	//SwSectionFrm
52 #include "ftnfrm.hxx"
53 
54 #undef WIDOWTWIPS
55 
56 
57 /*************************************************************************
58  *					inline IsNastyFollow()
59  *************************************************************************/
60 // Ein Follow, der auf der selben Seite steht, wie sein Master ist nasty.
61 inline sal_Bool IsNastyFollow( const SwTxtFrm *pFrm )
62 {
63 	ASSERT(	!pFrm->IsFollow() || !pFrm->GetPrev() ||
64 			((const SwTxtFrm*)pFrm->GetPrev())->GetFollow() == pFrm,
65 			"IsNastyFollow: Was ist denn hier los?" );
66 	return	pFrm->IsFollow() && pFrm->GetPrev();
67 }
68 
69 /*************************************************************************
70  *					SwTxtFrmBreak::SwTxtFrmBreak()
71  *************************************************************************/
72 
73 SwTxtFrmBreak::SwTxtFrmBreak( SwTxtFrm *pNewFrm, const SwTwips nRst )
74     : nRstHeight(nRst), pFrm(pNewFrm)
75 {
76     SWAP_IF_SWAPPED( pFrm )
77     SWRECTFN( pFrm )
78     nOrigin = (pFrm->*fnRect->fnGetPrtTop)();
79     SwSectionFrm* pSct;
80 	bKeep = !pFrm->IsMoveable() || IsNastyFollow( pFrm ) ||
81 			( pFrm->IsInSct() && (pSct=pFrm->FindSctFrm())->Lower()->IsColumnFrm()
82 			  && !pSct->MoveAllowed( pFrm ) ) ||
83 			!pFrm->GetTxtNode()->GetSwAttrSet().GetSplit().GetValue() ||
84 			pFrm->GetTxtNode()->GetSwAttrSet().GetKeep().GetValue();
85 	bBreak = sal_False;
86 
87 	if( !nRstHeight && !pFrm->IsFollow() && pFrm->IsInFtn() && pFrm->HasPara() )
88 	{
89 		nRstHeight = pFrm->GetFtnFrmHeight();
90         nRstHeight += (pFrm->Prt().*fnRect->fnGetHeight)() -
91                       (pFrm->Frm().*fnRect->fnGetHeight)();
92 		if( nRstHeight < 0 )
93 			nRstHeight = 0;
94 	}
95 
96     UNDO_SWAP( pFrm )
97 }
98 
99 /* BP 18.6.93: Widows.
100  * Im Gegensatz zur ersten Implementierung werden die Widows nicht
101  * mehr vorausschauend berechnet, sondern erst beim Formatieren des
102  * gesplitteten Follows festgestellt. Im Master faellt die Widows-
103  * Berechnung also generell weg (nWidows wird manipuliert).
104  * Wenn der Follow feststellt, dass die Widowsregel zutrifft,
105  * verschickt er an seinen Vorgaenger ein Prepare.
106  * Ein besonderes Problem ergibt sich, wenn die Widows zuschlagen,
107  * aber im Master noch ein paar Zeilen zur Verfuegung stehen.
108  *
109  */
110 
111 /*************************************************************************
112  *					SwTxtFrmBreak::IsInside()
113  *************************************************************************/
114 
115 /* BP(22.07.92): Berechnung von Witwen und Waisen.
116  * Die Methode liefert sal_True zurueck, wenn eine dieser Regelung zutrifft.
117  *
118  * Eine Schwierigkeit gibt es im Zusammenhang mit Widows und
119  * unterschiedlichen Formaten zwischen Master- und Folgeframes:
120  * Beispiel: Wenn die erste Spalte 3cm und die zweite 4cm breit ist
121  * und Widows auf sagen wir 3 gesetzt ist, so ist erst bei der Formatierung
122  * des Follows entscheidbar, ob die Widowsbedingung einhaltbar ist oder
123  * nicht. Leider ist davon abhaengig, ob der Absatz als Ganzes auf die
124  * naechste Seite rutscht.
125  */
126 
127 sal_Bool SwTxtFrmBreak::IsInside( SwTxtMargin &rLine ) const
128 {
129 	sal_Bool bFit = sal_False;
130 
131     SWAP_IF_SWAPPED( pFrm )
132     SWRECTFN( pFrm )
133     // nOrigin is an absolut value, rLine referes to the swapped situation.
134 
135     SwTwips nTmpY;
136     if ( pFrm->IsVertical() )
137         nTmpY = pFrm->SwitchHorizontalToVertical( rLine.Y() + rLine.GetLineHeight() );
138     else
139         nTmpY = rLine.Y() + rLine.GetLineHeight();
140 
141     SwTwips nLineHeight = (*fnRect->fnYDiff)( nTmpY , nOrigin );
142 
143 	// 7455 und 6114: Raum fuer die Umrandung unten einkalkulieren.
144     nLineHeight += (pFrm->*fnRect->fnGetBottomMargin)();
145 
146     if( nRstHeight )
147 		bFit = nRstHeight >= nLineHeight;
148 	else
149 	{
150 		// Der Frm besitzt eine Hoehe, mit der er auf die Seite passt.
151         SwTwips nHeight =
152             (*fnRect->fnYDiff)( (pFrm->GetUpper()->*fnRect->fnGetPrtBottom)(), nOrigin );
153 		// Wenn sich alles innerhalb des bestehenden Frames abspielt,
154 		// ist das Ergebnis sal_True;
155 		bFit = nHeight >= nLineHeight;
156 
157         // --> OD #i103292#
158         if ( !bFit )
159         {
160             if ( rLine.GetNext() &&
161                  pFrm->IsInTab() && !pFrm->GetFollow() && !pFrm->GetIndNext() )
162             {
163                 // add additional space taken as lower space as last content in a table
164                 // for all text lines except the last one.
165                 nHeight += pFrm->CalcAddLowerSpaceAsLastInTableCell();
166                 bFit = nHeight >= nLineHeight;
167             }
168         }
169         // <--
170 		if( !bFit )
171 		{
172 			// Die LineHeight sprengt die aktuelle Frm-Hoehe.
173 			// Nun rufen wir ein Probe-Grow, um zu ermitteln, ob der
174 			// Frame um den gewuenschten Bereich wachsen wuerde.
175 			nHeight += pFrm->GrowTst( LONG_MAX );
176 
177 			// Das Grow() returnt die Hoehe, um die der Upper des TxtFrm
178 			// den TxtFrm wachsen lassen wuerde.
179 			// Der TxtFrm selbst darf wachsen wie er will.
180 			bFit = nHeight >= nLineHeight;
181 		}
182 	}
183 
184     UNDO_SWAP( pFrm );
185 
186     return bFit;
187 }
188 
189 /*************************************************************************
190  *					SwTxtFrmBreak::IsBreakNow()
191  *************************************************************************/
192 
193 sal_Bool SwTxtFrmBreak::IsBreakNow( SwTxtMargin &rLine )
194 {
195     SWAP_IF_SWAPPED( pFrm )
196 
197 	// bKeep ist staerker als IsBreakNow()
198 	// Ist noch genug Platz ?
199 	if( bKeep || IsInside( rLine ) )
200 		bBreak = sal_False;
201 	else
202 	{
203 		/* Diese Klasse geht davon aus, dass der SwTxtMargin von Top nach Bottom
204 		 * durchgearbeitet wird. Aus Performancegruenden wird in folgenden
205 		 * Faellen der Laden fuer das weitere Aufspalten dicht gemacht:
206 		 * Wenn eine einzige Zeile nicht mehr passt.
207 		 * Sonderfall: bei DummyPortions ist LineNr == 1, obwohl wir splitten
208 		 * wollen.
209 		 */
210 		// 6010: DropLines mit einbeziehen
211 
212 		sal_Bool bFirstLine = 1 == rLine.GetLineNr() && !rLine.GetPrev();
213 		bBreak = sal_True;
214 		if( ( bFirstLine && pFrm->GetIndPrev() )
215 			|| ( rLine.GetLineNr() <= rLine.GetDropLines() ) )
216 		{
217 			bKeep = sal_True;
218 			bBreak = sal_False;
219 		}
220 		else if(bFirstLine && pFrm->IsInFtn() && !pFrm->FindFtnFrm()->GetPrev())
221 		{
222 			SwLayoutFrm* pTmp = pFrm->FindFtnBossFrm()->FindBodyCont();
223 			if( !pTmp || !pTmp->Lower() )
224 				bBreak = sal_False;
225 		}
226 	}
227 
228     UNDO_SWAP( pFrm )
229 
230 	return bBreak;
231 }
232 
233 // OD 2004-02-27 #106629# - no longer inline
234 void SwTxtFrmBreak::SetRstHeight( const SwTxtMargin &rLine )
235 {
236     // OD, FME 2004-02-27 #106629# - consider bottom margin
237     SWRECTFN( pFrm )
238 
239     nRstHeight = (pFrm->*fnRect->fnGetBottomMargin)();
240 
241     if ( bVert )
242     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
243     {
244        	if ( pFrm->IsVertLR() )
245       		nRstHeight = (*fnRect->fnYDiff)( pFrm->SwitchHorizontalToVertical( rLine.Y() ) , nOrigin );
246        	else
247        		nRstHeight += nOrigin - pFrm->SwitchHorizontalToVertical( rLine.Y() );
248     }
249     else
250         nRstHeight += rLine.Y() - nOrigin;
251 }
252 
253 /*************************************************************************
254  *					WidowsAndOrphans::WidowsAndOrphans()
255  *************************************************************************/
256 
257 WidowsAndOrphans::WidowsAndOrphans( SwTxtFrm *pNewFrm, const SwTwips nRst,
258 	sal_Bool bChkKeep	)
259     : SwTxtFrmBreak( pNewFrm, nRst ), nWidLines( 0 ), nOrphLines( 0 )
260 {
261     SWAP_IF_SWAPPED( pFrm )
262 
263 	if( bKeep )
264 	{
265 		// 5652: bei Absaetzen, die zusammengehalten werden sollen und
266 		// groesser sind als die Seite wird bKeep aufgehoben.
267 		if( bChkKeep && !pFrm->GetPrev() && !pFrm->IsInFtn() &&
268 			pFrm->IsMoveable() &&
269 			( !pFrm->IsInSct() || pFrm->FindSctFrm()->MoveAllowed(pFrm) ) )
270 			bKeep = sal_False;
271 		//Auch bei gesetztem Keep muessen Orphans beachtet werden,
272 		//z.B. bei verketteten Rahmen erhaelt ein Follow im letzten Rahmen ein Keep,
273 		//da er nicht (vorwaerts) Moveable ist,
274 		//er darf aber trotzdem vom Master Zeilen anfordern wg. der Orphanregel.
275 		if( pFrm->IsFollow() )
276 			nWidLines = pFrm->GetTxtNode()->GetSwAttrSet().GetWidows().GetValue();
277 	}
278 	else
279 	{
280 		const SwAttrSet& rSet = pFrm->GetTxtNode()->GetSwAttrSet();
281 		const SvxOrphansItem  &rOrph = rSet.GetOrphans();
282 		if ( rOrph.GetValue() > 1 )
283 			nOrphLines = rOrph.GetValue();
284 		if ( pFrm->IsFollow() )
285 			nWidLines = rSet.GetWidows().GetValue();
286 
287 	}
288 
289     if ( bKeep || nWidLines || nOrphLines )
290     {
291         bool bResetFlags = false;
292 
293         if ( pFrm->IsInTab() )
294         {
295             // For compatibility reasons, we disable Keep/Widows/Orphans
296             // inside splittable row frames:
297             if ( pFrm->GetNextCellLeaf( MAKEPAGE_NONE ) || pFrm->IsInFollowFlowRow() )
298             {
299                 const SwFrm* pTmpFrm = pFrm->GetUpper();
300                 while ( !pTmpFrm->IsRowFrm() )
301                     pTmpFrm = pTmpFrm->GetUpper();
302                 if ( static_cast<const SwRowFrm*>(pTmpFrm)->IsRowSplitAllowed() )
303                     bResetFlags = true;
304             }
305         }
306 
307         if( pFrm->IsInFtn() && !pFrm->GetIndPrev() )
308 	    {
309     		// Innerhalb von Fussnoten gibt es gute Gruende, das Keep-Attribut und
310 		    // die Widows/Orphans abzuschalten.
311 		    SwFtnFrm *pFtn = pFrm->FindFtnFrm();
312 		    sal_Bool bFt = !pFtn->GetAttr()->GetFtn().IsEndNote();
313 		    if( !pFtn->GetPrev() &&
314     			pFtn->FindFtnBossFrm( bFt ) != pFtn->GetRef()->FindFtnBossFrm( bFt )
315 			    && ( !pFrm->IsInSct() || pFrm->FindSctFrm()->MoveAllowed(pFrm) ) )
316 		    {
317     			bResetFlags = true;
318 		    }
319 	    }
320 
321         if ( bResetFlags )
322         {
323 			bKeep = sal_False;
324 			nOrphLines = 0;
325 			nWidLines = 0;
326         }
327     }
328 
329     UNDO_SWAP( pFrm )
330 }
331 
332 /*************************************************************************
333  *					WidowsAndOrphans::FindBreak()
334  *************************************************************************/
335 
336 /* Die Find*-Methoden suchen nicht nur, sondern stellen den SwTxtMargin auf
337  * die Zeile ein, wo der Absatz gebrochen werden soll und kuerzen ihn dort.
338  * FindBreak()
339  */
340 
341 sal_Bool WidowsAndOrphans::FindBreak( SwTxtFrm *pFrame, SwTxtMargin &rLine,
342 	sal_Bool bHasToFit )
343 {
344     // OD 2004-02-25 #i16128# - Why member <pFrm> _*and*_ parameter <pFrame>??
345     // Thus, assertion on situation, that these are different to figure out why.
346     ASSERT( pFrm == pFrame, "<WidowsAndOrphans::FindBreak> - pFrm != pFrame" );
347 
348     SWAP_IF_SWAPPED( pFrm )
349 
350 	sal_Bool bRet = sal_True;
351 	MSHORT nOldOrphans = nOrphLines;
352     if( bHasToFit )
353 		nOrphLines = 0;
354 	rLine.Bottom();
355     // OD 2004-02-25 #i16128# - method renamed
356     if( !IsBreakNowWidAndOrp( rLine ) )
357 		bRet = sal_False;
358     if( !FindWidows( pFrame, rLine ) )
359 	{
360 		sal_Bool bBack = sal_False;
361         // OD 2004-02-25 #i16128# - method renamed
362         while( IsBreakNowWidAndOrp( rLine ) )
363 		{
364 			if( rLine.PrevLine() )
365 				bBack = sal_True;
366 			else
367 				break;
368 		}
369 		// Eigentlich werden bei HasToFit Schusterjungen (Orphans) nicht
370 		// beruecksichtigt, wenn allerdings Dummy-Lines im Spiel sind und
371 		// die Orphansregel verletzt wird, machen wir mal eine Ausnahme:
372 		// Wir lassen einfach eine Dummyline zurueck und wandern mit dem Text
373 		// komplett auf die naechste Seite/Spalte.
374         if( rLine.GetLineNr() <= nOldOrphans &&
375             rLine.GetInfo().GetParaPortion()->IsDummy() &&
376             ( ( bHasToFit && bRet ) || IsBreakNow( rLine ) ) )
377 			rLine.Top();
378 
379 		rLine.TruncLines( sal_True );
380 		bRet = bBack;
381 	}
382 	nOrphLines = nOldOrphans;
383 
384     UNDO_SWAP( pFrm )
385 
386 	return bRet;
387 }
388 
389 /*************************************************************************
390  *					WidowsAndOrphans::FindWidows()
391  *************************************************************************/
392 
393 /*	FindWidows positioniert den SwTxtMargin des Masters auf die umzubrechende
394  *	Zeile, indem der Follow formatiert und untersucht wird.
395  *	Liefert sal_True zurueck, wenn die Widows-Regelung in Kraft tritt,
396  *	d.h. der Absatz _zusammengehalten_ werden soll !
397  */
398 
399 sal_Bool WidowsAndOrphans::FindWidows( SwTxtFrm *pFrame, SwTxtMargin &rLine )
400 {
401     ASSERT( ! pFrame->IsVertical() || ! pFrame->IsSwapped(),
402             "WidowsAndOrphans::FindWidows with swapped frame" )
403 
404     if( !nWidLines || !pFrame->IsFollow() )
405 		return sal_False;
406 
407 	rLine.Bottom();
408 
409 	// Wir koennen noch was abzwacken
410     SwTxtFrm *pMaster = pFrame->FindMaster();
411 	ASSERT(pMaster, "+WidowsAndOrphans::FindWidows: Widows in a master?");
412 	if( !pMaster )
413 		return sal_False;
414 
415 	// 5156: Wenn die erste Zeile des Follows nicht passt, wird der Master
416 	// wohl voll mit Dummies sein. In diesem Fall waere ein PREP_WIDOWS fatal.
417     if( pMaster->GetOfst() == pFrame->GetOfst() )
418 		return sal_False;
419 
420 	// Resthoehe des Masters
421     SWRECTFN( pFrame )
422 
423     const SwTwips nDocPrtTop = (pFrame->*fnRect->fnGetPrtTop)();
424     SwTwips nOldHeight;
425     SwTwips nTmpY = rLine.Y() + rLine.GetLineHeight();
426 
427     if ( bVert )
428     {
429         nTmpY = pFrame->SwitchHorizontalToVertical( nTmpY );
430         nOldHeight = -(pFrame->Prt().*fnRect->fnGetHeight)();
431     }
432     else
433         nOldHeight = (pFrame->Prt().*fnRect->fnGetHeight)();
434 
435     const SwTwips nChg = (*fnRect->fnYDiff)( nTmpY, nDocPrtTop + nOldHeight );
436 
437 	// Unterhalb der Widows-Schwelle...
438 	if( rLine.GetLineNr() >= nWidLines )
439 	{
440 		// 8575: Follow to Master I
441 		// Wenn der Follow *waechst*, so besteht fuer den Master die Chance,
442 		// Zeilen entgegenzunehmen, die er vor Kurzem gezwungen war an den
443 		// Follow abzugeben: Prepare(Need); diese Abfrage unterhalb von nChg!
444 		// (0W, 2O, 2M, 2F) + 1F = 3M, 2F
445         if( rLine.GetLineNr() > nWidLines && pFrame->IsJustWidow() )
446 		{
447 			// Wenn der Master gelockt ist, so hat er vermutlich gerade erst
448 			// eine Zeile an uns abgegeben, diese geben nicht zurueck, nur
449 			// weil bei uns daraus mehrere geworden sind (z.B. durch Rahmen).
450             if( !pMaster->IsLocked() && pMaster->GetUpper() )
451             {
452                 const SwTwips nTmpRstHeight = (pMaster->Frm().*fnRect->fnBottomDist)
453                             ( (pMaster->GetUpper()->*fnRect->fnGetPrtBottom)() );
454                 if ( nTmpRstHeight >=
455                      SwTwips(rLine.GetInfo().GetParaPortion()->Height() ) )
456                 {
457                     pMaster->Prepare( PREP_ADJUST_FRM );
458                     pMaster->_InvalidateSize();
459                     pMaster->InvalidatePage();
460                 }
461             }
462 
463             pFrame->SetJustWidow( sal_False );
464 		}
465 		return sal_False;
466 	}
467 
468 	// 8575: Follow to Master II
469 	// Wenn der Follow *schrumpft*, so besteht fuer den Master die Chance,
470 	// den kompletten Orphan zu inhalieren.
471 	// (0W, 2O, 2M, 1F) - 1F = 3M, 0F	  -> PREP_ADJUST_FRM
472 	// (0W, 2O, 3M, 2F) - 1F = 2M, 2F	  -> PREP_WIDOWS
473 
474     if( 0 > nChg && !pMaster->IsLocked() && pMaster->GetUpper() )
475     {
476         SwTwips nTmpRstHeight = (pMaster->Frm().*fnRect->fnBottomDist)
477                              ( (pMaster->GetUpper()->*fnRect->fnGetPrtBottom)() );
478         if( nTmpRstHeight >= SwTwips(rLine.GetInfo().GetParaPortion()->Height() ) )
479         {
480             pMaster->Prepare( PREP_ADJUST_FRM );
481             pMaster->_InvalidateSize();
482             pMaster->InvalidatePage();
483             pFrame->SetJustWidow( sal_False );
484             return sal_False;
485         }
486     }
487 
488 	// Master to Follow
489 	// Wenn der Follow nach seiner Formatierung weniger Zeilen enthaelt
490 	// als Widows, so besteht noch die Chance, einige Zeilen des Masters
491 	// abzuzwacken. Wenn dadurch die Orphans-Regel des Masters in Kraft
492 	// tritt muss im CalcPrep() des Master-Frame der Frame so vergroessert
493 	// werden, dass er nicht mehr auf seine urspruengliche Seite passt.
494 	// Wenn er noch ein paar Zeilen entbehren kann, dann muss im CalcPrep()
495 	// ein Shrink() erfolgen, der Follow mit dem Widows rutscht dann auf
496 	// die Seite des Masters, haelt sich aber zusammen, so dass er (endlich)
497 	// auf die naechste Seite rutscht. - So die Theorie!
498 
499 
500 	// Wir fordern nur noch ein Zeile zur Zeit an, weil eine Zeile des Masters
501 	// bei uns durchaus mehrere Zeilen ergeben koennten.
502 	// Dafuer behaelt CalcFollow solange die Kontrolle, bis der Follow alle
503 	// notwendigen Zeilen bekommen hat.
504 	MSHORT nNeed = 1; // frueher: nWidLines - rLine.GetLineNr();
505 
506     // Special case: Master cannot give lines to follow
507     // --> FME 2008-09-16 #i91421#
508     if ( !pMaster->GetIndPrev() )
509     {
510         sal_uLong nLines = pMaster->GetThisLines();
511         if(nLines == 0 && pMaster->HasPara())
512         {
513             const SwParaPortion *pMasterPara = pMaster->GetPara();
514             if(pMasterPara && pMasterPara->GetNext())
515                 nLines = 2;
516         }
517         if( nLines <= nNeed )
518             return sal_False;
519     }
520 
521 	pMaster->Prepare( PREP_WIDOWS, (void*)&nNeed );
522 	return sal_True;
523 }
524 
525 /*************************************************************************
526  *					WidowsAndOrphans::WouldFit()
527  *************************************************************************/
528 
529 sal_Bool WidowsAndOrphans::WouldFit( SwTxtMargin &rLine, SwTwips &rMaxHeight, sal_Bool bTst )
530 {
531     // Here it does not matter, if pFrm is swapped or not.
532     // IsInside() takes care for itself
533 
534 	// Wir erwarten, dass rLine auf der letzten Zeile steht!!
535 	ASSERT( !rLine.GetNext(), "WouldFit: aLine::Bottom missed!" );
536 	MSHORT nLineCnt = rLine.GetLineNr();
537 
538 	// Erstmal die Orphansregel und den Initialenwunsch erfuellen ...
539 	const MSHORT nMinLines = Max( GetOrphansLines(), rLine.GetDropLines() );
540 	if ( nLineCnt < nMinLines )
541 		return sal_False;
542 
543 	rLine.Top();
544 	SwTwips nLineSum = rLine.GetLineHeight();
545 
546 	while( nMinLines > rLine.GetLineNr() )
547 	{
548 		DBG_LOOP;
549 		if( !rLine.NextLine() )
550 			return sal_False;
551 		nLineSum += rLine.GetLineHeight();
552 	}
553 
554 	// Wenn wir jetzt schon nicht mehr passen ...
555 	if( !IsInside( rLine ) )
556 		return sal_False;
557 
558 	// Jetzt noch die Widows-Regel ueberpruefen
559 	if( !nWidLines && !pFrm->IsFollow() )
560 	{
561 		// I.A. brauchen Widows nur ueberprueft werden, wenn wir ein Follow
562 		// sind. Bei WouldFit muss aber auch fuer den Master die Regel ueber-
563 		// prueft werden, weil wir ja gerade erst die Trennstelle ermitteln.
564 		// Im Ctor von WidowsAndOrphans wurde nWidLines aber nur fuer Follows
565 		// aus dem AttrSet ermittelt, deshalb holen wir es hier nach:
566 		const SwAttrSet& rSet = pFrm->GetTxtNode()->GetSwAttrSet();
567 		nWidLines = rSet.GetWidows().GetValue();
568 	}
569 
570 	// Sind nach Orphans/Initialen noch genug Zeilen fuer die Widows uebrig?
571     // #111937#: If we are currently doing a test formatting, we may not
572     // consider the widows rule for two reasons:
573     // 1. The columns may have different widths.
574     //    Widow lines would have wrong width.
575     // 2. Test formatting is only done up to the given space.
576     //    we do not have any lines for widows at all.
577     if( bTst || nLineCnt - nMinLines >= GetWidowsLines() )
578 	{
579         if( rMaxHeight >= nLineSum )
580 		{
581 			rMaxHeight -= nLineSum;
582 			return sal_True;
583 		}
584 	}
585 	return sal_False;
586 }
587 
588