1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <pagefrm.hxx> 21 #include <rootfrm.hxx> 22 #include <cntfrm.hxx> 23 #include <dflyobj.hxx> 24 #include <dcontact.hxx> 25 #include <ftnfrm.hxx> 26 #include <frmtool.hxx> 27 #include <hints.hxx> 28 #include <sectfrm.hxx> 29 #include <notxtfrm.hxx> 30 #include <txtfly.hxx> 31 32 #include <svx/svdpage.hxx> 33 #include <editeng/ulspitem.hxx> 34 #include <fmtornt.hxx> 35 #include <fmtfsize.hxx> 36 #include <ndole.hxx> 37 #include <tabfrm.hxx> 38 #include <flyfrms.hxx> 39 #include <fmtfollowtextflow.hxx> 40 #include <environmentofanchoredobject.hxx> 41 #include <sortedobjs.hxx> 42 #include <viewimp.hxx> 43 #include <IDocumentSettingAccess.hxx> 44 #include <IDocumentDrawModelAccess.hxx> 45 #include <pam.hxx> 46 #include <ndindex.hxx> 47 #include <basegfx/matrix/b2dhommatrixtools.hxx> 48 #include <svx/sdr/attribute/sdrallfillattributeshelper.hxx> 49 50 using namespace ::com::sun::star; 51 52 SwFlyFreeFrame::SwFlyFreeFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch ) 53 : SwFlyFrame( pFormat, pSib, pAnch ), 54 // #i34753# 55 mbNoMakePos( false ), 56 // #i37068# 57 mbNoMoveOnCheckClip( false ), 58 maUnclippedFrame(), 59 // RotateFlyFrame3 60 mpTransformableSwFrame() 61 { 62 } 63 64 void SwFlyFreeFrame::DestroyImpl() 65 { 66 // #i28701# - use new method <GetPageFrame()> 67 if( GetPageFrame() ) 68 { 69 if( GetFormat()->GetDoc()->IsInDtor() ) 70 { 71 // #i29879# - remove also to-frame anchored Writer 72 // fly frame from page. 73 const bool bRemoveFromPage = 74 GetPageFrame()->GetSortedObjs() && 75 ( IsFlyAtContentFrame() || 76 ( GetAnchorFrame() && GetAnchorFrame()->IsFlyFrame() ) ); 77 if ( bRemoveFromPage ) 78 { 79 GetPageFrame()->GetSortedObjs()->Remove( *this ); 80 } 81 } 82 else 83 { 84 SwRect aTmp( GetObjRectWithSpaces() ); 85 SwFlyFreeFrame::NotifyBackground( GetPageFrame(), aTmp, PREP_FLY_LEAVE ); 86 } 87 } 88 89 SwFlyFrame::DestroyImpl(); 90 } 91 92 SwFlyFreeFrame::~SwFlyFreeFrame() 93 { 94 #if 0 95 // we are possibly in ContourCache, make sure we vanish 96 ::ClrContourCache(GetVirtDrawObj()); 97 #endif 98 } 99 100 // #i28701# 101 /** Notifies the background (all ContentFrames that currently are overlapping). 102 * 103 * Additionally, the window is also directly invalidated (especially where 104 * there are no overlapping ContentFrames). 105 * This also takes ContentFrames within other Flys into account. 106 */ 107 void SwFlyFreeFrame::NotifyBackground( SwPageFrame *pPageFrame, 108 const SwRect& rRect, PrepareHint eHint ) 109 { 110 ::Notify_Background( GetVirtDrawObj(), pPageFrame, rRect, eHint, true ); 111 } 112 113 void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/) 114 { 115 if ( !GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) ) 116 { 117 return; 118 } 119 120 if ( !GetAnchorFrame() || IsLocked() || IsColLocked() ) 121 { 122 return; 123 } 124 125 // #i28701# - use new method <GetPageFrame()> 126 if( !GetPageFrame() && GetAnchorFrame()->IsInFly() ) 127 { 128 SwFlyFrame* pFly = AnchorFrame()->FindFlyFrame(); 129 SwPageFrame *pPageFrame = pFly ? pFly->FindPageFrame() : nullptr; 130 if( pPageFrame ) 131 pPageFrame->AppendFlyToPage( this ); 132 } 133 134 if( !GetPageFrame() ) 135 { 136 return; 137 } 138 139 Lock(); // The curtain drops 140 141 // takes care of the notification in the dtor 142 const SwFlyNotify aNotify( this ); 143 144 if ( IsClipped() ) 145 { 146 setFrameAreaSizeValid(false); 147 m_bHeightClipped = m_bWidthClipped = false; 148 // no invalidation of position, 149 // if anchored object is anchored inside a Writer fly frame, 150 // its position is already locked, and it follows the text flow. 151 // #i34753# - add condition: 152 // no invalidation of position, if no direct move is requested in <CheckClip(..)> 153 if ( !IsNoMoveOnCheckClip() && 154 !( PositionLocked() && 155 GetAnchorFrame()->IsInFly() && 156 GetFrameFormat().GetFollowTextFlow().GetValue() ) ) 157 { 158 setFrameAreaPositionValid(false); 159 } 160 } 161 162 // #i81146# new loop control 163 int nLoopControlRuns = 0; 164 const int nLoopControlMax = 10; 165 166 // RotateFlyFrame3 - outer frame 167 const double fRotation(getLocalFrameRotation()); 168 const bool bRotated(!basegfx::fTools::equalZero(fRotation)); 169 170 if(bRotated) 171 { 172 // Re-layout may be partially (see all isFrameAreaDefinitionValid() flags), 173 // so resetting the local SwFrame(s) in the local SwFrameAreaDefinition is 174 // needed. Reset to BoundAreas will be done below automatically 175 if(isTransformableSwFrame()) 176 { 177 getTransformableSwFrame()->restoreFrameAreas(); 178 } 179 } 180 181 while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() || m_bFormatHeightOnly || !m_bValidContentPos ) 182 { 183 SwRectFnSet aRectFnSet(this); 184 const SwFormatFrameSize *pSz; 185 { // Additional scope, so aAccess will be destroyed before the check! 186 187 SwBorderAttrAccess aAccess( SwFrame::GetCache(), this ); 188 const SwBorderAttrs &rAttrs = *aAccess.Get(); 189 pSz = &rAttrs.GetAttrSet().GetFrameSize(); 190 191 // Only set when the flag is set! 192 if ( !isFrameAreaSizeValid() ) 193 { 194 setFramePrintAreaValid(false); 195 } 196 197 if ( !isFramePrintAreaValid() ) 198 { 199 MakePrtArea( rAttrs ); 200 m_bValidContentPos = false; 201 } 202 203 if ( !isFrameAreaSizeValid() || m_bFormatHeightOnly ) 204 { 205 setFrameAreaSizeValid(false); 206 Format( getRootFrame()->GetCurrShell()->GetOut(), &rAttrs ); 207 m_bFormatHeightOnly = false; 208 } 209 } 210 211 if ( !isFrameAreaPositionValid() ) 212 { 213 const Point aOldPos( aRectFnSet.GetPos(getFrameArea()) ); 214 // #i26791# - use new method <MakeObjPos()> 215 // #i34753# - no positioning, if requested. 216 if ( IsNoMakePos() ) 217 { 218 setFrameAreaPositionValid(true); 219 } 220 else 221 // #i26791# - use new method <MakeObjPos()> 222 MakeObjPos(); 223 if( aOldPos == aRectFnSet.GetPos(getFrameArea()) ) 224 { 225 if( !isFrameAreaPositionValid() && GetAnchorFrame()->IsInSct() && 226 !GetAnchorFrame()->FindSctFrame()->isFrameAreaDefinitionValid() ) 227 { 228 setFrameAreaPositionValid(true); 229 } 230 } 231 else 232 { 233 setFrameAreaSizeValid(false); 234 } 235 } 236 237 if ( !m_bValidContentPos ) 238 { 239 SwBorderAttrAccess aAccess( SwFrame::GetCache(), this ); 240 const SwBorderAttrs &rAttrs = *aAccess.Get(); 241 MakeContentPos( rAttrs ); 242 } 243 244 if ( isFrameAreaPositionValid() && isFrameAreaSizeValid() ) 245 { 246 ++nLoopControlRuns; 247 248 OSL_ENSURE( nLoopControlRuns < nLoopControlMax, "LoopControl in SwFlyFreeFrame::MakeAll" ); 249 250 if ( nLoopControlRuns < nLoopControlMax ) 251 CheckClip( *pSz ); 252 } 253 else 254 nLoopControlRuns = 0; 255 } 256 257 // RotateFlyFrame3 - outer frame 258 // Do not refresh transforms/Areas self here, this will be done 259 // when inner and outer frame are layouted, in SwNoTextFrame::MakeAll 260 if(bRotated) 261 { 262 // RotateFlyFrame3: Safe changes locally 263 // get center from outer frame (layout frame) to be on the safe side 264 const Point aCenter(getFrameArea().Center()); 265 const basegfx::B2DPoint aB2DCenter(aCenter.X(), aCenter.Y()); 266 267 if(!mpTransformableSwFrame) 268 { 269 mpTransformableSwFrame.reset(new TransformableSwFrame(*this)); 270 } 271 272 getTransformableSwFrame()->createFrameAreaTransformations( 273 fRotation, 274 aB2DCenter); 275 getTransformableSwFrame()->adaptFrameAreasToTransformations(); 276 } 277 else 278 { 279 // RotateFlyFrame3: Also need to clear ContourCache (if used), 280 // usually done in SwFlyFrame::NotifyDrawObj, but there relies on 281 // being in transform mode which is already resetted then 282 if(isTransformableSwFrame()) 283 { 284 ::ClrContourCache(GetVirtDrawObj()); 285 } 286 287 // reset transformations to show that they are not used 288 mpTransformableSwFrame.reset(); 289 } 290 291 Unlock(); 292 293 #if OSL_DEBUG_LEVEL > 0 294 SwRectFnSet aRectFnSet(this); 295 OSL_ENSURE( m_bHeightClipped || ( aRectFnSet.GetHeight(getFrameArea()) > 0 && 296 aRectFnSet.GetHeight(getFramePrintArea()) > 0), 297 "SwFlyFreeFrame::Format(), flipping Fly." ); 298 299 #endif 300 } 301 302 bool SwFlyFreeFrame::supportsAutoContour() const 303 { 304 static bool bOverrideHandleContourToAlwaysOff(true); 305 306 // RotateFlyFrameFix: For LO6.0 we need to deactivate the AutoContour feature again, it is simply 307 // not clear how/if to use and save/load it in ODF. This has to be discussed. 308 // The reason not to remove is that this may be used as-is now, using a new switch. 309 // Even when not, the detection if it is possible will be needed in any case later. 310 if(bOverrideHandleContourToAlwaysOff) 311 { 312 return false; 313 } 314 315 if(!isTransformableSwFrame()) 316 { 317 // support only when transformed, else there is no free space 318 return false; 319 } 320 321 // Check for Borders. If we have Borders, do (currently) not support, 322 // since borders do not transform with the object. 323 // (Will need to be enhanced to take into account if we have Borders and if these 324 // transform with the object) 325 SwBorderAttrAccess aAccess(SwFrame::GetCache(), this); 326 const SwBorderAttrs &rAttrs(*aAccess.Get()); 327 328 if(rAttrs.IsLine()) 329 { 330 return false; 331 } 332 333 // Check for Padding. Do not support when padding is used, this will 334 // produce a covered space around the object (filled with fill defines) 335 const SfxPoolItem* pItem(nullptr); 336 337 if(GetFormat() && SfxItemState::SET == GetFormat()->GetItemState(RES_BOX, false, &pItem)) 338 { 339 const SvxBoxItem& rBox = *static_cast< const SvxBoxItem* >(pItem); 340 341 if(rBox.HasBorder(/*bTreatPaddingAsBorder*/true)) 342 { 343 return false; 344 } 345 } 346 347 // check for Fill - if we have fill, it will fill the gaps and we will not 348 // support AutoContour 349 if(GetFormat() && GetFormat()->supportsFullDrawingLayerFillAttributeSet()) 350 { 351 const drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes(GetFormat()->getSdrAllFillAttributesHelper()); 352 353 if(aFillAttributes.get() && aFillAttributes->isUsed()) 354 { 355 return false; 356 } 357 } 358 else 359 { 360 const SvxBrushItem aBack(GetFormat()->makeBackgroundBrushItem()); 361 362 if(aBack.isUsed()) 363 { 364 return false; 365 } 366 } 367 368 // else, support 369 return true; 370 } 371 372 // RotateFlyFrame3 - Support for Transformations - outer frame 373 basegfx::B2DHomMatrix SwFlyFreeFrame::getFrameAreaTransformation() const 374 { 375 if(isTransformableSwFrame()) 376 { 377 // use pre-created transformation 378 return getTransformableSwFrame()->getLocalFrameAreaTransformation(); 379 } 380 381 // call parent 382 return SwFlyFrame::getFrameAreaTransformation(); 383 } 384 385 basegfx::B2DHomMatrix SwFlyFreeFrame::getFramePrintAreaTransformation() const 386 { 387 if(isTransformableSwFrame()) 388 { 389 // use pre-created transformation 390 return getTransformableSwFrame()->getLocalFramePrintAreaTransformation(); 391 } 392 393 // call parent 394 return SwFlyFrame::getFramePrintAreaTransformation(); 395 } 396 397 // RotateFlyFrame3 - Support for Transformations 398 void SwFlyFreeFrame::transform_translate(const Point& rOffset) 399 { 400 // call parent - this will do the basic transform for SwRect(s) 401 // in the SwFrameAreaDefinition 402 SwFlyFrame::transform_translate(rOffset); 403 404 // check if the Transformations need to be adapted 405 if(isTransformableSwFrame()) 406 { 407 const basegfx::B2DHomMatrix aTransform( 408 basegfx::utils::createTranslateB2DHomMatrix( 409 rOffset.X(), rOffset.Y())); 410 411 // transform using TransformableSwFrame 412 getTransformableSwFrame()->transform(aTransform); 413 } 414 } 415 416 // RotateFlyFrame3 - outer frame 417 double getLocalFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame) 418 { 419 return rNoTextFrame.getLocalFrameRotation(); 420 } 421 422 double SwFlyFreeFrame::getLocalFrameRotation() const 423 { 424 // SwLayoutFrame::Lower() != SwFrame::GetLower(), but SwFrame::GetLower() 425 // calls SwLayoutFrame::Lower() when it's a SwLayoutFrame - so use GetLower() 426 const SwNoTextFrame* pSwNoTextFrame(dynamic_cast< const SwNoTextFrame* >(GetLower())); 427 428 if(nullptr != pSwNoTextFrame) 429 { 430 return getLocalFrameRotation_from_SwNoTextFrame(*pSwNoTextFrame); 431 } 432 433 // no rotation 434 return 0.0; 435 } 436 437 /** determines, if direct environment of fly frame has 'auto' size 438 439 #i17297# 440 start with anchor frame and search via <GetUpper()> for a header, footer, 441 row or fly frame stopping at page frame. 442 return <true>, if such a frame is found and it has 'auto' size. 443 otherwise <false> is returned. 444 445 @return boolean indicating, that direct environment has 'auto' size 446 */ 447 bool SwFlyFreeFrame::HasEnvironmentAutoSize() const 448 { 449 bool bRetVal = false; 450 451 const SwFrame* pToBeCheckedFrame = GetAnchorFrame(); 452 while ( pToBeCheckedFrame && 453 !pToBeCheckedFrame->IsPageFrame() ) 454 { 455 if ( pToBeCheckedFrame->IsHeaderFrame() || 456 pToBeCheckedFrame->IsFooterFrame() || 457 pToBeCheckedFrame->IsRowFrame() || 458 pToBeCheckedFrame->IsFlyFrame() ) 459 { 460 bRetVal = ATT_FIX_SIZE != 461 pToBeCheckedFrame->GetAttrSet()->GetFrameSize().GetHeightSizeType(); 462 break; 463 } 464 else 465 { 466 pToBeCheckedFrame = pToBeCheckedFrame->GetUpper(); 467 } 468 } 469 470 return bRetVal; 471 } 472 473 void SwFlyFreeFrame::CheckClip( const SwFormatFrameSize &rSz ) 474 { 475 // It's probably time now to take appropriate measures, if the Fly 476 // doesn't fit into its surrounding. 477 // First, the Fly gives up its position, then it's formatted. 478 // Only if it still doesn't fit after giving up its position, the 479 // width or height are given up as well. The frame will be squeezed 480 // as much as needed. 481 482 const SwVirtFlyDrawObj *pObj = GetVirtDrawObj(); 483 SwRect aClip, aTmpStretch; 484 ::CalcClipRect( pObj, aClip ); 485 ::CalcClipRect( pObj, aTmpStretch, false ); 486 aClip.Intersection_( aTmpStretch ); 487 488 const long nBot = getFrameArea().Top() + getFrameArea().Height(); 489 const long nRig = getFrameArea().Left() + getFrameArea().Width(); 490 const long nClipBot = aClip.Top() + aClip.Height(); 491 const long nClipRig = aClip.Left() + aClip.Width(); 492 493 const bool bBot = nBot > nClipBot; 494 const bool bRig = nRig > nClipRig; 495 if ( bBot || bRig ) 496 { 497 bool bAgain = false; 498 // #i37068# - no move, if it's requested 499 if ( bBot && !IsNoMoveOnCheckClip() && 500 !GetDrawObjs() && !GetAnchorFrame()->IsInTab() ) 501 { 502 SwFrame* pHeader = FindFooterOrHeader(); 503 // In a header, correction of the position is no good idea. 504 // If the fly moves, some paragraphs have to be formatted, this 505 // could cause a change of the height of the headerframe, 506 // now the flyframe can change its position and so on ... 507 if ( !pHeader || !pHeader->IsHeaderFrame() ) 508 { 509 const long nOld = getFrameArea().Top(); 510 511 // tdf#112443 disable positioning if content is completely off page 512 bool bDisableOffPagePositioning = GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING); 513 if ( !bDisableOffPagePositioning || nOld <= nClipBot) 514 { 515 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); 516 aFrm.Pos().setY( std::max( aClip.Top(), nClipBot - aFrm.Height() ) ); 517 } 518 519 if ( getFrameArea().Top() != nOld ) 520 { 521 bAgain = true; 522 } 523 524 m_bHeightClipped = true; 525 } 526 } 527 if ( bRig ) 528 { 529 const long nOld = getFrameArea().Left(); 530 531 // tdf#112443 disable positioning if content is completely off page 532 bool bDisableOffPagePositioning = GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING); 533 if ( !bDisableOffPagePositioning || nOld <= nClipRig ) 534 { 535 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); 536 aFrm.Pos().setX( std::max( aClip.Left(), nClipRig - aFrm.Width() ) ); 537 } 538 539 if ( getFrameArea().Left() != nOld ) 540 { 541 const SwFormatHoriOrient &rH = GetFormat()->GetHoriOrient(); 542 // Left-aligned ones may not be moved to the left when they 543 // are avoiding another one. 544 if( rH.GetHoriOrient() == text::HoriOrientation::LEFT ) 545 { 546 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); 547 aFrm.Pos().setX( nOld ); 548 } 549 else 550 { 551 bAgain = true; 552 } 553 } 554 m_bWidthClipped = true; 555 } 556 if ( bAgain ) 557 { 558 setFrameAreaSizeValid(false); 559 } 560 else 561 { 562 // If we reach this branch, the Frame protrudes into forbidden 563 // areas, and correcting the position is not allowed or not 564 // possible or not required. 565 566 // For Flys with OLE objects as lower, we make sure that 567 // we always resize proportionally 568 Size aOldSize( getFrameArea().SSize() ); 569 570 // First, setup the FrameRect, then transfer it to the Frame. 571 SwRect aFrameRect( getFrameArea() ); 572 573 if ( bBot ) 574 { 575 long nDiff = nClipBot; 576 nDiff -= aFrameRect.Top(); // nDiff represents the available distance 577 nDiff = aFrameRect.Height() - nDiff; 578 aFrameRect.Height( aFrameRect.Height() - nDiff ); 579 m_bHeightClipped = true; 580 } 581 if ( bRig ) 582 { 583 long nDiff = nClipRig; 584 nDiff -= aFrameRect.Left();// nDiff represents the available distance 585 nDiff = aFrameRect.Width() - nDiff; 586 aFrameRect.Width( aFrameRect.Width() - nDiff ); 587 m_bWidthClipped = true; 588 } 589 590 // #i17297# - no proportional 591 // scaling of graphics in environments, which determines its size 592 // by its content ('auto' size). Otherwise layout loops can occur and 593 // layout sizes of the environment can be incorrect. 594 // Such environment are: 595 // (1) header and footer frames with 'auto' size 596 // (2) table row frames with 'auto' size 597 // (3) fly frames with 'auto' size 598 // Note: section frames seems to be not critical - didn't found 599 // any critical layout situation so far. 600 if ( Lower() && Lower()->IsNoTextFrame() && 601 (static_cast<SwNoTextFrame*>(Lower())->GetNode()->GetOLENode() || 602 !HasEnvironmentAutoSize() ) ) 603 { 604 // If width and height got adjusted, then the bigger 605 // change is relevant. 606 if ( aFrameRect.Width() != aOldSize.Width() && 607 aFrameRect.Height()!= aOldSize.Height() ) 608 { 609 if ( (aOldSize.Width() - aFrameRect.Width()) > 610 (aOldSize.Height()- aFrameRect.Height()) ) 611 aFrameRect.Height( aOldSize.Height() ); 612 else 613 aFrameRect.Width( aOldSize.Width() ); 614 } 615 616 // Adjusted the width? change height proportionally 617 if( aFrameRect.Width() != aOldSize.Width() ) 618 { 619 aFrameRect.Height( aFrameRect.Width() * aOldSize.Height() / 620 aOldSize.Width() ); 621 m_bHeightClipped = true; 622 } 623 // Adjusted the height? change width proportionally 624 else if( aFrameRect.Height() != aOldSize.Height() ) 625 { 626 aFrameRect.Width( aFrameRect.Height() * aOldSize.Width() / 627 aOldSize.Height() ); 628 m_bWidthClipped = true; 629 } 630 631 // #i17297# - reactivate change 632 // of size attribute for fly frames containing an ole object. 633 634 // Added the aFrameRect.HasArea() hack, because 635 // the environment of the ole object does not have to be valid 636 // at this moment, or even worse, it does not have to have a 637 // reasonable size. In this case we do not want to change to 638 // attributes permanently. Maybe one day somebody dares to remove 639 // this code. 640 if ( aFrameRect.HasArea() && 641 static_cast<SwNoTextFrame*>(Lower())->GetNode()->GetOLENode() && 642 ( m_bWidthClipped || m_bHeightClipped ) ) 643 { 644 SwFlyFrameFormat *pFormat = GetFormat(); 645 pFormat->LockModify(); 646 SwFormatFrameSize aFrameSize( rSz ); 647 aFrameSize.SetWidth( aFrameRect.Width() ); 648 aFrameSize.SetHeight( aFrameRect.Height() ); 649 pFormat->SetFormatAttr( aFrameSize ); 650 pFormat->UnlockModify(); 651 } 652 } 653 654 // Now change the Frame; for columns, we put the new values into the attributes, 655 // otherwise we'll end up with unwanted side-effects/oscillations 656 const long nPrtHeightDiff = getFrameArea().Height() - getFramePrintArea().Height(); 657 const long nPrtWidthDiff = getFrameArea().Width() - getFramePrintArea().Width(); 658 maUnclippedFrame = getFrameArea(); 659 660 { 661 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); 662 aFrm.Height( aFrameRect.Height() ); 663 aFrm.Width ( std::max( long(MINLAY), aFrameRect.Width() ) ); 664 } 665 666 if ( Lower() && Lower()->IsColumnFrame() ) 667 { 668 ColLock(); //lock grow/shrink 669 const Size aTmpOldSize( getFramePrintArea().SSize() ); 670 671 { 672 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); 673 aPrt.Height( getFrameArea().Height() - nPrtHeightDiff ); 674 aPrt.Width ( getFrameArea().Width() - nPrtWidthDiff ); 675 } 676 677 ChgLowersProp( aTmpOldSize ); 678 SwFrame *pLow = Lower(); 679 do 680 { 681 pLow->Calc(getRootFrame()->GetCurrShell()->GetOut()); 682 // also calculate the (Column)BodyFrame 683 static_cast<SwLayoutFrame*>(pLow)->Lower()->Calc(getRootFrame()->GetCurrShell()->GetOut()); 684 pLow = pLow->GetNext(); 685 } while ( pLow ); 686 ::CalcContent( this ); 687 ColUnlock(); 688 689 if ( !isFrameAreaSizeValid() && !m_bWidthClipped ) 690 { 691 setFrameAreaSizeValid(true); 692 m_bFormatHeightOnly = true; 693 } 694 } 695 else 696 { 697 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); 698 aPrt.Height( getFrameArea().Height() - nPrtHeightDiff ); 699 aPrt.Width ( getFrameArea().Width() - nPrtWidthDiff ); 700 } 701 } 702 } 703 704 // #i26945# 705 OSL_ENSURE( getFrameArea().Height() >= 0, 706 "<SwFlyFreeFrame::CheckClip(..)> - fly frame has negative height now." ); 707 } 708 709 /** method to determine, if a <MakeAll()> on the Writer fly frame is possible 710 #i43771# 711 */ 712 bool SwFlyFreeFrame::IsFormatPossible() const 713 { 714 return SwFlyFrame::IsFormatPossible() && 715 ( GetPageFrame() || 716 ( GetAnchorFrame() && GetAnchorFrame()->IsInFly() ) ); 717 } 718 719 SwFlyLayFrame::SwFlyLayFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch ) : 720 SwFlyFreeFrame( pFormat, pSib, pAnch ) 721 { 722 m_bLayout = true; 723 } 724 725 // #i28701# 726 727 void SwFlyLayFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew ) 728 { 729 const SwFormatAnchor *pAnch = nullptr; 730 731 if (pNew) 732 { 733 const sal_uInt16 nWhich = pNew->Which(); 734 if( RES_ATTRSET_CHG == nWhich && SfxItemState::SET == 735 static_cast<const SwAttrSetChg*>(pNew)->GetChgSet()->GetItemState( RES_ANCHOR, false, 736 reinterpret_cast<const SfxPoolItem**>(&pAnch) )) 737 ; // GetItemState sets the anchor pointer! 738 739 else if( RES_ANCHOR == nWhich ) 740 { 741 // Change of anchor. I'm attaching myself to the new place. 742 // It's not allowed to change the anchor type. This is only 743 // possible via SwFEShell. 744 pAnch = static_cast<const SwFormatAnchor*>(pNew); 745 } 746 } 747 748 if( pAnch ) 749 { 750 OSL_ENSURE( pAnch->GetAnchorId() == 751 GetFormat()->GetAnchor().GetAnchorId(), 752 "8-) Invalid change of anchor type." ); 753 754 // Unregister, get hold of the page, attach to the corresponding LayoutFrame. 755 SwRect aOld( GetObjRectWithSpaces() ); 756 // #i28701# - use new method <GetPageFrame()> 757 SwPageFrame *pOldPage = GetPageFrame(); 758 AnchorFrame()->RemoveFly( this ); 759 760 if ( RndStdIds::FLY_AT_PAGE == pAnch->GetAnchorId() ) 761 { 762 sal_uInt16 nPgNum = pAnch->GetPageNum(); 763 SwRootFrame *pRoot = getRootFrame(); 764 SwPageFrame *pTmpPage = static_cast<SwPageFrame*>(pRoot->Lower()); 765 for ( sal_uInt16 i = 1; (i <= nPgNum) && pTmpPage; ++i, 766 pTmpPage = static_cast<SwPageFrame*>(pTmpPage->GetNext()) ) 767 { 768 if ( i == nPgNum ) 769 { 770 // #i50432# - adjust synopsis of <PlaceFly(..)> 771 pTmpPage->PlaceFly( this, nullptr ); 772 } 773 } 774 if( !pTmpPage ) 775 { 776 pRoot->SetAssertFlyPages(); 777 pRoot->AssertFlyPages(); 778 } 779 } 780 else 781 { 782 SwNodeIndex aIdx( pAnch->GetContentAnchor()->nNode ); 783 SwContentFrame *pContent = GetFormat()->GetDoc()->GetNodes().GoNext( &aIdx )-> 784 GetContentNode()->getLayoutFrame(getRootFrame(), nullptr, nullptr); 785 if( pContent ) 786 { 787 SwFlyFrame *pTmp = pContent->FindFlyFrame(); 788 if( pTmp ) 789 pTmp->AppendFly( this ); 790 } 791 } 792 // #i28701# - use new method <GetPageFrame()> 793 if ( pOldPage && pOldPage != GetPageFrame() ) 794 NotifyBackground( pOldPage, aOld, PREP_FLY_LEAVE ); 795 SetCompletePaint(); 796 InvalidateAll(); 797 SetNotifyBack(); 798 } 799 else 800 SwFlyFrame::Modify( pOld, pNew ); 801 } 802 803 void SwPageFrame::AppendFlyToPage( SwFlyFrame *pNew ) 804 { 805 if ( !pNew->GetVirtDrawObj()->IsInserted() ) 806 getRootFrame()->GetDrawPage()->InsertObject( 807 static_cast<SdrObject*>(pNew->GetVirtDrawObj()), 808 pNew->GetVirtDrawObj()->GetReferencedObj().GetOrdNumDirect() ); 809 810 InvalidateSpelling(); 811 InvalidateSmartTags(); 812 InvalidateAutoCompleteWords(); 813 InvalidateWordCount(); 814 815 if ( GetUpper() ) 816 { 817 static_cast<SwRootFrame*>(GetUpper())->SetIdleFlags(); 818 static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth(); 819 } 820 821 SdrObject* pObj = pNew->GetVirtDrawObj(); 822 OSL_ENSURE( pNew->GetAnchorFrame(), "Fly without Anchor" ); 823 SwFlyFrame* pFly = const_cast<SwFlyFrame*>(pNew->GetAnchorFrame()->FindFlyFrame()); 824 if ( pFly && pObj->GetOrdNum() < pFly->GetVirtDrawObj()->GetOrdNum() ) 825 { 826 //#i119945# set pFly's OrdNum to _rNewObj's. So when pFly is removed by Undo, the original OrdNum will not be changed. 827 sal_uInt32 nNewNum = pObj->GetOrdNumDirect(); 828 if ( pObj->getSdrPageFromSdrObject() ) 829 pObj->getSdrPageFromSdrObject()->SetObjectOrdNum( pFly->GetVirtDrawObj()->GetOrdNumDirect(), nNewNum ); 830 else 831 pFly->GetVirtDrawObj()->SetOrdNum( nNewNum ); 832 } 833 834 // Don't look further at Flys that sit inside the Content. 835 if ( pNew->IsFlyInContentFrame() ) 836 InvalidateFlyInCnt(); 837 else 838 { 839 InvalidateFlyContent(); 840 841 if ( !m_pSortedObjs ) 842 { 843 m_pSortedObjs.reset(new SwSortedObjs()); 844 } 845 846 const bool bSuccessInserted = m_pSortedObjs->Insert( *pNew ); 847 OSL_ENSURE( bSuccessInserted, "Fly not inserted in Sorted." ); 848 849 // #i87493# 850 OSL_ENSURE( pNew->GetPageFrame() == nullptr || pNew->GetPageFrame() == this, 851 "<SwPageFrame::AppendFlyToPage(..)> - anchored fly frame seems to be registered at another page frame. Serious defect." ); 852 // #i28701# - use new method <SetPageFrame(..)> 853 pNew->SetPageFrame( this ); 854 pNew->InvalidatePage( this ); 855 // #i28701# 856 pNew->UnlockPosition(); 857 858 // Notify accessible layout. That's required at this place for 859 // frames only where the anchor is moved. Creation of new frames 860 // is additionally handled by the SwFrameNotify class. 861 if( GetUpper() && 862 static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() && 863 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() ) 864 { 865 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp() 866 ->AddAccessibleFrame( pNew ); 867 } 868 } 869 870 // #i28701# - correction: consider also drawing objects 871 if ( pNew->GetDrawObjs() ) 872 { 873 SwSortedObjs &rObjs = *pNew->GetDrawObjs(); 874 for (SwAnchoredObject* pTmpObj : rObjs) 875 { 876 if ( dynamic_cast<const SwFlyFrame*>( pTmpObj) != nullptr ) 877 { 878 SwFlyFrame* pTmpFly = static_cast<SwFlyFrame*>(pTmpObj); 879 // #i28701# - use new method <GetPageFrame()> 880 if ( pTmpFly->IsFlyFreeFrame() && !pTmpFly->GetPageFrame() ) 881 AppendFlyToPage( pTmpFly ); 882 } 883 else if ( dynamic_cast<const SwAnchoredDrawObject*>( pTmpObj) != nullptr ) 884 { 885 // #i87493# 886 if ( pTmpObj->GetPageFrame() != this ) 887 { 888 if ( pTmpObj->GetPageFrame() != nullptr ) 889 { 890 pTmpObj->GetPageFrame()->RemoveDrawObjFromPage( *pTmpObj ); 891 } 892 AppendDrawObjToPage( *pTmpObj ); 893 } 894 } 895 } 896 } 897 } 898 899 void SwPageFrame::RemoveFlyFromPage( SwFlyFrame *pToRemove ) 900 { 901 const sal_uInt32 nOrdNum = pToRemove->GetVirtDrawObj()->GetOrdNum(); 902 getRootFrame()->GetDrawPage()->RemoveObject( nOrdNum ); 903 pToRemove->GetVirtDrawObj()->ReferencedObj().SetOrdNum( nOrdNum ); 904 905 if ( GetUpper() ) 906 { 907 if ( !pToRemove->IsFlyInContentFrame() ) 908 static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous(); 909 static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth(); 910 } 911 912 // Don't look further at Flys that sit inside the Content. 913 if ( pToRemove->IsFlyInContentFrame() ) 914 return; 915 916 // Don't delete collections just yet. This will happen at the end of the 917 // action in the RemoveSuperfluous of the page, kicked off by a method of 918 // the same name in the root. 919 // The FlyColl might be gone already, because the page's dtor is being 920 // executed. 921 // Remove it _before_ disposing accessible frames to avoid accesses to 922 // the Frame from event handlers. 923 if (m_pSortedObjs) 924 { 925 m_pSortedObjs->Remove(*pToRemove); 926 if (!m_pSortedObjs->size()) 927 { 928 m_pSortedObjs.reset(); 929 } 930 } 931 932 // Notify accessible layout. That's required at this place for 933 // frames only where the anchor is moved. Creation of new frames 934 // is additionally handled by the SwFrameNotify class. 935 if( GetUpper() && 936 static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() && 937 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() ) 938 { 939 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp() 940 ->DisposeAccessibleFrame( pToRemove, true ); 941 } 942 943 // #i28701# - use new method <SetPageFrame(..)> 944 pToRemove->SetPageFrame( nullptr ); 945 } 946 947 void SwPageFrame::MoveFly( SwFlyFrame *pToMove, SwPageFrame *pDest ) 948 { 949 // Invalidations 950 if ( GetUpper() ) 951 { 952 static_cast<SwRootFrame*>(GetUpper())->SetIdleFlags(); 953 if ( !pToMove->IsFlyInContentFrame() && pDest->GetPhyPageNum() < GetPhyPageNum() ) 954 static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous(); 955 } 956 957 pDest->InvalidateSpelling(); 958 pDest->InvalidateSmartTags(); 959 pDest->InvalidateAutoCompleteWords(); 960 pDest->InvalidateWordCount(); 961 962 if ( pToMove->IsFlyInContentFrame() ) 963 { 964 pDest->InvalidateFlyInCnt(); 965 return; 966 } 967 968 // Notify accessible layout. That's required at this place for 969 // frames only where the anchor is moved. Creation of new frames 970 // is additionally handled by the SwFrameNotify class. 971 if( GetUpper() && 972 static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() && 973 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() ) 974 { 975 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp() 976 ->DisposeAccessibleFrame( pToMove, true ); 977 } 978 979 // The FlyColl might be gone already, because the page's dtor is being executed. 980 if ( m_pSortedObjs ) 981 { 982 m_pSortedObjs->Remove( *pToMove ); 983 if ( !m_pSortedObjs->size() ) 984 { 985 m_pSortedObjs.reset(); 986 } 987 } 988 989 // Register 990 if ( !pDest->GetSortedObjs() ) 991 pDest->m_pSortedObjs.reset(new SwSortedObjs()); 992 993 const bool bSuccessInserted = pDest->GetSortedObjs()->Insert( *pToMove ); 994 OSL_ENSURE( bSuccessInserted, "Fly not inserted in Sorted." ); 995 996 // #i28701# - use new method <SetPageFrame(..)> 997 pToMove->SetPageFrame( pDest ); 998 pToMove->InvalidatePage( pDest ); 999 pToMove->SetNotifyBack(); 1000 pDest->InvalidateFlyContent(); 1001 // #i28701# 1002 pToMove->UnlockPosition(); 1003 1004 // Notify accessible layout. That's required at this place for 1005 // frames only where the anchor is moved. Creation of new frames 1006 // is additionally handled by the SwFrameNotify class. 1007 if( GetUpper() && 1008 static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() && 1009 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() ) 1010 { 1011 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp() 1012 ->AddAccessibleFrame( pToMove ); 1013 } 1014 1015 // #i28701# - correction: move lowers of Writer fly frame 1016 if ( pToMove->GetDrawObjs() ) 1017 { 1018 SwSortedObjs &rObjs = *pToMove->GetDrawObjs(); 1019 for (SwAnchoredObject* pObj : rObjs) 1020 { 1021 if ( dynamic_cast<const SwFlyFrame*>( pObj) != nullptr ) 1022 { 1023 SwFlyFrame* pFly = static_cast<SwFlyFrame*>(pObj); 1024 if ( pFly->IsFlyFreeFrame() ) 1025 { 1026 // #i28701# - use new method <GetPageFrame()> 1027 SwPageFrame* pPageFrame = pFly->GetPageFrame(); 1028 if ( pPageFrame ) 1029 pPageFrame->MoveFly( pFly, pDest ); 1030 else 1031 pDest->AppendFlyToPage( pFly ); 1032 } 1033 } 1034 else if ( dynamic_cast<const SwAnchoredDrawObject*>( pObj) != nullptr ) 1035 { 1036 RemoveDrawObjFromPage( *pObj ); 1037 pDest->AppendDrawObjToPage( *pObj ); 1038 } 1039 } 1040 } 1041 } 1042 1043 void SwPageFrame::AppendDrawObjToPage( SwAnchoredObject& _rNewObj ) 1044 { 1045 if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rNewObj) == nullptr ) 1046 { 1047 OSL_FAIL( "SwPageFrame::AppendDrawObjToPage(..) - anchored object of unexpected type -> object not appended" ); 1048 return; 1049 } 1050 1051 if ( GetUpper() ) 1052 { 1053 static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth(); 1054 } 1055 1056 assert(_rNewObj.GetAnchorFrame()); 1057 SwFlyFrame* pFlyFrame = const_cast<SwFlyFrame*>(_rNewObj.GetAnchorFrame()->FindFlyFrame()); 1058 if ( pFlyFrame && 1059 _rNewObj.GetDrawObj()->GetOrdNum() < pFlyFrame->GetVirtDrawObj()->GetOrdNum() ) 1060 { 1061 //#i119945# set pFly's OrdNum to _rNewObj's. So when pFly is removed by Undo, the original OrdNum will not be changed. 1062 sal_uInt32 nNewNum = _rNewObj.GetDrawObj()->GetOrdNumDirect(); 1063 if ( _rNewObj.GetDrawObj()->getSdrPageFromSdrObject() ) 1064 _rNewObj.DrawObj()->getSdrPageFromSdrObject()->SetObjectOrdNum( pFlyFrame->GetVirtDrawObj()->GetOrdNumDirect(), nNewNum ); 1065 else 1066 pFlyFrame->GetVirtDrawObj()->SetOrdNum( nNewNum ); 1067 } 1068 1069 if ( RndStdIds::FLY_AS_CHAR == _rNewObj.GetFrameFormat().GetAnchor().GetAnchorId() ) 1070 { 1071 return; 1072 } 1073 1074 if ( !m_pSortedObjs ) 1075 { 1076 m_pSortedObjs.reset(new SwSortedObjs()); 1077 } 1078 if ( !m_pSortedObjs->Insert( _rNewObj ) ) 1079 { 1080 OSL_ENSURE( m_pSortedObjs->Contains( _rNewObj ), 1081 "Drawing object not appended into list <pSortedObjs>." ); 1082 } 1083 // #i87493# 1084 OSL_ENSURE( _rNewObj.GetPageFrame() == nullptr || _rNewObj.GetPageFrame() == this, 1085 "<SwPageFrame::AppendDrawObjToPage(..)> - anchored draw object seems to be registered at another page frame. Serious defect." ); 1086 _rNewObj.SetPageFrame( this ); 1087 1088 // invalidate page in order to force a reformat of object layout of the page. 1089 InvalidateFlyLayout(); 1090 } 1091 1092 void SwPageFrame::RemoveDrawObjFromPage( SwAnchoredObject& _rToRemoveObj ) 1093 { 1094 if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rToRemoveObj) == nullptr ) 1095 { 1096 OSL_FAIL( "SwPageFrame::RemoveDrawObjFromPage(..) - anchored object of unexpected type -> object not removed" ); 1097 return; 1098 } 1099 1100 if ( m_pSortedObjs ) 1101 { 1102 m_pSortedObjs->Remove( _rToRemoveObj ); 1103 if ( !m_pSortedObjs->size() ) 1104 { 1105 m_pSortedObjs.reset(); 1106 } 1107 if ( GetUpper() ) 1108 { 1109 if (RndStdIds::FLY_AS_CHAR != 1110 _rToRemoveObj.GetFrameFormat().GetAnchor().GetAnchorId()) 1111 { 1112 static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous(); 1113 InvalidatePage(); 1114 } 1115 static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth(); 1116 } 1117 } 1118 _rToRemoveObj.SetPageFrame( nullptr ); 1119 } 1120 1121 // #i50432# - adjust method description and synopsis. 1122 void SwPageFrame::PlaceFly( SwFlyFrame* pFly, SwFlyFrameFormat* pFormat ) 1123 { 1124 // #i50432# - consider the case that page is an empty page: 1125 // In this case append the fly frame at the next page 1126 OSL_ENSURE( !IsEmptyPage() || GetNext(), 1127 "<SwPageFrame::PlaceFly(..)> - empty page with no next page! -> fly frame appended at empty page" ); 1128 if ( IsEmptyPage() && GetNext() ) 1129 { 1130 static_cast<SwPageFrame*>(GetNext())->PlaceFly( pFly, pFormat ); 1131 } 1132 else 1133 { 1134 // If we received a Fly, we use that one. Otherwise, create a new 1135 // one using the Format. 1136 if ( pFly ) 1137 AppendFly( pFly ); 1138 else 1139 { 1140 OSL_ENSURE( pFormat, ":-( No Format given for Fly." ); 1141 pFly = new SwFlyLayFrame( pFormat, this, this ); 1142 AppendFly( pFly ); 1143 ::RegistFlys( this, pFly ); 1144 } 1145 } 1146 } 1147 1148 // #i18732# - adjustments for following text flow or not 1149 // AND alignment at 'page areas' for to paragraph/to character anchored objects 1150 // #i22305# - adjustment for following text flow for to frame anchored objects 1151 // #i29778# - Because calculating the floating screen object's position 1152 // (Writer fly frame or drawing object) doesn't perform a calculation on its 1153 // upper frames and its anchor frame, a calculation of the upper frames in this 1154 // method is no longer sensible. 1155 // #i28701# - if document compatibility option 'Consider wrapping style influence 1156 // on object positioning' is ON, the clip area corresponds to the one as the 1157 // object doesn't follow the text flow. 1158 bool CalcClipRect( const SdrObject *pSdrObj, SwRect &rRect, bool bMove ) 1159 { 1160 bool bRet = true; 1161 if ( auto pVirtFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) ) 1162 { 1163 const SwFlyFrame* pFly = pVirtFlyDrawObj->GetFlyFrame(); 1164 const bool bFollowTextFlow = pFly->GetFormat()->GetFollowTextFlow().GetValue(); 1165 // #i28701# 1166 const bool bConsiderWrapOnObjPos = 1167 pFly->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION); 1168 const SwFormatVertOrient &rV = pFly->GetFormat()->GetVertOrient(); 1169 if( pFly->IsFlyLayFrame() ) 1170 { 1171 const SwFrame* pClip; 1172 // #i22305# 1173 // #i28701# 1174 if ( !bFollowTextFlow || bConsiderWrapOnObjPos ) 1175 { 1176 pClip = pFly->GetAnchorFrame()->FindPageFrame(); 1177 } 1178 else 1179 { 1180 pClip = pFly->GetAnchorFrame(); 1181 } 1182 1183 rRect = pClip->getFrameArea(); 1184 SwRectFnSet aRectFnSet(pClip); 1185 1186 // vertical clipping: Top and Bottom, also to PrtArea if necessary 1187 if( rV.GetVertOrient() != text::VertOrientation::NONE && 1188 rV.GetRelationOrient() == text::RelOrientation::PRINT_AREA ) 1189 { 1190 aRectFnSet.SetTop( rRect, aRectFnSet.GetPrtTop(*pClip) ); 1191 aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pClip) ); 1192 } 1193 // horizontal clipping: Top and Bottom, also to PrtArea if necessary 1194 const SwFormatHoriOrient &rH = pFly->GetFormat()->GetHoriOrient(); 1195 if( rH.GetHoriOrient() != text::HoriOrientation::NONE && 1196 rH.GetRelationOrient() == text::RelOrientation::PRINT_AREA ) 1197 { 1198 aRectFnSet.SetLeft( rRect, aRectFnSet.GetPrtLeft(*pClip) ); 1199 aRectFnSet.SetRight(rRect, aRectFnSet.GetPrtRight(*pClip)); 1200 } 1201 } 1202 else if( pFly->IsFlyAtContentFrame() ) 1203 { 1204 // #i18732# - consider following text flow or not 1205 // AND alignment at 'page areas' 1206 const SwFrame* pVertPosOrientFrame = pFly->GetVertPosOrientFrame(); 1207 if ( !pVertPosOrientFrame ) 1208 { 1209 OSL_FAIL( "::CalcClipRect(..) - frame, vertical position is oriented at, is missing ."); 1210 pVertPosOrientFrame = pFly->GetAnchorFrame(); 1211 } 1212 1213 if ( !bFollowTextFlow || bConsiderWrapOnObjPos ) 1214 { 1215 const SwLayoutFrame* pClipFrame = pVertPosOrientFrame->FindPageFrame(); 1216 if (!pClipFrame) 1217 { 1218 OSL_FAIL("!pClipFrame: " 1219 "if you can reproduce this please file a bug"); 1220 return false; 1221 } 1222 rRect = bMove ? pClipFrame->GetUpper()->getFrameArea() 1223 : pClipFrame->getFrameArea(); 1224 // #i26945# - consider that a table, during 1225 // its format, can exceed its upper printing area bottom. 1226 // Thus, enlarge the clip rectangle, if such a case occurred 1227 if ( pFly->GetAnchorFrame()->IsInTab() ) 1228 { 1229 const SwTabFrame* pTabFrame = const_cast<SwFlyFrame*>(pFly) 1230 ->GetAnchorFrameContainingAnchPos()->FindTabFrame(); 1231 SwRect aTmp( pTabFrame->getFramePrintArea() ); 1232 aTmp += pTabFrame->getFrameArea().Pos(); 1233 rRect.Union( aTmp ); 1234 // #i43913# - consider also the cell frame 1235 const SwFrame* pCellFrame = const_cast<SwFlyFrame*>(pFly) 1236 ->GetAnchorFrameContainingAnchPos()->GetUpper(); 1237 while ( pCellFrame && !pCellFrame->IsCellFrame() ) 1238 { 1239 pCellFrame = pCellFrame->GetUpper(); 1240 } 1241 if ( pCellFrame ) 1242 { 1243 aTmp = pCellFrame->getFramePrintArea(); 1244 aTmp += pCellFrame->getFrameArea().Pos(); 1245 rRect.Union( aTmp ); 1246 } 1247 } 1248 } 1249 else if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_FRAME || 1250 rV.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA ) 1251 { 1252 // new class <SwEnvironmentOfAnchoredObject> 1253 objectpositioning::SwEnvironmentOfAnchoredObject 1254 aEnvOfObj( bFollowTextFlow ); 1255 const SwLayoutFrame& rVertClipFrame = 1256 aEnvOfObj.GetVertEnvironmentLayoutFrame( *pVertPosOrientFrame ); 1257 if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_FRAME ) 1258 { 1259 rRect = rVertClipFrame.getFrameArea(); 1260 } 1261 else if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA ) 1262 { 1263 if ( rVertClipFrame.IsPageFrame() ) 1264 { 1265 rRect = static_cast<const SwPageFrame&>(rVertClipFrame).PrtWithoutHeaderAndFooter(); 1266 } 1267 else 1268 { 1269 rRect = rVertClipFrame.getFrameArea(); 1270 } 1271 } 1272 const SwLayoutFrame* pHoriClipFrame = 1273 pFly->GetAnchorFrame()->FindPageFrame()->GetUpper(); 1274 SwRectFnSet aRectFnSet(pFly->GetAnchorFrame()); 1275 aRectFnSet.SetLeft( rRect, aRectFnSet.GetLeft(pHoriClipFrame->getFrameArea()) ); 1276 aRectFnSet.SetRight(rRect, aRectFnSet.GetRight(pHoriClipFrame->getFrameArea())); 1277 } 1278 else 1279 { 1280 // #i26945# 1281 const SwFrame *pClip = 1282 const_cast<SwFlyFrame*>(pFly)->GetAnchorFrameContainingAnchPos(); 1283 SwRectFnSet aRectFnSet(pClip); 1284 const SwLayoutFrame *pUp = pClip->GetUpper(); 1285 const SwFrame *pCell = pUp->IsCellFrame() ? pUp : nullptr; 1286 const SwFrameType nType = bMove 1287 ? SwFrameType::Root | SwFrameType::Fly | SwFrameType::Header | 1288 SwFrameType::Footer | SwFrameType::Ftn 1289 : SwFrameType::Body | SwFrameType::Fly | SwFrameType::Header | 1290 SwFrameType::Footer | SwFrameType::Cell| SwFrameType::Ftn; 1291 1292 while ( !(pUp->GetType() & nType) || pUp->IsColBodyFrame() ) 1293 { 1294 pUp = pUp->GetUpper(); 1295 if ( !pCell && pUp->IsCellFrame() ) 1296 pCell = pUp; 1297 } 1298 if ( bMove && pUp->IsRootFrame() ) 1299 { 1300 rRect = pUp->getFramePrintArea(); 1301 rRect += pUp->getFrameArea().Pos(); 1302 pUp = nullptr; 1303 } 1304 if ( pUp ) 1305 { 1306 if ( pUp->GetType() & SwFrameType::Body ) 1307 { 1308 const SwPageFrame *pPg; 1309 if ( pUp->GetUpper() != (pPg = pFly->FindPageFrame()) ) 1310 pUp = pPg->FindBodyCont(); 1311 if (pUp) 1312 { 1313 rRect = pUp->GetUpper()->getFrameArea(); 1314 aRectFnSet.SetTop( rRect, aRectFnSet.GetPrtTop(*pUp) ); 1315 aRectFnSet.SetBottom(rRect, aRectFnSet.GetPrtBottom(*pUp)); 1316 } 1317 } 1318 else 1319 { 1320 if( ( pUp->GetType() & (SwFrameType::Fly | SwFrameType::Ftn ) ) && 1321 !pUp->getFrameArea().IsInside( pFly->getFrameArea().Pos() ) ) 1322 { 1323 if( pUp->IsFlyFrame() ) 1324 { 1325 const SwFlyFrame *pTmpFly = static_cast<const SwFlyFrame*>(pUp); 1326 while( pTmpFly->GetNextLink() ) 1327 { 1328 pTmpFly = pTmpFly->GetNextLink(); 1329 if( pTmpFly->getFrameArea().IsInside( pFly->getFrameArea().Pos() ) ) 1330 break; 1331 } 1332 pUp = pTmpFly; 1333 } 1334 else if( pUp->IsInFootnote() ) 1335 { 1336 const SwFootnoteFrame *pTmp = pUp->FindFootnoteFrame(); 1337 while( pTmp->GetFollow() ) 1338 { 1339 pTmp = pTmp->GetFollow(); 1340 if( pTmp->getFrameArea().IsInside( pFly->getFrameArea().Pos() ) ) 1341 break; 1342 } 1343 pUp = pTmp; 1344 } 1345 } 1346 rRect = pUp->getFramePrintArea(); 1347 rRect.Pos() += pUp->getFrameArea().Pos(); 1348 if ( pUp->GetType() & (SwFrameType::Header | SwFrameType::Footer) ) 1349 { 1350 rRect.Left ( pUp->GetUpper()->getFrameArea().Left() ); 1351 rRect.Width( pUp->GetUpper()->getFrameArea().Width()); 1352 } 1353 else if ( pUp->IsCellFrame() ) //MA_FLY_HEIGHT 1354 { 1355 const SwFrame *pTab = pUp->FindTabFrame(); 1356 aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pTab->GetUpper()) ); 1357 // expand to left and right cell border 1358 rRect.Left ( pUp->getFrameArea().Left() ); 1359 rRect.Width( pUp->getFrameArea().Width() ); 1360 } 1361 } 1362 } 1363 if ( pCell ) 1364 { 1365 // CellFrames might also sit in unallowed areas. In this case, 1366 // the Fly is allowed to do so as well 1367 SwRect aTmp( pCell->getFramePrintArea() ); 1368 aTmp += pCell->getFrameArea().Pos(); 1369 rRect.Union( aTmp ); 1370 } 1371 } 1372 } 1373 else 1374 { 1375 const SwFrame *pUp = pFly->GetAnchorFrame()->GetUpper(); 1376 SwRectFnSet aRectFnSet(pFly->GetAnchorFrame()); 1377 while( pUp->IsColumnFrame() || pUp->IsSctFrame() || pUp->IsColBodyFrame()) 1378 pUp = pUp->GetUpper(); 1379 rRect = pUp->getFrameArea(); 1380 if( !pUp->IsBodyFrame() ) 1381 { 1382 rRect += pUp->getFramePrintArea().Pos(); 1383 rRect.SSize( pUp->getFramePrintArea().SSize() ); 1384 if ( pUp->IsCellFrame() ) 1385 { 1386 const SwFrame *pTab = pUp->FindTabFrame(); 1387 aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pTab->GetUpper()) ); 1388 } 1389 } 1390 else if ( pUp->GetUpper()->IsPageFrame() ) 1391 { 1392 // Objects anchored as character may exceed right margin 1393 // of body frame: 1394 aRectFnSet.SetRight( rRect, aRectFnSet.GetRight(pUp->GetUpper()->getFrameArea()) ); 1395 } 1396 long nHeight = (9*aRectFnSet.GetHeight(rRect))/10; 1397 long nTop; 1398 const SwFormat *pFormat = GetUserCall(pSdrObj)->GetFormat(); 1399 const SvxULSpaceItem &rUL = pFormat->GetULSpace(); 1400 if( bMove ) 1401 { 1402 nTop = aRectFnSet.IsVert() ? static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().X() : 1403 static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().Y(); 1404 nTop = aRectFnSet.YInc( nTop, -nHeight ); 1405 long nWidth = aRectFnSet.GetWidth(pFly->getFrameArea()); 1406 aRectFnSet.SetLeftAndWidth( rRect, aRectFnSet.IsVert() ? 1407 static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().Y() : 1408 static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().X(), nWidth ); 1409 nHeight = 2*nHeight - rUL.GetLower() - rUL.GetUpper(); 1410 } 1411 else 1412 { 1413 nTop = aRectFnSet.YInc( aRectFnSet.GetBottom(pFly->getFrameArea()), 1414 rUL.GetLower() - nHeight ); 1415 nHeight = 2*nHeight - aRectFnSet.GetHeight(pFly->getFrameArea()) 1416 - rUL.GetLower() - rUL.GetUpper(); 1417 } 1418 aRectFnSet.SetTopAndHeight( rRect, nTop, nHeight ); 1419 } 1420 } 1421 else 1422 { 1423 const SwDrawContact *pC = static_cast<const SwDrawContact*>(GetUserCall(pSdrObj)); 1424 const SwFrameFormat *pFormat = pC->GetFormat(); 1425 const SwFormatAnchor &rAnch = pFormat->GetAnchor(); 1426 if ( RndStdIds::FLY_AS_CHAR == rAnch.GetAnchorId() ) 1427 { 1428 const SwFrame* pAnchorFrame = pC->GetAnchorFrame( pSdrObj ); 1429 if( !pAnchorFrame ) 1430 { 1431 OSL_FAIL( "<::CalcClipRect(..)> - missing anchor frame." ); 1432 const_cast<SwDrawContact*>(pC)->ConnectToLayout(); 1433 pAnchorFrame = pC->GetAnchorFrame(); 1434 } 1435 const SwFrame* pUp = pAnchorFrame->GetUpper(); 1436 rRect = pUp->getFramePrintArea(); 1437 rRect += pUp->getFrameArea().Pos(); 1438 SwRectFnSet aRectFnSet(pAnchorFrame); 1439 long nHeight = (9*aRectFnSet.GetHeight(rRect))/10; 1440 long nTop; 1441 const SvxULSpaceItem &rUL = pFormat->GetULSpace(); 1442 SwRect aSnapRect( pSdrObj->GetSnapRect() ); 1443 long nTmpH = 0; 1444 if( bMove ) 1445 { 1446 nTop = aRectFnSet.YInc( aRectFnSet.IsVert() ? pSdrObj->GetAnchorPos().X() : 1447 pSdrObj->GetAnchorPos().Y(), -nHeight ); 1448 long nWidth = aRectFnSet.GetWidth(aSnapRect); 1449 aRectFnSet.SetLeftAndWidth( rRect, aRectFnSet.IsVert() ? 1450 pSdrObj->GetAnchorPos().Y() : 1451 pSdrObj->GetAnchorPos().X(), nWidth ); 1452 } 1453 else 1454 { 1455 // #i26791# - value of <nTmpH> is needed to 1456 // calculate value of <nTop>. 1457 nTmpH = aRectFnSet.IsVert() ? pSdrObj->GetCurrentBoundRect().GetWidth() : 1458 pSdrObj->GetCurrentBoundRect().GetHeight(); 1459 nTop = aRectFnSet.YInc( aRectFnSet.GetTop(aSnapRect), 1460 rUL.GetLower() + nTmpH - nHeight ); 1461 } 1462 nHeight = 2*nHeight - nTmpH - rUL.GetLower() - rUL.GetUpper(); 1463 aRectFnSet.SetTopAndHeight( rRect, nTop, nHeight ); 1464 } 1465 else 1466 { 1467 // restrict clip rectangle for drawing 1468 // objects in header/footer to the page frame. 1469 // #i26791# 1470 const SwFrame* pAnchorFrame = pC->GetAnchorFrame( pSdrObj ); 1471 if ( pAnchorFrame && pAnchorFrame->FindFooterOrHeader() ) 1472 { 1473 // clip frame is the page frame the header/footer is on. 1474 const SwFrame* pClipFrame = pAnchorFrame->FindPageFrame(); 1475 rRect = pClipFrame->getFrameArea(); 1476 } 1477 else 1478 { 1479 bRet = false; 1480 } 1481 } 1482 } 1483 return bRet; 1484 } 1485 1486 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1487
