Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / layout / flylay.cxx
blob40b8547811fd4934622d088530e6fbdbebe3334d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_wasm_strip.h>
22 #include <pagefrm.hxx>
23 #include <rootfrm.hxx>
24 #include <cntfrm.hxx>
25 #include <dflyobj.hxx>
26 #include <dcontact.hxx>
27 #include <ftnfrm.hxx>
28 #include <frmatr.hxx>
29 #include <frmtool.hxx>
30 #include <sectfrm.hxx>
31 #include <notxtfrm.hxx>
32 #include <txtfly.hxx>
34 #include <svx/svdpage.hxx>
35 #include <editeng/ulspitem.hxx>
36 #include <fmtornt.hxx>
37 #include <fmtfsize.hxx>
38 #include <ndole.hxx>
39 #include <tabfrm.hxx>
40 #include <flyfrms.hxx>
41 #include <fmtfollowtextflow.hxx>
42 #include <environmentofanchoredobject.hxx>
43 #include <sortedobjs.hxx>
44 #include <viewimp.hxx>
45 #include <IDocumentSettingAccess.hxx>
46 #include <IDocumentDrawModelAccess.hxx>
47 #include <pam.hxx>
48 #include <ndindex.hxx>
49 #include <basegfx/matrix/b2dhommatrixtools.hxx>
50 #include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
51 #include <osl/diagnose.h>
53 using namespace ::com::sun::star;
55 SwFlyFreeFrame::SwFlyFreeFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch, bool bFollow )
56 : SwFlyFrame( pFormat, pSib, pAnch, bFollow ),
57 // #i34753#
58 mbNoMakePos( false ),
59 // #i37068#
60 mbNoMoveOnCheckClip( false )
64 void SwFlyFreeFrame::DestroyImpl()
66 // #i28701# - use new method <GetPageFrame()>
67 if( GetPageFrame() )
69 if( GetFormat()->GetDoc()->IsInDtor() )
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 )
79 GetPageFrame()->GetSortedObjs()->Remove( *this );
82 else
84 SwRect aTmp( GetObjRectWithSpaces() );
85 SwFlyFreeFrame::NotifyBackground( GetPageFrame(), aTmp, PrepareHint::FlyFrameLeave );
89 SwFlyFrame::DestroyImpl();
92 SwFlyFreeFrame::~SwFlyFreeFrame()
94 #if 0
95 // we are possibly in ContourCache, make sure we vanish
96 ::ClrContourCache(GetVirtDrawObj());
97 #endif
100 // #i28701#
101 /** Notifies the background (all ContentFrames that currently are overlapping).
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.
107 void SwFlyFreeFrame::NotifyBackground( SwPageFrame *pPageFrame,
108 const SwRect& rRect, PrepareHint eHint )
110 ::Notify_Background( GetVirtDrawObj(), pPageFrame, rRect, eHint, true );
113 void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
115 if ( !GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) )
117 return;
120 if ( !GetAnchorFrame() || IsLocked() || IsColLocked() )
122 return;
125 // #i28701# - use new method <GetPageFrame()>
126 if( !GetPageFrame() && GetAnchorFrame()->IsInFly() )
128 SwFlyFrame* pFly = AnchorFrame()->FindFlyFrame();
129 SwPageFrame *pPageFrame = pFly ? pFly->FindPageFrame() : nullptr;
130 if( pPageFrame )
131 pPageFrame->AppendFlyToPage( this );
134 if( !GetPageFrame() )
136 return;
139 Lock(); // The curtain drops
141 // takes care of the notification in the dtor
142 const SwFlyNotify aNotify( this );
144 if ( IsClipped() )
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() ) )
158 setFrameAreaPositionValid(false);
162 // #i81146# new loop control
163 int nLoopControlRuns = 0;
164 const int nLoopControlMax = 10;
166 // RotateFlyFrame3 - outer frame
167 const double fRotation(getLocalFrameRotation());
168 const bool bRotated(!basegfx::fTools::equalZero(fRotation));
170 if(bRotated)
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())
177 getTransformableSwFrame()->restoreFrameAreas();
181 while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() || m_bFormatHeightOnly || !m_bValidContentPos )
183 SwRectFnSet aRectFnSet(this);
184 const SwFormatFrameSize *pSz;
185 { // Additional scope, so aAccess will be destroyed before the check!
187 SwBorderAttrAccess aAccess( SwFrame::GetCache(), this );
188 const SwBorderAttrs &rAttrs = *aAccess.Get();
189 pSz = &rAttrs.GetAttrSet().GetFrameSize();
191 // Only set when the flag is set!
192 if ( !isFrameAreaSizeValid() )
194 setFramePrintAreaValid(false);
197 if ( !isFramePrintAreaValid() )
199 MakePrtArea( rAttrs );
200 m_bValidContentPos = false;
203 if ( !isFrameAreaSizeValid() || m_bFormatHeightOnly )
205 setFrameAreaSizeValid(false);
206 Format( getRootFrame()->GetCurrShell()->GetOut(), &rAttrs );
207 m_bFormatHeightOnly = false;
211 if ( !isFrameAreaPositionValid() )
213 const Point aOldPos( aRectFnSet.GetPos(getFrameArea()) );
214 // #i26791# - use new method <MakeObjPos()>
215 // #i34753# - no positioning, if requested.
216 if ( IsNoMakePos() )
218 setFrameAreaPositionValid(true);
220 else
221 // #i26791# - use new method <MakeObjPos()>
222 MakeObjPos();
223 if (!IsForceNotifyNewBackground() && aOldPos == aRectFnSet.GetPos(getFrameArea()))
225 if( !isFrameAreaPositionValid() && GetAnchorFrame()->IsInSct() &&
226 !GetAnchorFrame()->FindSctFrame()->isFrameAreaDefinitionValid() )
228 setFrameAreaPositionValid(true);
231 else
233 setFrameAreaSizeValid(false);
237 if ( !m_bValidContentPos )
239 SwBorderAttrAccess aAccess( SwFrame::GetCache(), this );
240 const SwBorderAttrs &rAttrs = *aAccess.Get();
241 MakeContentPos( rAttrs );
244 if ( isFrameAreaPositionValid() && isFrameAreaSizeValid() )
246 ++nLoopControlRuns;
248 OSL_ENSURE( nLoopControlRuns < nLoopControlMax, "LoopControl in SwFlyFreeFrame::MakeAll" );
250 if ( nLoopControlRuns < nLoopControlMax )
251 CheckClip( *pSz );
253 else
254 nLoopControlRuns = 0;
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)
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());
267 if(!mpTransformableSwFrame)
269 mpTransformableSwFrame.reset(new TransformableSwFrame(*this));
272 getTransformableSwFrame()->createFrameAreaTransformations(
273 fRotation,
274 aB2DCenter);
275 getTransformableSwFrame()->adaptFrameAreasToTransformations();
277 else
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 reset then
282 if(isTransformableSwFrame())
284 ::ClrContourCache(GetVirtDrawObj());
287 // reset transformations to show that they are not used
288 mpTransformableSwFrame.reset();
291 Unlock();
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." );
299 #endif
302 bool SwFlyFreeFrame::supportsAutoContour() const
304 static bool bOverrideHandleContourToAlwaysOff(true); // loplugin:constvars:ignore
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)
312 return false;
315 if(!isTransformableSwFrame())
317 // support only when transformed, else there is no free space
318 return false;
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());
328 if(rAttrs.IsLine())
330 return false;
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 SvxBoxItem* pBoxItem(nullptr);
337 if(GetFormat() && (pBoxItem = GetFormat()->GetItemIfSet(RES_BOX, false)))
339 if(pBoxItem->HasBorder(/*bTreatPaddingAsBorder*/true))
341 return false;
345 // check for Fill - if we have fill, it will fill the gaps and we will not
346 // support AutoContour
347 if(GetFormat() && GetFormat()->supportsFullDrawingLayerFillAttributeSet())
349 const drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes(GetFormat()->getSdrAllFillAttributesHelper());
351 if(aFillAttributes && aFillAttributes->isUsed())
353 return false;
356 else
358 const std::unique_ptr<SvxBrushItem> aBack(GetFormat()->makeBackgroundBrushItem());
360 if(aBack->isUsed())
362 return false;
366 // else, support
367 return true;
370 // RotateFlyFrame3 - Support for Transformations - outer frame
371 basegfx::B2DHomMatrix SwFlyFreeFrame::getFrameAreaTransformation() const
373 if(isTransformableSwFrame())
375 // use pre-created transformation
376 return getTransformableSwFrame()->getLocalFrameAreaTransformation();
379 // call parent
380 return SwFlyFrame::getFrameAreaTransformation();
383 basegfx::B2DHomMatrix SwFlyFreeFrame::getFramePrintAreaTransformation() const
385 if(isTransformableSwFrame())
387 // use pre-created transformation
388 return getTransformableSwFrame()->getLocalFramePrintAreaTransformation();
391 // call parent
392 return SwFlyFrame::getFramePrintAreaTransformation();
395 // RotateFlyFrame3 - Support for Transformations
396 void SwFlyFreeFrame::transform_translate(const Point& rOffset)
398 // call parent - this will do the basic transform for SwRect(s)
399 // in the SwFrameAreaDefinition
400 SwFlyFrame::transform_translate(rOffset);
402 // check if the Transformations need to be adapted
403 if(isTransformableSwFrame())
405 const basegfx::B2DHomMatrix aTransform(
406 basegfx::utils::createTranslateB2DHomMatrix(
407 rOffset.X(), rOffset.Y()));
409 // transform using TransformableSwFrame
410 getTransformableSwFrame()->transform(aTransform);
414 // RotateFlyFrame3 - outer frame
415 double getLocalFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame)
417 return rNoTextFrame.getLocalFrameRotation();
420 double SwFlyFreeFrame::getLocalFrameRotation() const
422 // SwLayoutFrame::Lower() != SwFrame::GetLower(), but SwFrame::GetLower()
423 // calls SwLayoutFrame::Lower() when it's a SwLayoutFrame - so use GetLower()
424 const SwNoTextFrame* pSwNoTextFrame(dynamic_cast< const SwNoTextFrame* >(GetLower()));
426 if(nullptr != pSwNoTextFrame)
428 return getLocalFrameRotation_from_SwNoTextFrame(*pSwNoTextFrame);
431 // no rotation
432 return 0.0;
435 /** determines, if direct environment of fly frame has 'auto' size
437 #i17297#
438 start with anchor frame and search via <GetUpper()> for a header, footer,
439 row or fly frame stopping at page frame.
440 return <true>, if such a frame is found and it has 'auto' size.
441 otherwise <false> is returned.
443 @return boolean indicating, that direct environment has 'auto' size
445 bool SwFlyFreeFrame::HasEnvironmentAutoSize() const
447 bool bRetVal = false;
449 const SwFrame* pToBeCheckedFrame = GetAnchorFrame();
450 while ( pToBeCheckedFrame &&
451 !pToBeCheckedFrame->IsPageFrame() )
453 if ( pToBeCheckedFrame->IsHeaderFrame() ||
454 pToBeCheckedFrame->IsFooterFrame() ||
455 pToBeCheckedFrame->IsRowFrame() ||
456 pToBeCheckedFrame->IsFlyFrame() )
458 bRetVal = SwFrameSize::Fixed !=
459 pToBeCheckedFrame->GetAttrSet()->GetFrameSize().GetHeightSizeType();
460 break;
462 else
464 pToBeCheckedFrame = pToBeCheckedFrame->GetUpper();
468 return bRetVal;
471 void SwFlyFreeFrame::CheckClip( const SwFormatFrameSize &rSz )
473 // It's probably time now to take appropriate measures, if the Fly
474 // doesn't fit into its surrounding.
475 // First, the Fly gives up its position, then it's formatted.
476 // Only if it still doesn't fit after giving up its position, the
477 // width or height are given up as well. The frame will be squeezed
478 // as much as needed.
480 const SwVirtFlyDrawObj *pObj = GetVirtDrawObj();
481 SwRect aClip, aTmpStretch;
482 ::CalcClipRect( pObj, aClip );
483 ::CalcClipRect( pObj, aTmpStretch, false );
484 aClip.Intersection_( aTmpStretch );
486 const tools::Long nBot = getFrameArea().Top() + getFrameArea().Height();
487 const tools::Long nRig = getFrameArea().Left() + getFrameArea().Width();
488 const tools::Long nClipBot = aClip.Top() + aClip.Height();
489 const tools::Long nClipRig = aClip.Left() + aClip.Width();
491 const bool bBot = nBot > nClipBot;
492 const bool bRig = nRig > nClipRig;
493 if (( bBot || bRig ) && !IsDraggingOffPageAllowed(FindFrameFormat(GetDrawObj())))
495 bool bAgain = false;
496 // #i37068# - no move, if it's requested
497 if ( bBot && !IsNoMoveOnCheckClip() &&
498 !GetDrawObjs() && !GetAnchorFrame()->IsInTab() )
500 SwFrame* pHeader = FindFooterOrHeader();
501 // In a header, correction of the position is no good idea.
502 // If the fly moves, some paragraphs have to be formatted, this
503 // could cause a change of the height of the headerframe,
504 // now the flyframe can change its position and so on ...
505 if ( !pHeader || !pHeader->IsHeaderFrame() )
507 const tools::Long nOld = getFrameArea().Top();
509 // tdf#112443 disable positioning if content is completely off page
510 bool bDisableOffPagePositioning = GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
511 if ( !bDisableOffPagePositioning || nOld <= nClipBot)
513 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
514 aFrm.Pos().setY( std::max( aClip.Top(), nClipBot - aFrm.Height() ) );
517 if ( getFrameArea().Top() != nOld )
519 bAgain = true;
522 m_bHeightClipped = true;
525 if ( bRig )
527 const tools::Long nOld = getFrameArea().Left();
529 // tdf#112443 disable positioning if content is completely off page
530 bool bDisableOffPagePositioning = GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
531 if ( !bDisableOffPagePositioning || nOld <= nClipRig )
533 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
534 aFrm.Pos().setX( std::max( aClip.Left(), nClipRig - aFrm.Width() ) );
537 if ( getFrameArea().Left() != nOld )
539 const SwFormatHoriOrient &rH = GetFormat()->GetHoriOrient();
540 // Left-aligned ones may not be moved to the left when they
541 // are avoiding another one.
542 if( rH.GetHoriOrient() == text::HoriOrientation::LEFT )
544 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
545 aFrm.Pos().setX( nOld );
547 else
549 bAgain = true;
552 m_bWidthClipped = true;
554 if ( bAgain )
556 setFrameAreaSizeValid(false);
558 else
560 // If we reach this branch, the Frame protrudes into forbidden
561 // areas, and correcting the position is not allowed or not
562 // possible or not required.
564 // For Flys with OLE objects as lower, we make sure that
565 // we always resize proportionally
566 Size aOldSize( getFrameArea().SSize() );
568 // First, setup the FrameRect, then transfer it to the Frame.
569 SwRect aFrameRect( getFrameArea() );
571 if ( bBot )
573 tools::Long nDiff = nClipBot;
574 nDiff -= aFrameRect.Top(); // nDiff represents the available distance
575 nDiff = aFrameRect.Height() - nDiff;
576 aFrameRect.Height( aFrameRect.Height() - nDiff );
577 m_bHeightClipped = true;
579 if ( bRig )
581 tools::Long nDiff = nClipRig;
582 nDiff -= aFrameRect.Left();// nDiff represents the available distance
583 nDiff = aFrameRect.Width() - nDiff;
584 aFrameRect.Width( aFrameRect.Width() - nDiff );
585 m_bWidthClipped = true;
588 // #i17297# - no proportional
589 // scaling of graphics in environments, which determines its size
590 // by its content ('auto' size). Otherwise layout loops can occur and
591 // layout sizes of the environment can be incorrect.
592 // Such environment are:
593 // (1) header and footer frames with 'auto' size
594 // (2) table row frames with 'auto' size
595 // (3) fly frames with 'auto' size
596 // Note: section frames seems to be not critical - didn't found
597 // any critical layout situation so far.
598 if ( Lower() && Lower()->IsNoTextFrame() &&
599 (static_cast<SwNoTextFrame*>(Lower())->GetNode()->GetOLENode() ||
600 !HasEnvironmentAutoSize() ) )
602 // If width and height got adjusted, then the bigger
603 // change is relevant.
604 if ( aFrameRect.Width() != aOldSize.Width() &&
605 aFrameRect.Height()!= aOldSize.Height() )
607 if ( (aOldSize.Width() - aFrameRect.Width()) >
608 (aOldSize.Height()- aFrameRect.Height()) )
609 aFrameRect.Height( aOldSize.Height() );
610 else
611 aFrameRect.Width( aOldSize.Width() );
614 // Adjusted the width? change height proportionally
615 if( aFrameRect.Width() != aOldSize.Width() )
617 aFrameRect.Height( aFrameRect.Width() * aOldSize.Height() /
618 aOldSize.Width() );
619 m_bHeightClipped = true;
621 // Adjusted the height? change width proportionally
622 else if( aFrameRect.Height() != aOldSize.Height() )
624 aFrameRect.Width( aFrameRect.Height() * aOldSize.Width() /
625 aOldSize.Height() );
626 m_bWidthClipped = true;
629 // #i17297# - reactivate change
630 // of size attribute for fly frames containing an ole object.
632 // Added the aFrameRect.HasArea() hack, because
633 // the environment of the ole object does not have to be valid
634 // at this moment, or even worse, it does not have to have a
635 // reasonable size. In this case we do not want to change to
636 // attributes permanently. Maybe one day somebody dares to remove
637 // this code.
638 if ( aFrameRect.HasArea() &&
639 static_cast<SwNoTextFrame*>(Lower())->GetNode()->GetOLENode() &&
640 ( m_bWidthClipped || m_bHeightClipped ) )
642 SwFlyFrameFormat *pFormat = GetFormat();
643 pFormat->LockModify();
644 SwFormatFrameSize aFrameSize( rSz );
645 aFrameSize.SetWidth( aFrameRect.Width() );
646 aFrameSize.SetHeight( aFrameRect.Height() );
647 pFormat->SetFormatAttr( aFrameSize );
648 pFormat->UnlockModify();
652 // Now change the Frame; for columns, we put the new values into the attributes,
653 // otherwise we'll end up with unwanted side-effects/oscillations
654 const tools::Long nPrtHeightDiff = getFrameArea().Height() - getFramePrintArea().Height();
655 const tools::Long nPrtWidthDiff = getFrameArea().Width() - getFramePrintArea().Width();
656 maUnclippedFrame = getFrameArea();
659 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
660 aFrm.Height( aFrameRect.Height() );
661 aFrm.Width ( std::max( tools::Long(MINLAY), aFrameRect.Width() ) );
664 if ( Lower() && Lower()->IsColumnFrame() )
666 ColLock(); //lock grow/shrink
667 const Size aTmpOldSize( getFramePrintArea().SSize() );
670 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
671 aPrt.Height( getFrameArea().Height() - nPrtHeightDiff );
672 aPrt.Width ( getFrameArea().Width() - nPrtWidthDiff );
675 ChgLowersProp( aTmpOldSize );
676 SwFrame *pLow = Lower();
679 pLow->Calc(getRootFrame()->GetCurrShell()->GetOut());
680 // also calculate the (Column)BodyFrame
681 static_cast<SwLayoutFrame*>(pLow)->Lower()->Calc(getRootFrame()->GetCurrShell()->GetOut());
682 pLow = pLow->GetNext();
683 } while ( pLow );
684 ::CalcContent( this );
685 ColUnlock();
687 if ( !isFrameAreaSizeValid() && !m_bWidthClipped )
689 setFrameAreaSizeValid(true);
690 m_bFormatHeightOnly = true;
693 else
695 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
696 aPrt.Height( getFrameArea().Height() - nPrtHeightDiff );
697 aPrt.Width ( getFrameArea().Width() - nPrtWidthDiff );
702 // #i26945#
703 OSL_ENSURE( getFrameArea().Height() >= 0,
704 "<SwFlyFreeFrame::CheckClip(..)> - fly frame has negative height now." );
707 /** method to determine, if a <MakeAll()> on the Writer fly frame is possible
708 #i43771#
710 bool SwFlyFreeFrame::IsFormatPossible() const
712 return SwFlyFrame::IsFormatPossible() &&
713 ( GetPageFrame() ||
714 ( GetAnchorFrame() && GetAnchorFrame()->IsInFly() ) );
717 SwFlyLayFrame::SwFlyLayFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch ) :
718 SwFlyFreeFrame( pFormat, pSib, pAnch )
720 m_bLayout = true;
723 void SwFlyLayFrame::RegisterAtPage(SwPageFrame & rPageFrame)
725 assert(GetPageFrame() != &rPageFrame);
726 if (GetPageFrame())
728 GetPageFrame()->MoveFly( this, &rPageFrame );
730 else
732 rPageFrame.AppendFlyToPage( this );
736 // #i28701#
738 void SwFlyLayFrame::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
740 if (rHint.GetId() != SfxHintId::SwLegacyModify)
741 return;
742 auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
743 if(!pLegacy->m_pNew)
744 return;
745 const auto pAnch = GetAnchorFromPoolItem(*pLegacy->m_pNew);
747 if(!pAnch)
749 SwFlyFrame::SwClientNotify(rMod, rHint);
750 return;
752 SAL_WARN_IF(pAnch->GetAnchorId() == GetFormat()->GetAnchor().GetAnchorId(), "sw.core", "Invalid change of anchor type.");
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);
760 if(RndStdIds::FLY_AT_PAGE == pAnch->GetAnchorId())
762 SwRootFrame* pRoot = getRootFrame();
763 SwPageFrame* pTmpPage = static_cast<SwPageFrame*>(pRoot->Lower());
764 sal_uInt16 nPagesToFlip = pAnch->GetPageNum()-1;
765 while(pTmpPage && nPagesToFlip)
767 pTmpPage = static_cast<SwPageFrame*>(pTmpPage->GetNext());
768 --nPagesToFlip;
770 if(pTmpPage && !nPagesToFlip)
772 // #i50432# - adjust synopsis of <PlaceFly(..)>
773 pTmpPage->PlaceFly(this, nullptr);
775 if(!pTmpPage)
777 pRoot->SetAssertFlyPages();
778 pRoot->AssertFlyPages();
781 else
783 SwNodeIndex aIdx(*pAnch->GetAnchorNode());
784 SwContentFrame* pContent = GetFormat()->GetDoc()->GetNodes().GoNext(&aIdx)->
785 GetContentNode()->getLayoutFrame(getRootFrame(), nullptr, nullptr);
786 if(pContent)
788 SwFlyFrame *pTmp = pContent->FindFlyFrame();
789 if(pTmp)
790 pTmp->AppendFly(this);
793 // #i28701# - use new method <GetPageFrame()>
794 if ( pOldPage && pOldPage != GetPageFrame() )
795 NotifyBackground( pOldPage, aOld, PrepareHint::FlyFrameLeave );
796 SetCompletePaint();
797 InvalidateAll();
798 SetNotifyBack();
801 void SwPageFrame::AppendFlyToPage( SwFlyFrame *pNew )
803 if ( !pNew->GetVirtDrawObj()->IsInserted() )
804 getRootFrame()->GetDrawPage()->InsertObject(
805 static_cast<SdrObject*>(pNew->GetVirtDrawObj()),
806 pNew->GetVirtDrawObj()->GetReferencedObj().GetOrdNumDirect() );
808 InvalidateSpelling();
809 InvalidateSmartTags();
810 InvalidateAutoCompleteWords();
811 InvalidateWordCount();
813 if ( GetUpper() )
815 static_cast<SwRootFrame*>(GetUpper())->SetIdleFlags();
816 static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
819 SdrObject* pObj = pNew->GetVirtDrawObj();
820 OSL_ENSURE( pNew->GetAnchorFrame(), "Fly without Anchor" );
821 SwFlyFrame* pFly = const_cast<SwFlyFrame*>(pNew->GetAnchorFrame()->FindFlyFrame());
822 if ( pFly && pObj->GetOrdNum() < pFly->GetVirtDrawObj()->GetOrdNum() )
824 //#i119945# set pFly's OrdNum to _rNewObj's. So when pFly is removed by Undo, the original OrdNum will not be changed.
825 sal_uInt32 nNewNum = pObj->GetOrdNumDirect();
826 SdrObject* pDrawObj = nullptr;
827 if (auto pFormat = pFly->GetFormat())
828 if (auto pShapeFormat = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_FLYFRMFMT))
829 pDrawObj = pShapeFormat->FindRealSdrObject();
831 if (pDrawObj)
833 if (auto pPage = pDrawObj->getSdrPageFromSdrObject())
834 pPage->SetObjectOrdNum(pDrawObj->GetOrdNumDirect(), nNewNum);
835 else
836 pDrawObj->SetOrdNum(nNewNum);
839 if ( pObj->getSdrPageFromSdrObject() )
840 pObj->getSdrPageFromSdrObject()->SetObjectOrdNum( pFly->GetVirtDrawObj()->GetOrdNumDirect(), nNewNum + (pDrawObj ? 1 : 0) );
841 else
842 pFly->GetVirtDrawObj()->SetOrdNum( nNewNum + (pDrawObj ? 1 : 0));
845 // Don't look further at Flys that sit inside the Content.
846 if ( pNew->IsFlyInContentFrame() )
847 InvalidateFlyInCnt();
848 else
850 InvalidateFlyContent();
852 if ( !m_pSortedObjs )
854 m_pSortedObjs.reset(new SwSortedObjs());
857 const bool bSuccessInserted = m_pSortedObjs->Insert( *pNew );
858 OSL_ENSURE( bSuccessInserted, "Fly not inserted in Sorted." );
860 // #i87493#
861 OSL_ENSURE( pNew->GetPageFrame() == nullptr || pNew->GetPageFrame() == this,
862 "<SwPageFrame::AppendFlyToPage(..)> - anchored fly frame seems to be registered at another page frame. Serious defect." );
863 // #i28701# - use new method <SetPageFrame(..)>
864 pNew->SetPageFrame( this );
865 pNew->InvalidatePage( this );
866 // #i28701#
867 pNew->UnlockPosition();
868 // needed to reposition at-page anchored flys moved from different page
869 pNew->InvalidateObjPos();
871 // Notify accessible layout. That's required at this place for
872 // frames only where the anchor is moved. Creation of new frames
873 // is additionally handled by the SwFrameNotify class.
874 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
875 if( GetUpper() &&
876 static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
877 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
879 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
880 ->AddAccessibleFrame( pNew );
882 #endif
885 // #i28701# - correction: consider also drawing objects
886 if ( !pNew->GetDrawObjs() )
887 return;
889 SwSortedObjs &rObjs = *pNew->GetDrawObjs();
890 for (SwAnchoredObject* pTmpObj : rObjs)
892 if ( auto pTmpFly = pTmpObj->DynCastFlyFrame() )
894 // #i28701# - use new method <GetPageFrame()>
895 if ( pTmpFly->IsFlyFreeFrame() && !pTmpFly->GetPageFrame() )
896 AppendFlyToPage( pTmpFly );
898 else if ( dynamic_cast<const SwAnchoredDrawObject*>( pTmpObj) != nullptr )
900 // #i87493#
901 if ( pTmpObj->GetPageFrame() != this )
903 if ( pTmpObj->GetPageFrame() != nullptr )
905 pTmpObj->GetPageFrame()->RemoveDrawObjFromPage( *pTmpObj );
907 AppendDrawObjToPage( *pTmpObj );
913 void SwPageFrame::RemoveFlyFromPage( SwFlyFrame *pToRemove )
915 const sal_uInt32 nOrdNum = pToRemove->GetVirtDrawObj()->GetOrdNum();
916 getRootFrame()->GetDrawPage()->RemoveObject( nOrdNum );
917 pToRemove->GetVirtDrawObj()->ReferencedObj().SetOrdNum( nOrdNum );
919 if ( GetUpper() )
921 if ( !pToRemove->IsFlyInContentFrame() )
922 static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous();
923 static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
926 // Don't look further at Flys that sit inside the Content.
927 if ( pToRemove->IsFlyInContentFrame() )
928 return;
930 // Don't delete collections just yet. This will happen at the end of the
931 // action in the RemoveSuperfluous of the page, kicked off by a method of
932 // the same name in the root.
933 // The FlyColl might be gone already, because the page's dtor is being
934 // executed.
935 // Remove it _before_ disposing accessible frames to avoid accesses to
936 // the Frame from event handlers.
937 if (m_pSortedObjs)
939 m_pSortedObjs->Remove(*pToRemove);
940 if (!m_pSortedObjs->size())
942 m_pSortedObjs.reset();
946 // Notify accessible layout. That's required at this place for
947 // frames only where the anchor is moved. Creation of new frames
948 // is additionally handled by the SwFrameNotify class.
949 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
950 if( GetUpper() &&
951 static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
952 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
954 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
955 ->DisposeAccessibleFrame( pToRemove, true );
957 #endif
959 // #i28701# - use new method <SetPageFrame(..)>
960 pToRemove->SetPageFrame( nullptr );
963 void SwPageFrame::MoveFly( SwFlyFrame *pToMove, SwPageFrame *pDest )
965 // Invalidations
966 if ( GetUpper() )
968 static_cast<SwRootFrame*>(GetUpper())->SetIdleFlags();
969 if ( !pToMove->IsFlyInContentFrame() && pDest->GetPhyPageNum() < GetPhyPageNum() )
970 static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous();
973 pDest->InvalidateSpelling();
974 pDest->InvalidateSmartTags();
975 pDest->InvalidateAutoCompleteWords();
976 pDest->InvalidateWordCount();
978 if ( pToMove->IsFlyInContentFrame() )
980 pDest->InvalidateFlyInCnt();
981 return;
984 // Notify accessible layout. That's required at this place for
985 // frames only where the anchor is moved. Creation of new frames
986 // is additionally handled by the SwFrameNotify class.
987 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
988 if( GetUpper() &&
989 static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
990 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
992 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
993 ->DisposeAccessibleFrame( pToMove, true );
995 #endif
997 // The FlyColl might be gone already, because the page's dtor is being executed.
998 if ( m_pSortedObjs )
1000 m_pSortedObjs->Remove( *pToMove );
1001 if ( !m_pSortedObjs->size() )
1003 m_pSortedObjs.reset();
1006 // Removing a fly from the page affects the margin of tables, so update the frame print area
1007 // of the lowers of my body frame.
1008 SwFrame* pBodyFrame = FindBodyCont();
1009 if (pBodyFrame)
1011 for (SwFrame* pFrame = pBodyFrame->GetLower(); pFrame; pFrame = pFrame->GetNext())
1013 if (!pFrame->IsTabFrame())
1015 // This is meant to match SwTabFrame::CalcFlyOffsets(), so not relevant for
1016 // other frame types.
1017 continue;
1020 pFrame->InvalidatePrt();
1025 // Register
1026 if ( !pDest->GetSortedObjs() )
1027 pDest->m_pSortedObjs.reset(new SwSortedObjs());
1029 const bool bSuccessInserted = pDest->GetSortedObjs()->Insert( *pToMove );
1030 OSL_ENSURE( bSuccessInserted, "Fly not inserted in Sorted." );
1032 // #i28701# - use new method <SetPageFrame(..)>
1033 pToMove->SetPageFrame( pDest );
1034 pToMove->InvalidatePage( pDest );
1035 pToMove->SetNotifyBack();
1036 pDest->InvalidateFlyContent();
1037 // #i28701#
1038 pToMove->UnlockPosition();
1040 // Notify accessible layout. That's required at this place for
1041 // frames only where the anchor is moved. Creation of new frames
1042 // is additionally handled by the SwFrameNotify class.
1043 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1044 if( GetUpper() &&
1045 static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
1046 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
1048 static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
1049 ->AddAccessibleFrame( pToMove );
1051 #endif
1053 // #i28701# - correction: move lowers of Writer fly frame
1054 if ( !pToMove->GetDrawObjs() )
1055 return;
1057 SwSortedObjs &rObjs = *pToMove->GetDrawObjs();
1058 for (SwAnchoredObject* pObj : rObjs)
1060 if ( auto pFly = pObj->DynCastFlyFrame() )
1062 if ( pFly->IsFlyFreeFrame() )
1064 // #i28701# - use new method <GetPageFrame()>
1065 SwPageFrame* pPageFrame = pFly->GetPageFrame();
1066 if ( pPageFrame )
1067 pPageFrame->MoveFly( pFly, pDest );
1068 else
1069 pDest->AppendFlyToPage( pFly );
1072 else if ( dynamic_cast<const SwAnchoredDrawObject*>( pObj) != nullptr )
1074 RemoveDrawObjFromPage( *pObj );
1075 pDest->AppendDrawObjToPage( *pObj );
1080 void SwPageFrame::AppendDrawObjToPage( SwAnchoredObject& _rNewObj )
1082 if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rNewObj) == nullptr )
1084 OSL_FAIL( "SwPageFrame::AppendDrawObjToPage(..) - anchored object of unexpected type -> object not appended" );
1085 return;
1088 if ( GetUpper() )
1090 static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
1093 assert(_rNewObj.GetAnchorFrame());
1094 SwFlyFrame* pFlyFrame = const_cast<SwFlyFrame*>(_rNewObj.GetAnchorFrame()->FindFlyFrame());
1095 if ( pFlyFrame &&
1096 _rNewObj.GetDrawObj()->GetOrdNum() < pFlyFrame->GetVirtDrawObj()->GetOrdNum() )
1098 //#i119945# set pFly's OrdNum to _rNewObj's. So when pFly is removed by Undo, the original OrdNum will not be changed.
1099 sal_uInt32 nNewNum = _rNewObj.GetDrawObj()->GetOrdNumDirect();
1100 if ( _rNewObj.GetDrawObj()->getSdrPageFromSdrObject() )
1101 _rNewObj.DrawObj()->getSdrPageFromSdrObject()->SetObjectOrdNum( pFlyFrame->GetVirtDrawObj()->GetOrdNumDirect(), nNewNum );
1102 else
1103 pFlyFrame->GetVirtDrawObj()->SetOrdNum( nNewNum );
1106 if ( RndStdIds::FLY_AS_CHAR == _rNewObj.GetFrameFormat().GetAnchor().GetAnchorId() )
1108 return;
1111 if ( !m_pSortedObjs )
1113 m_pSortedObjs.reset(new SwSortedObjs());
1115 if ( !m_pSortedObjs->Insert( _rNewObj ) )
1117 OSL_ENSURE( m_pSortedObjs->Contains( _rNewObj ),
1118 "Drawing object not appended into list <pSortedObjs>." );
1120 // #i87493#
1121 OSL_ENSURE( _rNewObj.GetPageFrame() == nullptr || _rNewObj.GetPageFrame() == this,
1122 "<SwPageFrame::AppendDrawObjToPage(..)> - anchored draw object seems to be registered at another page frame. Serious defect." );
1123 _rNewObj.SetPageFrame( this );
1125 // invalidate page in order to force a reformat of object layout of the page.
1126 InvalidateFlyLayout();
1129 void SwPageFrame::RemoveDrawObjFromPage( SwAnchoredObject& _rToRemoveObj )
1131 if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rToRemoveObj) == nullptr )
1133 OSL_FAIL( "SwPageFrame::RemoveDrawObjFromPage(..) - anchored object of unexpected type -> object not removed" );
1134 return;
1137 if ( m_pSortedObjs )
1139 m_pSortedObjs->Remove( _rToRemoveObj );
1140 if ( !m_pSortedObjs->size() )
1142 m_pSortedObjs.reset();
1144 if ( GetUpper() )
1146 if (RndStdIds::FLY_AS_CHAR !=
1147 _rToRemoveObj.GetFrameFormat().GetAnchor().GetAnchorId())
1149 static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous();
1150 InvalidatePage();
1152 static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
1155 _rToRemoveObj.SetPageFrame( nullptr );
1158 // #i50432# - adjust method description and synopsis.
1159 void SwPageFrame::PlaceFly( SwFlyFrame* pFly, SwFlyFrameFormat* pFormat )
1161 // #i50432# - consider the case that page is an empty page:
1162 // In this case append the fly frame at the next page
1163 OSL_ENSURE( !IsEmptyPage() || GetNext(),
1164 "<SwPageFrame::PlaceFly(..)> - empty page with no next page! -> fly frame appended at empty page" );
1165 if ( IsEmptyPage() && GetNext() )
1167 static_cast<SwPageFrame*>(GetNext())->PlaceFly( pFly, pFormat );
1169 else
1171 // If we received a Fly, we use that one. Otherwise, create a new
1172 // one using the Format.
1173 if ( pFly )
1174 AppendFly( pFly );
1175 else
1177 OSL_ENSURE( pFormat, ":-( No Format given for Fly." );
1178 pFly = new SwFlyLayFrame( pFormat, this, this );
1179 AppendFly( pFly );
1180 ::RegistFlys( this, pFly );
1185 // #i18732# - adjustments for following text flow or not
1186 // AND alignment at 'page areas' for to paragraph/to character anchored objects
1187 // #i22305# - adjustment for following text flow for to frame anchored objects
1188 // #i29778# - Because calculating the floating screen object's position
1189 // (Writer fly frame or drawing object) doesn't perform a calculation on its
1190 // upper frames and its anchor frame, a calculation of the upper frames in this
1191 // method is no longer sensible.
1192 // #i28701# - if document compatibility option 'Consider wrapping style influence
1193 // on object positioning' is ON, the clip area corresponds to the one as the
1194 // object doesn't follow the text flow.
1195 bool CalcClipRect( const SdrObject *pSdrObj, SwRect &rRect, bool bMove )
1197 bool bRet = true;
1198 if ( auto pVirtFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) )
1200 const SwFlyFrame* pFly = pVirtFlyDrawObj->GetFlyFrame();
1201 const bool bFollowTextFlow = pFly->GetFormat()->GetFollowTextFlow().GetValue();
1202 // #i28701#
1203 const bool bConsiderWrapOnObjPos =
1204 pFly->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION);
1205 const SwFormatVertOrient &rV = pFly->GetFormat()->GetVertOrient();
1206 if( pFly->IsFlyLayFrame() )
1208 const SwFrame* pClip;
1209 // #i22305#
1210 // #i28701#
1211 if ( !bFollowTextFlow || bConsiderWrapOnObjPos )
1213 pClip = pFly->GetAnchorFrame()->FindPageFrame();
1215 else
1217 pClip = pFly->GetAnchorFrame();
1220 rRect = pClip->getFrameArea();
1221 SwRectFnSet aRectFnSet(pClip);
1223 // vertical clipping: Top and Bottom, also to PrtArea if necessary
1224 if( rV.GetVertOrient() != text::VertOrientation::NONE &&
1225 rV.GetRelationOrient() == text::RelOrientation::PRINT_AREA )
1227 aRectFnSet.SetTop( rRect, aRectFnSet.GetPrtTop(*pClip) );
1228 aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pClip) );
1230 // horizontal clipping: Top and Bottom, also to PrtArea if necessary
1231 const SwFormatHoriOrient &rH = pFly->GetFormat()->GetHoriOrient();
1232 if( rH.GetHoriOrient() != text::HoriOrientation::NONE &&
1233 rH.GetRelationOrient() == text::RelOrientation::PRINT_AREA )
1235 aRectFnSet.SetLeft( rRect, aRectFnSet.GetPrtLeft(*pClip) );
1236 aRectFnSet.SetRight(rRect, aRectFnSet.GetPrtRight(*pClip));
1239 else if( pFly->IsFlyAtContentFrame() )
1241 // #i18732# - consider following text flow or not
1242 // AND alignment at 'page areas'
1243 const SwFrame* pVertPosOrientFrame = pFly->GetVertPosOrientFrame();
1244 if ( !pVertPosOrientFrame )
1246 OSL_FAIL( "::CalcClipRect(..) - frame, vertical position is oriented at, is missing .");
1247 pVertPosOrientFrame = pFly->GetAnchorFrame();
1250 if ( !bFollowTextFlow || bConsiderWrapOnObjPos )
1252 const SwLayoutFrame* pClipFrame = pVertPosOrientFrame->FindPageFrame();
1253 if (!pClipFrame)
1255 OSL_FAIL("!pClipFrame: "
1256 "if you can reproduce this please file a bug");
1257 return false;
1259 rRect = bMove ? pClipFrame->GetUpper()->getFrameArea()
1260 : pClipFrame->getFrameArea();
1261 // #i26945# - consider that a table, during
1262 // its format, can exceed its upper printing area bottom.
1263 // Thus, enlarge the clip rectangle, if such a case occurred
1264 if ( pFly->GetAnchorFrame()->IsInTab() )
1266 const SwTabFrame* pTabFrame = const_cast<SwFlyFrame*>(pFly)
1267 ->GetAnchorFrameContainingAnchPos()->FindTabFrame();
1268 SwRect aTmp( pTabFrame->getFramePrintArea() );
1269 aTmp += pTabFrame->getFrameArea().Pos();
1270 rRect.Union( aTmp );
1271 // #i43913# - consider also the cell frame
1272 const SwFrame* pCellFrame = const_cast<SwFlyFrame*>(pFly)
1273 ->GetAnchorFrameContainingAnchPos()->GetUpper();
1274 while ( pCellFrame && !pCellFrame->IsCellFrame() )
1276 pCellFrame = pCellFrame->GetUpper();
1278 if ( pCellFrame )
1280 aTmp = pCellFrame->getFramePrintArea();
1281 aTmp += pCellFrame->getFrameArea().Pos();
1282 rRect.Union( aTmp );
1286 else if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_FRAME ||
1287 rV.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA )
1289 // new class <SwEnvironmentOfAnchoredObject>
1290 objectpositioning::SwEnvironmentOfAnchoredObject
1291 aEnvOfObj( bFollowTextFlow );
1292 const SwLayoutFrame& rVertClipFrame =
1293 aEnvOfObj.GetVertEnvironmentLayoutFrame( *pVertPosOrientFrame );
1294 if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_FRAME )
1296 rRect = rVertClipFrame.getFrameArea();
1298 else if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA )
1300 if ( rVertClipFrame.IsPageFrame() )
1302 rRect = static_cast<const SwPageFrame&>(rVertClipFrame).PrtWithoutHeaderAndFooter();
1304 else
1306 rRect = rVertClipFrame.getFrameArea();
1309 const SwLayoutFrame* pHoriClipFrame =
1310 pFly->GetAnchorFrame()->FindPageFrame()->GetUpper();
1311 SwRectFnSet aRectFnSet(pFly->GetAnchorFrame());
1312 aRectFnSet.SetLeft( rRect, aRectFnSet.GetLeft(pHoriClipFrame->getFrameArea()) );
1313 aRectFnSet.SetRight(rRect, aRectFnSet.GetRight(pHoriClipFrame->getFrameArea()));
1315 else
1317 // #i26945#
1318 const SwFrame *pClip =
1319 const_cast<SwFlyFrame*>(pFly)->GetAnchorFrameContainingAnchPos();
1320 SwRectFnSet aRectFnSet(pClip);
1321 const SwLayoutFrame *pUp = pClip->GetUpper();
1322 const SwFrame *pCell = pUp->IsCellFrame() ? pUp : nullptr;
1323 const SwFrameType nType = bMove
1324 ? SwFrameType::Root | SwFrameType::Fly | SwFrameType::Header |
1325 SwFrameType::Footer | SwFrameType::Ftn
1326 : SwFrameType::Body | SwFrameType::Fly | SwFrameType::Header |
1327 SwFrameType::Footer | SwFrameType::Cell| SwFrameType::Ftn;
1329 while ( !(pUp->GetType() & nType) || pUp->IsColBodyFrame() )
1331 pUp = pUp->GetUpper();
1332 if ( !pCell && pUp->IsCellFrame() )
1333 pCell = pUp;
1335 if ( bMove && pUp->IsRootFrame() )
1337 rRect = pUp->getFramePrintArea();
1338 rRect += pUp->getFrameArea().Pos();
1339 pUp = nullptr;
1341 if ( pUp )
1343 if ( pUp->GetType() & SwFrameType::Body )
1345 const SwPageFrame *pPg;
1346 if ( pUp->GetUpper() != (pPg = pFly->FindPageFrame()) )
1347 pUp = pPg->FindBodyCont();
1348 if (pUp)
1350 rRect = pUp->GetUpper()->getFrameArea();
1351 aRectFnSet.SetTop( rRect, aRectFnSet.GetPrtTop(*pUp) );
1352 aRectFnSet.SetBottom(rRect, aRectFnSet.GetPrtBottom(*pUp));
1355 else
1357 if( ( pUp->GetType() & (SwFrameType::Fly | SwFrameType::Ftn ) ) &&
1358 !pUp->getFrameArea().Contains( pFly->getFrameArea().Pos() ) )
1360 if( pUp->IsFlyFrame() )
1362 const SwFlyFrame *pTmpFly = static_cast<const SwFlyFrame*>(pUp);
1363 while( pTmpFly->GetNextLink() )
1365 pTmpFly = pTmpFly->GetNextLink();
1366 if( pTmpFly->getFrameArea().Contains( pFly->getFrameArea().Pos() ) )
1367 break;
1369 pUp = pTmpFly;
1371 else if( pUp->IsInFootnote() )
1373 const SwFootnoteFrame *pTmp = pUp->FindFootnoteFrame();
1374 while( pTmp->GetFollow() )
1376 pTmp = pTmp->GetFollow();
1377 if( pTmp->getFrameArea().Contains( pFly->getFrameArea().Pos() ) )
1378 break;
1380 pUp = pTmp;
1383 rRect = pUp->getFramePrintArea();
1384 rRect.Pos() += pUp->getFrameArea().Pos();
1385 if ( pUp->GetType() & (SwFrameType::Header | SwFrameType::Footer) )
1387 rRect.Left ( pUp->GetUpper()->getFrameArea().Left() );
1388 rRect.Width( pUp->GetUpper()->getFrameArea().Width());
1390 else if ( pUp->IsCellFrame() ) //MA_FLY_HEIGHT
1392 const SwFrame *pTab = pUp->FindTabFrame();
1393 aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pTab->GetUpper()) );
1394 // expand to left and right cell border
1395 rRect.Left ( pUp->getFrameArea().Left() );
1396 rRect.Width( pUp->getFrameArea().Width() );
1400 if ( pCell )
1402 // CellFrames might also sit in unallowed areas. In this case,
1403 // the Fly is allowed to do so as well
1404 SwRect aTmp( pCell->getFramePrintArea() );
1405 aTmp += pCell->getFrameArea().Pos();
1406 rRect.Union( aTmp );
1410 else
1412 const SwFrame *pUp = pFly->GetAnchorFrame()->GetUpper();
1413 SwRectFnSet aRectFnSet(pFly->GetAnchorFrame());
1414 while( pUp->IsColumnFrame() || pUp->IsSctFrame() || pUp->IsColBodyFrame())
1415 pUp = pUp->GetUpper();
1416 rRect = pUp->getFrameArea();
1417 if( !pUp->IsBodyFrame() )
1419 rRect += pUp->getFramePrintArea().Pos();
1420 rRect.SSize( pUp->getFramePrintArea().SSize() );
1421 if ( pUp->IsCellFrame() )
1423 const SwFrame *pTab = pUp->FindTabFrame();
1424 aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pTab->GetUpper()) );
1427 else if ( pUp->GetUpper()->IsPageFrame() )
1429 // Objects anchored as character may exceed right margin
1430 // of body frame:
1431 aRectFnSet.SetRight( rRect, aRectFnSet.GetRight(pUp->GetUpper()->getFrameArea()) );
1433 tools::Long nHeight = (9*aRectFnSet.GetHeight(rRect))/10;
1434 tools::Long nTop;
1435 const SwFormat *pFormat = GetUserCall(pSdrObj)->GetFormat();
1436 const SvxULSpaceItem &rUL = pFormat->GetULSpace();
1437 if( bMove )
1439 nTop = aRectFnSet.IsVert() ? static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().X() :
1440 static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().Y();
1441 nTop = aRectFnSet.YInc( nTop, -nHeight );
1442 tools::Long nWidth = aRectFnSet.GetWidth(pFly->getFrameArea());
1443 aRectFnSet.SetLeftAndWidth( rRect, aRectFnSet.IsVert() ?
1444 static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().Y() :
1445 static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().X(), nWidth );
1446 nHeight = 2*nHeight - rUL.GetLower() - rUL.GetUpper();
1448 else
1450 nTop = aRectFnSet.YInc( aRectFnSet.GetBottom(pFly->getFrameArea()),
1451 rUL.GetLower() - nHeight );
1452 nHeight = 2*nHeight - aRectFnSet.GetHeight(pFly->getFrameArea())
1453 - rUL.GetLower() - rUL.GetUpper();
1455 aRectFnSet.SetTopAndHeight( rRect, nTop, nHeight );
1458 else
1460 const SwDrawContact *pC = static_cast<const SwDrawContact*>(GetUserCall(pSdrObj));
1461 const SwFrameFormat *pFormat = pC->GetFormat();
1462 const SwFormatAnchor &rAnch = pFormat->GetAnchor();
1463 if ( RndStdIds::FLY_AS_CHAR == rAnch.GetAnchorId() )
1465 const SwFrame* pAnchorFrame = pC->GetAnchorFrame( pSdrObj );
1466 if( !pAnchorFrame )
1468 OSL_FAIL( "<::CalcClipRect(..)> - missing anchor frame." );
1469 const_cast<SwDrawContact*>(pC)->ConnectToLayout();
1470 pAnchorFrame = pC->GetAnchorFrame();
1472 const SwFrame* pUp = pAnchorFrame->GetUpper();
1473 rRect = pUp->getFramePrintArea();
1474 rRect += pUp->getFrameArea().Pos();
1475 SwRectFnSet aRectFnSet(pAnchorFrame);
1476 tools::Long nHeight = (9*aRectFnSet.GetHeight(rRect))/10;
1477 tools::Long nTop;
1478 const SvxULSpaceItem &rUL = pFormat->GetULSpace();
1479 SwRect aSnapRect( pSdrObj->GetSnapRect() );
1480 tools::Long nTmpH = 0;
1481 if( bMove )
1483 nTop = aRectFnSet.YInc( aRectFnSet.IsVert() ? pSdrObj->GetAnchorPos().X() :
1484 pSdrObj->GetAnchorPos().Y(), -nHeight );
1485 tools::Long nWidth = aRectFnSet.GetWidth(aSnapRect);
1486 aRectFnSet.SetLeftAndWidth( rRect, aRectFnSet.IsVert() ?
1487 pSdrObj->GetAnchorPos().Y() :
1488 pSdrObj->GetAnchorPos().X(), nWidth );
1490 else
1492 // #i26791# - value of <nTmpH> is needed to
1493 // calculate value of <nTop>.
1494 nTmpH = aRectFnSet.IsVert() ? pSdrObj->GetCurrentBoundRect().GetWidth() :
1495 pSdrObj->GetCurrentBoundRect().GetHeight();
1496 nTop = aRectFnSet.YInc( aRectFnSet.GetTop(aSnapRect),
1497 rUL.GetLower() + nTmpH - nHeight );
1499 nHeight = 2*nHeight - nTmpH - rUL.GetLower() - rUL.GetUpper();
1500 aRectFnSet.SetTopAndHeight( rRect, nTop, nHeight );
1502 else
1504 // restrict clip rectangle for drawing
1505 // objects in header/footer to the page frame.
1506 // #i26791#
1507 const SwFrame* pAnchorFrame = pC->GetAnchorFrame( pSdrObj );
1508 if ( pAnchorFrame && pAnchorFrame->FindFooterOrHeader() )
1510 // clip frame is the page frame the header/footer is on.
1511 const SwFrame* pClipFrame = pAnchorFrame->FindPageFrame();
1512 rRect = pClipFrame->getFrameArea();
1514 else
1516 bRet = false;
1520 return bRet;
1523 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */