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 #include <objectformatter.hxx> 31 #include <objectformattertxtfrm.hxx> 32 #include <objectformatterlayfrm.hxx> 33 #include <anchoredobject.hxx> 34 #include <anchoreddrawobject.hxx> 35 #include <sortedobjs.hxx> 36 #include <pagefrm.hxx> 37 #include <flyfrms.hxx> 38 #include <txtfrm.hxx> 39 #include <layact.hxx> 40 #include <frmfmt.hxx> 41 #include <fmtanchr.hxx> 42 #include <doc.hxx> 43 44 #include <vector> 45 46 // ============================================================================= 47 // helper class <SwPageNumAndTypeOfAnchors> 48 // --> OD 2004-10-04 #i26945# - Additionally the type of the anchor text frame 49 // is collected - by type is meant 'master' or 'follow'. 50 // ============================================================================= 51 class SwPageNumAndTypeOfAnchors 52 { 53 private: 54 struct tEntry 55 { 56 SwAnchoredObject* mpAnchoredObj; 57 sal_uInt32 mnPageNumOfAnchor; 58 bool mbAnchoredAtMaster; 59 }; 60 61 std::vector< tEntry* > maObjList; 62 63 public: 64 inline SwPageNumAndTypeOfAnchors() 65 { 66 } 67 inline ~SwPageNumAndTypeOfAnchors() 68 { 69 for ( std::vector< tEntry* >::iterator aIter = maObjList.begin(); 70 aIter != maObjList.end(); ++aIter ) 71 { 72 delete (*aIter); 73 } 74 maObjList.clear(); 75 } 76 77 inline void Collect( SwAnchoredObject& _rAnchoredObj ) 78 { 79 tEntry* pNewEntry = new tEntry(); 80 pNewEntry->mpAnchoredObj = &_rAnchoredObj; 81 // --> OD 2004-09-23 #i33751#, #i34060# - method <GetPageFrmOfAnchor()> 82 // is replaced by method <FindPageFrmOfAnchor()>. It's return value 83 // have to be checked. 84 SwPageFrm* pPageFrmOfAnchor = _rAnchoredObj.FindPageFrmOfAnchor(); 85 if ( pPageFrmOfAnchor ) 86 { 87 pNewEntry->mnPageNumOfAnchor = pPageFrmOfAnchor->GetPhyPageNum(); 88 } 89 else 90 { 91 pNewEntry->mnPageNumOfAnchor = 0; 92 } 93 // <-- 94 // --> OD 2004-10-04 #i26945# - collect type of anchor 95 SwTxtFrm* pAnchorCharFrm = _rAnchoredObj.FindAnchorCharFrm(); 96 if ( pAnchorCharFrm ) 97 { 98 pNewEntry->mbAnchoredAtMaster = !pAnchorCharFrm->IsFollow(); 99 } 100 else 101 { 102 pNewEntry->mbAnchoredAtMaster = true; 103 } 104 // <-- 105 maObjList.push_back( pNewEntry ); 106 } 107 108 inline SwAnchoredObject* operator[]( sal_uInt32 _nIndex ) 109 { 110 SwAnchoredObject* bRetObj = 0L; 111 112 if ( _nIndex < Count()) 113 { 114 bRetObj = maObjList[_nIndex]->mpAnchoredObj; 115 } 116 117 return bRetObj; 118 } 119 120 inline sal_uInt32 GetPageNum( sal_uInt32 _nIndex ) 121 { 122 sal_uInt32 nRetPgNum = 0L; 123 124 if ( _nIndex < Count()) 125 { 126 nRetPgNum = maObjList[_nIndex]->mnPageNumOfAnchor; 127 } 128 129 return nRetPgNum; 130 } 131 132 // --> OD 2004-10-04 #i26945# 133 inline bool AnchoredAtMaster( sal_uInt32 _nIndex ) 134 { 135 bool bAnchoredAtMaster( true ); 136 137 if ( _nIndex < Count()) 138 { 139 bAnchoredAtMaster = maObjList[_nIndex]->mbAnchoredAtMaster; 140 } 141 142 return bAnchoredAtMaster; 143 } 144 // <-- 145 146 inline sal_uInt32 Count() const 147 { 148 return maObjList.size(); 149 } 150 }; 151 152 // ============================================================================= 153 // implementation of class <SwObjectFormatter> 154 // ============================================================================= 155 SwObjectFormatter::SwObjectFormatter( const SwPageFrm& _rPageFrm, 156 SwLayAction* _pLayAction, 157 const bool _bCollectPgNumOfAnchors ) 158 : mrPageFrm( _rPageFrm ), 159 mbFormatOnlyAsCharAnchored( false ), 160 mbConsiderWrapOnObjPos( _rPageFrm.GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ), 161 mpLayAction( _pLayAction ), 162 // --> OD 2004-10-04 #i26945# 163 mpPgNumAndTypeOfAnchors( _bCollectPgNumOfAnchors ? new SwPageNumAndTypeOfAnchors() : 0L ) 164 // <-- 165 { 166 } 167 168 SwObjectFormatter::~SwObjectFormatter() 169 { 170 delete mpPgNumAndTypeOfAnchors; 171 } 172 173 SwObjectFormatter* SwObjectFormatter::CreateObjFormatter( 174 SwFrm& _rAnchorFrm, 175 const SwPageFrm& _rPageFrm, 176 SwLayAction* _pLayAction ) 177 { 178 SwObjectFormatter* pObjFormatter = 0L; 179 if ( _rAnchorFrm.IsTxtFrm() ) 180 { 181 pObjFormatter = SwObjectFormatterTxtFrm::CreateObjFormatter( 182 static_cast<SwTxtFrm&>(_rAnchorFrm), 183 _rPageFrm, _pLayAction ); 184 } 185 else if ( _rAnchorFrm.IsLayoutFrm() ) 186 { 187 pObjFormatter = SwObjectFormatterLayFrm::CreateObjFormatter( 188 static_cast<SwLayoutFrm&>(_rAnchorFrm), 189 _rPageFrm, _pLayAction ); 190 } 191 else 192 { 193 ASSERT( false, 194 "<SwObjectFormatter::CreateObjFormatter(..)> - unexcepted type of anchor frame" ); 195 } 196 197 return pObjFormatter; 198 } 199 200 /** method to format all floating screen objects at the given anchor frame 201 202 @author OD 203 */ 204 bool SwObjectFormatter::FormatObjsAtFrm( SwFrm& _rAnchorFrm, 205 const SwPageFrm& _rPageFrm, 206 SwLayAction* _pLayAction ) 207 { 208 bool bSuccess( true ); 209 210 // create corresponding object formatter 211 SwObjectFormatter* pObjFormatter = 212 SwObjectFormatter::CreateObjFormatter( _rAnchorFrm, _rPageFrm, _pLayAction ); 213 214 if ( pObjFormatter ) 215 { 216 // format anchored floating screen objects 217 bSuccess = pObjFormatter->DoFormatObjs(); 218 } 219 delete pObjFormatter; 220 221 return bSuccess; 222 } 223 224 /** method to format a given floating screen object 225 226 @author OD 227 */ 228 bool SwObjectFormatter::FormatObj( SwAnchoredObject& _rAnchoredObj, 229 SwFrm* _pAnchorFrm, 230 const SwPageFrm* _pPageFrm, 231 SwLayAction* _pLayAction ) 232 { 233 bool bSuccess( true ); 234 235 ASSERT( _pAnchorFrm || _rAnchoredObj.GetAnchorFrm(), 236 "<SwObjectFormatter::FormatObj(..)> - missing anchor frame" ); 237 SwFrm& rAnchorFrm = _pAnchorFrm ? *(_pAnchorFrm) : *(_rAnchoredObj.AnchorFrm()); 238 239 ASSERT( _pPageFrm || rAnchorFrm.FindPageFrm(), 240 "<SwObjectFormatter::FormatObj(..)> - missing page frame" ); 241 const SwPageFrm& rPageFrm = _pPageFrm ? *(_pPageFrm) : *(rAnchorFrm.FindPageFrm()); 242 243 // create corresponding object formatter 244 SwObjectFormatter* pObjFormatter = 245 SwObjectFormatter::CreateObjFormatter( rAnchorFrm, rPageFrm, _pLayAction ); 246 247 if ( pObjFormatter ) 248 { 249 // format given floating screen object 250 // --> OD 2005-01-10 #i40147# - check for moved forward anchor frame 251 bSuccess = pObjFormatter->DoFormatObj( _rAnchoredObj, true ); 252 // <-- 253 } 254 delete pObjFormatter; 255 256 return bSuccess; 257 } 258 259 /** helper method for method <_FormatObj(..)> - performs the intrinsic format 260 of the layout of the given layout frame and all its lower layout frames. 261 262 OD 2004-06-28 #i28701# 263 IMPORTANT NOTE: 264 Method corresponds to methods <SwLayAction::FormatLayoutFly(..)> and 265 <SwLayAction::FormatLayout(..)>. Thus, its code for the formatting have 266 to be synchronised. 267 268 @author OD 269 */ 270 void SwObjectFormatter::_FormatLayout( SwLayoutFrm& _rLayoutFrm ) 271 { 272 _rLayoutFrm.Calc(); 273 274 SwFrm* pLowerFrm = _rLayoutFrm.Lower(); 275 while ( pLowerFrm ) 276 { 277 if ( pLowerFrm->IsLayoutFrm() ) 278 { 279 _FormatLayout( *(static_cast<SwLayoutFrm*>(pLowerFrm)) ); 280 } 281 pLowerFrm = pLowerFrm->GetNext(); 282 } 283 } 284 285 /** helper method for method <_FormatObj(..)> - performs the intrinsic 286 format of the content of the given floating screen object. 287 288 OD 2004-06-28 #i28701# 289 290 @author OD 291 */ 292 void SwObjectFormatter::_FormatObjCntnt( SwAnchoredObject& _rAnchoredObj ) 293 { 294 if ( !_rAnchoredObj.ISA(SwFlyFrm) ) 295 { 296 // only Writer fly frames have content 297 return; 298 } 299 300 SwFlyFrm& rFlyFrm = static_cast<SwFlyFrm&>(_rAnchoredObj); 301 SwCntntFrm* pCntnt = rFlyFrm.ContainsCntnt(); 302 303 while ( pCntnt ) 304 { 305 // format content 306 pCntnt->OptCalc(); 307 308 // format floating screen objects at content text frame 309 // --> OD 2004-11-01 #i23129#, #i36347# - pass correct page frame to 310 // the object formatter 311 if ( pCntnt->IsTxtFrm() && 312 !SwObjectFormatter::FormatObjsAtFrm( *pCntnt, 313 *(pCntnt->FindPageFrm()), 314 GetLayAction() ) ) 315 // <-- 316 { 317 // restart format with first content 318 pCntnt = rFlyFrm.ContainsCntnt(); 319 continue; 320 } 321 322 // continue with next content 323 pCntnt = pCntnt->GetNextCntntFrm(); 324 } 325 } 326 327 /** performs the intrinsic format of a given floating screen object and its content. 328 329 OD 2004-06-28 #i28701# 330 331 @author OD 332 */ 333 void SwObjectFormatter::_FormatObj( SwAnchoredObject& _rAnchoredObj ) 334 { 335 // check, if only as-character anchored object have to be formatted, and 336 // check the anchor type 337 if ( FormatOnlyAsCharAnchored() && 338 !(_rAnchoredObj.GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AS_CHAR) ) 339 { 340 return; 341 } 342 343 // collect anchor object and its 'anchor' page number, if requested 344 if ( mpPgNumAndTypeOfAnchors ) 345 { 346 mpPgNumAndTypeOfAnchors->Collect( _rAnchoredObj ); 347 } 348 349 if ( _rAnchoredObj.ISA(SwFlyFrm) ) 350 { 351 SwFlyFrm& rFlyFrm = static_cast<SwFlyFrm&>(_rAnchoredObj); 352 // --> OD 2004-11-15 #i34753# - reset flag, which prevents a positioning 353 if ( rFlyFrm.IsFlyLayFrm() ) 354 { 355 static_cast<SwFlyLayFrm&>(rFlyFrm).SetNoMakePos( false ); 356 } 357 // <-- 358 359 // FME 2007-08-30 #i81146# new loop control 360 sal_uInt16 nLoopControlRuns = 0; 361 const sal_uInt16 nLoopControlMax = 15; 362 363 do { 364 if ( mpLayAction ) 365 { 366 mpLayAction->FormatLayoutFly( &rFlyFrm ); 367 // --> OD 2005-07-13 #124218# - consider, if the layout action 368 // has to be restarted due to a delete of a page frame. 369 if ( mpLayAction->IsAgain() ) 370 { 371 break; 372 } 373 // <-- 374 } 375 else 376 { 377 _FormatLayout( rFlyFrm ); 378 } 379 // --> OD 2004-11-15 #i34753# - prevent further positioning, if 380 // to-page|to-fly anchored Writer fly frame is already clipped. 381 if ( rFlyFrm.IsFlyLayFrm() && rFlyFrm.IsClipped() ) 382 { 383 static_cast<SwFlyLayFrm&>(rFlyFrm).SetNoMakePos( true ); 384 } 385 // <-- 386 // --> OD 2004-11-02 #i23129#, #i36347# - pass correct page frame 387 // to the object formatter 388 SwObjectFormatter::FormatObjsAtFrm( rFlyFrm, 389 *(rFlyFrm.FindPageFrm()), 390 mpLayAction ); 391 // <-- 392 if ( mpLayAction ) 393 { 394 mpLayAction->_FormatFlyCntnt( &rFlyFrm ); 395 // --> OD 2005-07-13 #124218# - consider, if the layout action 396 // has to be restarted due to a delete of a page frame. 397 if ( mpLayAction->IsAgain() ) 398 { 399 break; 400 } 401 // <-- 402 } 403 else 404 { 405 _FormatObjCntnt( rFlyFrm ); 406 } 407 408 if ( ++nLoopControlRuns >= nLoopControlMax ) 409 { 410 #if OSL_DEBUG_LEVEL > 1 411 ASSERT( false, "LoopControl in SwObjectFormatter::_FormatObj: Stage 3!!!" ); 412 #endif 413 rFlyFrm.ValidateThisAndAllLowers( 2 ); 414 nLoopControlRuns = 0; 415 } 416 417 // --> OD 2006-02-02 #i57917# 418 // stop formatting of anchored object, if restart of layout process is requested. 419 } while ( !rFlyFrm.IsValid() && 420 !_rAnchoredObj.RestartLayoutProcess() && 421 rFlyFrm.GetAnchorFrm() == &GetAnchorFrm() ); 422 // <-- 423 } 424 else if ( _rAnchoredObj.ISA(SwAnchoredDrawObject) ) 425 { 426 _rAnchoredObj.MakeObjPos(); 427 } 428 } 429 430 /** invokes the intrinsic format method for all floating screen objects, 431 anchored at anchor frame on the given page frame 432 433 OD 2004-06-28 #i28701# 434 OD 2004-10-08 #i26945# - for format of floating screen objects for 435 follow text frames, the 'master' text frame is passed to the method. 436 Thus, the objects, whose anchor character is inside the follow text 437 frame can be formatted. 438 439 @author OD 440 */ 441 bool SwObjectFormatter::_FormatObjsAtFrm( SwTxtFrm* _pMasterTxtFrm ) 442 { 443 // --> OD 2004-10-08 #i26945# 444 SwFrm* pAnchorFrm( 0L ); 445 if ( GetAnchorFrm().IsTxtFrm() && 446 static_cast<SwTxtFrm&>(GetAnchorFrm()).IsFollow() && 447 _pMasterTxtFrm ) 448 { 449 pAnchorFrm = _pMasterTxtFrm; 450 } 451 else 452 { 453 pAnchorFrm = &GetAnchorFrm(); 454 } 455 // <-- 456 if ( !pAnchorFrm->GetDrawObjs() ) 457 { 458 // nothing to do, if no floating screen object is registered at the anchor frame. 459 return true; 460 } 461 462 bool bSuccess( true ); 463 464 sal_uInt32 i = 0; 465 for ( ; i < pAnchorFrm->GetDrawObjs()->Count(); ++i ) 466 { 467 SwAnchoredObject* pAnchoredObj = (*pAnchorFrm->GetDrawObjs())[i]; 468 469 // check, if object's anchor is on the given page frame or 470 // object is registered at the given page frame. 471 // --> OD 2004-10-05 #i26945# - check, if the anchor character of the 472 // anchored object is located in a follow text frame. If this anchor 473 // follow text frame differs from the given anchor frame, the given 474 // anchor frame is a 'master' text frame of the anchor follow text frame. 475 // If the anchor follow text frame is in the same body as its 'master' 476 // text frame, do not format the anchored object. 477 // E.g., this situation can occur during the table row splitting algorithm. 478 SwTxtFrm* pAnchorCharFrm = pAnchoredObj->FindAnchorCharFrm(); 479 const bool bAnchoredAtFollowInSameBodyAsMaster = 480 pAnchorCharFrm && pAnchorCharFrm->IsFollow() && 481 pAnchorCharFrm != pAnchoredObj->GetAnchorFrm() && 482 pAnchorCharFrm->FindBodyFrm() == 483 static_cast<SwTxtFrm*>(pAnchoredObj->AnchorFrm())->FindBodyFrm(); 484 if ( bAnchoredAtFollowInSameBodyAsMaster ) 485 { 486 continue; 487 } 488 // <-- 489 // --> OD 2004-09-23 #i33751#, #i34060# - method <GetPageFrmOfAnchor()> 490 // is replaced by method <FindPageFrmOfAnchor()>. It's return value 491 // have to be checked. 492 SwPageFrm* pPageFrmOfAnchor = pAnchoredObj->FindPageFrmOfAnchor(); 493 ASSERT( pPageFrmOfAnchor, 494 "<SwObjectFormatter::_FormatObjsAtFrm()> - missing page frame." ); 495 // --> OD 2004-10-08 #i26945# 496 if ( pPageFrmOfAnchor && pPageFrmOfAnchor == &mrPageFrm ) 497 // <-- 498 { 499 // if format of object fails, stop formatting and pass fail to 500 // calling method via the return value. 501 if ( !DoFormatObj( *pAnchoredObj ) ) 502 { 503 bSuccess = false; 504 break; 505 } 506 507 // considering changes at <pAnchorFrm->GetDrawObjs()> during 508 // format of the object. 509 if ( !pAnchorFrm->GetDrawObjs() || 510 i > pAnchorFrm->GetDrawObjs()->Count() ) 511 { 512 break; 513 } 514 else 515 { 516 sal_uInt32 nActPosOfObj = 517 pAnchorFrm->GetDrawObjs()->ListPosOf( *pAnchoredObj ); 518 if ( nActPosOfObj == pAnchorFrm->GetDrawObjs()->Count() || 519 nActPosOfObj > i ) 520 { 521 --i; 522 } 523 else if ( nActPosOfObj < i ) 524 { 525 i = nActPosOfObj; 526 } 527 } 528 } 529 } // end of loop on <pAnchorFrm->.GetDrawObjs()> 530 531 return bSuccess; 532 } 533 534 /** accessor to collected anchored object 535 536 OD 2004-07-05 #i28701# 537 538 @author OD 539 */ 540 SwAnchoredObject* SwObjectFormatter::GetCollectedObj( const sal_uInt32 _nIndex ) 541 { 542 return mpPgNumAndTypeOfAnchors ? (*mpPgNumAndTypeOfAnchors)[_nIndex] : 0L; 543 } 544 545 /** accessor to 'anchor' page number of collected anchored object 546 547 OD 2004-07-05 #i28701# 548 549 @author OD 550 */ 551 sal_uInt32 SwObjectFormatter::GetPgNumOfCollected( const sal_uInt32 _nIndex ) 552 { 553 return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->GetPageNum(_nIndex) : 0L; 554 } 555 556 /** accessor to 'anchor' type of collected anchored object 557 558 OD 2004-10-04 #i26945# 559 560 @author OD 561 */ 562 bool SwObjectFormatter::IsCollectedAnchoredAtMaster( const sal_uInt32 _nIndex ) 563 { 564 return mpPgNumAndTypeOfAnchors 565 ? mpPgNumAndTypeOfAnchors->AnchoredAtMaster(_nIndex) 566 : true; 567 } 568 569 /** accessor to total number of collected anchored objects 570 571 OD 2004-07-05 #i28701# 572 573 @author OD 574 */ 575 sal_uInt32 SwObjectFormatter::CountOfCollected() 576 { 577 return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->Count() : 0L; 578 } 579