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