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. 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 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 123 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 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 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 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 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 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 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