summaryrefslogtreecommitdiffstats
path: root/sw/source/core/layout/flylay.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/layout/flylay.cxx')
-rw-r--r--sw/source/core/layout/flylay.cxx1489
1 files changed, 1489 insertions, 0 deletions
diff --git a/sw/source/core/layout/flylay.cxx b/sw/source/core/layout/flylay.cxx
new file mode 100644
index 000000000..72d673b22
--- /dev/null
+++ b/sw/source/core/layout/flylay.cxx
@@ -0,0 +1,1489 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <pagefrm.hxx>
+#include <rootfrm.hxx>
+#include <cntfrm.hxx>
+#include <dflyobj.hxx>
+#include <dcontact.hxx>
+#include <ftnfrm.hxx>
+#include <frmatr.hxx>
+#include <frmtool.hxx>
+#include <hints.hxx>
+#include <sectfrm.hxx>
+#include <notxtfrm.hxx>
+#include <txtfly.hxx>
+
+#include <svx/svdpage.hxx>
+#include <editeng/ulspitem.hxx>
+#include <fmtornt.hxx>
+#include <fmtfsize.hxx>
+#include <ndole.hxx>
+#include <tabfrm.hxx>
+#include <flyfrms.hxx>
+#include <fmtfollowtextflow.hxx>
+#include <environmentofanchoredobject.hxx>
+#include <sortedobjs.hxx>
+#include <viewimp.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <pam.hxx>
+#include <ndindex.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
+
+using namespace ::com::sun::star;
+
+SwFlyFreeFrame::SwFlyFreeFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch )
+: SwFlyFrame( pFormat, pSib, pAnch ),
+ // #i34753#
+ mbNoMakePos( false ),
+ // #i37068#
+ mbNoMoveOnCheckClip( false ),
+ maUnclippedFrame(),
+ // RotateFlyFrame3
+ mpTransformableSwFrame()
+{
+}
+
+void SwFlyFreeFrame::DestroyImpl()
+{
+ // #i28701# - use new method <GetPageFrame()>
+ if( GetPageFrame() )
+ {
+ if( GetFormat()->GetDoc()->IsInDtor() )
+ {
+ // #i29879# - remove also to-frame anchored Writer
+ // fly frame from page.
+ const bool bRemoveFromPage =
+ GetPageFrame()->GetSortedObjs() &&
+ ( IsFlyAtContentFrame() ||
+ ( GetAnchorFrame() && GetAnchorFrame()->IsFlyFrame() ) );
+ if ( bRemoveFromPage )
+ {
+ GetPageFrame()->GetSortedObjs()->Remove( *this );
+ }
+ }
+ else
+ {
+ SwRect aTmp( GetObjRectWithSpaces() );
+ SwFlyFreeFrame::NotifyBackground( GetPageFrame(), aTmp, PrepareHint::FlyFrameLeave );
+ }
+ }
+
+ SwFlyFrame::DestroyImpl();
+}
+
+SwFlyFreeFrame::~SwFlyFreeFrame()
+{
+#if 0
+ // we are possibly in ContourCache, make sure we vanish
+ ::ClrContourCache(GetVirtDrawObj());
+#endif
+}
+
+// #i28701#
+/** Notifies the background (all ContentFrames that currently are overlapping).
+ *
+ * Additionally, the window is also directly invalidated (especially where
+ * there are no overlapping ContentFrames).
+ * This also takes ContentFrames within other Flys into account.
+ */
+void SwFlyFreeFrame::NotifyBackground( SwPageFrame *pPageFrame,
+ const SwRect& rRect, PrepareHint eHint )
+{
+ ::Notify_Background( GetVirtDrawObj(), pPageFrame, rRect, eHint, true );
+}
+
+void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
+{
+ if ( !GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) )
+ {
+ return;
+ }
+
+ if ( !GetAnchorFrame() || IsLocked() || IsColLocked() )
+ {
+ return;
+ }
+
+ // #i28701# - use new method <GetPageFrame()>
+ if( !GetPageFrame() && GetAnchorFrame()->IsInFly() )
+ {
+ SwFlyFrame* pFly = AnchorFrame()->FindFlyFrame();
+ SwPageFrame *pPageFrame = pFly ? pFly->FindPageFrame() : nullptr;
+ if( pPageFrame )
+ pPageFrame->AppendFlyToPage( this );
+ }
+
+ if( !GetPageFrame() )
+ {
+ return;
+ }
+
+ Lock(); // The curtain drops
+
+ // takes care of the notification in the dtor
+ const SwFlyNotify aNotify( this );
+
+ if ( IsClipped() )
+ {
+ setFrameAreaSizeValid(false);
+ m_bHeightClipped = m_bWidthClipped = false;
+ // no invalidation of position,
+ // if anchored object is anchored inside a Writer fly frame,
+ // its position is already locked, and it follows the text flow.
+ // #i34753# - add condition:
+ // no invalidation of position, if no direct move is requested in <CheckClip(..)>
+ if ( !IsNoMoveOnCheckClip() &&
+ !( PositionLocked() &&
+ GetAnchorFrame()->IsInFly() &&
+ GetFrameFormat().GetFollowTextFlow().GetValue() ) )
+ {
+ setFrameAreaPositionValid(false);
+ }
+ }
+
+ // #i81146# new loop control
+ int nLoopControlRuns = 0;
+ const int nLoopControlMax = 10;
+
+ // RotateFlyFrame3 - outer frame
+ const double fRotation(getLocalFrameRotation());
+ const bool bRotated(!basegfx::fTools::equalZero(fRotation));
+
+ if(bRotated)
+ {
+ // Re-layout may be partially (see all isFrameAreaDefinitionValid() flags),
+ // so resetting the local SwFrame(s) in the local SwFrameAreaDefinition is
+ // needed. Reset to BoundAreas will be done below automatically
+ if(isTransformableSwFrame())
+ {
+ getTransformableSwFrame()->restoreFrameAreas();
+ }
+ }
+
+ while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() || m_bFormatHeightOnly || !m_bValidContentPos )
+ {
+ SwRectFnSet aRectFnSet(this);
+ const SwFormatFrameSize *pSz;
+ { // Additional scope, so aAccess will be destroyed before the check!
+
+ SwBorderAttrAccess aAccess( SwFrame::GetCache(), this );
+ const SwBorderAttrs &rAttrs = *aAccess.Get();
+ pSz = &rAttrs.GetAttrSet().GetFrameSize();
+
+ // Only set when the flag is set!
+ if ( !isFrameAreaSizeValid() )
+ {
+ setFramePrintAreaValid(false);
+ }
+
+ if ( !isFramePrintAreaValid() )
+ {
+ MakePrtArea( rAttrs );
+ m_bValidContentPos = false;
+ }
+
+ if ( !isFrameAreaSizeValid() || m_bFormatHeightOnly )
+ {
+ setFrameAreaSizeValid(false);
+ Format( getRootFrame()->GetCurrShell()->GetOut(), &rAttrs );
+ m_bFormatHeightOnly = false;
+ }
+ }
+
+ if ( !isFrameAreaPositionValid() )
+ {
+ const Point aOldPos( aRectFnSet.GetPos(getFrameArea()) );
+ // #i26791# - use new method <MakeObjPos()>
+ // #i34753# - no positioning, if requested.
+ if ( IsNoMakePos() )
+ {
+ setFrameAreaPositionValid(true);
+ }
+ else
+ // #i26791# - use new method <MakeObjPos()>
+ MakeObjPos();
+ if( aOldPos == aRectFnSet.GetPos(getFrameArea()) )
+ {
+ if( !isFrameAreaPositionValid() && GetAnchorFrame()->IsInSct() &&
+ !GetAnchorFrame()->FindSctFrame()->isFrameAreaDefinitionValid() )
+ {
+ setFrameAreaPositionValid(true);
+ }
+ }
+ else
+ {
+ setFrameAreaSizeValid(false);
+ }
+ }
+
+ if ( !m_bValidContentPos )
+ {
+ SwBorderAttrAccess aAccess( SwFrame::GetCache(), this );
+ const SwBorderAttrs &rAttrs = *aAccess.Get();
+ MakeContentPos( rAttrs );
+ }
+
+ if ( isFrameAreaPositionValid() && isFrameAreaSizeValid() )
+ {
+ ++nLoopControlRuns;
+
+ OSL_ENSURE( nLoopControlRuns < nLoopControlMax, "LoopControl in SwFlyFreeFrame::MakeAll" );
+
+ if ( nLoopControlRuns < nLoopControlMax )
+ CheckClip( *pSz );
+ }
+ else
+ nLoopControlRuns = 0;
+ }
+
+ // RotateFlyFrame3 - outer frame
+ // Do not refresh transforms/Areas self here, this will be done
+ // when inner and outer frame are layouted, in SwNoTextFrame::MakeAll
+ if(bRotated)
+ {
+ // RotateFlyFrame3: Safe changes locally
+ // get center from outer frame (layout frame) to be on the safe side
+ const Point aCenter(getFrameArea().Center());
+ const basegfx::B2DPoint aB2DCenter(aCenter.X(), aCenter.Y());
+
+ if(!mpTransformableSwFrame)
+ {
+ mpTransformableSwFrame.reset(new TransformableSwFrame(*this));
+ }
+
+ getTransformableSwFrame()->createFrameAreaTransformations(
+ fRotation,
+ aB2DCenter);
+ getTransformableSwFrame()->adaptFrameAreasToTransformations();
+ }
+ else
+ {
+ // RotateFlyFrame3: Also need to clear ContourCache (if used),
+ // usually done in SwFlyFrame::NotifyDrawObj, but there relies on
+ // being in transform mode which is already reset then
+ if(isTransformableSwFrame())
+ {
+ ::ClrContourCache(GetVirtDrawObj());
+ }
+
+ // reset transformations to show that they are not used
+ mpTransformableSwFrame.reset();
+ }
+
+ Unlock();
+
+#if OSL_DEBUG_LEVEL > 0
+ SwRectFnSet aRectFnSet(this);
+ OSL_ENSURE( m_bHeightClipped || ( aRectFnSet.GetHeight(getFrameArea()) > 0 &&
+ aRectFnSet.GetHeight(getFramePrintArea()) > 0),
+ "SwFlyFreeFrame::Format(), flipping Fly." );
+
+#endif
+}
+
+bool SwFlyFreeFrame::supportsAutoContour() const
+{
+ static bool bOverrideHandleContourToAlwaysOff(true); // loplugin:constvars:ignore
+
+ // RotateFlyFrameFix: For LO6.0 we need to deactivate the AutoContour feature again, it is simply
+ // not clear how/if to use and save/load it in ODF. This has to be discussed.
+ // The reason not to remove is that this may be used as-is now, using a new switch.
+ // Even when not, the detection if it is possible will be needed in any case later.
+ if(bOverrideHandleContourToAlwaysOff)
+ {
+ return false;
+ }
+
+ if(!isTransformableSwFrame())
+ {
+ // support only when transformed, else there is no free space
+ return false;
+ }
+
+ // Check for Borders. If we have Borders, do (currently) not support,
+ // since borders do not transform with the object.
+ // (Will need to be enhanced to take into account if we have Borders and if these
+ // transform with the object)
+ SwBorderAttrAccess aAccess(SwFrame::GetCache(), this);
+ const SwBorderAttrs &rAttrs(*aAccess.Get());
+
+ if(rAttrs.IsLine())
+ {
+ return false;
+ }
+
+ // Check for Padding. Do not support when padding is used, this will
+ // produce a covered space around the object (filled with fill defines)
+ const SfxPoolItem* pItem(nullptr);
+
+ if(GetFormat() && SfxItemState::SET == GetFormat()->GetItemState(RES_BOX, false, &pItem))
+ {
+ const SvxBoxItem& rBox = *static_cast< const SvxBoxItem* >(pItem);
+
+ if(rBox.HasBorder(/*bTreatPaddingAsBorder*/true))
+ {
+ return false;
+ }
+ }
+
+ // check for Fill - if we have fill, it will fill the gaps and we will not
+ // support AutoContour
+ if(GetFormat() && GetFormat()->supportsFullDrawingLayerFillAttributeSet())
+ {
+ const drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes(GetFormat()->getSdrAllFillAttributesHelper());
+
+ if(aFillAttributes && aFillAttributes->isUsed())
+ {
+ return false;
+ }
+ }
+ else
+ {
+ const std::unique_ptr<SvxBrushItem> aBack(GetFormat()->makeBackgroundBrushItem());
+
+ if(aBack && aBack->isUsed())
+ {
+ return false;
+ }
+ }
+
+ // else, support
+ return true;
+}
+
+// RotateFlyFrame3 - Support for Transformations - outer frame
+basegfx::B2DHomMatrix SwFlyFreeFrame::getFrameAreaTransformation() const
+{
+ if(isTransformableSwFrame())
+ {
+ // use pre-created transformation
+ return getTransformableSwFrame()->getLocalFrameAreaTransformation();
+ }
+
+ // call parent
+ return SwFlyFrame::getFrameAreaTransformation();
+}
+
+basegfx::B2DHomMatrix SwFlyFreeFrame::getFramePrintAreaTransformation() const
+{
+ if(isTransformableSwFrame())
+ {
+ // use pre-created transformation
+ return getTransformableSwFrame()->getLocalFramePrintAreaTransformation();
+ }
+
+ // call parent
+ return SwFlyFrame::getFramePrintAreaTransformation();
+}
+
+// RotateFlyFrame3 - Support for Transformations
+void SwFlyFreeFrame::transform_translate(const Point& rOffset)
+{
+ // call parent - this will do the basic transform for SwRect(s)
+ // in the SwFrameAreaDefinition
+ SwFlyFrame::transform_translate(rOffset);
+
+ // check if the Transformations need to be adapted
+ if(isTransformableSwFrame())
+ {
+ const basegfx::B2DHomMatrix aTransform(
+ basegfx::utils::createTranslateB2DHomMatrix(
+ rOffset.X(), rOffset.Y()));
+
+ // transform using TransformableSwFrame
+ getTransformableSwFrame()->transform(aTransform);
+ }
+}
+
+// RotateFlyFrame3 - outer frame
+double getLocalFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame)
+{
+ return rNoTextFrame.getLocalFrameRotation();
+}
+
+double SwFlyFreeFrame::getLocalFrameRotation() const
+{
+ // SwLayoutFrame::Lower() != SwFrame::GetLower(), but SwFrame::GetLower()
+ // calls SwLayoutFrame::Lower() when it's a SwLayoutFrame - so use GetLower()
+ const SwNoTextFrame* pSwNoTextFrame(dynamic_cast< const SwNoTextFrame* >(GetLower()));
+
+ if(nullptr != pSwNoTextFrame)
+ {
+ return getLocalFrameRotation_from_SwNoTextFrame(*pSwNoTextFrame);
+ }
+
+ // no rotation
+ return 0.0;
+}
+
+/** determines, if direct environment of fly frame has 'auto' size
+
+ #i17297#
+ start with anchor frame and search via <GetUpper()> for a header, footer,
+ row or fly frame stopping at page frame.
+ return <true>, if such a frame is found and it has 'auto' size.
+ otherwise <false> is returned.
+
+ @return boolean indicating, that direct environment has 'auto' size
+*/
+bool SwFlyFreeFrame::HasEnvironmentAutoSize() const
+{
+ bool bRetVal = false;
+
+ const SwFrame* pToBeCheckedFrame = GetAnchorFrame();
+ while ( pToBeCheckedFrame &&
+ !pToBeCheckedFrame->IsPageFrame() )
+ {
+ if ( pToBeCheckedFrame->IsHeaderFrame() ||
+ pToBeCheckedFrame->IsFooterFrame() ||
+ pToBeCheckedFrame->IsRowFrame() ||
+ pToBeCheckedFrame->IsFlyFrame() )
+ {
+ bRetVal = SwFrameSize::Fixed !=
+ pToBeCheckedFrame->GetAttrSet()->GetFrameSize().GetHeightSizeType();
+ break;
+ }
+ else
+ {
+ pToBeCheckedFrame = pToBeCheckedFrame->GetUpper();
+ }
+ }
+
+ return bRetVal;
+}
+
+void SwFlyFreeFrame::CheckClip( const SwFormatFrameSize &rSz )
+{
+ // It's probably time now to take appropriate measures, if the Fly
+ // doesn't fit into its surrounding.
+ // First, the Fly gives up its position, then it's formatted.
+ // Only if it still doesn't fit after giving up its position, the
+ // width or height are given up as well. The frame will be squeezed
+ // as much as needed.
+
+ const SwVirtFlyDrawObj *pObj = GetVirtDrawObj();
+ SwRect aClip, aTmpStretch;
+ ::CalcClipRect( pObj, aClip );
+ ::CalcClipRect( pObj, aTmpStretch, false );
+ aClip.Intersection_( aTmpStretch );
+
+ const long nBot = getFrameArea().Top() + getFrameArea().Height();
+ const long nRig = getFrameArea().Left() + getFrameArea().Width();
+ const long nClipBot = aClip.Top() + aClip.Height();
+ const long nClipRig = aClip.Left() + aClip.Width();
+
+ const bool bBot = nBot > nClipBot;
+ const bool bRig = nRig > nClipRig;
+ if ( bBot || bRig )
+ {
+ bool bAgain = false;
+ // #i37068# - no move, if it's requested
+ if ( bBot && !IsNoMoveOnCheckClip() &&
+ !GetDrawObjs() && !GetAnchorFrame()->IsInTab() )
+ {
+ SwFrame* pHeader = FindFooterOrHeader();
+ // In a header, correction of the position is no good idea.
+ // If the fly moves, some paragraphs have to be formatted, this
+ // could cause a change of the height of the headerframe,
+ // now the flyframe can change its position and so on ...
+ if ( !pHeader || !pHeader->IsHeaderFrame() )
+ {
+ const long nOld = getFrameArea().Top();
+
+ // tdf#112443 disable positioning if content is completely off page
+ bool bDisableOffPagePositioning = GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
+ if ( !bDisableOffPagePositioning || nOld <= nClipBot)
+ {
+ SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
+ aFrm.Pos().setY( std::max( aClip.Top(), nClipBot - aFrm.Height() ) );
+ }
+
+ if ( getFrameArea().Top() != nOld )
+ {
+ bAgain = true;
+ }
+
+ m_bHeightClipped = true;
+ }
+ }
+ if ( bRig )
+ {
+ const long nOld = getFrameArea().Left();
+
+ // tdf#112443 disable positioning if content is completely off page
+ bool bDisableOffPagePositioning = GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
+ if ( !bDisableOffPagePositioning || nOld <= nClipRig )
+ {
+ SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
+ aFrm.Pos().setX( std::max( aClip.Left(), nClipRig - aFrm.Width() ) );
+ }
+
+ if ( getFrameArea().Left() != nOld )
+ {
+ const SwFormatHoriOrient &rH = GetFormat()->GetHoriOrient();
+ // Left-aligned ones may not be moved to the left when they
+ // are avoiding another one.
+ if( rH.GetHoriOrient() == text::HoriOrientation::LEFT )
+ {
+ SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
+ aFrm.Pos().setX( nOld );
+ }
+ else
+ {
+ bAgain = true;
+ }
+ }
+ m_bWidthClipped = true;
+ }
+ if ( bAgain )
+ {
+ setFrameAreaSizeValid(false);
+ }
+ else
+ {
+ // If we reach this branch, the Frame protrudes into forbidden
+ // areas, and correcting the position is not allowed or not
+ // possible or not required.
+
+ // For Flys with OLE objects as lower, we make sure that
+ // we always resize proportionally
+ Size aOldSize( getFrameArea().SSize() );
+
+ // First, setup the FrameRect, then transfer it to the Frame.
+ SwRect aFrameRect( getFrameArea() );
+
+ if ( bBot )
+ {
+ long nDiff = nClipBot;
+ nDiff -= aFrameRect.Top(); // nDiff represents the available distance
+ nDiff = aFrameRect.Height() - nDiff;
+ aFrameRect.Height( aFrameRect.Height() - nDiff );
+ m_bHeightClipped = true;
+ }
+ if ( bRig )
+ {
+ long nDiff = nClipRig;
+ nDiff -= aFrameRect.Left();// nDiff represents the available distance
+ nDiff = aFrameRect.Width() - nDiff;
+ aFrameRect.Width( aFrameRect.Width() - nDiff );
+ m_bWidthClipped = true;
+ }
+
+ // #i17297# - no proportional
+ // scaling of graphics in environments, which determines its size
+ // by its content ('auto' size). Otherwise layout loops can occur and
+ // layout sizes of the environment can be incorrect.
+ // Such environment are:
+ // (1) header and footer frames with 'auto' size
+ // (2) table row frames with 'auto' size
+ // (3) fly frames with 'auto' size
+ // Note: section frames seems to be not critical - didn't found
+ // any critical layout situation so far.
+ if ( Lower() && Lower()->IsNoTextFrame() &&
+ (static_cast<SwNoTextFrame*>(Lower())->GetNode()->GetOLENode() ||
+ !HasEnvironmentAutoSize() ) )
+ {
+ // If width and height got adjusted, then the bigger
+ // change is relevant.
+ if ( aFrameRect.Width() != aOldSize.Width() &&
+ aFrameRect.Height()!= aOldSize.Height() )
+ {
+ if ( (aOldSize.Width() - aFrameRect.Width()) >
+ (aOldSize.Height()- aFrameRect.Height()) )
+ aFrameRect.Height( aOldSize.Height() );
+ else
+ aFrameRect.Width( aOldSize.Width() );
+ }
+
+ // Adjusted the width? change height proportionally
+ if( aFrameRect.Width() != aOldSize.Width() )
+ {
+ aFrameRect.Height( aFrameRect.Width() * aOldSize.Height() /
+ aOldSize.Width() );
+ m_bHeightClipped = true;
+ }
+ // Adjusted the height? change width proportionally
+ else if( aFrameRect.Height() != aOldSize.Height() )
+ {
+ aFrameRect.Width( aFrameRect.Height() * aOldSize.Width() /
+ aOldSize.Height() );
+ m_bWidthClipped = true;
+ }
+
+ // #i17297# - reactivate change
+ // of size attribute for fly frames containing an ole object.
+
+ // Added the aFrameRect.HasArea() hack, because
+ // the environment of the ole object does not have to be valid
+ // at this moment, or even worse, it does not have to have a
+ // reasonable size. In this case we do not want to change to
+ // attributes permanently. Maybe one day somebody dares to remove
+ // this code.
+ if ( aFrameRect.HasArea() &&
+ static_cast<SwNoTextFrame*>(Lower())->GetNode()->GetOLENode() &&
+ ( m_bWidthClipped || m_bHeightClipped ) )
+ {
+ SwFlyFrameFormat *pFormat = GetFormat();
+ pFormat->LockModify();
+ SwFormatFrameSize aFrameSize( rSz );
+ aFrameSize.SetWidth( aFrameRect.Width() );
+ aFrameSize.SetHeight( aFrameRect.Height() );
+ pFormat->SetFormatAttr( aFrameSize );
+ pFormat->UnlockModify();
+ }
+ }
+
+ // Now change the Frame; for columns, we put the new values into the attributes,
+ // otherwise we'll end up with unwanted side-effects/oscillations
+ const long nPrtHeightDiff = getFrameArea().Height() - getFramePrintArea().Height();
+ const long nPrtWidthDiff = getFrameArea().Width() - getFramePrintArea().Width();
+ maUnclippedFrame = getFrameArea();
+
+ {
+ SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
+ aFrm.Height( aFrameRect.Height() );
+ aFrm.Width ( std::max( long(MINLAY), aFrameRect.Width() ) );
+ }
+
+ if ( Lower() && Lower()->IsColumnFrame() )
+ {
+ ColLock(); //lock grow/shrink
+ const Size aTmpOldSize( getFramePrintArea().SSize() );
+
+ {
+ SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
+ aPrt.Height( getFrameArea().Height() - nPrtHeightDiff );
+ aPrt.Width ( getFrameArea().Width() - nPrtWidthDiff );
+ }
+
+ ChgLowersProp( aTmpOldSize );
+ SwFrame *pLow = Lower();
+ do
+ {
+ pLow->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ // also calculate the (Column)BodyFrame
+ static_cast<SwLayoutFrame*>(pLow)->Lower()->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ pLow = pLow->GetNext();
+ } while ( pLow );
+ ::CalcContent( this );
+ ColUnlock();
+
+ if ( !isFrameAreaSizeValid() && !m_bWidthClipped )
+ {
+ setFrameAreaSizeValid(true);
+ m_bFormatHeightOnly = true;
+ }
+ }
+ else
+ {
+ SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
+ aPrt.Height( getFrameArea().Height() - nPrtHeightDiff );
+ aPrt.Width ( getFrameArea().Width() - nPrtWidthDiff );
+ }
+ }
+ }
+
+ // #i26945#
+ OSL_ENSURE( getFrameArea().Height() >= 0,
+ "<SwFlyFreeFrame::CheckClip(..)> - fly frame has negative height now." );
+}
+
+/** method to determine, if a <MakeAll()> on the Writer fly frame is possible
+ #i43771#
+*/
+bool SwFlyFreeFrame::IsFormatPossible() const
+{
+ return SwFlyFrame::IsFormatPossible() &&
+ ( GetPageFrame() ||
+ ( GetAnchorFrame() && GetAnchorFrame()->IsInFly() ) );
+}
+
+SwFlyLayFrame::SwFlyLayFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch ) :
+ SwFlyFreeFrame( pFormat, pSib, pAnch )
+{
+ m_bLayout = true;
+}
+
+// #i28701#
+
+void SwFlyLayFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
+{
+ const SwFormatAnchor *pAnch = nullptr;
+
+ if (pNew)
+ {
+ const sal_uInt16 nWhich = pNew->Which();
+ if( RES_ATTRSET_CHG == nWhich && SfxItemState::SET ==
+ static_cast<const SwAttrSetChg*>(pNew)->GetChgSet()->GetItemState( RES_ANCHOR, false,
+ reinterpret_cast<const SfxPoolItem**>(&pAnch) ))
+ ; // GetItemState sets the anchor pointer!
+
+ else if( RES_ANCHOR == nWhich )
+ {
+ // Change of anchor. I'm attaching myself to the new place.
+ // It's not allowed to change the anchor type. This is only
+ // possible via SwFEShell.
+ pAnch = static_cast<const SwFormatAnchor*>(pNew);
+ }
+ }
+
+ if( pAnch )
+ {
+ OSL_ENSURE( pAnch->GetAnchorId() ==
+ GetFormat()->GetAnchor().GetAnchorId(),
+ "8-) Invalid change of anchor type." );
+
+ // Unregister, get hold of the page, attach to the corresponding LayoutFrame.
+ SwRect aOld( GetObjRectWithSpaces() );
+ // #i28701# - use new method <GetPageFrame()>
+ SwPageFrame *pOldPage = GetPageFrame();
+ AnchorFrame()->RemoveFly( this );
+
+ if ( RndStdIds::FLY_AT_PAGE == pAnch->GetAnchorId() )
+ {
+ sal_uInt16 nPgNum = pAnch->GetPageNum();
+ SwRootFrame *pRoot = getRootFrame();
+ SwPageFrame *pTmpPage = static_cast<SwPageFrame*>(pRoot->Lower());
+ for ( sal_uInt16 i = 1; (i <= nPgNum) && pTmpPage; ++i,
+ pTmpPage = static_cast<SwPageFrame*>(pTmpPage->GetNext()) )
+ {
+ if ( i == nPgNum )
+ {
+ // #i50432# - adjust synopsis of <PlaceFly(..)>
+ pTmpPage->PlaceFly( this, nullptr );
+ }
+ }
+ if( !pTmpPage )
+ {
+ pRoot->SetAssertFlyPages();
+ pRoot->AssertFlyPages();
+ }
+ }
+ else
+ {
+ SwNodeIndex aIdx( pAnch->GetContentAnchor()->nNode );
+ SwContentFrame *pContent = GetFormat()->GetDoc()->GetNodes().GoNext( &aIdx )->
+ GetContentNode()->getLayoutFrame(getRootFrame(), nullptr, nullptr);
+ if( pContent )
+ {
+ SwFlyFrame *pTmp = pContent->FindFlyFrame();
+ if( pTmp )
+ pTmp->AppendFly( this );
+ }
+ }
+ // #i28701# - use new method <GetPageFrame()>
+ if ( pOldPage && pOldPage != GetPageFrame() )
+ NotifyBackground( pOldPage, aOld, PrepareHint::FlyFrameLeave );
+ SetCompletePaint();
+ InvalidateAll();
+ SetNotifyBack();
+ }
+ else
+ SwFlyFrame::Modify( pOld, pNew );
+}
+
+void SwPageFrame::AppendFlyToPage( SwFlyFrame *pNew )
+{
+ if ( !pNew->GetVirtDrawObj()->IsInserted() )
+ getRootFrame()->GetDrawPage()->InsertObject(
+ static_cast<SdrObject*>(pNew->GetVirtDrawObj()),
+ pNew->GetVirtDrawObj()->GetReferencedObj().GetOrdNumDirect() );
+
+ InvalidateSpelling();
+ InvalidateSmartTags();
+ InvalidateAutoCompleteWords();
+ InvalidateWordCount();
+
+ if ( GetUpper() )
+ {
+ static_cast<SwRootFrame*>(GetUpper())->SetIdleFlags();
+ static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
+ }
+
+ SdrObject* pObj = pNew->GetVirtDrawObj();
+ OSL_ENSURE( pNew->GetAnchorFrame(), "Fly without Anchor" );
+ SwFlyFrame* pFly = const_cast<SwFlyFrame*>(pNew->GetAnchorFrame()->FindFlyFrame());
+ if ( pFly && pObj->GetOrdNum() < pFly->GetVirtDrawObj()->GetOrdNum() )
+ {
+ //#i119945# set pFly's OrdNum to _rNewObj's. So when pFly is removed by Undo, the original OrdNum will not be changed.
+ sal_uInt32 nNewNum = pObj->GetOrdNumDirect();
+ if ( pObj->getSdrPageFromSdrObject() )
+ pObj->getSdrPageFromSdrObject()->SetObjectOrdNum( pFly->GetVirtDrawObj()->GetOrdNumDirect(), nNewNum );
+ else
+ pFly->GetVirtDrawObj()->SetOrdNum( nNewNum );
+ }
+
+ // Don't look further at Flys that sit inside the Content.
+ if ( pNew->IsFlyInContentFrame() )
+ InvalidateFlyInCnt();
+ else
+ {
+ InvalidateFlyContent();
+
+ if ( !m_pSortedObjs )
+ {
+ m_pSortedObjs.reset(new SwSortedObjs());
+ }
+
+ const bool bSuccessInserted = m_pSortedObjs->Insert( *pNew );
+ OSL_ENSURE( bSuccessInserted, "Fly not inserted in Sorted." );
+
+ // #i87493#
+ OSL_ENSURE( pNew->GetPageFrame() == nullptr || pNew->GetPageFrame() == this,
+ "<SwPageFrame::AppendFlyToPage(..)> - anchored fly frame seems to be registered at another page frame. Serious defect." );
+ // #i28701# - use new method <SetPageFrame(..)>
+ pNew->SetPageFrame( this );
+ pNew->InvalidatePage( this );
+ // #i28701#
+ pNew->UnlockPosition();
+ // needed to reposition at-page anchored flys moved from different page
+ pNew->InvalidateObjPos();
+
+ // Notify accessible layout. That's required at this place for
+ // frames only where the anchor is moved. Creation of new frames
+ // is additionally handled by the SwFrameNotify class.
+ if( GetUpper() &&
+ static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
+ static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
+ {
+ static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
+ ->AddAccessibleFrame( pNew );
+ }
+ }
+
+ // #i28701# - correction: consider also drawing objects
+ if ( pNew->GetDrawObjs() )
+ {
+ SwSortedObjs &rObjs = *pNew->GetDrawObjs();
+ for (SwAnchoredObject* pTmpObj : rObjs)
+ {
+ if ( dynamic_cast<const SwFlyFrame*>( pTmpObj) != nullptr )
+ {
+ SwFlyFrame* pTmpFly = static_cast<SwFlyFrame*>(pTmpObj);
+ // #i28701# - use new method <GetPageFrame()>
+ if ( pTmpFly->IsFlyFreeFrame() && !pTmpFly->GetPageFrame() )
+ AppendFlyToPage( pTmpFly );
+ }
+ else if ( dynamic_cast<const SwAnchoredDrawObject*>( pTmpObj) != nullptr )
+ {
+ // #i87493#
+ if ( pTmpObj->GetPageFrame() != this )
+ {
+ if ( pTmpObj->GetPageFrame() != nullptr )
+ {
+ pTmpObj->GetPageFrame()->RemoveDrawObjFromPage( *pTmpObj );
+ }
+ AppendDrawObjToPage( *pTmpObj );
+ }
+ }
+ }
+ }
+}
+
+void SwPageFrame::RemoveFlyFromPage( SwFlyFrame *pToRemove )
+{
+ const sal_uInt32 nOrdNum = pToRemove->GetVirtDrawObj()->GetOrdNum();
+ getRootFrame()->GetDrawPage()->RemoveObject( nOrdNum );
+ pToRemove->GetVirtDrawObj()->ReferencedObj().SetOrdNum( nOrdNum );
+
+ if ( GetUpper() )
+ {
+ if ( !pToRemove->IsFlyInContentFrame() )
+ static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous();
+ static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
+ }
+
+ // Don't look further at Flys that sit inside the Content.
+ if ( pToRemove->IsFlyInContentFrame() )
+ return;
+
+ // Don't delete collections just yet. This will happen at the end of the
+ // action in the RemoveSuperfluous of the page, kicked off by a method of
+ // the same name in the root.
+ // The FlyColl might be gone already, because the page's dtor is being
+ // executed.
+ // Remove it _before_ disposing accessible frames to avoid accesses to
+ // the Frame from event handlers.
+ if (m_pSortedObjs)
+ {
+ m_pSortedObjs->Remove(*pToRemove);
+ if (!m_pSortedObjs->size())
+ {
+ m_pSortedObjs.reset();
+ }
+ }
+
+ // Notify accessible layout. That's required at this place for
+ // frames only where the anchor is moved. Creation of new frames
+ // is additionally handled by the SwFrameNotify class.
+ if( GetUpper() &&
+ static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
+ static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
+ {
+ static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
+ ->DisposeAccessibleFrame( pToRemove, true );
+ }
+
+ // #i28701# - use new method <SetPageFrame(..)>
+ pToRemove->SetPageFrame( nullptr );
+}
+
+void SwPageFrame::MoveFly( SwFlyFrame *pToMove, SwPageFrame *pDest )
+{
+ // Invalidations
+ if ( GetUpper() )
+ {
+ static_cast<SwRootFrame*>(GetUpper())->SetIdleFlags();
+ if ( !pToMove->IsFlyInContentFrame() && pDest->GetPhyPageNum() < GetPhyPageNum() )
+ static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous();
+ }
+
+ pDest->InvalidateSpelling();
+ pDest->InvalidateSmartTags();
+ pDest->InvalidateAutoCompleteWords();
+ pDest->InvalidateWordCount();
+
+ if ( pToMove->IsFlyInContentFrame() )
+ {
+ pDest->InvalidateFlyInCnt();
+ return;
+ }
+
+ // Notify accessible layout. That's required at this place for
+ // frames only where the anchor is moved. Creation of new frames
+ // is additionally handled by the SwFrameNotify class.
+ if( GetUpper() &&
+ static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
+ static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
+ {
+ static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
+ ->DisposeAccessibleFrame( pToMove, true );
+ }
+
+ // The FlyColl might be gone already, because the page's dtor is being executed.
+ if ( m_pSortedObjs )
+ {
+ m_pSortedObjs->Remove( *pToMove );
+ if ( !m_pSortedObjs->size() )
+ {
+ m_pSortedObjs.reset();
+ }
+ }
+
+ // Register
+ if ( !pDest->GetSortedObjs() )
+ pDest->m_pSortedObjs.reset(new SwSortedObjs());
+
+ const bool bSuccessInserted = pDest->GetSortedObjs()->Insert( *pToMove );
+ OSL_ENSURE( bSuccessInserted, "Fly not inserted in Sorted." );
+
+ // #i28701# - use new method <SetPageFrame(..)>
+ pToMove->SetPageFrame( pDest );
+ pToMove->InvalidatePage( pDest );
+ pToMove->SetNotifyBack();
+ pDest->InvalidateFlyContent();
+ // #i28701#
+ pToMove->UnlockPosition();
+
+ // Notify accessible layout. That's required at this place for
+ // frames only where the anchor is moved. Creation of new frames
+ // is additionally handled by the SwFrameNotify class.
+ if( GetUpper() &&
+ static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
+ static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
+ {
+ static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
+ ->AddAccessibleFrame( pToMove );
+ }
+
+ // #i28701# - correction: move lowers of Writer fly frame
+ if ( pToMove->GetDrawObjs() )
+ {
+ SwSortedObjs &rObjs = *pToMove->GetDrawObjs();
+ for (SwAnchoredObject* pObj : rObjs)
+ {
+ if ( dynamic_cast<const SwFlyFrame*>( pObj) != nullptr )
+ {
+ SwFlyFrame* pFly = static_cast<SwFlyFrame*>(pObj);
+ if ( pFly->IsFlyFreeFrame() )
+ {
+ // #i28701# - use new method <GetPageFrame()>
+ SwPageFrame* pPageFrame = pFly->GetPageFrame();
+ if ( pPageFrame )
+ pPageFrame->MoveFly( pFly, pDest );
+ else
+ pDest->AppendFlyToPage( pFly );
+ }
+ }
+ else if ( dynamic_cast<const SwAnchoredDrawObject*>( pObj) != nullptr )
+ {
+ RemoveDrawObjFromPage( *pObj );
+ pDest->AppendDrawObjToPage( *pObj );
+ }
+ }
+ }
+}
+
+void SwPageFrame::AppendDrawObjToPage( SwAnchoredObject& _rNewObj )
+{
+ if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rNewObj) == nullptr )
+ {
+ OSL_FAIL( "SwPageFrame::AppendDrawObjToPage(..) - anchored object of unexpected type -> object not appended" );
+ return;
+ }
+
+ if ( GetUpper() )
+ {
+ static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
+ }
+
+ assert(_rNewObj.GetAnchorFrame());
+ SwFlyFrame* pFlyFrame = const_cast<SwFlyFrame*>(_rNewObj.GetAnchorFrame()->FindFlyFrame());
+ if ( pFlyFrame &&
+ _rNewObj.GetDrawObj()->GetOrdNum() < pFlyFrame->GetVirtDrawObj()->GetOrdNum() )
+ {
+ //#i119945# set pFly's OrdNum to _rNewObj's. So when pFly is removed by Undo, the original OrdNum will not be changed.
+ sal_uInt32 nNewNum = _rNewObj.GetDrawObj()->GetOrdNumDirect();
+ if ( _rNewObj.GetDrawObj()->getSdrPageFromSdrObject() )
+ _rNewObj.DrawObj()->getSdrPageFromSdrObject()->SetObjectOrdNum( pFlyFrame->GetVirtDrawObj()->GetOrdNumDirect(), nNewNum );
+ else
+ pFlyFrame->GetVirtDrawObj()->SetOrdNum( nNewNum );
+ }
+
+ if ( RndStdIds::FLY_AS_CHAR == _rNewObj.GetFrameFormat().GetAnchor().GetAnchorId() )
+ {
+ return;
+ }
+
+ if ( !m_pSortedObjs )
+ {
+ m_pSortedObjs.reset(new SwSortedObjs());
+ }
+ if ( !m_pSortedObjs->Insert( _rNewObj ) )
+ {
+ OSL_ENSURE( m_pSortedObjs->Contains( _rNewObj ),
+ "Drawing object not appended into list <pSortedObjs>." );
+ }
+ // #i87493#
+ OSL_ENSURE( _rNewObj.GetPageFrame() == nullptr || _rNewObj.GetPageFrame() == this,
+ "<SwPageFrame::AppendDrawObjToPage(..)> - anchored draw object seems to be registered at another page frame. Serious defect." );
+ _rNewObj.SetPageFrame( this );
+
+ // invalidate page in order to force a reformat of object layout of the page.
+ InvalidateFlyLayout();
+}
+
+void SwPageFrame::RemoveDrawObjFromPage( SwAnchoredObject& _rToRemoveObj )
+{
+ if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rToRemoveObj) == nullptr )
+ {
+ OSL_FAIL( "SwPageFrame::RemoveDrawObjFromPage(..) - anchored object of unexpected type -> object not removed" );
+ return;
+ }
+
+ if ( m_pSortedObjs )
+ {
+ m_pSortedObjs->Remove( _rToRemoveObj );
+ if ( !m_pSortedObjs->size() )
+ {
+ m_pSortedObjs.reset();
+ }
+ if ( GetUpper() )
+ {
+ if (RndStdIds::FLY_AS_CHAR !=
+ _rToRemoveObj.GetFrameFormat().GetAnchor().GetAnchorId())
+ {
+ static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous();
+ InvalidatePage();
+ }
+ static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
+ }
+ }
+ _rToRemoveObj.SetPageFrame( nullptr );
+}
+
+// #i50432# - adjust method description and synopsis.
+void SwPageFrame::PlaceFly( SwFlyFrame* pFly, SwFlyFrameFormat* pFormat )
+{
+ // #i50432# - consider the case that page is an empty page:
+ // In this case append the fly frame at the next page
+ OSL_ENSURE( !IsEmptyPage() || GetNext(),
+ "<SwPageFrame::PlaceFly(..)> - empty page with no next page! -> fly frame appended at empty page" );
+ if ( IsEmptyPage() && GetNext() )
+ {
+ static_cast<SwPageFrame*>(GetNext())->PlaceFly( pFly, pFormat );
+ }
+ else
+ {
+ // If we received a Fly, we use that one. Otherwise, create a new
+ // one using the Format.
+ if ( pFly )
+ AppendFly( pFly );
+ else
+ {
+ OSL_ENSURE( pFormat, ":-( No Format given for Fly." );
+ pFly = new SwFlyLayFrame( pFormat, this, this );
+ AppendFly( pFly );
+ ::RegistFlys( this, pFly );
+ }
+ }
+}
+
+// #i18732# - adjustments for following text flow or not
+// AND alignment at 'page areas' for to paragraph/to character anchored objects
+// #i22305# - adjustment for following text flow for to frame anchored objects
+// #i29778# - Because calculating the floating screen object's position
+// (Writer fly frame or drawing object) doesn't perform a calculation on its
+// upper frames and its anchor frame, a calculation of the upper frames in this
+// method is no longer sensible.
+// #i28701# - if document compatibility option 'Consider wrapping style influence
+// on object positioning' is ON, the clip area corresponds to the one as the
+// object doesn't follow the text flow.
+bool CalcClipRect( const SdrObject *pSdrObj, SwRect &rRect, bool bMove )
+{
+ bool bRet = true;
+ if ( auto pVirtFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) )
+ {
+ const SwFlyFrame* pFly = pVirtFlyDrawObj->GetFlyFrame();
+ const bool bFollowTextFlow = pFly->GetFormat()->GetFollowTextFlow().GetValue();
+ // #i28701#
+ const bool bConsiderWrapOnObjPos =
+ pFly->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION);
+ const SwFormatVertOrient &rV = pFly->GetFormat()->GetVertOrient();
+ if( pFly->IsFlyLayFrame() )
+ {
+ const SwFrame* pClip;
+ // #i22305#
+ // #i28701#
+ if ( !bFollowTextFlow || bConsiderWrapOnObjPos )
+ {
+ pClip = pFly->GetAnchorFrame()->FindPageFrame();
+ }
+ else
+ {
+ pClip = pFly->GetAnchorFrame();
+ }
+
+ rRect = pClip->getFrameArea();
+ SwRectFnSet aRectFnSet(pClip);
+
+ // vertical clipping: Top and Bottom, also to PrtArea if necessary
+ if( rV.GetVertOrient() != text::VertOrientation::NONE &&
+ rV.GetRelationOrient() == text::RelOrientation::PRINT_AREA )
+ {
+ aRectFnSet.SetTop( rRect, aRectFnSet.GetPrtTop(*pClip) );
+ aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pClip) );
+ }
+ // horizontal clipping: Top and Bottom, also to PrtArea if necessary
+ const SwFormatHoriOrient &rH = pFly->GetFormat()->GetHoriOrient();
+ if( rH.GetHoriOrient() != text::HoriOrientation::NONE &&
+ rH.GetRelationOrient() == text::RelOrientation::PRINT_AREA )
+ {
+ aRectFnSet.SetLeft( rRect, aRectFnSet.GetPrtLeft(*pClip) );
+ aRectFnSet.SetRight(rRect, aRectFnSet.GetPrtRight(*pClip));
+ }
+ }
+ else if( pFly->IsFlyAtContentFrame() )
+ {
+ // #i18732# - consider following text flow or not
+ // AND alignment at 'page areas'
+ const SwFrame* pVertPosOrientFrame = pFly->GetVertPosOrientFrame();
+ if ( !pVertPosOrientFrame )
+ {
+ OSL_FAIL( "::CalcClipRect(..) - frame, vertical position is oriented at, is missing .");
+ pVertPosOrientFrame = pFly->GetAnchorFrame();
+ }
+
+ if ( !bFollowTextFlow || bConsiderWrapOnObjPos )
+ {
+ const SwLayoutFrame* pClipFrame = pVertPosOrientFrame->FindPageFrame();
+ if (!pClipFrame)
+ {
+ OSL_FAIL("!pClipFrame: "
+ "if you can reproduce this please file a bug");
+ return false;
+ }
+ rRect = bMove ? pClipFrame->GetUpper()->getFrameArea()
+ : pClipFrame->getFrameArea();
+ // #i26945# - consider that a table, during
+ // its format, can exceed its upper printing area bottom.
+ // Thus, enlarge the clip rectangle, if such a case occurred
+ if ( pFly->GetAnchorFrame()->IsInTab() )
+ {
+ const SwTabFrame* pTabFrame = const_cast<SwFlyFrame*>(pFly)
+ ->GetAnchorFrameContainingAnchPos()->FindTabFrame();
+ SwRect aTmp( pTabFrame->getFramePrintArea() );
+ aTmp += pTabFrame->getFrameArea().Pos();
+ rRect.Union( aTmp );
+ // #i43913# - consider also the cell frame
+ const SwFrame* pCellFrame = const_cast<SwFlyFrame*>(pFly)
+ ->GetAnchorFrameContainingAnchPos()->GetUpper();
+ while ( pCellFrame && !pCellFrame->IsCellFrame() )
+ {
+ pCellFrame = pCellFrame->GetUpper();
+ }
+ if ( pCellFrame )
+ {
+ aTmp = pCellFrame->getFramePrintArea();
+ aTmp += pCellFrame->getFrameArea().Pos();
+ rRect.Union( aTmp );
+ }
+ }
+ }
+ else if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_FRAME ||
+ rV.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA )
+ {
+ // new class <SwEnvironmentOfAnchoredObject>
+ objectpositioning::SwEnvironmentOfAnchoredObject
+ aEnvOfObj( bFollowTextFlow );
+ const SwLayoutFrame& rVertClipFrame =
+ aEnvOfObj.GetVertEnvironmentLayoutFrame( *pVertPosOrientFrame );
+ if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_FRAME )
+ {
+ rRect = rVertClipFrame.getFrameArea();
+ }
+ else if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA )
+ {
+ if ( rVertClipFrame.IsPageFrame() )
+ {
+ rRect = static_cast<const SwPageFrame&>(rVertClipFrame).PrtWithoutHeaderAndFooter();
+ }
+ else
+ {
+ rRect = rVertClipFrame.getFrameArea();
+ }
+ }
+ const SwLayoutFrame* pHoriClipFrame =
+ pFly->GetAnchorFrame()->FindPageFrame()->GetUpper();
+ SwRectFnSet aRectFnSet(pFly->GetAnchorFrame());
+ aRectFnSet.SetLeft( rRect, aRectFnSet.GetLeft(pHoriClipFrame->getFrameArea()) );
+ aRectFnSet.SetRight(rRect, aRectFnSet.GetRight(pHoriClipFrame->getFrameArea()));
+ }
+ else
+ {
+ // #i26945#
+ const SwFrame *pClip =
+ const_cast<SwFlyFrame*>(pFly)->GetAnchorFrameContainingAnchPos();
+ SwRectFnSet aRectFnSet(pClip);
+ const SwLayoutFrame *pUp = pClip->GetUpper();
+ const SwFrame *pCell = pUp->IsCellFrame() ? pUp : nullptr;
+ const SwFrameType nType = bMove
+ ? SwFrameType::Root | SwFrameType::Fly | SwFrameType::Header |
+ SwFrameType::Footer | SwFrameType::Ftn
+ : SwFrameType::Body | SwFrameType::Fly | SwFrameType::Header |
+ SwFrameType::Footer | SwFrameType::Cell| SwFrameType::Ftn;
+
+ while ( !(pUp->GetType() & nType) || pUp->IsColBodyFrame() )
+ {
+ pUp = pUp->GetUpper();
+ if ( !pCell && pUp->IsCellFrame() )
+ pCell = pUp;
+ }
+ if ( bMove && pUp->IsRootFrame() )
+ {
+ rRect = pUp->getFramePrintArea();
+ rRect += pUp->getFrameArea().Pos();
+ pUp = nullptr;
+ }
+ if ( pUp )
+ {
+ if ( pUp->GetType() & SwFrameType::Body )
+ {
+ const SwPageFrame *pPg;
+ if ( pUp->GetUpper() != (pPg = pFly->FindPageFrame()) )
+ pUp = pPg->FindBodyCont();
+ if (pUp)
+ {
+ rRect = pUp->GetUpper()->getFrameArea();
+ aRectFnSet.SetTop( rRect, aRectFnSet.GetPrtTop(*pUp) );
+ aRectFnSet.SetBottom(rRect, aRectFnSet.GetPrtBottom(*pUp));
+ }
+ }
+ else
+ {
+ if( ( pUp->GetType() & (SwFrameType::Fly | SwFrameType::Ftn ) ) &&
+ !pUp->getFrameArea().IsInside( pFly->getFrameArea().Pos() ) )
+ {
+ if( pUp->IsFlyFrame() )
+ {
+ const SwFlyFrame *pTmpFly = static_cast<const SwFlyFrame*>(pUp);
+ while( pTmpFly->GetNextLink() )
+ {
+ pTmpFly = pTmpFly->GetNextLink();
+ if( pTmpFly->getFrameArea().IsInside( pFly->getFrameArea().Pos() ) )
+ break;
+ }
+ pUp = pTmpFly;
+ }
+ else if( pUp->IsInFootnote() )
+ {
+ const SwFootnoteFrame *pTmp = pUp->FindFootnoteFrame();
+ while( pTmp->GetFollow() )
+ {
+ pTmp = pTmp->GetFollow();
+ if( pTmp->getFrameArea().IsInside( pFly->getFrameArea().Pos() ) )
+ break;
+ }
+ pUp = pTmp;
+ }
+ }
+ rRect = pUp->getFramePrintArea();
+ rRect.Pos() += pUp->getFrameArea().Pos();
+ if ( pUp->GetType() & (SwFrameType::Header | SwFrameType::Footer) )
+ {
+ rRect.Left ( pUp->GetUpper()->getFrameArea().Left() );
+ rRect.Width( pUp->GetUpper()->getFrameArea().Width());
+ }
+ else if ( pUp->IsCellFrame() ) //MA_FLY_HEIGHT
+ {
+ const SwFrame *pTab = pUp->FindTabFrame();
+ aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pTab->GetUpper()) );
+ // expand to left and right cell border
+ rRect.Left ( pUp->getFrameArea().Left() );
+ rRect.Width( pUp->getFrameArea().Width() );
+ }
+ }
+ }
+ if ( pCell )
+ {
+ // CellFrames might also sit in unallowed areas. In this case,
+ // the Fly is allowed to do so as well
+ SwRect aTmp( pCell->getFramePrintArea() );
+ aTmp += pCell->getFrameArea().Pos();
+ rRect.Union( aTmp );
+ }
+ }
+ }
+ else
+ {
+ const SwFrame *pUp = pFly->GetAnchorFrame()->GetUpper();
+ SwRectFnSet aRectFnSet(pFly->GetAnchorFrame());
+ while( pUp->IsColumnFrame() || pUp->IsSctFrame() || pUp->IsColBodyFrame())
+ pUp = pUp->GetUpper();
+ rRect = pUp->getFrameArea();
+ if( !pUp->IsBodyFrame() )
+ {
+ rRect += pUp->getFramePrintArea().Pos();
+ rRect.SSize( pUp->getFramePrintArea().SSize() );
+ if ( pUp->IsCellFrame() )
+ {
+ const SwFrame *pTab = pUp->FindTabFrame();
+ aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pTab->GetUpper()) );
+ }
+ }
+ else if ( pUp->GetUpper()->IsPageFrame() )
+ {
+ // Objects anchored as character may exceed right margin
+ // of body frame:
+ aRectFnSet.SetRight( rRect, aRectFnSet.GetRight(pUp->GetUpper()->getFrameArea()) );
+ }
+ long nHeight = (9*aRectFnSet.GetHeight(rRect))/10;
+ long nTop;
+ const SwFormat *pFormat = GetUserCall(pSdrObj)->GetFormat();
+ const SvxULSpaceItem &rUL = pFormat->GetULSpace();
+ if( bMove )
+ {
+ nTop = aRectFnSet.IsVert() ? static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().X() :
+ static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().Y();
+ nTop = aRectFnSet.YInc( nTop, -nHeight );
+ long nWidth = aRectFnSet.GetWidth(pFly->getFrameArea());
+ aRectFnSet.SetLeftAndWidth( rRect, aRectFnSet.IsVert() ?
+ static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().Y() :
+ static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().X(), nWidth );
+ nHeight = 2*nHeight - rUL.GetLower() - rUL.GetUpper();
+ }
+ else
+ {
+ nTop = aRectFnSet.YInc( aRectFnSet.GetBottom(pFly->getFrameArea()),
+ rUL.GetLower() - nHeight );
+ nHeight = 2*nHeight - aRectFnSet.GetHeight(pFly->getFrameArea())
+ - rUL.GetLower() - rUL.GetUpper();
+ }
+ aRectFnSet.SetTopAndHeight( rRect, nTop, nHeight );
+ }
+ }
+ else
+ {
+ const SwDrawContact *pC = static_cast<const SwDrawContact*>(GetUserCall(pSdrObj));
+ const SwFrameFormat *pFormat = pC->GetFormat();
+ const SwFormatAnchor &rAnch = pFormat->GetAnchor();
+ if ( RndStdIds::FLY_AS_CHAR == rAnch.GetAnchorId() )
+ {
+ const SwFrame* pAnchorFrame = pC->GetAnchorFrame( pSdrObj );
+ if( !pAnchorFrame )
+ {
+ OSL_FAIL( "<::CalcClipRect(..)> - missing anchor frame." );
+ const_cast<SwDrawContact*>(pC)->ConnectToLayout();
+ pAnchorFrame = pC->GetAnchorFrame();
+ }
+ const SwFrame* pUp = pAnchorFrame->GetUpper();
+ rRect = pUp->getFramePrintArea();
+ rRect += pUp->getFrameArea().Pos();
+ SwRectFnSet aRectFnSet(pAnchorFrame);
+ long nHeight = (9*aRectFnSet.GetHeight(rRect))/10;
+ long nTop;
+ const SvxULSpaceItem &rUL = pFormat->GetULSpace();
+ SwRect aSnapRect( pSdrObj->GetSnapRect() );
+ long nTmpH = 0;
+ if( bMove )
+ {
+ nTop = aRectFnSet.YInc( aRectFnSet.IsVert() ? pSdrObj->GetAnchorPos().X() :
+ pSdrObj->GetAnchorPos().Y(), -nHeight );
+ long nWidth = aRectFnSet.GetWidth(aSnapRect);
+ aRectFnSet.SetLeftAndWidth( rRect, aRectFnSet.IsVert() ?
+ pSdrObj->GetAnchorPos().Y() :
+ pSdrObj->GetAnchorPos().X(), nWidth );
+ }
+ else
+ {
+ // #i26791# - value of <nTmpH> is needed to
+ // calculate value of <nTop>.
+ nTmpH = aRectFnSet.IsVert() ? pSdrObj->GetCurrentBoundRect().GetWidth() :
+ pSdrObj->GetCurrentBoundRect().GetHeight();
+ nTop = aRectFnSet.YInc( aRectFnSet.GetTop(aSnapRect),
+ rUL.GetLower() + nTmpH - nHeight );
+ }
+ nHeight = 2*nHeight - nTmpH - rUL.GetLower() - rUL.GetUpper();
+ aRectFnSet.SetTopAndHeight( rRect, nTop, nHeight );
+ }
+ else
+ {
+ // restrict clip rectangle for drawing
+ // objects in header/footer to the page frame.
+ // #i26791#
+ const SwFrame* pAnchorFrame = pC->GetAnchorFrame( pSdrObj );
+ if ( pAnchorFrame && pAnchorFrame->FindFooterOrHeader() )
+ {
+ // clip frame is the page frame the header/footer is on.
+ const SwFrame* pClipFrame = pAnchorFrame->FindPageFrame();
+ rRect = pClipFrame->getFrameArea();
+ }
+ else
+ {
+ bRet = false;
+ }
+ }
+ }
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */