xref: /AOO41X/main/sw/source/core/text/widorp.cxx (revision 79aad27f7f29270c03e208e3d687e8e3850af11d)
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