Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/sw/source/core/layout/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 130 kB image not shown  

Quelle  fly.cxx   Sprache: C

 
/* -*- 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 <svl/itemiter.hxx>
#include <vcl/imap.hxx>
#include <tools/helpers.hxx>
#include <editeng/protitem.hxx>
#include <editeng/opaqitem.hxx>
#include <editeng/ulspitem.hxx>
#include <editeng/frmdiritem.hxx>
#include <fmtfsize.hxx>
#include <fmtclds.hxx>
#include <fmtcntnt.hxx>
#include <fmturl.hxx>
#include <fmtsrnd.hxx>
#include <fmtornt.hxx>
#include <fmtcnct.hxx>
#include <ndgrf.hxx>
#include <tolayoutanchoredobjectposition.hxx>
#include <fmtfollowtextflow.hxx>
#include <sortedobjs.hxx>
#include <objectformatter.hxx>
#include <ndole.hxx>
#include <swtable.hxx>
#include <svx/svdoashp.hxx>
#include <svx/svdpage.hxx>
#include <layouter.hxx>
#include <layact.hxx>
#include <pagefrm.hxx>
#include <rootfrm.hxx>
#include <viewimp.hxx>
#include <viewopt.hxx>
#include <dcontact.hxx>
#include <dflyobj.hxx>
#include <dview.hxx>
#include <frmatr.hxx>
#include <frmtool.hxx>
#include <hints.hxx>
#include <tabfrm.hxx>
#include <txtfrm.hxx>
#include <notxtfrm.hxx>
#include <flyfrms.hxx>
#include <sectfrm.hxx>
#include <vcl/svapp.hxx>
#include <calbck.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <IDocumentSettingAccess.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <textboxhelper.hxx>
#include <txtfly.hxx>
#include <ndindex.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <osl/diagnose.h>
#include <o3tl/string_view.hxx>
#include <rtl/math.hxx>

#include <wrtsh.hxx>
#include <view.hxx>
#include <edtwin.hxx>
#include <bodyfrm.hxx>
#include <FrameControlsManager.hxx>
#include <ndtxt.hxx>
#include <formatflysplit.hxx>

using namespace ::com::sun::star;

namespace
{
/// Gets the bottom position which is a deadline for a split fly.
SwTwips GetFlyAnchorBottom(SwFlyFrame* pFly, const SwFrame& rAnchor)
{
    SwRectFnSet aRectFnSet(pFly);

    const SwPageFrame* pPage = rAnchor.FindPageFrame();
    if (!pPage)
    {
        return 0;
    }

    const SwFrame* pBody = pPage->FindBodyCont();
    if (!pBody)
    {
        return 0;
    }

    const auto* pFrameFormat = pFly->GetFrameFormat();
    const IDocumentSettingAccess& rIDSA = pFrameFormat->getIDocumentSettingAccess();
    // Allow overlap with bottom margin / footer only in case we're relative to the page frame.
    bool bVertPageFrame = pFrameFormat->GetVertOrient().GetRelationOrient() == text::RelOrientation::PAGE_FRAME;
    bool bInBody = rAnchor.IsInDocBody();
    bool bLegacy = rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN) && (bVertPageFrame || !bInBody);
    if (bLegacy)
    {
        // Word <= 2010 style: the fly can overlap with the bottom margin / footer area in case the
        // fly height fits the body height and the fly bottom fits the page.
        // See if the fly height would fit at least the page height, ignoring the vertical offset.
        SwTwips nFlyHeight = aRectFnSet.GetHeight(pFly->getFrameArea());
        SwTwips nPageHeight = aRectFnSet.GetHeight(pPage->getFramePrintArea());
        SwTwips nFlyTop = aRectFnSet.GetTop(pFly->getFrameArea());
        SwTwips nBodyTop = aRectFnSet.GetTop(pBody->getFrameArea());
        if (nFlyTop < nBodyTop)
        {
            // Fly frame overlaps with the top margin area, ignore that part of the fly frame for
            // top/height purposes.
            nFlyHeight -= nBodyTop - nFlyTop;
            nFlyTop = nBodyTop;
        }
        if (nFlyHeight <= nPageHeight)
        {
            // Yes, it would fit: allow overlap if there is no problematic vertical offset.
            SwTwips nDeadline = aRectFnSet.GetBottom(pPage->getFrameArea());
            SwTwips nBodyHeight = aRectFnSet.GetHeight(pBody->getFramePrintArea());
            if (nDeadline - nFlyTop > nBodyHeight)
            {
                // If the fly would now grow to nDeadline then it would not fit the body height, so
                // limit the height.
                nDeadline = nFlyTop + nBodyHeight;
            }
            return nDeadline;
        }
    }

    // Word >= 2013 style: the fly has to stay inside the body frame.
    return aRectFnSet.GetPrtBottom(*pBody);
}
}

static SwTwips lcl_CalcAutoWidth( const SwLayoutFrame& rFrame );

SwFlyFrame::SwFlyFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch, bool bFollow ) :
    SwLayoutFrame( pFormat, pSib ),
     // #i26791#
    m_pPrevLink( nullptr ),
    m_pNextLink( nullptr ),
    m_bInCnt( false ),
    m_bAtCnt( false ),
    m_bLayout( false ),
    m_bAutoPosition( false ),
    m_bDeleted( false ),
    m_nAuthor( std::string::npos ),
    m_bValidContentPos( false )
{
    mnFrameType = SwFrameType::Fly;

    m_bInvalid = m_bNotifyBack = true;
    m_bLocked  = m_bMinHeight =
    m_bHeightClipped = m_bWidthClipped = m_bFormatHeightOnly = false;

    // Size setting: Fixed size is always the width
    const SwFormatFrameSize &rFrameSize = pFormat->GetFrameSize();
    const SvxFrameDirection nDir = pFormat->GetFormatAttr( RES_FRAMEDIR ).GetValue();
    if( SvxFrameDirection::Environment == nDir )
    {
        mbDerivedVert = true;
        mbDerivedR2L = true;
    }
    else
    {
        mbInvalidVert = false;
        mbDerivedVert = false;
        mbDerivedR2L = false;
        if( SvxFrameDirection::Horizontal_LR_TB == nDir || SvxFrameDirection::Horizontal_RL_TB == nDir )
        {
            mbVertLR = false;
            mbVertical = false;
        }
        else
        {
            const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
            if( pSh && pSh->GetViewOptions()->getBrowseMode() )
            {
                mbVertLR = false;
                mbVertical = false;
            }
            else
            {
                mbVertical = true;

                if ( SvxFrameDirection::Vertical_LR_TB == nDir )
                    mbVertLR = true;
                else if (nDir == SvxFrameDirection::Vertical_LR_BT)
                {
                    mbVertLR = true;
                    mbVertLRBT = true;
                }
                else
                    mbVertLR = false;
            }
        }

        mbInvalidR2L = false;
        if( SvxFrameDirection::Horizontal_RL_TB == nDir )
            mbRightToLeft = true;
        else
            mbRightToLeft = false;
    }

    {
        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
        aFrm.Width( rFrameSize.GetWidth() );
        aFrm.Height( rFrameSize.GetHeightSizeType() == SwFrameSize::Variable ? MINFLY : rFrameSize.GetHeight() );
    }

    // Fixed or variable Height?
    if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Minimum )
        m_bMinHeight = true;
    else if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Fixed )
        mbFixSize = true;

    // insert columns, if necessary
    InsertColumns();

    // First the Init, then the Content:
    // This is due to the fact that the Content may have Objects/Frames,
    // which are then registered
    InitDrawObj(*pAnch);

    Chain( pAnch );

    if (!bFollow)
    {
        InsertCnt();
    }

    // Put it somewhere outside so that out document is not formatted unnecessarily often
    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
    aFrm.Pos().setX(FAR_AWAY);
    aFrm.Pos().setY(FAR_AWAY);
}

void SwFlyFrame::Chain( SwFrame* _pAnch )
{
    // Connect to chain neighbours.
    // No problem, if a neighbor doesn't exist - the construction of the
    // neighbor will make the connection
    const SwFormatChain& rChain = GetFormat()->GetChain();
    if ( !(rChain.GetPrev() || rChain.GetNext()) )
        return;

    if ( rChain.GetNext() )
    {
        SwFlyFrame* pFollow = FindChainNeighbour( *rChain.GetNext(), _pAnch );
        if ( pFollow )
        {
            OSL_ENSURE( !pFollow->GetPrevLink(), "wrong chain detected" );
            if ( !pFollow->GetPrevLink() )
                SwFlyFrame::ChainFrames( *this, *pFollow );
        }
    }
    if ( rChain.GetPrev() )
    {
        SwFlyFrame *pMaster = FindChainNeighbour( *rChain.GetPrev(), _pAnch );
        if ( pMaster )
        {
            OSL_ENSURE( !pMaster->GetNextLink(), "wrong chain detected" );
            if ( !pMaster->GetNextLink() )
                SwFlyFrame::ChainFrames( *pMaster, *this );
        }
    }
}

void SwFlyFrame::InsertCnt()
{
    if ( GetPrevLink() )
        return;

    const SwFormatContent& rContent = GetFormat()->GetContent();
    OSL_ENSURE( rContent.GetContentIdx(), ":-( no content prepared." );
    SwNodeOffset nIndex = rContent.GetContentIdx()->GetIndex();
    // Lower() means SwColumnFrame; the Content then needs to be inserted into the (Column)BodyFrame
    ::InsertCnt_( Lower() ? static_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame*>(Lower())->Lower()) : static_cast<SwLayoutFrame*>(this),
                  GetFormat()->GetDoc(), nIndex );

    // NoText always have a fixed height.
    SwFrame* pLower = Lower();
    if ( pLower && pLower->IsNoTextFrame() )
    {
        mbFixSize = true;
        m_bMinHeight = false;
    }
}

void SwFlyFrame::InsertColumns()
{
    // #i97379#
    // Check, if column are allowed.
    // Columns are not allowed for fly frames, which represent graphics or embedded objects.
    const SwFormatContent& rContent = GetFormat()->GetContent();
    OSL_ENSURE( rContent.GetContentIdx(), " - no content prepared." );
    SwNodeIndex aFirstContent( *(rContent.GetContentIdx()), 1 );
    if ( aFirstContent.GetNode().IsNoTextNode() )
    {
        return;
    }

    const SwFormatCol &rCol = GetFormat()->GetCol();
    if ( rCol.GetNumCols() <= 1 )
        return;

    // Start off PrtArea to be as large as Frame, so that we can put in the columns
    // properly. It'll adjust later on.
    {
        SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
        aPrt.Width( getFrameArea().Width() );
        aPrt.Height( getFrameArea().Height() );
    }

    const SwFormatCol aOld; // ChgColumns() also needs an old value passed
    ChgColumns( aOld, rCol );
}

void SwFlyFrame::DestroyImpl()
{
    // Accessible objects for fly frames will be destroyed in this destructor.
    // For frames bound as char or frames that don't have an anchor we have
    // to do that ourselves. For any other frame the call RemoveFly at the
    // anchor will do that.
#if !ENABLE_WASM_STRIP_ACCESSIBILITY
    if( IsAccessibleFrame() && GetFormat() && (IsFlyInContentFrame() || !GetAnchorFrame()) )
    {
        SwRootFrame *pRootFrame = getRootFrame();
        if( pRootFrame && pRootFrame->IsAnyShellAccessible() )
        {
            SwViewShell *pVSh = pRootFrame->GetCurrShell();
            if( pVSh && pVSh->Imp() )
            {
                // Lowers aren't disposed already, so we have to do a recursive
                // dispose
                pVSh->Imp()->DisposeAccessibleFrame( thistrue );
            }
        }
    }
#endif

    if( GetFormat() && !GetFormat()->GetDoc().IsInDtor() )
    {
        ClearTmpConsiderWrapInfluence(); // remove this from SwLayouter

        Unchain();

        DeleteCnt();

        if ( GetAnchorFrame() )
            AnchorFrame()->RemoveFly( this );
    }

    FinitDrawObj();

    SwLayoutFrame::DestroyImpl();

    SwWrtShell* pWrtSh = dynamic_cast<SwWrtShell*>(getRootFrame()->GetCurrShell());
    UpdateUnfloatButton(pWrtSh, false);
}

SwFlyFrame::~SwFlyFrame()
{
}

const IDocumentDrawModelAccess& SwFlyFrame::getIDocumentDrawModelAccess()
{
    return GetFormat()->getIDocumentDrawModelAccess();
}

void SwFlyFrame::Unchain()
{
    if ( GetPrevLink() )
        UnchainFrames( *GetPrevLink(), *this );
    if ( GetNextLink() )
        UnchainFrames( *this, *GetNextLink() );
}

void SwFlyFrame::DeleteCnt()
{
    SwFrame* pFrame = m_pLower;
    while ( pFrame )
    {
        while ( pFrame->GetDrawObjs() && pFrame->GetDrawObjs()->size() )
        {
            SwAnchoredObject *pAnchoredObj = (*pFrame->GetDrawObjs())[0];
            if ( auto pFlyFrame = pAnchoredObj->DynCastFlyFrame() )
            {
                SwFrame::DestroyFrame(pFlyFrame);
            }
            else if ( dynamic_cast<const SwAnchoredDrawObject*>( pAnchoredObj) !=  nullptr )
            {
                // consider 'virtual' drawing objects
                SdrObject* pObj = pAnchoredObj->DrawObj();
                if ( auto pDrawVirtObj = dynamic_cast<SwDrawVirtObj*>( pObj) )
                {
                    pDrawVirtObj->RemoveFromWriterLayout();
                    pDrawVirtObj->RemoveFromDrawingPage();
                }
                else
                {
                    SwDrawContact* pContact =
                            static_cast<SwDrawContact*>(::GetUserCall( pObj ));
                    if ( pContact )
                    {
                        pContact->DisconnectFromLayout();
                    }
                }
            }
        }

        pFrame->RemoveFromLayout();
        SwFrame::DestroyFrame(pFrame);
        pFrame = m_pLower;
    }

    InvalidatePage();
}

void SwFlyFrame::InitDrawObj(SwFrame& rAnchorFrame)
{
    SetDrawObj(*SwFlyDrawContact::CreateNewRef(this, GetFormat(), rAnchorFrame));

    // Set the right Layer
    const IDocumentSettingAccess& rIDSA = GetFormat()->getIDocumentSettingAccess();
    bool isPaintHellOverHF = rIDSA.get(DocumentSettingId::PAINT_HELL_OVER_HEADER_FOOTER);
    IDocumentDrawModelAccess& rIDDMA = GetFormat()->getIDocumentDrawModelAccess();
    SdrLayerID nHeavenId = rIDDMA.GetHeavenId();
    SdrLayerID nHellId = rIDDMA.GetHellId();
    bool isOpaque = GetFormat()->GetOpaque().GetValue();
    if (!isOpaque && isPaintHellOverHF)
    {
        if (!rAnchorFrame.FindFooterOrHeader())
            nHellId = rIDDMA.GetHeaderFooterHellId();
    }
    GetVirtDrawObj()->SetLayer( isOpaque ? nHeavenId :nHellId );
}

static SwPosition ResolveFlyAnchor(SwFrameFormat const& rFlyFrame)
{
    SwFormatAnchor const& rAnch(rFlyFrame.GetAnchor());
    if (rAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE)
    {   // arbitrarily pick last node
        return SwPosition(rFlyFrame.GetDoc().GetNodes().GetEndOfContent(), SwNodeOffset(-1));
    }
    else
    {
        SwPosition const*const pPos(rAnch.GetContentAnchor());
        assert(pPos);
        if (SwFrameFormat const*const pParent = pPos->GetNode().GetFlyFormat())
        {
            return ResolveFlyAnchor(*pParent);
        }
        else if (pPos->GetContentNode())
        {
            return *pPos;
        }
        else
        {
            return SwPosition(*pPos->GetNode().GetContentNode(), 0);
        }
    }
}

void SwFlyFrame::FinitDrawObj()
{
    if(!GetVirtDrawObj() )
        return;
    SwFormat* pFormat = GetFormat();
    // Deregister from SdrPageViews if the Objects is still selected there.
    if(!pFormat->GetDoc().IsInDtor())
    {
        SwViewShell* p1St = getRootFrame()->GetCurrShell();
        if(p1St)
        {
            for(SwViewShell& rCurrentShell : p1St->GetRingContainer())
            {   // At the moment the Drawing can do just do an Unmark on everything,
                // as the Object was already removed
                if (rCurrentShell.HasDrawView() &&
                    rCurrentShell.Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount())
                {
                    SwFlyFrame const*const pOldSelFly = ::GetFlyFromMarked(nullptr, &rCurrentShell);
                    if (pOldSelFly == this)
                    {
                        assert(rCurrentShell.Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() == 1);
                        if (SwFEShell *const pFEShell = dynamic_cast<SwFEShell*>(&rCurrentShell))
                        {   // tdf#131679 move any cursor out of fly
                            rCurrentShell.Imp()->GetDrawView()->UnmarkAll();
                            SwPaM const temp(ResolveFlyAnchor(*pOldSelFly->GetFormat()));
                            pFEShell->SetSelection(temp);
                            // could also call SetCursor() like SwFEShell::SelectObj()
                            // does, but that would access layout a bit much...
                        }
                        else
                        {
                            rCurrentShell.Imp()->GetDrawView()->UnmarkAll();
                        }
                    }
                }
            }
        }
    }

    SwVirtFlyDrawObj* pVirtDrawObj = GetVirtDrawObj();
    // Else calls delete of the ContactObj
    pVirtDrawObj->SetUserCall(nullptr);

    if ( pVirtDrawObj->getSdrPageFromSdrObject() )
        pVirtDrawObj->getSdrPageFromSdrObject()->RemoveObject( pVirtDrawObj->GetOrdNum() );
    ClearDrawObj();
}

void SwFlyFrame::ChainFrames( SwFlyFrame &rMaster, SwFlyFrame &rFollow )
{
    OSL_ENSURE( !rMaster.GetNextLink(), "link can not be changed" );
    OSL_ENSURE( !rFollow.GetPrevLink(), "link can not be changed" );

    rMaster.m_pNextLink = &rFollow;
    rFollow.m_pPrevLink = &rMaster;

    if ( rMaster.ContainsContent() )
    {
        // To get a text flow we need to invalidate
        SwFrame *pInva = rMaster.FindLastLower();
        SwRectFnSet aRectFnSet(&rMaster);
        const tools::Long nBottom = aRectFnSet.GetPrtBottom(rMaster);
        while ( pInva )
        {
            if( aRectFnSet.BottomDist( pInva->getFrameArea(), nBottom ) <= 0 )
            {
                pInva->InvalidateSize();
                pInva->Prepare();
                pInva = pInva->FindPrev();
            }
            else
                pInva = nullptr;
        }
    }

    if ( rFollow.ContainsContent() )
    {
        // There's only the content from the Masters left; the content from the Follow
        // does not have any Frames left (should always be exactly one empty TextNode).
        SwFrame *pFrame = rFollow.ContainsContent();
        OSL_ENSURE( !pFrame->IsTabFrame() && !pFrame->FindNext(), "follow in chain contains content" );
        pFrame->Cut();
        SwFrame::DestroyFrame(pFrame);
    }

    // invalidate accessible relation set (accessibility wrapper)
#if !ENABLE_WASM_STRIP_ACCESSIBILITY
    SwViewShell* pSh = rMaster.getRootFrame()->GetCurrShell();
    if( pSh )
    {
        SwRootFrame* pLayout = rMaster.getRootFrame();
        if( pLayout && pLayout->IsAnyShellAccessible() )
            pSh->Imp()->InvalidateAccessibleRelationSet(rMaster, rFollow);
    }
#endif
}

void SwFlyFrame::UnchainFrames( SwFlyFrame &rMaster, SwFlyFrame &rFollow )
{
    rMaster.m_pNextLink = nullptr;
    rFollow.m_pPrevLink = nullptr;

    if ( rFollow.ContainsContent() )
    {
        // The Master sucks up the content of the Follow
        SwLayoutFrame *pUpper = &rMaster;
        SwFrame* pLower = pUpper->Lower();
        if ( pLower && pLower->IsColumnFrame() )
        {
            pUpper = static_cast<SwLayoutFrame*>(pUpper->GetLastLower());
            pUpper = static_cast<SwLayoutFrame*>(pUpper->Lower()); // The (Column)BodyFrame
            OSL_ENSURE( pUpper && pUpper->IsColBodyFrame(), "Missing ColumnBody" );
        }
        SwFlyFrame *pFoll = &rFollow;
        while ( pFoll )
        {
            SwFrame *pTmp = ::SaveContent( pFoll );
            if ( pTmp )
                ::RestoreContent( pTmp, pUpper, rMaster.FindLastLower() );
            pFoll->SetCompletePaint();
            pFoll->InvalidateSize();
            pFoll = pFoll->GetNextLink();
        }
    }

    // The Follow needs his own content to be served
    const SwFormatContent &rContent = rFollow.GetFormat()->GetContent();
    OSL_ENSURE( rContent.GetContentIdx(), ":-( No content prepared." );
    SwNodeOffset nIndex = rContent.GetContentIdx()->GetIndex();
    // Lower() means SwColumnFrame: this one contains another SwBodyFrame
    SwFrame* pLower = rFollow.Lower();
    ::InsertCnt_( pLower ? const_cast<SwLayoutFrame*>(static_cast<const SwLayoutFrame*>(static_cast<const SwLayoutFrame*>(pLower)->Lower()))
                                   : static_cast<SwLayoutFrame*>(&rFollow),
                  rFollow.GetFormat()->GetDoc(), ++nIndex );

    // invalidate accessible relation set (accessibility wrapper)
#if !ENABLE_WASM_STRIP_ACCESSIBILITY
    SwViewShell* pSh = rMaster.getRootFrame()->GetCurrShell();
    if( pSh )
    {
        SwRootFrame* pLayout = rMaster.getRootFrame();
        if( pLayout && pLayout->IsAnyShellAccessible() )
            pSh->Imp()->InvalidateAccessibleRelationSet(rMaster, rFollow);
    }
#endif
}

SwFlyFrame *SwFlyFrame::FindChainNeighbour( SwFrameFormat const &rChain, SwFrame *pAnch )
{
    // We look for the Fly that's in the same Area.
    // Areas can for now only be Head/Footer or Flys.

    if ( !pAnch ) // If an Anchor was passed along, that one counts (ctor!)
        pAnch = AnchorFrame();

    SwLayoutFrame *pLay;
    if ( pAnch->IsInFly() )
        pLay = pAnch->FindFlyFrame();
    else
    {
        // FindFooterOrHeader is not appropriate here, as we may not have a
        // connection to the Anchor yet.
        pLay = pAnch->GetUpper();
        while ( pLay && !(pLay->GetType() & (SwFrameType::Header|SwFrameType::Footer)) )
            pLay = pLay->GetUpper();
    }

    SwIterator<SwFlyFrame,SwFormat> aIter( rChain );
    SwFlyFrame *pFly = aIter.First();
    if ( pLay )
    {
        while ( pFly )
        {
            if ( pFly->GetAnchorFrame() )
            {
                if ( pFly->GetAnchorFrame()->IsInFly() )
                {
                    if ( pFly->AnchorFrame()->FindFlyFrame() == pLay )
                        break;
                }
                else if ( pLay == pFly->FindFooterOrHeader() )
                    break;
            }
            pFly = aIter.Next();
        }
    }
    else if ( pFly )
    {
        OSL_ENSURE( !aIter.Next(), "chain with more than one instance" );
    }
    return pFly;
}

bool SwFlyFrame::IsFlySplitAllowed() const
{
    if (!IsFlyAtContentFrame())
    {
        return false;
    }

    const IDocumentSettingAccess& rIDSA = GetFormat()->getIDocumentSettingAccess();
    if (rIDSA.get(DocumentSettingId::DO_NOT_BREAK_WRAPPED_TABLES))
    {
        return false;
    }

    if (FindFooterOrHeader())
    {
        // Adding a new page would not increase the header/footer area.
        return false;
    }

    const SwFrame* pFlyAnchor = GetAnchorFrame();
    if (pFlyAnchor && pFlyAnchor->FindColFrame())
    {
        // No split in multi-column sections, so GetFlyAnchorBottom() can assume that our innermost
        // body frame and the page's body frame is the same.
        // This is also consistent with the Word behavior.
        return false;
    }

    if (pFlyAnchor && pFlyAnchor->IsInFootnote())
    {
        // No split in footnotes.
        return false;
    }

    const SwFlyFrameFormat* pFormat = GetFormat();
    const SwFormatVertOrient& rVertOrient = pFormat->GetVertOrient();
    if (rVertOrient.GetVertOrient() == text::VertOrientation::BOTTOM)
    {
        // We have to grow from bottom to top, and the fly split code assumes that we grow from top
        // to bottom, so don't split for now.
        if (rVertOrient.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA)
        {
            // Growing from the bottom of the body frame.
            return false;
        }
    }

    return pFormat->GetFlySplit().GetValue();
}

SwFrame *SwFlyFrame::FindLastLower()
{
    SwFrame *pRet = ContainsAny();
    if ( pRet && pRet->IsInTab() )
        pRet = pRet->FindTabFrame();
    SwFrame *pNxt = pRet;
    while ( pNxt && IsAnLower( pNxt ) )
    {   pRet = pNxt;
        pNxt = pNxt->FindNext();
    }
    return pRet;
}

bool SwFlyFrame::FrameSizeChg( const SwFormatFrameSize &rFrameSize )
{
    bool bRet = false;
    SwTwips nDiffHeight = getFrameArea().Height();
    if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Variable )
        mbFixSize = m_bMinHeight = false;
    else
    {
        if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Fixed )
        {
            mbFixSize = true;
            m_bMinHeight = false;
        }
        else if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Minimum )
        {
            mbFixSize = false;
            m_bMinHeight = true;
        }
        nDiffHeight -= rFrameSize.GetHeight();
    }
    // If the Fly contains columns, we already need to set the Fly
    // and the Columns to the required value or else we run into problems.
    if (SwFrame* pLower = Lower())
    {
        if ( pLower->IsColumnFrame() )
        {
            const SwRect aOld( GetObjRectWithSpaces() );
            const Size   aOldSz( getFramePrintArea().SSize() );
            const SwTwips nDiffWidth = getFrameArea().Width() - rFrameSize.GetWidth();

            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                aFrm.Height( aFrm.Height() - nDiffHeight );
                aFrm.Width ( aFrm.Width()  - nDiffWidth  );
            }

            // #i68520#
            InvalidateObjRectWithSpaces();

            {
                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                aPrt.Height( aPrt.Height() - nDiffHeight );
                aPrt.Width ( aPrt.Width()  - nDiffWidth  );
            }

            ChgLowersProp( aOldSz );
            ::Notify( this, FindPageFrame(), aOld );
            setFrameAreaPositionValid(false);
            bRet = true;
        }
        else if ( pLower->IsNoTextFrame() )
        {
            mbFixSize = true;
            m_bMinHeight = false;
        }
    }
    return bRet;
}

void SwFlyFrame::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
{
    if (rHint.GetId() == SfxHintId::SwFormatChange ||
        rHint.GetId() == SfxHintId::SwLegacyModify ||
        rHint.GetId() == SfxHintId::SwAttrSetChange)
    {
        SwFlyFrameInvFlags eInvFlags = SwFlyFrameInvFlags::NONE;
        if (rHint.GetId() == SfxHintId::SwFormatChange)
        {
            auto pChangeHint = static_cast<const SwFormatChangeHint*>(&rHint);
            UpdateAttrForFormatChange(pChangeHint->m_pOldFormat, pChangeHint->m_pNewFormat, eInvFlags);
        }
        else if (rHint.GetId() == SfxHintId::SwAttrSetChange)
        {
            auto pChangeHint = static_cast<const sw::AttrSetChangeHint*>(&rHint);
            if(pChangeHint->m_pNew && pChangeHint->m_pOld)
            {
                SfxItemIter aNIter(*pChangeHint->m_pNew->GetChgSet());
                SfxItemIter aOIter(*pChangeHint->m_pOld->GetChgSet());
                const SfxPoolItem* pNItem = aNIter.GetCurItem();
                const SfxPoolItem* pOItem = aOIter.GetCurItem();
                SwAttrSetChg aOldSet(*pChangeHint->m_pOld);
                SwAttrSetChg aNewSet(*pChangeHint->m_pNew);
                do
                {
                    UpdateAttr_(pOItem, pNItem, eInvFlags, &aOldSet, &aNewSet);
                    pNItem = aNIter.NextItem();
                    pOItem = aOIter.NextItem();
                } while(pNItem);
                if(aOldSet.Count() || aNewSet.Count())
                    SwLayoutFrame::SwClientNotify(rMod, sw::AttrSetChangeHint(&aOldSet, &aNewSet));
            }
        }
        else // rHint.GetId() == SfxHintId::SwLegacyModify
        {
            auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
            UpdateAttr_(pLegacy->m_pOld, pLegacy->m_pNew, eInvFlags);
        }

        if(eInvFlags == SwFlyFrameInvFlags::NONE)
            return;

        Invalidate_();
        if(eInvFlags & SwFlyFrameInvFlags::InvalidatePos)
        {
            InvalidatePos_();
            // #i68520#
            InvalidateObjRectWithSpaces();
        }
        if(eInvFlags & SwFlyFrameInvFlags::InvalidateSize)
        {
            InvalidateSize_();
            // #i68520#
            InvalidateObjRectWithSpaces();
        }
        if(eInvFlags & SwFlyFrameInvFlags::InvalidatePrt)
            InvalidatePrt_();
        if(eInvFlags & SwFlyFrameInvFlags::SetNotifyBack)
            SetNotifyBack();
        if(eInvFlags & SwFlyFrameInvFlags::SetCompletePaint)
            SetCompletePaint();

        SwFrame* pLower = Lower();
        if((eInvFlags & SwFlyFrameInvFlags::ClearContourCache) && pLower && pLower->IsNoTextFrame())
            ClrContourCache( GetVirtDrawObj() );
        SwRootFrame *pRoot;
        if(eInvFlags & SwFlyFrameInvFlags::InvalidateBrowseWidth && nullptr != (pRoot = getRootFrame()))
            pRoot->InvalidateBrowseWidth();
        // #i28701#
        if(eInvFlags & SwFlyFrameInvFlags::UpdateObjInSortedList)
        {
            // update sorted object lists, the Writer fly frame is registered at.
            UpdateObjInSortedList();
        }

        // #i87645# - reset flags for the layout process (only if something has been invalidated)
        ResetLayoutProcessBools();
    }
    else if (rHint.GetId() == SfxHintId::SwAutoFormatUsedHint)
    {
        // There's a FlyFrame, so use it
        static_cast<const sw::AutoFormatUsedHint&>(rHint).SetUsed();
        return;
    }
    else if (rHint.GetId() == SfxHintId::SwGetZOrder)
    {
        auto pGetZOrdnerHint = static_cast<const sw::GetZOrderHint*>(&rHint);
        const auto& rFormat(dynamic_cast<const SwFrameFormat&>(rMod));
        if (rFormat.Which() == RES_FLYFRMFMT && rFormat.getIDocumentLayoutAccess().GetCurrentViewShell()) // #i11176#
            pGetZOrdnerHint->m_rnZOrder = GetVirtDrawObj()->GetOrdNum();
    }
    else if (rHint.GetId() == SfxHintId::SwGetObjectConnected)
    {
        auto pConnectedHint = static_cast<const sw::GetObjectConnectedHint*>(&rHint);
        const auto& rFormat(dynamic_cast<const SwFrameFormat&>(rMod));
        if (!pConnectedHint->m_risConnected && rFormat.Which() == RES_FLYFRMFMT && (!pConnectedHint->m_pRoot || pConnectedHint->m_pRoot == getRootFrame()))
            pConnectedHint->m_risConnected = true;
    }
}

void SwFlyFrame::UpdateAttr_( const SfxPoolItem *pOld, const SfxPoolItem *pNew,
                            SwFlyFrameInvFlags &rInvFlags,
                            SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet )
{
    bool bClear = true;
    const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
    SwViewShell *pSh = getRootFrame()->GetCurrShell();
    switch( nWhich )
    {
        case RES_VERT_ORIENT:
        case RES_HORI_ORIENT:
        //  #i18732# - consider new option 'follow text flow'
        case RES_FOLLOW_TEXT_FLOW:
        {
            // ATTENTION: Always also change Action in ChgRePos()!
            rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::SetNotifyBack;
        }
        break;
        // #i28701# - consider new option 'wrap influence on position'
        case RES_WRAP_INFLUENCE_ON_OBJPOS:
        {
            rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::SetNotifyBack
                         | SwFlyFrameInvFlags::UpdateObjInSortedList;
        }
        break;
        case RES_SURROUND:
        {
            //#i28701# - invalidate position on change of
            // wrapping style.
            rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::ClearContourCache;
            // The background needs to be messaged and invalidated
            const SwRect aTmp( GetObjRectWithSpaces() );
            NotifyBackground( FindPageFrame(), aTmp, PrepareHint::FlyFrameAttributesChanged );

            // By changing the flow of frame-bound Frames, a vertical alignment
            // can be activated/deactivated => MakeFlyPos
            if( RndStdIds::FLY_AT_FLY == GetFormat()->GetAnchor().GetAnchorId() )
                rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::SetNotifyBack;

            // Delete contour in the Node if necessary
            SwFrame* pLower = Lower();
            if ( pLower && pLower->IsNoTextFrame() &&
                 !GetFormat()->GetSurround().IsContour() )
            {
                SwNoTextNode *pNd = static_cast<SwNoTextNode*>(static_cast<SwNoTextFrame*>(pLower)->GetNode());
                if ( pNd->HasContour() )
                    pNd->SetContour( nullptr );
            }
            // #i28701# - perform reorder of object lists
            // at anchor frame and at page frame.
            rInvFlags |= SwFlyFrameInvFlags::UpdateObjInSortedList;
        }
        break;

        case RES_PROTECT:
            if (pNew)
            {
                const SvxProtectItem *pP = static_cast<const SvxProtectItem*>(pNew);
                GetVirtDrawObj()->SetMoveProtect( pP->IsPosProtected()   );
                GetVirtDrawObj()->SetResizeProtect( pP->IsSizeProtected() );
#if !ENABLE_WASM_STRIP_ACCESSIBILITY
                if( pSh )
                {
                    SwRootFrame* pLayout = getRootFrame();
                    if( pLayout && pLayout->IsAnyShellAccessible() )
                        pSh->Imp()->InvalidateAccessibleEditableState( truethis );
                }
#endif
            }
            break;
        case RES_COL:
            if (pOld && pNew)
            {
                ChgColumns( *static_cast<const SwFormatCol*>(pOld), *static_cast<const SwFormatCol*>(pNew) );
                const SwFormatFrameSize &rNew = GetFormat()->GetFrameSize();
                if ( FrameSizeChg( rNew ) )
                    NotifyDrawObj();
                rInvFlags |= SwFlyFrameInvFlags::InvalidateSize | SwFlyFrameInvFlags::SetNotifyBack
                             | SwFlyFrameInvFlags::SetCompletePaint;
            }
            break;

        case RES_FRM_SIZE:
        case RES_FLY_SPLIT:
        {
            const SwFormatFrameSize &rNew = GetFormat()->GetFrameSize();
            if ( FrameSizeChg( rNew ) )
                NotifyDrawObj();
            rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::InvalidateSize
                         | SwFlyFrameInvFlags::InvalidatePrt | SwFlyFrameInvFlags::SetNotifyBack
                         | SwFlyFrameInvFlags::SetCompletePaint
                         | SwFlyFrameInvFlags::InvalidateBrowseWidth
                         | SwFlyFrameInvFlags::ClearContourCache;

            SwFormatURL aURL( GetFormat()->GetURL() );

            SwFormatFrameSize *pNewFormatFrameSize = nullptr;
            if (nWhich == RES_FRM_SIZE)
                pNewFormatFrameSize = const_cast<SwFormatFrameSize*>(static_cast<const SwFormatFrameSize*>(pNew));
            else if (nWhich == RES_FLY_SPLIT)
            {
                // If the fly frame has a table lower, invalidate that, so it joins its follow tab
                // frames and re-splits according to the new fly split rule.
                if (Lower() && Lower()->IsTabFrame())
                {
                    Lower()->InvalidateAll_();
                }
            }

            if (aURL.GetMap() && pNewFormatFrameSize)
            {
                const SwFormatFrameSize &rOld = *pNewFormatFrameSize;
                //#35091# Can be "times zero", when loading the template
                if ( rOld.GetWidth() && rOld.GetHeight() )
                {

                    Fraction aScaleX( rOld.GetWidth(), rNew.GetWidth() );
                    Fraction aScaleY( rOld.GetHeight(), rOld.GetHeight() );
                    aURL.GetMap()->Scale( aScaleX, aScaleY );
                    SwFrameFormat *pFormat = GetFormat();
                    pFormat->LockModify();
                    pFormat->SetFormatAttr( aURL );
                    pFormat->UnlockModify();
                }
            }
            const SvxProtectItem &rP = GetFormat()->GetProtect();
            GetVirtDrawObj()->SetMoveProtect( rP.IsPosProtected()    );
            GetVirtDrawObj()->SetResizeProtect( rP.IsSizeProtected() );

            if ( pSh )
                pSh->InvalidateWindows( getFrameArea() );
            const IDocumentDrawModelAccess& rIDDMA = GetFormat()->getIDocumentDrawModelAccess();
            const IDocumentSettingAccess& rIDSA = GetFormat()->getIDocumentSettingAccess();
            bool isPaintHellOverHF = rIDSA.get(DocumentSettingId::PAINT_HELL_OVER_HEADER_FOOTER);
            SdrLayerID nHellId = rIDDMA.GetHellId();

            if (isPaintHellOverHF && !GetAnchorFrame()->FindFooterOrHeader())
            {
                nHellId = rIDDMA.GetHeaderFooterHellId();
            }
            bool bNoClippingWithWrapPolygon = rIDSA.get(DocumentSettingId::NO_CLIPPING_WITH_WRAP_POLYGON);
            SdrLayerID nId = nHellId;
            if (GetFormat()->GetOpaque().GetValue() &&
                !(bNoClippingWithWrapPolygon && GetFrameFormat()->GetSurround().IsContour()))
                nId = rIDDMA.GetHeavenId();
            GetVirtDrawObj()->SetLayer( nId );

            if ( SwFrame* pLower = Lower() )
            {
                // Delete contour in the Node if necessary
                if( pLower->IsNoTextFrame() &&
                     !GetFormat()->GetSurround().IsContour() )
                {
                    SwNoTextNode *pNd = static_cast<SwNoTextNode*>(static_cast<SwNoTextFrame*>(pLower)->GetNode());
                    if ( pNd->HasContour() )
                        pNd->SetContour( nullptr );
                }
                else if( !pLower->IsColumnFrame() )
                {
                    SwFrame* pFrame = GetLastLower();
                    if( pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsUndersized() )
                        pFrame->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
                }
            }

            // #i28701# - perform reorder of object lists
            // at anchor frame and at page frame.
            rInvFlags |= SwFlyFrameInvFlags::UpdateObjInSortedList;

            break;
        }
        case RES_UL_SPACE:
        case RES_LR_SPACE:
        {
            rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::ClearContourCache;
            if( pSh && pSh->GetViewOptions()->getBrowseMode() )
                getRootFrame()->InvalidateBrowseWidth();
            SwRect aNew( GetObjRectWithSpaces() );
            SwRect aOld( getFrameArea() );
            if (pNew)
            {
                if ( RES_UL_SPACE == nWhich )
                {
                    const SvxULSpaceItem &rUL = *static_cast<const SvxULSpaceItem*>(pNew);
                    aOld.Top( std::max( aOld.Top() - tools::Long(rUL.GetUpper()), tools::Long(0) ) );
                    aOld.AddHeight(rUL.GetLower() );
                }
                else
                {
                    const SvxLRSpaceItem &rLR = *static_cast<const SvxLRSpaceItem*>(pNew);
                    aOld.Left(std::max(aOld.Left() - rLR.ResolveLeft({}), tools::Long(0)));
                    aOld.AddWidth(rLR.ResolveRight({}));
                }
            }
            aNew.Union( aOld );
            NotifyBackground( FindPageFrame(), aNew, PrepareHint::Clear );
        }
        break;

        case RES_TEXT_VERT_ADJUST:
        {
            InvalidateContentPos();
            rInvFlags |= SwFlyFrameInvFlags::SetCompletePaint;
        }
        break;

        case RES_BOX:
        case RES_SHADOW:
            rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::InvalidateSize
                         | SwFlyFrameInvFlags::InvalidatePrt | SwFlyFrameInvFlags::SetCompletePaint;
            break;

        case RES_FRAMEDIR :
            SetDerivedVert( false );
            SetDerivedR2L( false );
            CheckDirChange();
            break;

        case RES_OPAQUE:
            if (pNew)
            {
                if ( pSh )
                    pSh->InvalidateWindows( getFrameArea() );

                const IDocumentDrawModelAccess& rIDDMA = GetFormat()->getIDocumentDrawModelAccess();
                const SdrLayerID nId = static_cast<const SvxOpaqueItem*>(pNew)->GetValue() ?
                                    rIDDMA.GetHeavenId() :
                                    rIDDMA.GetHellId();
                GetVirtDrawObj()->SetLayer( nId );
#if !ENABLE_WASM_STRIP_ACCESSIBILITY
                if( pSh )
                {
                    SwRootFrame* pLayout = getRootFrame();
                    if( pLayout && pLayout->IsAnyShellAccessible() )
                    {
                        pSh->Imp()->DisposeAccessibleFrame( this );
                        pSh->Imp()->AddAccessibleFrame( this );
                    }
                }
#endif
                // #i28701# - perform reorder of object lists
                // at anchor frame and at page frame.
                rInvFlags |= SwFlyFrameInvFlags::UpdateObjInSortedList;
            }
            break;

        case RES_URL:
        {
            // The interface changes the frame size when interacting with text frames,
            // the Map, however, needs to be relative to FrameSize().
            SwFrame* pLower = Lower();
            if ( (!pLower || !pLower->IsNoTextFrame()) && pNew && pOld &&
                 static_cast<const SwFormatURL*>(pNew)->GetMap() && static_cast<const SwFormatURL*>(pOld)->GetMap() )
            {
                const SwFormatFrameSize &rSz = GetFormat()->GetFrameSize();
                if ( rSz.GetHeight() != getFrameArea().Height() ||
                     rSz.GetWidth()  != getFrameArea().Width() )
                {
                    SwFormatURL aURL( GetFormat()->GetURL() );
                    Fraction aScaleX( getFrameArea().Width(),  rSz.GetWidth() );
                    Fraction aScaleY( getFrameArea().Height(), rSz.GetHeight() );
                    aURL.GetMap()->Scale( aScaleX, aScaleY );
                    SwFrameFormat *pFormat = GetFormat();
                    pFormat->LockModify();
                    pFormat->SetFormatAttr( aURL );
                    pFormat->UnlockModify();
                }
            }
        }
        // No invalidation necessary
        break;

        case RES_CHAIN:
            if (pNew)
            {
                const SwFormatChain *pChain = static_cast<const SwFormatChain*>(pNew);
                if ( pChain->GetNext() )
                {
                    SwFlyFrame *pFollow = FindChainNeighbour( *pChain->GetNext() );
                    if ( GetNextLink() && pFollow != GetNextLink() )
                        SwFlyFrame::UnchainFrames( *this, *GetNextLink());
                    if ( pFollow )
                    {
                        if ( pFollow->GetPrevLink() &&
                             pFollow->GetPrevLink() != this )
                            SwFlyFrame::UnchainFrames( *pFollow->GetPrevLink(),
                                                     *pFollow );
                        if ( !GetNextLink() )
                            SwFlyFrame::ChainFrames( *this, *pFollow );
                    }
                }
                else if ( GetNextLink() )
                    SwFlyFrame::UnchainFrames( *this, *GetNextLink() );
                if ( pChain->GetPrev() )
                {
                    SwFlyFrame *pMaster = FindChainNeighbour( *pChain->GetPrev() );
                    if ( GetPrevLink() && pMaster != GetPrevLink() )
                        SwFlyFrame::UnchainFrames( *GetPrevLink(), *this );
                    if ( pMaster )
                    {
                        if ( pMaster->GetNextLink() &&
                             pMaster->GetNextLink() != this )
                            SwFlyFrame::UnchainFrames( *pMaster, *pMaster->GetNextLink() );
                        if ( !GetPrevLink() )
                            SwFlyFrame::ChainFrames( *pMaster, *this );
                    }
                }
                else if ( GetPrevLink() )
                    SwFlyFrame::UnchainFrames( *GetPrevLink(), *this );
            }
            [[fallthrough]];
        default:
            bClear = false;
    }
    if ( !bClear )
        return;

    if ( pOldSet || pNewSet )
    {
        if ( pOldSet )
            pOldSet->ClearItem( nWhich );
        if ( pNewSet )
            pNewSet->ClearItem( nWhich );
    }
    else
    {
        SwModify aMod;
        SwLayoutFrame::SwClientNotify(aMod, sw::LegacyModifyHint(pOld, pNew));
    }
}

void SwFlyFrame::UpdateAttrForFormatChange( SwFormat *pOldFormat, SwFormat *pNewFormat,
                            SwFlyFrameInvFlags &rInvFlags )
{
    SwViewShell *pSh = getRootFrame()->GetCurrShell();
    {
        const SwFormatFrameSize &rNew = GetFormat()->GetFrameSize();
        if ( FrameSizeChg( rNew ) )
            NotifyDrawObj();
        rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::InvalidateSize
                     | SwFlyFrameInvFlags::InvalidatePrt | SwFlyFrameInvFlags::SetNotifyBack
                     | SwFlyFrameInvFlags::SetCompletePaint
                     | SwFlyFrameInvFlags::InvalidateBrowseWidth
                     | SwFlyFrameInvFlags::ClearContourCache;
        {
            SwRect aNew( GetObjRectWithSpaces() );
            SwRect aOld( getFrameArea() );
            const SvxULSpaceItem &rUL = pOldFormat->GetULSpace();
            aOld.Top( std::max( aOld.Top() - tools::Long(rUL.GetUpper()), tools::Long(0) ) );
            aOld.AddHeight(rUL.GetLower() );
            const SvxLRSpaceItem &rLR = pOldFormat->GetLRSpace();
            aOld.Left(std::max(aOld.Left() - rLR.ResolveLeft({}), tools::Long(0)));
            aOld.AddWidth(rLR.ResolveRight({}));
            aNew.Union( aOld );
            NotifyBackground( FindPageFrame(), aNew, PrepareHint::Clear );

            // Special case:
            // When assigning a template we cannot rely on the old column
            // attribute. As there need to be at least enough for ChgColumns,
            // we need to create a temporary attribute.
            SwFormatCol aCol;
            if ( Lower() && Lower()->IsColumnFrame() )
            {
                sal_uInt16 nCol = 0;
                SwFrame *pTmp = Lower();
                do
                {   ++nCol;
                    pTmp = pTmp->GetNext();
                } while ( pTmp );
                aCol.Init( nCol, 0, 1000 );
            }
            ChgColumns( aCol, GetFormat()->GetCol() );
        }

        SwFormatURL aURL( GetFormat()->GetURL() );

        if (aURL.GetMap() && pOldFormat)
        {
            const SwFormatFrameSize &rOld = pOldFormat->GetFrameSize();
            //#35091# Can be "times zero", when loading the template
            if ( rOld.GetWidth() && rOld.GetHeight() )
            {

                Fraction aScaleX( rOld.GetWidth(), rNew.GetWidth() );
                Fraction aScaleY( rOld.GetHeight(), rOld.GetHeight() );
                aURL.GetMap()->Scale( aScaleX, aScaleY );
                SwFrameFormat *pFormat = GetFormat();
                pFormat->LockModify();
                pFormat->SetFormatAttr( aURL );
                pFormat->UnlockModify();
            }
        }
        const SvxProtectItem &rP = GetFormat()->GetProtect();
        GetVirtDrawObj()->SetMoveProtect( rP.IsPosProtected()    );
        GetVirtDrawObj()->SetResizeProtect( rP.IsSizeProtected() );

        if ( pSh )
            pSh->InvalidateWindows( getFrameArea() );
        const IDocumentDrawModelAccess& rIDDMA = GetFormat()->getIDocumentDrawModelAccess();
        const IDocumentSettingAccess& rIDSA = GetFormat()->getIDocumentSettingAccess();
        bool isPaintHellOverHF = rIDSA.get(DocumentSettingId::PAINT_HELL_OVER_HEADER_FOOTER);
        SdrLayerID nHellId = rIDDMA.GetHellId();

        if (isPaintHellOverHF && !GetAnchorFrame()->FindFooterOrHeader())
        {
            nHellId = rIDDMA.GetHeaderFooterHellId();
        }
        bool bNoClippingWithWrapPolygon = rIDSA.get(DocumentSettingId::NO_CLIPPING_WITH_WRAP_POLYGON);
        SdrLayerID nId = nHellId;
        if (GetFormat()->GetOpaque().GetValue() &&
            !(bNoClippingWithWrapPolygon && GetFrameFormat()->GetSurround().IsContour()))
            nId = rIDDMA.GetHeavenId();
        GetVirtDrawObj()->SetLayer( nId );

        SwFrame* pFrame = Lower();
        if ( pFrame )
        {
            // Delete contour in the Node if necessary
            if( pFrame->IsNoTextFrame() &&
                 !GetFormat()->GetSurround().IsContour() )
            {
                SwNoTextNode *pNd = static_cast<SwNoTextNode*>(static_cast<SwNoTextFrame*>(pFrame)->GetNode());
                if ( pNd->HasContour() )
                    pNd->SetContour( nullptr );
            }
            else if( !pFrame->IsColumnFrame() )
            {
                pFrame = GetLastLower();
                if( pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsUndersized() )
                    pFrame->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
            }
        }

        // #i28701# - perform reorder of object lists
        // at anchor frame and at page frame.
        rInvFlags |= SwFlyFrameInvFlags::UpdateObjInSortedList;
    }

    SwModify aMod;
    SwLayoutFrame::SwClientNotify(aMod, SwFormatChangeHint(pOldFormat, pNewFormat));
}

void SwFlyFrame::Invalidate_( SwPageFrame const *pPage )
{
    InvalidatePage( pPage );
    m_bNotifyBack = m_bInvalid = true;

    SwFlyFrame *pFrame;
    if ( GetAnchorFrame() && nullptr != (pFrame = AnchorFrame()->FindFlyFrame()) )
    {
        // Very bad case: If the Fly is bound within another Fly which
        // contains columns, the Format should be from that one.
        SwFrame* pLower = pFrame->Lower();
        if ( !pFrame->IsLocked() && !pFrame->IsColLocked() &&
             pLower && pLower->IsColumnFrame() )
            pFrame->InvalidateSize();
    }

    // #i85216#
    // if vertical position is oriented at a layout frame inside a ghost section,
    // assure that the position is invalidated and that the information about
    // the vertical position oriented frame is cleared
    if ( GetVertPosOrientFrame() && GetVertPosOrientFrame()->IsLayoutFrame() )
    {
        const SwSectionFrame* pSectFrame( GetVertPosOrientFrame()->FindSctFrame() );
        if ( pSectFrame && pSectFrame->GetSection() == nullptr )
        {
            InvalidatePos();
            ClearVertPosOrientFrame();
        }
    }
}

/** Change the relative position
 *
 * The position will be Fix automatically and the attribute is changed accordingly.
 */

void SwFlyFrame::ChgRelPos( const Point &rNewPos )
{
    if ( GetCurrRelPos() == rNewPos )
        return;

    SwFrameFormat *pFormat = GetFormat();
    const bool bVert = GetAnchorFrame()->IsVertical();
    const SwTwips nNewY = bVert ? rNewPos.X() : rNewPos.Y();
    SwTwips nTmpY = nNewY == LONG_MAX ? 0 : nNewY;
    if( bVert )
        nTmpY = -nTmpY;
    SfxItemSetFixed<RES_VERT_ORIENT, RES_HORI_ORIENT> aSet( pFormat->GetDoc().GetAttrPool() );

    SwFormatVertOrient aVert( pFormat->GetVertOrient() );
    const SwTextFrame *pAutoFrame = nullptr;
    // #i34948# - handle also at-page and at-fly anchored
    // Writer fly frames
    const RndStdIds eAnchorType = GetFrameFormat()->GetAnchor().GetAnchorId();
    if ( eAnchorType == RndStdIds::FLY_AT_PAGE )
    {
        aVert.SetVertOrient( text::VertOrientation::NONE );
        aVert.SetRelationOrient( text::RelOrientation::PAGE_FRAME );
    }
    else if ( eAnchorType == RndStdIds::FLY_AT_FLY )
    {
        aVert.SetVertOrient( text::VertOrientation::NONE );
        aVert.SetRelationOrient( text::RelOrientation::FRAME );
    }
    else if ( IsFlyAtContentFrame() || text::VertOrientation::NONE != aVert.GetVertOrient() )
    {
        if( text::RelOrientation::CHAR == aVert.GetRelationOrient() && IsAutoPos() )
        {
            if( LONG_MAX != nNewY )
            {
                aVert.SetVertOrient( text::VertOrientation::NONE );
                assert(GetAnchorFrame()->IsTextFrame());
                pAutoFrame = static_cast<const SwTextFrame*>(GetAnchorFrame());
                TextFrameIndex const nOfs(pAutoFrame->MapModelToViewPos(
                            *pFormat->GetAnchor().GetContentAnchor()));
                while( pAutoFrame->GetFollow() &&
                       pAutoFrame->GetFollow()->GetOffset() <= nOfs )
                {
                    if( pAutoFrame == GetAnchorFrame() )
                        nTmpY += pAutoFrame->GetRelPos().Y();
                    nTmpY -= pAutoFrame->GetUpper()->getFramePrintArea().Height();
                    pAutoFrame = pAutoFrame->GetFollow();
                }
                nTmpY = static_cast<SwFlyAtContentFrame*>(this)->GetRelCharY(pAutoFrame)-nTmpY;
            }
            else
                aVert.SetVertOrient( text::VertOrientation::CHAR_BOTTOM );
        }
        else
        {
            aVert.SetVertOrient( text::VertOrientation::NONE );
            aVert.SetRelationOrient( text::RelOrientation::FRAME );
        }
    }
    aVert.SetPos( nTmpY );
    aSet.Put( aVert );

    // For Flys in the Cnt, the horizontal orientation is of no interest,
    // as it's always 0
    if ( !IsFlyInContentFrame() )
    {
        const SwTwips nNewX = bVert ? rNewPos.Y() : rNewPos.X();
        SwTwips nTmpX = nNewX == LONG_MAX ? 0 : nNewX;
        SwFormatHoriOrient aHori( pFormat->GetHoriOrient() );
        // #i34948# - handle also at-page and at-fly anchored
        // Writer fly frames
        if ( eAnchorType == RndStdIds::FLY_AT_PAGE )
        {
            aHori.SetHoriOrient( text::HoriOrientation::NONE );
            aHori.SetRelationOrient( text::RelOrientation::PAGE_FRAME );
            aHori.SetPosToggle( false );
        }
        else if ( eAnchorType == RndStdIds::FLY_AT_FLY )
        {
            aHori.SetHoriOrient( text::HoriOrientation::NONE );
            aHori.SetRelationOrient( text::RelOrientation::FRAME );
            aHori.SetPosToggle( false );
        }
        else if ( IsFlyAtContentFrame() || text::HoriOrientation::NONE != aHori.GetHoriOrient() )
        {
            aHori.SetHoriOrient( text::HoriOrientation::NONE );
            if( text::RelOrientation::CHAR == aHori.GetRelationOrient() && IsAutoPos() )
            {
                if( LONG_MAX != nNewX )
                {
                    if( !pAutoFrame )
                    {
                        assert(GetAnchorFrame()->IsTextFrame());
                        pAutoFrame = static_cast<const SwTextFrame*>(GetAnchorFrame());
                        TextFrameIndex const nOfs(pAutoFrame->MapModelToViewPos(
                                    *pFormat->GetAnchor().GetContentAnchor()));
                        while( pAutoFrame->GetFollow() &&
                               pAutoFrame->GetFollow()->GetOffset() <= nOfs )
                            pAutoFrame = pAutoFrame->GetFollow();
                    }
                    nTmpX -= static_cast<SwFlyAtContentFrame*>(this)->GetRelCharX(pAutoFrame);
                }
            }
            else
                aHori.SetRelationOrient( text::RelOrientation::FRAME );
            aHori.SetPosToggle( false );
        }
        aHori.SetPos( nTmpX );
        aSet.Put( aHori );
    }
    SetCurrRelPos( rNewPos );
    pFormat->GetDoc().SetAttr( aSet, *pFormat );

}

/** "Formats" the Frame; Frame and PrtArea.
 *
 * The FixSize is not inserted here.
 */

void SwFlyFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs *pAttrs )
{
    OSL_ENSURE( pAttrs, "FlyFrame::Format, pAttrs is 0." );

    ColLock();

    if ( !isFrameAreaSizeValid() )
    {
        if ( getFrameArea().Top() == FAR_AWAY && getFrameArea().Left() == FAR_AWAY )
        {
            // Remove safety switch (see SwFrame::CTor)
            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                aFrm.Pos().setX(0);
                aFrm.Pos().setY(0);
            }

            // #i68520#
            InvalidateObjRectWithSpaces();
        }

        // Check column width and set it if needed
        SwFrame* pLower = Lower();
        if ( pLower && pLower->IsColumnFrame() )
            AdjustColumns( nullptr, false );

        setFrameAreaSizeValid(true);

        const SwTwips nUL = pAttrs->CalcTopLine()  + pAttrs->CalcBottomLine();
        const SwTwips nLR = pAttrs->CalcLeftLine() + pAttrs->CalcRightLine();
        const SwFormatFrameSize &rFrameSz = GetFormat()->GetFrameSize();
        Size aRelSize( CalcRel( rFrameSz ) );

        OSL_ENSURE( pAttrs->GetSize().Height() != 0 || rFrameSz.GetHeightPercent(), "FrameAttr height is 0." );
        OSL_ENSURE( pAttrs->GetSize().Width()  != 0 || rFrameSz.GetWidthPercent(), "FrameAttr width is 0." );

        SwRectFnSet aRectFnSet(this);
        if( !HasFixSize() )
        {
            tools::Long nMinHeight = 0;
            if( IsMinHeight() )
                nMinHeight = aRectFnSet.IsVert() ? aRelSize.Width() : aRelSize.Height();

            SwTwips nRemaining = CalcContentHeight(pAttrs, nMinHeight, nUL);
            if( IsMinHeight() && (nRemaining + nUL) < nMinHeight )
                nRemaining = nMinHeight - nUL;
            // Because the Grow/Shrink of the Flys does not directly
            // set the size - only indirectly by triggering a Format()
            // via Invalidate() - the sizes need to be set here.
            // Notification is running along already.
            // As we already got a lot of zeros per attribute, we block them
            // from now on.

            if ( nRemaining < MINFLY )
                nRemaining = MINFLY;

            const SwFrame* pAnchor = GetAnchorFrame();
            if (SwFrame* pAnchorChar = FindAnchorCharFrame())
            {
                // If we find a follow of the anchor that is effectively the anchor of this fly,
                // then use that as the anchor for sizing purposes.
                pAnchor = pAnchorChar;
            }
            if (pAnchor && IsFlySplitAllowed())
            {
                // If the fly is allowed to be split, then limit its size to the upper of the
                // anchor.
                SwTwips nDeadline = GetFlyAnchorBottom(this, *pAnchor);
                SwTwips nTop = aRectFnSet.GetTop(getFrameArea());
                SwTwips nBottom = aRectFnSet.GetTop(getFrameArea()) + nRemaining;
                if (nBottom > nDeadline)
                {
                    if (nDeadline > nTop)
                    {
                        nRemaining = nDeadline - nTop;
                    }
                    else
                    {
                        // Even the top is below the deadline, set size to empty and mark it as
                        // clipped so we re-format later.
                        nRemaining = 0;
                        m_bHeightClipped = true;
                    }
                }
            }

            {
                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                aRectFnSet.SetHeight( aPrt, nRemaining );
            }

            nRemaining -= aRectFnSet.GetHeight(getFrameArea());

            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                aRectFnSet.AddBottom( aFrm, nRemaining + nUL );
            }

            // #i68520#
            if ( nRemaining + nUL != 0 )
            {
                InvalidateObjRectWithSpaces();
            }

            setFrameAreaSizeValid(true);

            if (SwFrameFormat* pShapeFormat = SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_FLYFRMFMT))
            {
                // This fly is a textbox of a draw shape.
                SdrObject* pShape = pShapeFormat->FindSdrObject();
                if (SdrObjCustomShape* pCustomShape = dynamic_cast<SdrObjCustomShape*>( pShape) )
                {
                    // The shape is a customshape: then inform it about the calculated fly size.
                    Size aSize(getFrameArea().Width(), getFrameArea().Height());
                    pCustomShape->SuggestTextFrameSize(aSize);
                    // Do the calculations normally done after touching editeng text of the shape.
                    pCustomShape->NbcSetOutlinerParaObjectForText(std::nullopt, nullptr);
                }
            }
        }
        else
        {
            // Fixed Frames do not Format itself
            setFrameAreaSizeValid(true);

            // Flys set their size using the attr
            SwTwips nNewSize = aRectFnSet.IsVert() ? aRelSize.Width() : aRelSize.Height();
            nNewSize -= nUL;
            if( nNewSize < MINFLY )
                nNewSize = MINFLY;

            {
                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                aRectFnSet.SetHeight( aPrt, nNewSize );
            }

            nNewSize += nUL - aRectFnSet.GetHeight(getFrameArea());

            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                aRectFnSet.AddBottom( aFrm, nNewSize );
            }

            // #i68520#
            if ( nNewSize != 0 )
            {
                InvalidateObjRectWithSpaces();
            }
        }

        if ( !m_bFormatHeightOnly )
        {
            OSL_ENSURE( aRelSize == CalcRel( rFrameSz ), "SwFlyFrame::Format CalcRel problem" );
            SwTwips nNewSize = aRectFnSet.IsVert() ? aRelSize.Height() : aRelSize.Width();

            if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed )
            {
                // #i9046# Autowidth for fly frames
                const SwTwips nAutoWidth = lcl_CalcAutoWidth( *this );
                if ( nAutoWidth )
                {
                    if( SwFrameSize::Minimum == rFrameSz.GetWidthSizeType() )
                        nNewSize = std::max( nNewSize - nLR, nAutoWidth );
                    else
                        nNewSize = nAutoWidth;
                }
            }
            else
                nNewSize -= nLR;

            if( nNewSize < MINFLY )
                nNewSize = MINFLY;

            {
                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                aRectFnSet.SetWidth( aPrt, nNewSize );
            }

            nNewSize += nLR - aRectFnSet.GetWidth(getFrameArea());

            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                aRectFnSet.AddRight( aFrm, nNewSize );
            }

            // #i68520#
            if ( nNewSize != 0 )
            {
                InvalidateObjRectWithSpaces();
            }
        }
    }
    ColUnlock();
}

// #i11760# - change parameter <bNoColl>: type <bool>;
//   add new parameter <bNoCalcFollow> with
//  new parameter <bNoCalcFollow> was used by method
//                          <FormatWidthCols(..)> to avoid follow formatting
//                          for text frames. But, unformatted follows causes
//                          problems in method <SwContentFrame::WouldFit_(..)>,
//                          which assumes that the follows are formatted.
//                          Thus, <bNoCalcFollow> no longer used by <FormatWidthCols(..)>.
void CalcContent( SwLayoutFrame *pLay, bool bNoColl )
{
    SwViewShell & rShell(*pLay->getRootFrame()->GetCurrShell());
    vcl::RenderContext* pRenderContext = rShell.GetOut();
    SwSectionFrame* pSect;
    bool bCollect = false;
    if( pLay->IsSctFrame() )
    {
        pSect = static_cast<SwSectionFrame*>(pLay);
        if( pSect->IsEndnAtEnd() && !bNoColl )
        {
            bCollect = true;
            SwLayouter::CollectEndnotes( pLay->GetFormat()->GetDoc(), pSect );
        }
        pSect->CalcFootnoteContent();
    }
    else
        pSect = nullptr;
    SwFrame *pFrame = pLay->ContainsAny();
    if ( !pFrame )
    {
        if( pSect )
        {
            if( pSect->HasFollow() )
                pFrame = pSect->GetFollow()->ContainsAny();
            if( !pFrame )
            {
                if( pSect->IsEndnAtEnd() )
                {
                    if( bCollect )
                        pLay->GetFormat()->GetDoc().getIDocumentLayoutAccess().GetLayouter()->
                            InsertEndnotes( pSect );
                    bool bLock = pSect->IsFootnoteLock();
                    pSect->SetFootnoteLock( true );
                    pSect->CalcFootnoteContent();
                    pSect->CalcFootnoteContent();
                    pSect->SetFootnoteLock( bLock );
                }
                return;
            }
            pFrame->InvalidatePos_();
        }
        else
            return;
    }
    pFrame->InvalidatePage();

    do
    {
        // local variables to avoid loops caused by anchored object positioning
        SwAnchoredObject* pAgainObj1 = nullptr;
        SwAnchoredObject* pAgainObj2 = nullptr;

        // FME 2007-08-30 #i81146# new loop control
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=91 H=96 G=93

¤ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.