/* -*- 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 <config_wasm_strip.h>
 
#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 <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>
#include <osl/diagnose.h>
 
using namespace ::com::sun::star;
 
SwFlyFreeFrame::SwFlyFreeFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch, bool bFollow )
:   SwFlyFrame( pFormat, pSib, pAnch, bFollow ),
    // #i34753#
    mbNoMakePos( false ),
    // #i37068#
    mbNoMoveOnCheckClip( false )
{
}
 
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 (!IsForceNotifyNewBackground() && 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 SvxBoxItem* pBoxItem(nullptr);
 
    if(GetFormat() && (pBoxItem = GetFormat()->GetItemIfSet(RES_BOX, false)))
    {
        if(pBoxItem->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->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 tools::Long nBot = getFrameArea().Top() + getFrameArea().Height();
    const tools::Long nRig = getFrameArea().Left() + getFrameArea().Width();
    const tools::Long nClipBot = aClip.Top() + aClip.Height();
    const tools::Long nClipRig = aClip.Left() + aClip.Width();
 
    const bool bBot = nBot > nClipBot;
    const bool bRig = nRig > nClipRig;
    if (( bBot || bRig ) && !IsDraggingOffPageAllowed(FindFrameFormat(GetDrawObj())))
    {
        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 tools::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 tools::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 )
            {
                tools::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 )
            {
                tools::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 tools::Long nPrtHeightDiff = getFrameArea().Height() - getFramePrintArea().Height();
            const tools::Long nPrtWidthDiff  = getFrameArea().Width()  - getFramePrintArea().Width();
            maUnclippedFrame = getFrameArea();
 
            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                aFrm.Height( aFrameRect.Height() );
                aFrm.Width ( std::max( tools::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;
}
 
void SwFlyLayFrame::RegisterAtPage(SwPageFrame & rPageFrame)
{
    assert(GetPageFrame() != &rPageFrame);
    if (GetPageFrame())
    {
        GetPageFrame()->MoveFly( this, &rPageFrame );
    }
    else
    {
        rPageFrame.AppendFlyToPage( this );
    }
}
 
// #i28701#
 
void SwFlyLayFrame::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
{
    if (rHint.GetId() == SfxHintId::SwAutoFormatUsedHint)
    {
        // There's a FlyFrame, so use it
        static_cast<const sw::AutoFormatUsedHint&>(rHint).SetUsed();
        return;
    }
    if (rHint.GetId() != SfxHintId::SwLegacyModify)
        return;
    auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
    if(!pLegacy->m_pNew)
        return;
    const auto pAnch = GetAnchorFromPoolItem(*pLegacy->m_pNew);
 
    if(!pAnch)
    {
        SwFlyFrame::SwClientNotify(rMod, rHint);
        return;
    }
    SAL_WARN_IF(pAnch->GetAnchorId() == GetFormat()->GetAnchor().GetAnchorId(), "sw.core", "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())
    {
        SwRootFrame* pRoot = getRootFrame();
        SwPageFrame* pTmpPage = static_cast<SwPageFrame*>(pRoot->Lower());
        sal_uInt16 nPagesToFlip = pAnch->GetPageNum()-1;
        while(pTmpPage && nPagesToFlip)
        {
            pTmpPage = static_cast<SwPageFrame*>(pTmpPage->GetNext());
            --nPagesToFlip;
        }
        if(pTmpPage && !nPagesToFlip)
        {
            // #i50432# - adjust synopsis of <PlaceFly(..)>
            pTmpPage->PlaceFly(this, nullptr);
        }
        if(!pTmpPage)
        {
            pRoot->SetAssertFlyPages();
            pRoot->AssertFlyPages();
        }
    }
    else
    {
        SwNodeIndex aIdx(*pAnch->GetAnchorNode());
        SwContentFrame* pContent = SwNodes::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();
}
 
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();
        SdrObject* pDrawObj = nullptr;
        if (auto pFormat = pFly->GetFormat())
            if (auto pShapeFormat = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_FLYFRMFMT))
                pDrawObj = pShapeFormat->FindRealSdrObject();
 
        if (pDrawObj)
        {
            if (auto pPage = pDrawObj->getSdrPageFromSdrObject())
                pPage->SetObjectOrdNum(pDrawObj->GetOrdNumDirect(), nNewNum);
            else
                pDrawObj->SetOrdNum(nNewNum);
        }
 
        if ( pObj->getSdrPageFromSdrObject() )
            pObj->getSdrPageFromSdrObject()->SetObjectOrdNum( pFly->GetVirtDrawObj()->GetOrdNumDirect(), nNewNum + (pDrawObj ? 1 : 0) );
        else
            pFly->GetVirtDrawObj()->SetOrdNum( nNewNum + (pDrawObj ? 1 : 0));
    }
 
    // 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 !ENABLE_WASM_STRIP_ACCESSIBILITY
        if( GetUpper() &&
            static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
             static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
        {
            static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
                                      ->AddAccessibleFrame( pNew );
        }
#endif
    }
 
    // #i28701# - correction: consider also drawing objects
    if ( !pNew->GetDrawObjs() )
        return;
 
    SwSortedObjs &rObjs = *pNew->GetDrawObjs();
    for (SwAnchoredObject* pTmpObj : rObjs)
    {
        if ( auto pTmpFly = pTmpObj->DynCastFlyFrame() )
        {
            // #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 )
            {
                pTmpObj->RegisterAtPage(*this);
            }
        }
    }
}
 
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 !ENABLE_WASM_STRIP_ACCESSIBILITY
    if( GetUpper() &&
        static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
        static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
    {
        static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
                                  ->DisposeAccessibleFrame( pToRemove, true );
    }
#endif
 
    // #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 !ENABLE_WASM_STRIP_ACCESSIBILITY
    if( GetUpper() &&
        static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
        static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
    {
        static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
                                  ->DisposeAccessibleFrame( pToMove, true );
    }
#endif
 
    // 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();
        }
 
        // Removing a fly from the page affects the margin of tables, so update the frame print area
        // of the lowers of my body frame.
        SwFrame* pBodyFrame = FindBodyCont();
        if (pBodyFrame)
        {
            for (SwFrame* pFrame = pBodyFrame->GetLower(); pFrame; pFrame = pFrame->GetNext())
            {
                if (!pFrame->IsTabFrame())
                {
                    // This is meant to match SwTabFrame::CalcFlyOffsets(), so not relevant for
                    // other frame types.
                    continue;
                }
 
                pFrame->InvalidatePrt();
            }
        }
    }
 
    // 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();
 
    if (pToMove->IsFlySplitAllowed())
    {
        // Inserting a fly to the page affects the fly portions of the intersecting paragraphs, so
        // update the portions of the anchor of the fly frame.
        SwTextFrame* pAnchor = pToMove->FindAnchorCharFrame();
        if (pAnchor)
        {
            pAnchor->ClearPara();
        }
    }
 
    // 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 !ENABLE_WASM_STRIP_ACCESSIBILITY
    if( GetUpper() &&
        static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
        static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
    {
        static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
                                  ->AddAccessibleFrame( pToMove );
    }
#endif
 
    // #i28701# - correction: move lowers of Writer fly frame
    if ( !pToMove->GetDrawObjs() )
        return;
 
    SwSortedObjs &rObjs = *pToMove->GetDrawObjs();
    for (SwAnchoredObject* pObj : rObjs)
    {
        pObj->RegisterAtPage(*pDest);
    }
}
 
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() )
        {
            const SwFrameFormat* pObjFormat = _rToRemoveObj.GetFrameFormat();
            if (pObjFormat
                && RndStdIds::FLY_AS_CHAR != pObjFormat->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().Contains( pFly->getFrameArea().Pos() ) )
                        {
                            if( pUp->IsFlyFrame() )
                            {
                                const SwFlyFrame *pTmpFly = static_cast<const SwFlyFrame*>(pUp);
                                while( pTmpFly->GetNextLink() )
                                {
                                    pTmpFly = pTmpFly->GetNextLink();
                                    if( pTmpFly->getFrameArea().Contains( pFly->getFrameArea().Pos() ) )
                                        break;
                                }
                                pUp = pTmpFly;
                            }
                            else if( pUp->IsInFootnote() )
                            {
                                const SwFootnoteFrame *pTmp = pUp->FindFootnoteFrame();
                                while( pTmp->GetFollow() )
                                {
                                    pTmp = pTmp->GetFollow();
                                    if( pTmp->getFrameArea().Contains( 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());
            bool bOnlyCellFrame = pUp->IsCellFrame();
            while( pUp->IsColumnFrame() || pUp->IsSctFrame() || pUp->IsColBodyFrame())
                pUp = pUp->GetUpper();
            rRect = pUp->getFrameArea();
            if( !pUp->IsBodyFrame() )
            {
                bool bCropByFixedHeightCell = false;
                // allow zoom image cropped by fixed height table cell
                if ( bOnlyCellFrame && pUp->IsCellFrame() && pUp->GetUpper() &&
                     // is a fixed height table row?
                     pUp->GetUpper()->IsRowFrame() && SwFrameSize::Fixed ==
                         pUp->GetUpper()->GetAttrSet()->GetFrameSize().GetHeightSizeType() )
                {
                    // is image anchored as character?
                    if ( const SwContact* pC = GetUserCall(pSdrObj) )
                    {
                        const SwFrameFormat* pFormat = pC->GetFormat();
                        const SwFormatAnchor& rAnch = pFormat->GetAnchor();
                        if ( RndStdIds::FLY_AS_CHAR == rAnch.GetAnchorId() )
                        {
                            const SwPageFrame *pPageFrame = pFly->FindPageFrame();
                            Size aSize( pPageFrame->getFramePrintArea().SSize() );
                            // TODO doubled print area is still cropped by full page size, yet
                            rRect.SSize(Size(aSize.getWidth() * 2, aSize.getHeight() * 2));
                            bCropByFixedHeightCell = true;
                        }
                    }
                }
 
                if ( !bCropByFixedHeightCell )
                {
                    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()) );
            }
            tools::Long nHeight = (9*aRectFnSet.GetHeight(rRect))/10;
            tools::Long nTop;
            if (const SwContact* pContact = ::GetUserCall( pSdrObj ))
            {
                const SwFormat *pFormat = pContact->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 );
                    tools::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
    {
        if (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);
                tools::Long nHeight = (9 * aRectFnSet.GetHeight(rRect)) / 10;
                tools::Long nTop;
                const SvxULSpaceItem& rUL = pFormat->GetULSpace();
                SwRect aSnapRect(pSdrObj->GetSnapRect());
                tools::Long nTmpH = 0;
                if (bMove)
                {
                    nTop = aRectFnSet.YInc(aRectFnSet.IsVert() ? pSdrObj->GetAnchorPos().X()
                                                               : pSdrObj->GetAnchorPos().Y(),
                                           -nHeight);
                    tools::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: */

V530 The return value of function 'Intersection_' is required to be utilized.

V530 The return value of function 'Union' is required to be utilized.

V530 The return value of function 'Union' is required to be utilized.

V530 The return value of function 'Union' is required to be utilized.