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