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 29 #include "layouter.hxx" 30 #include "doc.hxx" 31 #include "sectfrm.hxx" 32 #include "ftnboss.hxx" 33 #include "cntfrm.hxx" 34 #include "pagefrm.hxx" 35 #include "ftnfrm.hxx" 36 #include "txtfrm.hxx" 37 38 // --> OD 2004-06-23 #i28701# 39 #include <movedfwdfrmsbyobjpos.hxx> 40 // <-- 41 // --> OD 2004-10-22 #i35911# 42 #include <objstmpconsiderwrapinfl.hxx> 43 // <-- 44 45 #define LOOP_DETECT 250 46 47 class SwLooping 48 { 49 sal_uInt16 nMinPage; 50 sal_uInt16 nMaxPage; 51 sal_uInt16 nCount; 52 sal_uInt16 mnLoopControlStage; 53 public: 54 SwLooping( SwPageFrm* pPage ); 55 void Control( SwPageFrm* pPage ); 56 void Drastic( SwFrm* pFrm ); 57 bool IsLoopingLouieLight() const { return nCount > LOOP_DETECT - 30; }; 58 }; 59 60 class SwEndnoter 61 { 62 SwLayouter* pMaster; 63 SwSectionFrm* pSect; 64 SvPtrarr* pEndArr; 65 public: 66 SwEndnoter( SwLayouter* pLay ) 67 : pMaster( pLay ), pSect( NULL ), pEndArr( NULL ) {} 68 ~SwEndnoter() { delete pEndArr; } 69 void CollectEndnotes( SwSectionFrm* pSct ); 70 void CollectEndnote( SwFtnFrm* pFtn ); 71 const SwSectionFrm* GetSect() { return pSect; } 72 void InsertEndnotes(); 73 sal_Bool HasEndnotes() const { return pEndArr && pEndArr->Count(); } 74 }; 75 76 void SwEndnoter::CollectEndnotes( SwSectionFrm* pSct ) 77 { 78 ASSERT( pSct, "CollectEndnotes: Which section?" ); 79 if( !pSect ) 80 pSect = pSct; 81 else if( pSct != pSect ) 82 return; 83 pSect->CollectEndnotes( pMaster ); 84 } 85 86 void SwEndnoter::CollectEndnote( SwFtnFrm* pFtn ) 87 { 88 if( pEndArr && USHRT_MAX != pEndArr->GetPos( (VoidPtr)pFtn ) ) 89 return; 90 91 if( pFtn->GetUpper() ) 92 { 93 // pFtn is the master, he incorporates its follows 94 SwFtnFrm *pNxt = pFtn->GetFollow(); 95 while ( pNxt ) 96 { 97 SwFrm *pCnt = pNxt->ContainsAny(); 98 if ( pCnt ) 99 { 100 do 101 { SwFrm *pNxtCnt = pCnt->GetNext(); 102 pCnt->Cut(); 103 pCnt->Paste( pFtn ); 104 pCnt = pNxtCnt; 105 } while ( pCnt ); 106 } 107 else 108 { ASSERT( pNxt->Lower() && pNxt->Lower()->IsSctFrm(), 109 "Endnote without content?" ); 110 pNxt->Cut(); 111 delete pNxt; 112 } 113 pNxt = pFtn->GetFollow(); 114 } 115 if( pFtn->GetMaster() ) 116 return; 117 pFtn->Cut(); 118 } 119 else if( pEndArr ) 120 { 121 for ( sal_uInt16 i = 0; i < pEndArr->Count(); ++i ) 122 { 123 SwFtnFrm *pEndFtn = (SwFtnFrm*)((*pEndArr)[i]); 124 if( pEndFtn->GetAttr() == pFtn->GetAttr() ) 125 { 126 delete pFtn; 127 return; 128 } 129 } 130 } 131 if( !pEndArr ) 132 pEndArr = new SvPtrarr( 5, 5 ); // deleted from the SwLayouter 133 pEndArr->Insert( (VoidPtr)pFtn, pEndArr->Count() ); 134 } 135 136 void SwEndnoter::InsertEndnotes() 137 { 138 if( !pSect ) 139 return; 140 if( !pEndArr || !pEndArr->Count() ) 141 { 142 pSect = NULL; 143 return; 144 } 145 ASSERT( pSect->Lower() && pSect->Lower()->IsFtnBossFrm(), 146 "InsertEndnotes: Where's my column?" ); 147 SwFrm* pRef = pSect->FindLastCntnt( FINDMODE_MYLAST ); 148 SwFtnBossFrm *pBoss = pRef ? pRef->FindFtnBossFrm() 149 : (SwFtnBossFrm*)pSect->Lower(); 150 pBoss->_MoveFtns( *pEndArr ); 151 delete pEndArr; 152 pEndArr = NULL; 153 pSect = NULL; 154 } 155 156 SwLooping::SwLooping( SwPageFrm* pPage ) 157 { 158 ASSERT( pPage, "Where's my page?" ); 159 nMinPage = pPage->GetPhyPageNum(); 160 nMaxPage = nMinPage; 161 nCount = 0; 162 mnLoopControlStage = 0; 163 } 164 165 void SwLooping::Drastic( SwFrm* pFrm ) 166 { 167 while( pFrm ) 168 { 169 pFrm->ValidateThisAndAllLowers( mnLoopControlStage ); 170 pFrm = pFrm->GetNext(); 171 } 172 } 173 174 void SwLooping::Control( SwPageFrm* pPage ) 175 { 176 if( !pPage ) 177 return; 178 sal_uInt16 nNew = pPage->GetPhyPageNum(); 179 if( nNew > nMaxPage ) 180 nMaxPage = nNew; 181 if( nNew < nMinPage ) 182 { 183 nMinPage = nNew; 184 nMaxPage = nNew; 185 nCount = 0; 186 mnLoopControlStage = 0; 187 } 188 else if( nNew > nMinPage + 2 ) 189 { 190 nMinPage = nNew - 2; 191 nMaxPage = nNew; 192 nCount = 0; 193 mnLoopControlStage = 0; 194 } 195 else if( ++nCount > LOOP_DETECT ) 196 { 197 #ifdef DBG_UTIL 198 #if OSL_DEBUG_LEVEL > 1 199 static sal_Bool bNoLouie = sal_False; 200 if( bNoLouie ) 201 return; 202 #endif 203 #endif 204 205 // FME 2007-08-30 #i81146# new loop control 206 #if OSL_DEBUG_LEVEL > 1 207 ASSERT( 0 != mnLoopControlStage, "Looping Louie: Stage 1!" ); 208 ASSERT( 1 != mnLoopControlStage, "Looping Louie: Stage 2!!" ); 209 ASSERT( 2 > mnLoopControlStage, "Looping Louie: Stage 3!!!" ); 210 #endif 211 212 Drastic( pPage->Lower() ); 213 if( nNew > nMinPage && pPage->GetPrev() ) 214 Drastic( ((SwPageFrm*)pPage->GetPrev())->Lower() ); 215 if( nNew < nMaxPage && pPage->GetNext() ) 216 Drastic( ((SwPageFrm*)pPage->GetNext())->Lower() ); 217 218 ++mnLoopControlStage; 219 nCount = 0; 220 } 221 } 222 223 /************************************************************************* 224 |* 225 |* SwLayouter::SwLayouter() 226 |* 227 |* Ersterstellung AMA 02. Nov. 99 228 |* Letzte Aenderung AMA 02. Nov. 99 229 |* 230 |*************************************************************************/ 231 232 SwLayouter::SwLayouter() 233 : pEndnoter( NULL ), 234 pLooping( NULL ), 235 // --> OD 2004-06-23 #i28701# 236 mpMovedFwdFrms( 0L ), 237 // <-- 238 // --> OD 2004-10-22 #i35911# 239 mpObjsTmpConsiderWrapInfl( 0L ) 240 // <-- 241 { 242 } 243 244 SwLayouter::~SwLayouter() 245 { 246 delete pEndnoter; 247 delete pLooping; 248 // --> OD 2004-06-23 #i28701# 249 delete mpMovedFwdFrms; 250 mpMovedFwdFrms = 0L; 251 // <-- 252 // --> OD 2004-10-22 #i35911# 253 delete mpObjsTmpConsiderWrapInfl; 254 mpObjsTmpConsiderWrapInfl = 0L; 255 // <-- 256 } 257 258 void SwLayouter::_CollectEndnotes( SwSectionFrm* pSect ) 259 { 260 if( !pEndnoter ) 261 pEndnoter = new SwEndnoter( this ); 262 pEndnoter->CollectEndnotes( pSect ); 263 } 264 265 sal_Bool SwLayouter::HasEndnotes() const 266 { 267 return pEndnoter->HasEndnotes(); 268 } 269 270 void SwLayouter::CollectEndnote( SwFtnFrm* pFtn ) 271 { 272 pEndnoter->CollectEndnote( pFtn ); 273 } 274 275 void SwLayouter::InsertEndnotes( SwSectionFrm* pSect ) 276 { 277 if( !pEndnoter || pEndnoter->GetSect() != pSect ) 278 return; 279 pEndnoter->InsertEndnotes(); 280 } 281 282 void SwLayouter::LoopControl( SwPageFrm* pPage, sal_uInt8 ) 283 { 284 ASSERT( pLooping, "Looping: Lost control" ); 285 pLooping->Control( pPage ); 286 } 287 288 void SwLayouter::LoopingLouieLight( const SwDoc& rDoc, const SwTxtFrm& rFrm ) 289 { 290 if ( pLooping && pLooping->IsLoopingLouieLight() ) 291 { 292 #if OSL_DEBUG_LEVEL > 1 293 ASSERT( false, "Looping Louie (Light): Fixating fractious frame" ) 294 #endif 295 SwLayouter::InsertMovedFwdFrm( rDoc, rFrm, rFrm.FindPageFrm()->GetPhyPageNum() ); 296 } 297 } 298 299 sal_Bool SwLayouter::StartLooping( SwPageFrm* pPage ) 300 { 301 if( pLooping ) 302 return sal_False; 303 pLooping = new SwLooping( pPage ); 304 return sal_True; 305 } 306 307 void SwLayouter::EndLoopControl() 308 { 309 delete pLooping; 310 pLooping = NULL; 311 } 312 313 void SwLayouter::CollectEndnotes( SwDoc* pDoc, SwSectionFrm* pSect ) 314 { 315 ASSERT( pDoc, "No doc, no fun" ); 316 if( !pDoc->GetLayouter() ) 317 pDoc->SetLayouter( new SwLayouter() ); 318 pDoc->GetLayouter()->_CollectEndnotes( pSect ); 319 } 320 321 sal_Bool SwLayouter::Collecting( SwDoc* pDoc, SwSectionFrm* pSect, SwFtnFrm* pFtn ) 322 { 323 if( !pDoc->GetLayouter() ) 324 return sal_False; 325 SwLayouter *pLayouter = pDoc->GetLayouter(); 326 if( pLayouter->pEndnoter && pLayouter->pEndnoter->GetSect() && pSect && 327 ( pLayouter->pEndnoter->GetSect()->IsAnFollow( pSect ) || 328 pSect->IsAnFollow( pLayouter->pEndnoter->GetSect() ) ) ) 329 { 330 if( pFtn ) 331 pLayouter->CollectEndnote( pFtn ); 332 return sal_True; 333 } 334 return sal_False; 335 } 336 337 sal_Bool SwLayouter::StartLoopControl( SwDoc* pDoc, SwPageFrm *pPage ) 338 { 339 ASSERT( pDoc, "No doc, no fun" ); 340 if( !pDoc->GetLayouter() ) 341 pDoc->SetLayouter( new SwLayouter() ); 342 return !pDoc->GetLayouter()->pLooping && 343 pDoc->GetLayouter()->StartLooping( pPage ); 344 } 345 346 // --> OD 2004-06-23 #i28701# 347 // ----------------------------------------------------------------------------- 348 // methods to manage text frames, which are moved forward by the positioning 349 // of its anchored objects 350 // ----------------------------------------------------------------------------- 351 void SwLayouter::ClearMovedFwdFrms( const SwDoc& _rDoc ) 352 { 353 if ( _rDoc.GetLayouter() && 354 _rDoc.GetLayouter()->mpMovedFwdFrms ) 355 { 356 _rDoc.GetLayouter()->mpMovedFwdFrms->Clear(); 357 } 358 } 359 360 void SwLayouter::InsertMovedFwdFrm( const SwDoc& _rDoc, 361 const SwTxtFrm& _rMovedFwdFrmByObjPos, 362 const sal_uInt32 _nToPageNum ) 363 { 364 if ( !_rDoc.GetLayouter() ) 365 { 366 const_cast<SwDoc&>(_rDoc).SetLayouter( new SwLayouter() ); 367 } 368 369 if ( !_rDoc.GetLayouter()->mpMovedFwdFrms ) 370 { 371 const_cast<SwDoc&>(_rDoc).GetLayouter()->mpMovedFwdFrms = 372 new SwMovedFwdFrmsByObjPos(); 373 } 374 375 _rDoc.GetLayouter()->mpMovedFwdFrms->Insert( _rMovedFwdFrmByObjPos, 376 _nToPageNum ); 377 } 378 379 // --> OD 2005-01-12 #i40155# 380 void SwLayouter::RemoveMovedFwdFrm( const SwDoc& _rDoc, 381 const SwTxtFrm& _rTxtFrm ) 382 { 383 sal_uInt32 nDummy; 384 if ( SwLayouter::FrmMovedFwdByObjPos( _rDoc, _rTxtFrm, nDummy ) ) 385 { 386 _rDoc.GetLayouter()->mpMovedFwdFrms->Remove( _rTxtFrm ); 387 } 388 } 389 // <-- 390 391 bool SwLayouter::FrmMovedFwdByObjPos( const SwDoc& _rDoc, 392 const SwTxtFrm& _rTxtFrm, 393 sal_uInt32& _ornToPageNum ) 394 { 395 if ( !_rDoc.GetLayouter() ) 396 { 397 _ornToPageNum = 0; 398 return false; 399 } 400 else if ( !_rDoc.GetLayouter()->mpMovedFwdFrms ) 401 { 402 _ornToPageNum = 0; 403 return false; 404 } 405 else 406 { 407 return _rDoc.GetLayouter()->mpMovedFwdFrms-> 408 FrmMovedFwdByObjPos( _rTxtFrm, _ornToPageNum ); 409 } 410 } 411 // <-- 412 // --> OD 2004-10-05 #i26945# 413 bool SwLayouter::DoesRowContainMovedFwdFrm( const SwDoc& _rDoc, 414 const SwRowFrm& _rRowFrm ) 415 { 416 if ( !_rDoc.GetLayouter() ) 417 { 418 return false; 419 } 420 else if ( !_rDoc.GetLayouter()->mpMovedFwdFrms ) 421 { 422 return false; 423 } 424 else 425 { 426 return _rDoc.GetLayouter()-> 427 mpMovedFwdFrms->DoesRowContainMovedFwdFrm( _rRowFrm ); 428 } 429 } 430 // <-- 431 432 // --> OD 2004-10-22 #i35911# 433 void SwLayouter::ClearObjsTmpConsiderWrapInfluence( const SwDoc& _rDoc ) 434 { 435 if ( _rDoc.GetLayouter() && 436 _rDoc.GetLayouter()->mpObjsTmpConsiderWrapInfl ) 437 { 438 _rDoc.GetLayouter()->mpObjsTmpConsiderWrapInfl->Clear(); 439 } 440 } 441 void SwLayouter::InsertObjForTmpConsiderWrapInfluence( 442 const SwDoc& _rDoc, 443 SwAnchoredObject& _rAnchoredObj ) 444 { 445 if ( !_rDoc.GetLayouter() ) 446 { 447 const_cast<SwDoc&>(_rDoc).SetLayouter( new SwLayouter() ); 448 } 449 450 if ( !_rDoc.GetLayouter()->mpObjsTmpConsiderWrapInfl ) 451 { 452 const_cast<SwDoc&>(_rDoc).GetLayouter()->mpObjsTmpConsiderWrapInfl = 453 new SwObjsMarkedAsTmpConsiderWrapInfluence(); 454 } 455 456 _rDoc.GetLayouter()->mpObjsTmpConsiderWrapInfl->Insert( _rAnchoredObj ); 457 } 458 // <-- 459 // --> OD 2005-01-12 #i40155# 460 void SwLayouter::ClearFrmsNotToWrap( const SwDoc& _rDoc ) 461 { 462 if ( _rDoc.GetLayouter() ) 463 { 464 const_cast<SwDoc&>(_rDoc).GetLayouter()->maFrmsNotToWrap.clear(); 465 } 466 } 467 468 void SwLayouter::InsertFrmNotToWrap( const SwDoc& _rDoc, 469 const SwFrm& _rFrm ) 470 { 471 if ( !_rDoc.GetLayouter() ) 472 { 473 const_cast<SwDoc&>(_rDoc).SetLayouter( new SwLayouter() ); 474 } 475 476 if ( !SwLayouter::FrmNotToWrap( _rDoc, _rFrm ) ) 477 { 478 const_cast<SwDoc&>(_rDoc).GetLayouter()->maFrmsNotToWrap.push_back( &_rFrm ); 479 } 480 } 481 482 bool SwLayouter::FrmNotToWrap( const IDocumentLayoutAccess& _rDLA, 483 const SwFrm& _rFrm ) 484 { 485 const SwLayouter* pLayouter = _rDLA.GetLayouter(); 486 if ( !pLayouter ) 487 { 488 return false; 489 } 490 else 491 { 492 bool bFrmNotToWrap( false ); 493 std::vector< const SwFrm* >::const_iterator aIter = 494 pLayouter->maFrmsNotToWrap.begin(); 495 for ( ; aIter != pLayouter->maFrmsNotToWrap.end(); ++aIter ) 496 { 497 const SwFrm* pFrm = *(aIter); 498 if ( pFrm == &_rFrm ) 499 { 500 bFrmNotToWrap = true; 501 break; 502 } 503 } 504 return bFrmNotToWrap; 505 } 506 } 507 // <-- 508 509 void LOOPING_LOUIE_LIGHT( bool bCondition, const SwTxtFrm& rTxtFrm ) 510 { 511 if ( bCondition ) 512 { 513 const SwDoc& rDoc = *rTxtFrm.GetAttrSet()->GetDoc(); 514 if ( rDoc.GetLayouter() ) 515 { 516 const_cast<SwDoc&>(rDoc).GetLayouter()->LoopingLouieLight( rDoc, rTxtFrm ); 517 } 518 } 519 } 520 521 // --> OD 2006-05-10 #i65250# 522 bool SwLayouter::MoveBwdSuppressed( const SwDoc& p_rDoc, 523 const SwFlowFrm& p_rFlowFrm, 524 const SwLayoutFrm& p_rNewUpperFrm ) 525 { 526 bool bMoveBwdSuppressed( false ); 527 528 if ( !p_rDoc.GetLayouter() ) 529 { 530 const_cast<SwDoc&>(p_rDoc).SetLayouter( new SwLayouter() ); 531 } 532 533 // create hash map key 534 tMoveBwdLayoutInfoKey aMoveBwdLayoutInfo; 535 aMoveBwdLayoutInfo.mnFrmId = p_rFlowFrm.GetFrm()->GetFrmId(); 536 aMoveBwdLayoutInfo.mnNewUpperPosX = p_rNewUpperFrm.Frm().Pos().X(); 537 aMoveBwdLayoutInfo.mnNewUpperPosY = p_rNewUpperFrm.Frm().Pos().Y(); 538 aMoveBwdLayoutInfo.mnNewUpperWidth = p_rNewUpperFrm.Frm().Width(); 539 aMoveBwdLayoutInfo.mnNewUpperHeight = p_rNewUpperFrm.Frm().Height(); 540 SWRECTFN( (&p_rNewUpperFrm) ) 541 const SwFrm* pLastLower( p_rNewUpperFrm.Lower() ); 542 while ( pLastLower && pLastLower->GetNext() ) 543 { 544 pLastLower = pLastLower->GetNext(); 545 } 546 aMoveBwdLayoutInfo.mnFreeSpaceInNewUpper = 547 pLastLower 548 ? (pLastLower->Frm().*fnRect->fnBottomDist)( (p_rNewUpperFrm.*fnRect->fnGetPrtBottom)() ) 549 : (p_rNewUpperFrm.Frm().*fnRect->fnGetHeight)(); 550 551 // check for moving backward suppress threshold 552 const sal_uInt16 cMoveBwdCountSuppressThreshold = 20; 553 if ( ++const_cast<SwDoc&>(p_rDoc).GetLayouter()->maMoveBwdLayoutInfo[ aMoveBwdLayoutInfo ] > 554 cMoveBwdCountSuppressThreshold ) 555 { 556 bMoveBwdSuppressed = true; 557 } 558 559 return bMoveBwdSuppressed; 560 } 561 562 void SwLayouter::ClearMoveBwdLayoutInfo( const SwDoc& _rDoc ) 563 { 564 if ( _rDoc.GetLayouter() ) 565 const_cast<SwDoc&>(_rDoc).GetLayouter()->maMoveBwdLayoutInfo.clear(); 566 } 567 // <-- 568