Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  dcontact.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 <memory>
#include <hintids.hxx>
#include <svx/svdpage.hxx>
#include <svx/svditer.hxx>
#include <svx/svdogrp.hxx>
#include <svx/svdotext.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdviter.hxx>
#include <svx/svdview.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
#include <svx/sdr/contact/objectcontact.hxx>
#include <drawdoc.hxx>
#include <fmtornt.hxx>
#include <viewimp.hxx>
#include <fmtsrnd.hxx>
#include <fmtanchr.hxx>
#include <node.hxx>
#include <fmtcntnt.hxx>
#include <fmtfsize.hxx>
#include <pam.hxx>
#include <pagefrm.hxx>
#include <rootfrm.hxx>
#include <frmtool.hxx>
#include <flyfrm.hxx>
#include <textboxhelper.hxx>
#include <frmfmt.hxx>
#include <fmtfollowtextflow.hxx>
#include <dflyobj.hxx>
#include <dcontact.hxx>
#include <unodraw.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentState.hxx>
#include <IDocumentUndoRedo.hxx>
#include <doc.hxx>
#include <hints.hxx>
#include <txtfrm.hxx>
#include <frameformats.hxx>
#include <sortedobjs.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <svx/sdr/contact/viewcontactofvirtobj.hxx>
#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
#include <drawinglayer/geometry/viewinformation2d.hxx>
#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
#include <com/sun/star/text/WritingMode2.hpp>
#include <calbck.hxx>
#include <algorithm>
#include <txtfly.hxx>
#include <sal/log.hxx>

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

namespace
{
    /** unary function used to find a 'virtual' drawing object anchored at a given frame */
    struct VirtObjAnchoredAtFramePred
    {
        const SwFrame* m_pAnchorFrame;

        // #i26791# - compare with master frame
        static const SwFrame* FindFrame(const SwFrame* pFrame)
        {
            if(!pFrame || !pFrame->IsContentFrame())
                return pFrame;
            auto pContentFrame = static_cast<const SwContentFrame*>(pFrame);
            while(pContentFrame->IsFollow())
                pContentFrame = pContentFrame->FindMaster();
            return pContentFrame;
        }

        VirtObjAnchoredAtFramePred(const SwFrame* pAnchorFrame)
        :   m_pAnchorFrame(FindFrame(pAnchorFrame))
        {}

        bool operator()(const rtl::Reference<SwDrawVirtObj>& rpDrawVirtObj)
        {
            return FindFrame(rpDrawVirtObj->GetAnchorFrame()) == m_pAnchorFrame;
        }
    };
}

void setContextWritingMode(SdrObject* pObj, SwFrame const * pAnchor)
{
    if(!pObj || !pAnchor)
        return;
    short nWritingDirection =
            pAnchor->IsVertical()    ? text::WritingMode2::TB_RL :
            pAnchor->IsRightToLeft() ? text::WritingMode2::RL_TB :
                    text::WritingMode2::LR_TB;
    pObj->SetContextWritingMode(nWritingDirection);
}


/** The Get reverse way: seeks the format to the specified object.
 * If the object is a SwVirtFlyDrawObj then the format of this
 * will be acquired.
 * Otherwise it is just a simple drawing object. This has a
 * UserCall and is the client of the searched format.
*/

SwFrameFormat *FindFrameFormat( SdrObject *pObj )
{
    if (SwVirtFlyDrawObj* pFlyDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
       return pFlyDrawObj->GetFormat();

    if (SwContact* pContact = GetUserCall(pObj))
        return pContact->GetFormat();

    return nullptr;
}

bool HasWrap( const SdrObject* pObj )
{
    if ( pObj )
    {
        const SwFrameFormat* pFormat = ::FindFrameFormat( pObj );
        if ( pFormat )
        {
            return css::text::WrapTextMode_THROUGH != pFormat->GetSurround().GetSurround();
        }
    }

    return false;
}

/// returns the BoundRect _inclusive_ distance of the object.
SwRect GetBoundRectOfAnchoredObj( const SdrObject* pObj )
{
    SwRect aRet( pObj->GetCurrentBoundRect() );
    // #i68520# - call cache of <SwAnchoredObject>
    SwContact* pContact( GetUserCall( pObj ) );
    if ( pContact )
    {
        const SwAnchoredObject* pAnchoredObj( pContact->GetAnchoredObj( pObj ) );
        if ( pAnchoredObj )
        {
            aRet = pAnchoredObj->GetObjRectWithSpaces();
        }
    }
    return aRet;
}

/// Returns the UserCall if applicable from the group object
SwContact* GetUserCall( const SdrObject* pObj )
{
    for (; pObj; pObj = pObj->getParentSdrObjectFromSdrObject())
    {
        if (auto pUserCall = pObj->GetUserCall())
        {
            assert(dynamic_cast<SwContact*>(pUserCall)
                   && "<::GetUserCall(..)> - wrong type of found object user call.");
            return static_cast<SwContact*>(pUserCall);
        }
    }
    return nullptr;
}

/// Returns true if the SrdObject is a Marquee-Object (scrolling text)
bool IsMarqueeTextObj( const SdrObject& rObj )
{
    if (SdrInventor::Default != rObj.GetObjInventor() ||
        SdrObjKind::Text != rObj.GetObjIdentifier())
        return false;
    SdrTextAniKind eTKind = static_cast<const SdrTextObj&>(rObj).GetTextAniKind();
    return ( SdrTextAniKind::Scroll == eTKind
         || SdrTextAniKind::Alternate == eTKind || SdrTextAniKind::Slide == eTKind );
}

SwContact::SwContact( SwFrameFormat *pToRegisterIn ) :
    SwClient( pToRegisterIn ),
    mbInDTOR( false )
{}

SwContact::~SwContact()
{
    SetInDTOR();
}


void SwContact::SetInDTOR()
{
    mbInDTOR = true;
}

/// method to move drawing object to corresponding visible layer
void SwContact::MoveObjToVisibleLayer( SdrObject* _pDrawObj )
{
    // #i46297# - notify background about the arriving of
    // the object and invalidate its position.
    const bool bNotify( !GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) );

    MoveObjToLayer( true, _pDrawObj );

    // #i46297#
    if ( !bNotify )
        return;

    SwAnchoredObject* pAnchoredObj = GetAnchoredObj( _pDrawObj );
    assert(pAnchoredObj);
    ::setContextWritingMode( _pDrawObj, pAnchoredObj->GetAnchorFrameContainingAnchPos() );
    // Note: as-character anchored objects aren't registered at a page frame and
    //       a notification of its background isn't needed.
    if ( pAnchoredObj->GetPageFrame() )
    {
        ::Notify_Background( _pDrawObj, pAnchoredObj->GetPageFrame(),
                             pAnchoredObj->GetObjRect(), PrepareHint::FlyFrameArrive, true );
    }

    pAnchoredObj->InvalidateObjPos();
}

/// method to move drawing object to corresponding invisible layer - #i18447#
void SwContact::MoveObjToInvisibleLayer( SdrObject* _pDrawObj )
{
    // #i46297# - notify background about the leaving of the object.
    const bool bNotify( GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) );

    MoveObjToLayer( false, _pDrawObj );

    // #i46297#
    if ( bNotify )
    {
        SwAnchoredObject* pAnchoredObj = GetAnchoredObj( _pDrawObj );
        assert(pAnchoredObj);
        // Note: as-character anchored objects aren't registered at a page frame and
        //       a notification of its background isn't needed.
        if (pAnchoredObj->GetPageFrame())
        {
            ::Notify_Background( _pDrawObj, pAnchoredObj->GetPageFrame(),
                                 pAnchoredObj->GetObjRect(), PrepareHint::FlyFrameLeave, true );
        }
    }
}

/** method to move object to visible/invisible layer -  #i18447#

    implementation for the public method <MoveObjToVisibleLayer(..)>
    and <MoveObjToInvisibleLayer(..)>
*/

void SwContact::MoveObjToLayer( const bool _bToVisible,
                                 SdrObject* _pDrawObj )
{
    if ( !_pDrawObj )
    {
        OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing object!" );
        return;
    }

    if ( !GetRegisteredIn() )
    {
        OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing frame format!" );
        return;
    }

    const IDocumentDrawModelAccess& rIDDMA = static_cast<SwFrameFormat*>(GetRegisteredInNonConst())->getIDocumentDrawModelAccess();

    SdrLayerID nToHellLayerId =
        _bToVisible ? rIDDMA.GetHellId() : rIDDMA.GetInvisibleHellId();
    SdrLayerID nToHeavenLayerId =
        _bToVisible ? rIDDMA.GetHeavenId() : rIDDMA.GetInvisibleHeavenId();
    SdrLayerID nToControlLayerId =
        _bToVisible ? rIDDMA.GetControlsId() : rIDDMA.GetInvisibleControlsId();
    SdrLayerID nFromHellLayerId =
        _bToVisible ? rIDDMA.GetInvisibleHellId() : rIDDMA.GetHellId();
    SdrLayerID nFromHeavenLayerId =
        _bToVisible ? rIDDMA.GetInvisibleHeavenId() : rIDDMA.GetHeavenId();
    SdrLayerID nFromControlLayerId =
        _bToVisible ? rIDDMA.GetInvisibleControlsId() : rIDDMA.GetControlsId();

    if ( dynamic_cast<const SdrObjGroup*>( _pDrawObj) !=  nullptr )
    {
        // determine layer for group object
        {
            // proposed layer of a group object is the hell layer
            SdrLayerID nNewLayerId = nToHellLayerId;
            if ( ::CheckControlLayer( _pDrawObj ) )
            {
                // it has to be the control layer, if one of the member
                // is a control
                nNewLayerId = nToControlLayerId;
            }
            else if ( _pDrawObj->GetLayer() == rIDDMA.GetHeavenId() ||
                      _pDrawObj->GetLayer() == rIDDMA.GetInvisibleHeavenId() )
            {
                // it has to be the heaven layer, if method <GetLayer()> reveals
                // a heaven layer
                nNewLayerId = nToHeavenLayerId;
            }
            // set layer at group object, but do *not* broadcast and
            // no propagation to the members.
            // Thus, call <NbcSetLayer(..)> at super class
            _pDrawObj->SdrObject::NbcSetLayer( nNewLayerId );
        }

        // call method recursively for group object members
        const SdrObjList* pLst =
                static_cast<SdrObjGroup*>(_pDrawObj)->GetSubList();
        if ( pLst )
        {
            for (const rtl::Reference<SdrObject>& pObj : *pLst)
            {
                MoveObjToLayer( _bToVisible, pObj.get() );
            }
        }
    }
    else
    {
        const SdrLayerID nLayerIdOfObj = _pDrawObj->GetLayer();
        if ( nLayerIdOfObj == nFromHellLayerId )
        {
            _pDrawObj->SetLayer( nToHellLayerId );
        }
        else if ( nLayerIdOfObj == nFromHeavenLayerId )
        {
            _pDrawObj->SetLayer( nToHeavenLayerId );
        }
        else if ( nLayerIdOfObj == nFromControlLayerId )
        {
            _pDrawObj->SetLayer( nToControlLayerId );
        }
    }
}

/// get minimum order number of anchored objects handled by with contact
sal_uInt32 SwContact::GetMinOrdNum() const
{
    sal_uInt32 nMinOrdNum( SAL_MAX_UINT32 );

    std::vector< SwAnchoredObject* > aObjs;
    GetAnchoredObjs( aObjs );

    while ( !aObjs.empty() )
    {
        sal_uInt32 nTmpOrdNum = aObjs.back()->GetDrawObj()->GetOrdNum();

        if ( nTmpOrdNum < nMinOrdNum )
        {
            nMinOrdNum = nTmpOrdNum;
        }

        aObjs.pop_back();
    }

    OSL_ENSURE( nMinOrdNum != SAL_MAX_UINT32,
            "<SwContact::GetMinOrdNum()> - no order number found." );
    return nMinOrdNum;
}

/// get maximum order number of anchored objects handled by with contact
sal_uInt32 SwContact::GetMaxOrdNum() const
{
    sal_uInt32 nMaxOrdNum( 0 );

    std::vector< SwAnchoredObject* > aObjs;
    GetAnchoredObjs( aObjs );

    while ( !aObjs.empty() )
    {
        sal_uInt32 nTmpOrdNum = aObjs.back()->GetDrawObj()->GetOrdNum();

        if ( nTmpOrdNum > nMaxOrdNum )
        {
            nMaxOrdNum = nTmpOrdNum;
        }

        aObjs.pop_back();
    }

    return nMaxOrdNum;
}

namespace
{
    Point lcl_GetWW8Pos(SwAnchoredObject const * pAnchoredObj, const bool bFollowTextFlow, sw::WW8AnchorConv& reConv)
    {
        switch(reConv)
        {
            case sw::WW8AnchorConv::CONV2PG:
            {
                bool bRelToTableCell(false);
                Point aPos(pAnchoredObj->GetRelPosToPageFrame(bFollowTextFlow, bRelToTableCell));
                if(bRelToTableCell)
                    reConv = sw::WW8AnchorConv::RELTOTABLECELL;
                return aPos;
            }
            case sw::WW8AnchorConv::CONV2COL_OR_PARA:
                return pAnchoredObj->GetRelPosToAnchorFrame();
            case sw::WW8AnchorConv::CONV2CHAR:
                return pAnchoredObj->GetRelPosToChar();
            case sw::WW8AnchorConv::CONV2LINE:
                return pAnchoredObj->GetRelPosToLine();
            default: ;
        }
        return Point();
    }
}
void SwContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
{
    // this does not call SwClient::SwClientNotify and thus doesn't handle RES_OBJECTDYING as usual. Is this intentional?
    if (rHint.GetId() == SfxHintId::SwFindSdrObject)
    {
        auto pFindSdrObjectHint = static_cast<const sw::FindSdrObjectHint*>(&rHint);
        if(!pFindSdrObjectHint->m_rpObject)
            pFindSdrObjectHint->m_rpObject = GetMaster();
    }
    else if (rHint.GetId() == SfxHintId::SwWW8AnchorConv)
    {
        auto pWW8AnchorConvHint = static_cast<const sw::WW8AnchorConvHint*>(&rHint);
        // determine anchored object
        SwAnchoredObject* pAnchoredObj(nullptr);
        {
            std::vector<SwAnchoredObject*> aAnchoredObjs;
            GetAnchoredObjs(aAnchoredObjs);
            if(!aAnchoredObjs.empty())
                pAnchoredObj = aAnchoredObjs.front();
        }
        // no anchored object found. Thus, the needed layout information can't
        // be determined. --> no conversion
        if(!pAnchoredObj)
            return;
        // no conversion for anchored drawing object, which aren't attached to an
        // anchor frame.
        // This is the case for drawing objects, which are anchored inside a page
        // header/footer of an *unused* page style.
        if(dynamic_cast<SwAnchoredDrawObject*>(pAnchoredObj) && !pAnchoredObj->GetAnchorFrame())
            return;
        const bool bFollowTextFlow = static_cast<const SwFrameFormat&>(rMod).GetFollowTextFlow().GetValue();
        sw::WW8AnchorConvResult& rResult(pWW8AnchorConvHint->m_rResult);
        // No distinction between layout directions, because of missing
        // information about WW8 in vertical layout.
        rResult.m_aPos.setX(lcl_GetWW8Pos(pAnchoredObj, bFollowTextFlow, rResult.m_eHoriConv).getX());
        rResult.m_aPos.setY(lcl_GetWW8Pos(pAnchoredObj, bFollowTextFlow, rResult.m_eVertConv).getY());
        rResult.m_bConverted = true;
    }
}


SwFlyDrawContact::SwFlyDrawContact(
    SwFlyFrameFormat *pToRegisterIn,
    SdrModel& rTargetModel)
:   SwContact(pToRegisterIn),
    mpMasterObj(new SwFlyDrawObj(rTargetModel))
{
    // #i26791# - class <SwFlyDrawContact> contains the 'master'
    // drawing object of type <SwFlyDrawObj> on its own.
    mpMasterObj->SetOrdNum( 0xFFFFFFFE );
    mpMasterObj->SetUserCall( this );
}

SwFlyDrawContact::~SwFlyDrawContact()
{
    if ( mpMasterObj )
    {
        mpMasterObj->SetUserCall( nullptr );
        if ( mpMasterObj->getSdrPageFromSdrObject() )
            mpMasterObj->getSdrPageFromSdrObject()->RemoveObject( mpMasterObj->GetOrdNum() );
    }
}

sal_uInt32 SwFlyDrawContact::GetOrdNumForNewRef(const SwFlyFrame* pFly,
        SwFrame const& rAnchorFrame)
{
    // maintain invariant that a shape's textbox immediately follows the shape
    // also for the multiple SdrVirtObj created for shapes in header/footer
    if (SwFrameFormat const*const pDrawFormat =
            SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_FLYFRMFMT))
    {
        // assume that the draw SdrVirtObj is always created before the flyframe one
        if (SwSortedObjs const*const pObjs = rAnchorFrame.GetDrawObjs())
        {
            for (SwAnchoredObject const*const pAnchoredObj : *pObjs)
            {
                if (pAnchoredObj->GetFrameFormat() == pDrawFormat)
                {
                    return pAnchoredObj->GetDrawObj()->GetOrdNum() + 1;
                }
            }
        }
        // if called from AppendObjs(), this is a problem; if called from lcl_SetFlyFrameAttr() it's not
        SAL_INFO("sw""GetOrdNumForNewRef: cannot find SdrObject for text box's shape");
    }
    // search for another Writer fly frame registered at same frame format
    SwIterator<SwFlyFrame,SwFormat> aIter(*GetFormat());
    const SwFlyFrame* pFlyFrame(nullptr);
    for(pFlyFrame = aIter.First(); pFlyFrame; pFlyFrame = aIter.Next())
    {
        if(pFlyFrame != pFly)
            break;
    }

    if(pFlyFrame)
    {
        // another Writer fly frame found. Take its order number
        return pFlyFrame->GetVirtDrawObj()->GetOrdNum();
    }
    // no other Writer fly frame found. Take order number of 'master' object
    // #i35748# - use method <GetOrdNumDirect()> instead
    // of method <GetOrdNum()> to avoid a recalculation of the order number,
    // which isn't intended.
    return GetMaster()->GetOrdNumDirect();
}

SwVirtFlyDrawObj* SwFlyDrawContact::CreateNewRef(SwFlyFrame* pFly,
        SwFlyFrameFormat* pFormat, SwFrame const& rAnchorFrame)
{
    // Find ContactObject from the Format. If there's already one, we just
    // need to create a new Ref, else we create the Contact now.

    IDocumentDrawModelAccess& rIDDMA = pFormat->getIDocumentDrawModelAccess();
    SwFlyDrawContact* pContact = pFormat->GetOrCreateContact();
    rtl::Reference<SwVirtFlyDrawObj> pDrawObj(
        new SwVirtFlyDrawObj(
            pContact->GetMaster()->getSdrModelFromSdrObject(),
            *pContact->GetMaster(),
            pFly));
    pDrawObj->SetUserCall(pContact);

    // The Reader creates the Masters and inserts them into the Page in
    // order to transport the z-order.
    // After creating the first Reference the Masters are removed from the
    // List and are not important anymore.
    SdrPage* pPg = pContact->GetMaster()->getSdrPageFromSdrObject();
    if(nullptr != pPg)
    {
        const size_t nOrdNum = pContact->GetMaster()->GetOrdNum();
        pPg->ReplaceObject(pDrawObj.get(), nOrdNum);
    }
    // #i27030# - insert new <SwVirtFlyDrawObj> instance
    // into drawing page with correct order number
    else
        rIDDMA.GetDrawModel()->GetPage(0)->InsertObject(pDrawObj.get(), pContact->GetOrdNumForNewRef(pFly, rAnchorFrame));
    // #i38889# - assure, that new <SwVirtFlyDrawObj> instance
    // is in a visible layer.
    pContact->MoveObjToVisibleLayer(pDrawObj.get());
    return pDrawObj.get();
}

// #i26791#
const SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(const SdrObject* pSdrObj) const
{
    assert(pSdrObj);
    assert(dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) != nullptr);
    assert(GetUserCall(pSdrObj) == this &&
        "<SwFlyDrawContact::GetAnchoredObj(..)> - provided object doesn't belong to this contact");

    const SwAnchoredObject *const pRetAnchoredObj =
        static_cast<const SwVirtFlyDrawObj*>(pSdrObj)->GetFlyFrame();

    return pRetAnchoredObj;
}

SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(SdrObject *const pSdrObj)
{
    return const_cast<SwAnchoredObject *>(const_cast<SwFlyDrawContact const*>(this)->GetAnchoredObj(pSdrObj));
}

SdrObject* SwFlyDrawContact::GetMaster()
{
    return mpMasterObj.get();
}

/**
 * @note Overriding method to control Writer fly frames, which are linked, and
 *       to assure that all objects anchored at/inside the Writer fly frame are
 *       also made visible.
 */

void SwFlyDrawContact::MoveObjToVisibleLayer( SdrObject* _pDrawObj )
{
    assert(dynamic_cast<const SwVirtFlyDrawObj*>(_pDrawObj) != nullptr);

    if ( GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) )
    {
        // nothing to do
        return;
    }

    SwFlyFrame* pFlyFrame = static_cast<SwVirtFlyDrawObj*>(_pDrawObj)->GetFlyFrame();

    // #i44464# - consider, that Writer fly frame content
    // already exists - (e.g. WW8 document is inserted into an existing document).
    if ( !pFlyFrame->Lower() )
    {
        pFlyFrame->InsertColumns();
        pFlyFrame->Chain( pFlyFrame->AnchorFrame() );
        pFlyFrame->InsertCnt();
    }
    if ( pFlyFrame->GetDrawObjs() )
    {
        for (SwAnchoredObject* i : *pFlyFrame->GetDrawObjs())
        {
            // #i28701# - consider type of objects in sorted object list.
            SdrObject* pObj = i->DrawObj();
            SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
            pContact->MoveObjToVisibleLayer( pObj );
        }
    }

    // make fly frame visible
    SwContact::MoveObjToVisibleLayer( _pDrawObj );
}

/**
 * @note Override method to control Writer fly frames, which are linked, and
 *       to assure that all objects anchored at/inside the Writer fly frame are
 *       also made invisible.
 */

void SwFlyDrawContact::MoveObjToInvisibleLayer( SdrObject* _pDrawObj )
{
    assert(dynamic_cast<const SwVirtFlyDrawObj*>(_pDrawObj) != nullptr);

    if ( !GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) )
    {
        // nothing to do
        return;
    }

    SwFlyFrame* pFlyFrame = static_cast<SwVirtFlyDrawObj*>(_pDrawObj)->GetFlyFrame();

    pFlyFrame->Unchain();
    pFlyFrame->DeleteCnt();
    if ( pFlyFrame->GetDrawObjs() )
    {
        for (SwAnchoredObject* i : *pFlyFrame->GetDrawObjs())
        {
            // #i28701# - consider type of objects in sorted object list.
            SdrObject* pObj = i->DrawObj();
            SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
            pContact->MoveObjToInvisibleLayer( pObj );
        }
    }

    // make fly frame invisible
    SwContact::MoveObjToInvisibleLayer( _pDrawObj );
}

/// get data collection of anchored objects, handled by with contact
void SwFlyDrawContact::GetAnchoredObjs( std::vector<SwAnchoredObject*>& _roAnchoredObjs ) const
{
    const SwFrameFormat* pFormat = GetFormat();
    SwFlyFrame::GetAnchoredObjects( _roAnchoredObjs, *pFormat );
}
void SwFlyDrawContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
{
    SwContact::SwClientNotify(rMod, rHint);
    if(rHint.GetId() == SfxHintId::SwGetZOrder)
    {
        auto pGetZOrdnerHint = static_cast<const sw::GetZOrderHint*>(&rHint);
        // #i11176#
        // This also needs to work when no layout exists. Thus, for
        // FlyFrames an alternative method is used now in that case.
        auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
        if (pFormat && pFormat->Which() == RES_FLYFRMFMT && !pFormat->getIDocumentLayoutAccess().GetCurrentViewShell())
            pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
    }
}

// SwDrawContact

bool CheckControlLayer( const SdrObject *pObj )
{
    if ( SdrInventor::FmForm == pObj->GetObjInventor() )
        return true;
    if (const SdrObjGroup *pObjGroup = dynamic_cast<const SdrObjGroup*>(pObj))
    {
        const SdrObjList *pLst = pObjGroup->GetSubList();
        for (const rtl::Reference<SdrObject>& pChildObj : *pLst)
        {
            if ( ::CheckControlLayer( pChildObj.get() ) )
            {
                // #i18447# - return correct value ;-)
                return true;
            }
        }
    }
    return false;
}

SwDrawContact::SwDrawContact( SwFrameFormat* pToRegisterIn, SdrObject* pObj ) :
    SwContact( pToRegisterIn ),
    mbMasterObjCleared( false ),
    mbDisconnectInProgress( false ),
    mbUserCallActive( false ),
    // Note: value of <meEventTypeOfCurrentUserCall> isn't of relevance, because
    //       <mbUserCallActive> is false.
    meEventTypeOfCurrentUserCall( SdrUserCallType::MoveOnly )
{
    // --> #i33909# - assure, that drawing object is inserted
    // in the drawing page.
    if ( !pObj->IsInserted() )
    {
        pToRegisterIn->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
                                InsertObject( pObj, pObj->GetOrdNumDirect() );
    }

    // Controls have to be always in the Control-Layer. This is also true for
    // group objects, if they contain controls.
    if ( ::CheckControlLayer( pObj ) )
    {
        // set layer of object to corresponding invisible layer.
        pObj->SetLayer( pToRegisterIn->getIDocumentDrawModelAccess().GetInvisibleControlsId() );
    }

    // #i26791#
    pObj->SetUserCall( this );
    maAnchoredDrawObj.SetDrawObj( *pObj );

    // if there already exists an SwXShape for the object, ensure it knows about us, and the SdrObject
    // #i99056#
    SwXShape::AddExistingShapeToFormat( *pObj );
}

SwDrawContact::~SwDrawContact()
{
    SetInDTOR();

    DisconnectFromLayout();

    // remove 'master' from drawing page
    RemoveMasterFromDrawPage();

    // remove and destroy 'virtual' drawing objects.
    RemoveAllVirtObjs();

    if ( !mbMasterObjCleared )
        maAnchoredDrawObj.ClearDrawObj();
}

void SwDrawContact::GetTextObjectsFromFormat(std::list<SdrTextObj*>& o_rTextObjects, SwDoc& rDoc)
{
    for(sw::SpzFrameFormat* pFly: *rDoc.GetSpzFrameFormats())
    {
        if(pFly->Which() == RES_DRAWFRMFMT) // ie. SwDrawFrameFormat*
            pFly->CallSwClientNotify(sw::CollectTextObjectsHint(o_rTextObjects));
    }
}

// #i26791#
const SwAnchoredObject* SwDrawContact::GetAnchoredObj(const SdrObject* pSdrObj ) const
{
    // handle default parameter value
    if (!pSdrObj)
    {
        pSdrObj = GetMaster();
    }

    assert(pSdrObj);
    assert(dynamic_cast<const SwDrawVirtObj*>(pSdrObj) != nullptr ||
           dynamic_cast<const SdrVirtObj*>(pSdrObj) == nullptr);
    assert((GetUserCall(pSdrObj) == this ||
            pSdrObj == GetMaster()) &&
            "<SwDrawContact::GetAnchoredObj(..)> - provided object doesn't belongs to this contact" );

    const SwAnchoredObject* pRetAnchoredObj = nullptr;

    if (auto pVirtObj = dynamic_cast<const SwDrawVirtObj*>(pSdrObj))
    {
        pRetAnchoredObj = &(pVirtObj->GetAnchoredObj());
    }
    else
    {
        assert(dynamic_cast<const SdrVirtObj*>(pSdrObj) == nullptr);
        pRetAnchoredObj = &maAnchoredDrawObj;
    }

    return pRetAnchoredObj;
}

SwAnchoredObject* SwDrawContact::GetAnchoredObj(SdrObject *const pSdrObj)
{
    return const_cast<SwAnchoredObject*>(const_cast<SwDrawContact const*>(this)->GetAnchoredObj(pSdrObj));
}

SdrObject* SwDrawContact::GetMaster()
{
    return !mbMasterObjCleared
           ? maAnchoredDrawObj.DrawObj()
           : nullptr;
}

const SwFrame* SwDrawContact::GetAnchorFrame( const SdrObject* _pDrawObj ) const
{
    const SwFrame* pAnchorFrame = nullptr;
    if ( !_pDrawObj ||
         _pDrawObj == GetMaster() ||
         ( !_pDrawObj->GetUserCall() &&
           GetUserCall( _pDrawObj ) == this ) )
    {
        pAnchorFrame = maAnchoredDrawObj.GetAnchorFrame();
    }
    else
    {
        assert(dynamic_cast<SwDrawVirtObj const*>(_pDrawObj) !=  nullptr);
        pAnchorFrame = static_cast<const SwDrawVirtObj*>(_pDrawObj)->GetAnchorFrame();
    }

    return pAnchorFrame;
}

SwFrame* SwDrawContact::GetAnchorFrame(SdrObject const *const pDrawObj)
{
    return const_cast<SwFrame *>(const_cast<SwDrawContact const*>(this)->GetAnchorFrame(pDrawObj));
}

/** add a 'virtual' drawing object to drawing page.
 */

SwDrawVirtObj* SwDrawContact::AddVirtObj(SwFrame const& rAnchorFrame)
{
    maDrawVirtObjs.push_back(
            new SwDrawVirtObj(
                GetMaster()->getSdrModelFromSdrObject(),
                *GetMaster(),
                *this));
    maDrawVirtObjs.back()->AddToDrawingPage(rAnchorFrame);
    return maDrawVirtObjs.back().get();
}

/// remove 'virtual' drawing objects and destroy them.
void SwDrawContact::RemoveAllVirtObjs()
{
    for(auto& rpDrawVirtObj : maDrawVirtObjs)
    {
        // remove and destroy 'virtual object'
        rpDrawVirtObj->RemoveFromWriterLayout();
        rpDrawVirtObj->RemoveFromDrawingPage();
        // to break the reference cycle
        rpDrawVirtObj->AnchoredObj().ClearDrawObj();
    }
    maDrawVirtObjs.clear();
}


/// get drawing object ('master' or 'virtual') by frame.
SdrObject* SwDrawContact::GetDrawObjectByAnchorFrame( const SwFrame& _rAnchorFrame )
{
    SdrObject* pRetDrawObj = nullptr;

    // #i26791# - compare master frames instead of direct frames
    const SwFrame* pProposedAnchorFrame = &_rAnchorFrame;
    if ( pProposedAnchorFrame->IsContentFrame() )
    {
        const SwContentFrame* pTmpFrame =
                            static_cast<const SwContentFrame*>( pProposedAnchorFrame );
        while ( pTmpFrame->IsFollow() )
        {
            pTmpFrame = pTmpFrame->FindMaster();
        }
        pProposedAnchorFrame = pTmpFrame;
    }

    const SwFrame* pMasterObjAnchorFrame = GetAnchorFrame();
    if ( pMasterObjAnchorFrame && pMasterObjAnchorFrame->IsContentFrame() )
    {
        const SwContentFrame* pTmpFrame =
                            static_cast<const SwContentFrame*>( pMasterObjAnchorFrame );
        while ( pTmpFrame->IsFollow() )
        {
            pTmpFrame = pTmpFrame->FindMaster();
        }
        pMasterObjAnchorFrame = pTmpFrame;
    }

    if ( pMasterObjAnchorFrame && pMasterObjAnchorFrame == pProposedAnchorFrame )
    {
        pRetDrawObj = GetMaster();
    }
    else
    {
        const auto ppFoundVirtObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
                VirtObjAnchoredAtFramePred(pProposedAnchorFrame)));
        if(ppFoundVirtObj != maDrawVirtObjs.end())
            pRetDrawObj = ppFoundVirtObj->get();
    }

    return pRetDrawObj;
}

void SwDrawContact::NotifyBackgroundOfAllVirtObjs(const tools::Rectangle* pOldBoundRect)
{
    for(const auto& rpDrawVirtObj : maDrawVirtObjs)
    {
        SwDrawVirtObj* pDrawVirtObj(rpDrawVirtObj.get());
        if ( pDrawVirtObj->GetAnchorFrame() )
        {
            // #i34640# - determine correct page frame
            SwPageFrame* pPage = pDrawVirtObj->AnchoredObj().FindPageFrameOfAnchor();
            if( pOldBoundRect && pPage )
            {
                SwRect aOldRect( *pOldBoundRect );
                aOldRect.Pos() += pDrawVirtObj->GetOffset();
                if( aOldRect.HasArea() )
                    ::Notify_Background( pDrawVirtObj, pPage,
                                         aOldRect, PrepareHint::FlyFrameLeave,true);
            }
            // #i34640# - include spacing for wrapping
            SwRect aRect( pDrawVirtObj->GetAnchoredObj().GetObjRectWithSpaces() );
            if (aRect.HasArea() && pPage)
            {
                SwPageFrame* pPg = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aRect, pPage )));
                if ( pPg )
                    ::Notify_Background( pDrawVirtObj, pPg, aRect,
                                         PrepareHint::FlyFrameArrive, true );
            }
            ::ClrContourCache( pDrawVirtObj );
        }
    }
}

/// local method to notify the background for a drawing object - #i26791#
static void lcl_NotifyBackgroundOfObj( SwDrawContact const & _rDrawContact,
                                const SdrObject& _rObj,
                                const tools::Rectangle* _pOldObjRect )
{
    // #i34640#
    SwAnchoredObject* pAnchoredObj =
        const_cast<SwAnchoredObject*>(_rDrawContact.GetAnchoredObj( &_rObj ));
    if ( !(pAnchoredObj && pAnchoredObj->GetAnchorFrame()) )
        return;

    // #i34640# - determine correct page frame
    SwPageFrame* pPageFrame = pAnchoredObj->FindPageFrameOfAnchor();
    if( _pOldObjRect && pPageFrame )
    {
        SwRect aOldRect( *_pOldObjRect );
        if( aOldRect.HasArea() )
        {
            // #i34640# - determine correct page frame
            SwPageFrame* pOldPageFrame = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aOldRect, pPageFrame )));
            ::Notify_Background( &_rObj, pOldPageFrame, aOldRect,
                                 PrepareHint::FlyFrameLeave, true);
        }
    }
    // #i34640# - include spacing for wrapping
    SwRect aNewRect( pAnchoredObj->GetObjRectWithSpaces() );
    if( aNewRect.HasArea() && pPageFrame )
    {
        pPageFrame = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aNewRect, pPageFrame )));
        ::Notify_Background( &_rObj, pPageFrame, aNewRect,
                             PrepareHint::FlyFrameArrive, true );
    }
    ClrContourCache( &_rObj );
}

void SwDrawContact::Changed( const SdrObject& rObj,
                             SdrUserCallType eType,
                             const tools::Rectangle& rOldBoundRect )
{
    // #i26791# - no event handling, if existing <SwViewShell>
    // is in construction
    SwDoc& rDoc = GetFormat()->GetDoc();
    if ( rDoc.getIDocumentLayoutAccess().GetCurrentViewShell() &&
         rDoc.getIDocumentLayoutAccess().GetCurrentViewShell()->IsInConstructor() )
    {
        return;
    }

    // #i44339#
    // no event handling, if document is in destruction.
    // Exception: It's the SdrUserCallType::Delete event
    if ( rDoc.IsInDtor() && eType != SdrUserCallType::Delete )
    {
        return;
    }

    //Put on Action, but not if presently anywhere an action runs.
    bool bHasActions(true);
    SwRootFrame *pTmpRoot = rDoc.getIDocumentLayoutAccess().GetCurrentLayout();
    if ( pTmpRoot && pTmpRoot->IsCallbackActionEnabled() )
    {
        SwViewShell* const pSh = rDoc.getIDocumentLayoutAccess().GetCurrentViewShell();
        if ( pSh )
        {
            for(SwViewShell& rShell : pSh->GetRingContainer() )
            {
                if ( rShell.Imp()->IsAction() || rShell.Imp()->IsIdleAction() )
                {
                    bHasActions = true;
                    break;
                }
                bHasActions = false;
            }
        }
        if(!bHasActions)
            pTmpRoot->StartAllAction();
    }
    SdrObjUserCall::Changed( rObj, eType, rOldBoundRect );
    Changed_( rObj, eType, &rOldBoundRect );    //Attention, possibly suicidal!

    if(!bHasActions)
        pTmpRoot->EndAllAction();
}

/// helper class for method <SwDrawContact::Changed_(..)> for handling nested
/// <SdrObjUserCall> events
class NestedUserCallHdl
{
    private:
        SwDrawContact* mpDrawContact;
        bool mbParentUserCallActive;
        SdrUserCallType meParentUserCallEventType;

    public:
        NestedUserCallHdl( SwDrawContact* _pDrawContact,
                           SdrUserCallType _eEventType )
            : mpDrawContact( _pDrawContact ),
              mbParentUserCallActive( _pDrawContact->mbUserCallActive ),
              meParentUserCallEventType( _pDrawContact->meEventTypeOfCurrentUserCall )
        {
            mpDrawContact->mbUserCallActive = true;
            mpDrawContact->meEventTypeOfCurrentUserCall = _eEventType;
        }

        ~NestedUserCallHdl()
        {
            if ( mpDrawContact )
            {
                mpDrawContact->mbUserCallActive = mbParentUserCallActive;
                mpDrawContact->meEventTypeOfCurrentUserCall = meParentUserCallEventType;
            }
        }

        void DrawContactDeleted()
        {
            mpDrawContact = nullptr;
        }

        bool IsNestedUserCall() const
        {
            return mbParentUserCallActive;
        }

        void AssertNestedUserCall()
        {
            if ( !IsNestedUserCall() )
                return;

            bool bTmpAssert( true );
            // Currently its known, that a nested event SdrUserCallType::Resize
            // could occur during parent user call SdrUserCallType::Inserted,
            // SdrUserCallType::Delete and SdrUserCallType::Resize for edge objects.
            // Also possible are nested SdrUserCallType::ChildResize events for
            // edge objects
            // Thus, assert all other combinations
            if ( ( meParentUserCallEventType == SdrUserCallType::Inserted ||
                   meParentUserCallEventType == SdrUserCallType::Delete ||
                   meParentUserCallEventType == SdrUserCallType::Resize ) &&
                 mpDrawContact->meEventTypeOfCurrentUserCall == SdrUserCallType::Resize )
            {
                bTmpAssert = false;
            }
            else if ( meParentUserCallEventType == SdrUserCallType::ChildResize &&
                      mpDrawContact->meEventTypeOfCurrentUserCall == SdrUserCallType::ChildResize )
            {
                bTmpAssert = false;
            }

            if ( bTmpAssert )
            {
                OSL_FAIL( "<SwDrawContact::Changed_(..)> - unknown nested <UserCall> event. This is serious." );
            }
        }
};

/// Notify the format's textbox that it should reconsider its position / size.
static void lcl_textBoxSizeNotify(SwFrameFormat* pFormat)
{
    if (SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT))
    {
        // Just notify the textbox that the size has changed, the actual object size is not interesting.
        SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE> aResizeSet(pFormat->GetDoc().GetAttrPool());
        SwFormatFrameSize aSize;
        aResizeSet.Put(aSize);
        SwTextBoxHelper::syncFlyFrameAttr(*pFormat, aResizeSet, pFormat->FindRealSdrObject());
    }
}

// !!!ATTENTION!!! The object may commit suicide!!!

void SwDrawContact::Changed_( const SdrObject& rObj,
                              SdrUserCallType eType,
                              const tools::Rectangle* pOldBoundRect )
{
    // suppress handling of nested <SdrObjUserCall> events
    NestedUserCallHdl aNestedUserCallHdl( this, eType );
    if ( aNestedUserCallHdl.IsNestedUserCall() )
    {
        aNestedUserCallHdl.AssertNestedUserCall();
        return;
    }
    // do *not* notify, if document is destructing
    // #i35912# - do *not* notify for as-character anchored
    // drawing objects.
    // #i35007#
    // improvement: determine as-character anchored object flag only once.
    const bool bAnchoredAsChar = ObjAnchoredAsChar();
    const bool bNotify = !(GetFormat()->GetDoc().IsInDtor()) &&
                         ( css::text::WrapTextMode_THROUGH != GetFormat()->GetSurround().GetSurround() ) &&
                         !bAnchoredAsChar;
    switch( eType )
    {
        case SdrUserCallType::Delete:
            {
                if ( bNotify )
                {
                    lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
                    // --> #i36181# - background of 'virtual'
                    // drawing objects have also been notified.
                    NotifyBackgroundOfAllVirtObjs( pOldBoundRect );
                }
                DisconnectFromLayout( false );
                mbMasterObjCleared = true;
                delete this;
                // --> #i65784# Prevent memory corruption
                aNestedUserCallHdl.DrawContactDeleted();
                break;
            }
        case SdrUserCallType::Inserted:
            {
                if ( mbDisconnectInProgress )
                {
                    OSL_FAIL( "<SwDrawContact::Changed_(..)> - Insert event during disconnection from layout is invalid." );
                }
                else
                {
                    ConnectToLayout();
                    if ( bNotify )
                    {
                        lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
                    }
                }
                break;
            }
        case SdrUserCallType::Removed:
            {
                if ( bNotify )
                {
                    lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
                }
                DisconnectFromLayout( false );
                break;
            }
        case SdrUserCallType::ChildInserted :
        case SdrUserCallType::ChildRemoved :
        {
            // --> #i113730#
            // force layer of controls for group objects containing control objects
            if(dynamic_cast< SdrObjGroup* >(maAnchoredDrawObj.DrawObj()))
            {
                if(::CheckControlLayer(maAnchoredDrawObj.DrawObj()))
                {
                    const IDocumentDrawModelAccess& rIDDMA = static_cast<SwFrameFormat*>(GetRegisteredInNonConst())->getIDocumentDrawModelAccess();
                    const SdrLayerID aCurrentLayer(maAnchoredDrawObj.DrawObj()->GetLayer());
                    const SdrLayerID aControlLayerID(rIDDMA.GetControlsId());
                    const SdrLayerID aInvisibleControlLayerID(rIDDMA.GetInvisibleControlsId());

                    if(aCurrentLayer != aControlLayerID && aCurrentLayer != aInvisibleControlLayerID)
                    {
                        if ( aCurrentLayer == rIDDMA.GetInvisibleHellId() ||
                             aCurrentLayer == rIDDMA.GetInvisibleHeavenId() )
                        {
                            maAnchoredDrawObj.DrawObj()->SetLayer(aInvisibleControlLayerID);
                        }
                        else
                        {
                            maAnchoredDrawObj.DrawObj()->SetLayer(aControlLayerID);
                        }
                    }
                }
            }
            [[fallthrough]];
        }
        case SdrUserCallType::MoveOnly:
        case SdrUserCallType::Resize:
        case SdrUserCallType::ChildMoveOnly :
        case SdrUserCallType::ChildResize :
        case SdrUserCallType::ChildChangeAttr :
        case SdrUserCallType::ChildDelete :
        {
            // #i31698# - improvement
            // get instance <SwAnchoredDrawObject> only once
            const SwAnchoredDrawObject* pAnchoredDrawObj =
                static_cast<const SwAnchoredDrawObject*>( GetAnchoredObj( &rObj ) );

            /* protect against NULL pointer dereferencing */
            if(!pAnchoredDrawObj)
            {
                break;
            }

            // #i26791# - adjust positioning and alignment attributes,
            // if positioning of drawing object isn't in progress.
            // #i53320# - no adjust of positioning attributes,
            // if drawing object isn't positioned.
            if ( !pAnchoredDrawObj->IsPositioningInProgress() &&
                 !pAnchoredDrawObj->NotYetPositioned() )
            {
                // #i34748# - If no last object rectangle is
                // provided by the anchored object, use parameter <pOldBoundRect>.
                const tools::Rectangle& aOldObjRect = pAnchoredDrawObj->GetLastObjRect()
                                               ? *(pAnchoredDrawObj->GetLastObjRect())
                                               : *pOldBoundRect;
                // #i79400#
                // always invalidate object rectangle inclusive spaces
                pAnchoredDrawObj->InvalidateObjRectWithSpaces();
                // #i41324# - notify background before
                // adjusting position
                if ( bNotify )
                {
                    // #i31573# - correction
                    // background of given drawing object.
                    lcl_NotifyBackgroundOfObj( *this, rObj, &aOldObjRect );
                }
                // #i31698# - determine layout direction
                // via draw frame format.
                SwFrameFormat::tLayoutDir eLayoutDir =
                                pAnchoredDrawObj->GetFrameFormat()->GetLayoutDir();
                // use geometry of drawing object
                tools::Rectangle aObjRect( rObj.GetSnapRect() );
                // If drawing object is a member of a group, the adjustment
                // of the positioning and the alignment attributes has to
                // be done for the top group object.
                if ( rObj.getParentSdrObjectFromSdrObject() )
                {
                    const SdrObject* pGroupObj = rObj.getParentSdrObjectFromSdrObject();
                    while ( pGroupObj->getParentSdrObjectFromSdrObject() )
                    {
                        pGroupObj = pGroupObj->getParentSdrObjectFromSdrObject();
                    }
                    // use geometry of drawing object
                    aObjRect = pGroupObj->GetSnapRect();

                    SwTextBoxHelper::synchronizeGroupTextBoxProperty(&SwTextBoxHelper::changeAnchor, GetFormat(), &const_cast<SdrObject&>(rObj));
                    SwTextBoxHelper::synchronizeGroupTextBoxProperty(&SwTextBoxHelper::syncTextBoxSize, GetFormat(), &const_cast<SdrObject&>(rObj));

                }
                SwTwips nXPosDiff(0);
                SwTwips nYPosDiff(0);
                switch ( eLayoutDir )
                {
                    case SwFrameFormat::HORI_L2R:
                    {
                        nXPosDiff = aObjRect.Left() - aOldObjRect.Left();
                        nYPosDiff = aObjRect.Top() - aOldObjRect.Top();
                    }
                    break;
                    case SwFrameFormat::HORI_R2L:
                    {
                        nXPosDiff = aOldObjRect.Right() - aObjRect.Right();
                        nYPosDiff = aObjRect.Top() - aOldObjRect.Top();
                    }
                    break;
                    case SwFrameFormat::VERT_R2L:
                    {
                        nXPosDiff = aObjRect.Top() - aOldObjRect.Top();
                        nYPosDiff = aOldObjRect.Right() - aObjRect.Right();
                    }
                    break;
                    default:
                    {
                        assert(!"<SwDrawContact::Changed_(..)> - unsupported layout direction");
                    }
                }
                SfxItemSetFixed<RES_VERT_ORIENT, RES_HORI_ORIENT> aSet( GetFormat()->GetDoc().GetAttrPool() );
                const SwFormatVertOrient& rVert = GetFormat()->GetVertOrient();
                if ( nYPosDiff != 0 )
                {
                    if ( rVert.GetRelationOrient() == text::RelOrientation::CHAR ||
                         rVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
                    {
                        nYPosDiff = -nYPosDiff;
                    }
                    aSet.Put( SwFormatVertOrient( rVert.GetPos()+nYPosDiff,
                                               text::VertOrientation::NONE,
                                               rVert.GetRelationOrient() ) );
                }

                const SwFormatHoriOrient& rHori = GetFormat()->GetHoriOrient();
                if ( !bAnchoredAsChar && nXPosDiff != 0 )
                {
                    aSet.Put( SwFormatHoriOrient( rHori.GetPos()+nXPosDiff,
                                               text::HoriOrientation::NONE,
                                               rHori.GetRelationOrient() ) );
                }

                if ( nYPosDiff ||
                     ( !bAnchoredAsChar && nXPosDiff != 0 ) )
                {
                    GetFormat()->GetDoc().SetFlyFrameAttr( *(GetFormat()), aSet );
                    // keep new object rectangle, to avoid multiple
                    // changes of the attributes by multiple event from
                    // the drawing layer - e.g. group objects and its members
                    // #i34748# - use new method
                    // <SwAnchoredDrawObject::SetLastObjRect(..)>.
                    const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj)
                                    ->SetLastObjRect( aObjRect );
                }
                else if ( aObjRect.GetSize() != aOldObjRect.GetSize() )
                {
                    InvalidateObjs_();
                    // #i35007# - notify anchor frame
                    // of as-character anchored object
                    if ( bAnchoredAsChar )
                    {
                        SwFrame* pAnchorFrame = const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj)->AnchorFrame();
                        if(pAnchorFrame)
                        {
                            pAnchorFrame->Prepare( PrepareHint::FlyFrameAttributesChanged, GetFormat() );
                        }
                    }

                    lcl_textBoxSizeNotify(GetFormat());
                }
                else if (eType == SdrUserCallType::Resize)
                    // Even if the bounding box of the shape didn't change,
                    // notify about the size change, as an adjustment change
                    // may affect the size of the underlying textbox.
                    lcl_textBoxSizeNotify(GetFormat());
            }

            // tdf#135198: keep text box together with its shape
            const SwPageFrame* rPageFrame = pAnchoredDrawObj->GetPageFrame();
            if (rPageFrame && rPageFrame->isFrameAreaPositionValid() && GetFormat()
                && GetFormat()->GetOtherTextBoxFormats())
            {
                SwDoc& rDoc = GetFormat()->GetDoc();

                // avoid Undo creation
                ::sw::UndoGuard const ug(rDoc.GetIDocumentUndoRedo());

                // hide any artificial "changes" made by synchronizing the textbox position
                const bool bEnableSetModified = rDoc.getIDocumentState().IsEnableSetModified();
                rDoc.getIDocumentState().SetEnableSetModified(false);

                SfxItemSetFixed<RES_VERT_ORIENT, RES_HORI_ORIENT, RES_ANCHOR, RES_ANCHOR>
                    aSyncSet( rDoc.GetAttrPool() );
                aSyncSet.Put(GetFormat()->GetHoriOrient());
                bool bRelToTableCell(false);
                aSyncSet.Put(SwFormatVertOrient(pAnchoredDrawObj->GetRelPosToPageFrame(false, bRelToTableCell).getY(),
                                                text::VertOrientation::NONE,
                                                text::RelOrientation::PAGE_FRAME));
                aSyncSet.Put(SwFormatAnchor(RndStdIds::FLY_AT_PAGE, rPageFrame->GetPhyPageNum()));

                auto pSdrObj = const_cast<SdrObject*>(&rObj);
                if (pSdrObj != GetFormat()->FindRealSdrObject())
                {
                    SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE>  aSet( rDoc.GetAttrPool() );

                    aSet.Put(aSyncSet);
                    aSet.Put(pSdrObj->GetMergedItem(RES_FRM_SIZE));
                    SwTextBoxHelper::syncFlyFrameAttr(*GetFormat(), aSet, pSdrObj);

                    SwTextBoxHelper::synchronizeGroupTextBoxProperty(
                        &SwTextBoxHelper::changeAnchor, GetFormat(),
                        GetFormat()->FindRealSdrObject());
                    SwTextBoxHelper::synchronizeGroupTextBoxProperty(
                        &SwTextBoxHelper::syncTextBoxSize, GetFormat(),
                        GetFormat()->FindRealSdrObject());
                }
                else
                    SwTextBoxHelper::syncFlyFrameAttr(*GetFormat(), aSyncSet, GetFormat()->FindRealSdrObject());

                rDoc.getIDocumentState().SetEnableSetModified(bEnableSetModified);
            }
        }
        break;
        case SdrUserCallType::ChangeAttr:
            if ( bNotify )
            {
                lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
            }
            break;
        default:
            break;
    }
}

namespace
{
    const SwFormatAnchor* lcl_getAnchorFormat( const SfxPoolItem& _rItem )
    {
        sal_uInt16 nWhich = _rItem.Which();
        const SwFormatAnchor* pAnchorFormat = nullptr;
        if ( RES_ANCHOR == nWhich )
        {
            pAnchorFormat = &static_cast<const SwFormatAnchor&>(_rItem);
        }
        return pAnchorFormat;
    }
    const SwFormatAnchor* lcl_getAnchorFormat( const SwAttrSetChg& _rItem )
    {
        return _rItem.GetChgSet()->GetItemIfSet( RES_ANCHOR, false );
    }
}

void SwDrawContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
{
    SwClient::SwClientNotify(rMod, rHint); // needed as SwContact::SwClientNotify doesn't explicitly call SwClient::SwClientNotify
    SwContact::SwClientNotify(rMod, rHint);
    if(SfxHintId::SwRemoveUnoObject == rHint.GetId())
    {
        // nothing to do
        // #i51474#
        GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
    }
    else if(SfxHintId::SwFormatChange == rHint.GetId()
            || SfxHintId::SwUpdateAttr == rHint.GetId())
    {
        // #i51474#
        GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
    }
    else if (rHint.GetId() == SfxHintId::SwLegacyModify
            || rHint.GetId() == SfxHintId::SwAttrSetChange
            || rHint.GetId() == SfxHintId::SwObjectDying)
    {
        SAL_WARN_IF(mbDisconnectInProgress, "sw.core""<SwDrawContact::Modify(..)> called during disconnection.");

        const SwFormatAnchor* pNewAnchorFormat = nullptr;
        const SwFormatAnchor* pOldAnchorFormat = nullptr;
        if (rHint.GetId() == SfxHintId::SwLegacyModify)
        {
            auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint);
            if (pLegacyHint->m_pNew)
                pNewAnchorFormat = lcl_getAnchorFormat(*pLegacyHint->m_pNew);
            if (pLegacyHint->m_pOld)
                pOldAnchorFormat = lcl_getAnchorFormat(*pLegacyHint->m_pOld);
        }
        else if (rHint.GetId() == SfxHintId::SwAttrSetChange)
        {
            auto pChangeHint = static_cast<const sw::AttrSetChangeHint*>(&rHint);
            if (pChangeHint->m_pNew)
                pNewAnchorFormat = lcl_getAnchorFormat(*pChangeHint->m_pNew);
            if (pChangeHint->m_pOld)
                pOldAnchorFormat = lcl_getAnchorFormat(*pChangeHint->m_pOld);
        }

        if(pNewAnchorFormat)
        {
            // Do not respond to a Reset Anchor!
            if(GetFormat()->GetAttrSet().GetItemState(RES_ANCHOR, false) == SfxItemState::SET)
            {
                // no connect to layout during disconnection
                if(!mbDisconnectInProgress)
                {
                    // determine old object rectangle of 'master' drawing object
                    // for notification
                    const tools::Rectangle* pOldRect = nullptr;
                    tools::Rectangle aOldRect;
                    if(GetAnchorFrame())
                    {
                        // --> #i36181# - include spacing in object
                        // rectangle for notification.
                        aOldRect = maAnchoredDrawObj.GetObjRectWithSpaces().SVRect();
                        pOldRect = &aOldRect;
                    }
                    // re-connect to layout due to anchor format change
                    ConnectToLayout(pNewAnchorFormat);
                    // notify background of drawing objects
                    lcl_NotifyBackgroundOfObj(*this, *GetMaster(), pOldRect);
                    NotifyBackgroundOfAllVirtObjs(pOldRect);

                    if(!pOldAnchorFormat || (pOldAnchorFormat->GetAnchorId() != pNewAnchorFormat->GetAnchorId()))
                    {
                        if(maAnchoredDrawObj.DrawObj())
                        {
                            // --> #i102752#
                            // assure that a ShapePropertyChangeNotifier exists
                            maAnchoredDrawObj.DrawObj()->notifyShapePropertyChange(u"AnchorType"_ustr);
                        }
                        else
                            SAL_WARN("sw.core""SwDrawContact::Modify: no draw object here?");
                    }
                }
            }
            else
                DisconnectFromLayout();
        }
        // --> #i62875# - no further notification, if not connected to Writer layout
        else if ( maAnchoredDrawObj.GetAnchorFrame() &&
                  maAnchoredDrawObj.GetDrawObj()->GetUserCall() )
        {
            bool bUpdateSortedObjsList(false);
            if (rHint.GetId() == SfxHintId::SwLegacyModify)
            {
                auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint);
                sal_uInt16 nWhich = pLegacyHint->m_pNew ? pLegacyHint->m_pNew->Which() : 0;
                switch(nWhich)
                {
                    case RES_UL_SPACE:
                    case RES_LR_SPACE:
                    case RES_HORI_ORIENT:
                    case RES_VERT_ORIENT:
                    case RES_FOLLOW_TEXT_FLOW: // #i28701# - add attribute 'Follow text flow'
                        break;
                    case RES_SURROUND:
                    case RES_OPAQUE:
                    case RES_WRAP_INFLUENCE_ON_OBJPOS:
                        // --> #i28701# - on change of wrapping style, hell|heaven layer,
                        // or wrapping style influence an update of the <SwSortedObjs> list,
                        // the drawing object is registered in, has to be performed. This is triggered
                        // by the 1st parameter of method call <InvalidateObjs_(..)>.
                        bUpdateSortedObjsList = true;
                        break;
                    default:
                        assert(!"<SwDraw Contact::Modify(..)> - unhandled attribute?");
                }
            }
            else if (rHint.GetId() == SfxHintId::SwAttrSetChange)
            {
                // #i35443#
                auto pChangeHint = static_cast<const sw::AttrSetChangeHint*>(&rHint);
                auto pChgSet = pChangeHint->m_pNew ? pChangeHint->m_pNew->GetChgSet() : nullptr;
                if(pChgSet && (pChgSet->GetItemState(RES_SURROUND, false) == SfxItemState::SET ||
                        pChgSet->GetItemState(RES_OPAQUE, false) == SfxItemState::SET ||
                        pChgSet->GetItemState(RES_WRAP_INFLUENCE_ON_OBJPOS, false) == SfxItemState::SET))
                    bUpdateSortedObjsList = true;
            }
            lcl_NotifyBackgroundOfObj(*this, *GetMaster(), nullptr);
            NotifyBackgroundOfAllVirtObjs(nullptr);
            InvalidateObjs_(bUpdateSortedObjsList);
        }

        // #i51474#
        GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
    }
    else if (rHint.GetId() == SfxHintId::SwDrawFrameFormat)
    {
        auto pDrawFrameFormatHint = static_cast<const sw::DrawFrameFormatHint*>(&rHint);
        switch(pDrawFrameFormatHint->m_eId)
        {
            case sw::DrawFrameFormatHintId::DYING:
                delete this;
                break;
            case sw::DrawFrameFormatHintId::PREPPASTING:
                MoveObjToVisibleLayer(GetMaster());
                break;
            case sw::DrawFrameFormatHintId::PREP_INSERT_FLY:
                InsertMasterIntoDrawPage();
                // #i40845# - follow-up of #i35635#
                // move object to visible layer
                MoveObjToVisibleLayer(GetMaster());
                // tdf#135661 InsertMasterIntoDrawPage may have created a new
                // SwXShape with null m_pFormat; fix that
                SwXShape::AddExistingShapeToFormat(*GetMaster());
                break;
            case sw::DrawFrameFormatHintId::PREP_DELETE_FLY:
                RemoveMasterFromDrawPage();
                break;
            case sw::DrawFrameFormatHintId::PAGE_OUT_OF_BOUNDS:
            case sw::DrawFrameFormatHintId::DELETE_FRAMES:
                DisconnectFromLayout();
                break;
            case sw::DrawFrameFormatHintId::MAKE_FRAMES:
                 ConnectToLayout();
                 break;
            case sw::DrawFrameFormatHintId::POST_RESTORE_FLY_ANCHOR:
                GetAnchoredObj(GetMaster())->MakeObjPos();
                break;
            default:
                ;
        }
    }
    else if (rHint.GetId() == SfxHintId::SwCheckDrawFrameFormatLayer)
    {
        auto pCheckDrawFrameFormatLayerHint = static_cast<const sw::CheckDrawFrameFormatLayerHint*>(&rHint);
        *(pCheckDrawFrameFormatLayerHint->m_bCheckControlLayer) |= (GetMaster() && CheckControlLayer(GetMaster()));
    }
    else if (rHint.GetId() == SfxHintId::SwContactChanged)
    {
        auto pContactChangedHint = static_cast<const sw::ContactChangedHint*>(&rHint);
        if(!*pContactChangedHint->m_ppObject)
            *pContactChangedHint->m_ppObject = GetMaster();
        auto pObject = *pContactChangedHint->m_ppObject;
        Changed(*pObject, SdrUserCallType::Delete, pObject->GetLastBoundRect());
    }
    else if (rHint.GetId() == SfxHintId::SwDrawFormatLayoutCopy)
    {
        auto pDrawFormatLayoutCopyHint = static_cast<const sw::DrawFormatLayoutCopyHint*>(&rHint);
        const SwDrawFrameFormat& rFormat = static_cast<const SwDrawFrameFormat&>(rMod);
        rtl::Reference<SdrObject> xNewObj =
                pDrawFormatLayoutCopyHint->m_rDestDoc.CloneSdrObj(
                        *GetMaster(),
                        pDrawFormatLayoutCopyHint->m_rDestDoc.IsCopyIsMove() && &pDrawFormatLayoutCopyHint->m_rDestDoc == &rFormat.GetDoc());
        new SwDrawContact(
                &pDrawFormatLayoutCopyHint->m_rDestFormat, xNewObj.get() );
        // #i49730# - notify draw frame format that position attributes are
        // already set, if the position attributes are already set at the
        // source draw frame format.
        if(rFormat.IsPosAttrSet())
            pDrawFormatLayoutCopyHint->m_rDestFormat.PosAttrSet();
    }
    else if (rHint.GetId() == SfxHintId::SwRestoreFlyAnchor)
    {
        auto pRestoreFlyAnchorHint = static_cast<const sw::RestoreFlyAnchorHint*>(&rHint);
        SdrObject* pObj = GetMaster();
        if(GetAnchorFrame() && !pObj->IsInserted())
        {
            auto pDrawModel = const_cast<SwDrawFrameFormat&>(static_cast<const SwDrawFrameFormat&&gt;(rMod)).GetDoc().getIDocumentDrawModelAccess().GetDrawModel();
            assert(pDrawModel);
            pDrawModel->GetPage(0)->InsertObject(pObj);
        }
        pObj->SetRelativePos(pRestoreFlyAnchorHint->m_aPos);
    }
    else if (rHint.GetId() == SfxHintId::SwCreatePortion)
    {
        auto pCreatePortionHint = static_cast<const sw::CreatePortionHint*>(&rHint);
        if(*pCreatePortionHint->m_ppContact)
            return;
        *pCreatePortionHint->m_ppContact = this// This is kind of ridiculous: the FrameFormat doesn't even hold a pointer to the contact itself,  but here we are leaking it out randomly
        if(!GetAnchorFrame())
        {
            // No direct positioning needed any more
            ConnectToLayout();
            // Move object to visible layer
            MoveObjToVisibleLayer(GetMaster());
        }
    }
    else if (rHint.GetId() == SfxHintId::SwCollectTextObjects)
    {
        auto pCollectTextObjectsHint = static_cast<const sw::CollectTextObjectsHint*>(&rHint);
        auto pSdrO = GetMaster();
        if(!pSdrO)
            return;
        if(dynamic_cast<const SdrObjGroup*>(pSdrO))
        {
            SdrObjListIter aListIter(*pSdrO, SdrIterMode::DeepNoGroups);
            //iterate inside of a grouped object
            while(aListIter.IsMore())
            {
                SdrTextObj* pTextObj = DynCastSdrTextObj(aListIter.Next());
                if(pTextObj && pTextObj->HasText())
                    pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
            }
        }
        else if(SdrTextObj* pTextObj = DynCastSdrTextObj(pSdrO))
        {
            if(pTextObj->HasText())
                pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
        }
    }
    else if (rHint.GetId() == SfxHintId::SwGetZOrder)
    {
        auto pGetZOrdnerHint = static_cast<const sw::GetZOrderHint*>(&rHint);
        auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
        if (pFormat && pFormat->Which() == RES_DRAWFRMFMT)
            pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
    }
    else if (rHint.GetId() == SfxHintId::SwGetObjectConnected)
    {
        auto pConnectedHint = static_cast<const sw::GetObjectConnectedHint*>(&rHint);
        pConnectedHint->m_risConnected |= (GetAnchorFrame() != nullptr);
    }
}

// #i26791#
// #i28701# - added parameter <_bUpdateSortedObjsList>
void SwDrawContact::InvalidateObjs_( const bool _bUpdateSortedObjsList )
{
    for(const auto& rpDrawVirtObj : maDrawVirtObjs)
    // invalidate position of existing 'virtual' drawing objects
    {
        SwDrawVirtObj* pDrawVirtObj(rpDrawVirtObj.get());
        // #i33313# - invalidation only for connected
        // 'virtual' drawing objects
        if ( pDrawVirtObj->IsConnected() )
        {
            pDrawVirtObj->AnchoredObj().InvalidateObjPos();
            // #i28701#
            if ( _bUpdateSortedObjsList )
            {
                pDrawVirtObj->AnchoredObj().UpdateObjInSortedList();
            }
        }
    }

    // invalidate position of 'master' drawing object
    SwAnchoredObject* pAnchoredObj = GetAnchoredObj( nullptr );
    pAnchoredObj->InvalidateObjPos();
    // #i28701#
    if ( _bUpdateSortedObjsList )
    {
        pAnchoredObj->UpdateObjInSortedList();
    }
}

void SwDrawContact::DisconnectFromLayout( bool _bMoveMasterToInvisibleLayer )
{
    mbDisconnectInProgress = true;

    // --> #i36181# - notify background of drawing object
    if ( _bMoveMasterToInvisibleLayer &&
         !(GetFormat()->GetDoc().IsInDtor()) &&
         GetAnchorFrame() && !GetAnchorFrame()->IsInDtor() )
    {
        const tools::Rectangle aOldRect( maAnchoredDrawObj.GetObjRectWithSpaces().SVRect() );
        lcl_NotifyBackgroundOfObj( *this, *GetMaster(), &aOldRect );
        NotifyBackgroundOfAllVirtObjs( &aOldRect );
    }

    // remove 'virtual' drawing objects from writer
    // layout and from drawing page
    for(auto& rpVirtDrawObj : maDrawVirtObjs)
    {
        rpVirtDrawObj->RemoveFromWriterLayout();
        rpVirtDrawObj->RemoveFromDrawingPage();
    }

    if ( maAnchoredDrawObj.GetAnchorFrame() )
    {
        maAnchoredDrawObj.AnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
    }

    if ( _bMoveMasterToInvisibleLayer && GetMaster() && GetMaster()->IsInserted() )
    {
        SdrViewIter::ForAllViews( GetMaster(),
            [this] (SdrView* pView)
            {
                pView->MarkObj( GetMaster(), pView->GetSdrPageView(), true );
            });

        // Instead of removing 'master' object from drawing page, move the
        // 'master' drawing object into the corresponding invisible layer.
        {
            //static_cast<SwFrameFormat*>(GetRegisteredIn())->getIDocumentDrawModelAccess()->GetDrawModel()->GetPage(0)->
            //                            RemoveObject( GetMaster()->GetOrdNum() );
            // #i18447# - in order to consider group object correct
            // use new method <SwDrawContact::MoveObjToInvisibleLayer(..)>
            MoveObjToInvisibleLayer( GetMaster() );
        }
    }

    mbDisconnectInProgress = false;
}

/// method to remove 'master' drawing object from drawing page.
void SwDrawContact::RemoveMasterFromDrawPage()
{
    if ( GetMaster() )
    {
        GetMaster()->SetUserCall( nullptr );
        if ( GetMaster()->IsInserted() )
        {
            static_cast<SwFrameFormat*>(GetRegisteredIn())->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
                                        RemoveObject( GetMaster()->GetOrdNum() );
        }
    }
}

// disconnect for a dedicated drawing object - could be 'master' or 'virtual'.
// a 'master' drawing object will disconnect a 'virtual' drawing object
// in order to take its place.
// #i19919# - no special case, if drawing object isn't in
// page header/footer, in order to get drawing objects in repeating table headers
// also working.
void SwDrawContact::DisconnectObjFromLayout( SdrObject* _pDrawObj )
{
    if ( auto pSwDrawVirtObj = dynamic_cast<SwDrawVirtObj*>( _pDrawObj) )
    {
        pSwDrawVirtObj->RemoveFromWriterLayout();
        pSwDrawVirtObj->RemoveFromDrawingPage();
    }
    else
    {
        const auto ppVirtDrawObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
                [] (const rtl::Reference<SwDrawVirtObj>& pObj) { return pObj->IsConnected(); }));

        if(ppVirtDrawObj != maDrawVirtObjs.end())
        {
            // replace found 'virtual' drawing object by 'master' drawing
            // object and disconnect the 'virtual' one
            SwDrawVirtObj* pDrawVirtObj(ppVirtDrawObj->get());
            SwFrame* pNewAnchorFrameOfMaster = pDrawVirtObj->AnchorFrame();
            // disconnect 'virtual' drawing object
            pDrawVirtObj->RemoveFromWriterLayout();
            pDrawVirtObj->RemoveFromDrawingPage();
            // disconnect 'master' drawing object from current frame
            GetAnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
            // re-connect 'master' drawing object to frame of found 'virtual'
            // drawing object.
            pNewAnchorFrameOfMaster->AppendDrawObj( maAnchoredDrawObj );
        }
        else
        {
            // no connected 'virtual' drawing object found. Thus, disconnect
            // completely from layout.
            DisconnectFromLayout();
        }
    }
}

static SwTextFrame* lcl_GetFlyInContentAnchor( SwTextFrame* _pProposedAnchorFrame,
                                   SwPosition const& rAnchorPos)
{
    SwTextFrame* pAct = _pProposedAnchorFrame;
    SwTextFrame* pTmp;
    TextFrameIndex const nTextOffset(_pProposedAnchorFrame->MapModelToViewPos(rAnchorPos));
    do
    {
        pTmp = pAct;
        pAct = pTmp->GetFollow();
    }
    while (pAct && nTextOffset >= pAct->GetOffset());
    return pTmp;
}

void SwDrawContact::ConnectToLayout( const SwFormatAnchor* pAnch )
{
    // *no* connect to layout during disconnection from layout.
    if ( mbDisconnectInProgress )
    {
        OSL_FAIL( "<SwDrawContact::ConnectToLayout(..)> called during disconnection.");
        return;
    }

    // --> #i33909# - *no* connect to layout, if 'master' drawing
    // object isn't inserted in the drawing page
    if ( !GetMaster()->IsInserted() )
    {
        OSL_FAIL( "<SwDrawContact::ConnectToLayout(..)> - master drawing object not inserted -> no connect to layout. Please inform od@openoffice.org" );
        return;
    }

    SwFrameFormat* pDrawFrameFormat = static_cast<SwFrameFormat*>(GetRegisteredIn());

    if( !pDrawFrameFormat->getIDocumentLayoutAccess().GetCurrentViewShell() )
        return;

    // remove 'virtual' drawing objects from writer
    // layout and from drawing page, and remove 'master' drawing object from
    // writer layout - 'master' object will remain in drawing page.
    DisconnectFromLayout( false );

    if ( !pAnch )
    {
        pAnch = &(pDrawFrameFormat->GetAnchor());
    }

    switch ( pAnch->GetAnchorId() )
    {
        case RndStdIds::FLY_AT_PAGE:
                {
                sal_uInt16 nPgNum = pAnch->GetPageNum();
                SwViewShell *pShell = pDrawFrameFormat->getIDocumentLayoutAccess().GetCurrentViewShell();
                if( !pShell )
                    break;
                SwRootFrame* pRoot = pShell->GetLayout();
                SwPageFrame *pPage = static_cast<SwPageFrame*>(pRoot->Lower());

                for ( sal_uInt16 i = 1; i < nPgNum && pPage; ++i )
                {
                    pPage = static_cast<SwPageFrame*>(pPage->GetNext());
                }

                if ( pPage )
                {
                    pPage->AppendDrawObj( maAnchoredDrawObj );
                }
                else
                    //Looks stupid but is allowed (compare SwFEShell::SetPageObjsNewPage)
                    pRoot->SetAssertFlyPages();
                }
                break;

        case RndStdIds::FLY_AT_CHAR:
        case RndStdIds::FLY_AT_PARA:
        case RndStdIds::FLY_AT_FLY:
        case RndStdIds::FLY_AS_CHAR:
            {
                if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
                {
                    ClrContourCache( GetMaster() );
                }
                // support drawing objects in header/footer,
                // but not control objects:
                // anchor at first found frame the 'master' object and
                // at the following frames 'virtual' drawing objects.
                // Note: method is similar to <SwFlyFrameFormat::MakeFrames(..)>
                sw::BroadcastingModify *pModify = nullptr;
                if( pAnch->GetAnchorNode() )
                {
                    if ( pAnch->GetAnchorId() == RndStdIds::FLY_AT_FLY )
                    {
                        SwNodeIndex aIdx( *pAnch->GetAnchorNode() );
                        SwContentNode* pCNd = SwNodes::GoNext(&aIdx);
                        if (SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pCNd).First())
                            pModify = pCNd;
                        else
                        {
                            const SwNode& rIdx = *pAnch->GetAnchorNode();
                            for(sw::SpzFrameFormat* pFlyFormat :*(pDrawFrameFormat->GetDoc().GetSpzFrameFormats()))
                            {
                                if( pFlyFormat->GetContent().GetContentIdx() &&
                                    rIdx == pFlyFormat->GetContent().GetContentIdx()->GetNode() )
                                {
                                    pModify = pFlyFormat;
                                    break;
                                }
                            }
                        }
                    }
                    else
                    {
                        pModify = pAnch->GetAnchorNode()->GetContentNode();
                    }
                }

                // #i29199# - It is possible, that
                // the anchor doesn't exist - E.g., reordering the
                // sub-documents in a master document.
                // Note: The anchor will be inserted later.
                if ( !pModify )
                {
                    // break to end of the current switch case.
                    break;
                }

                SwIterator<SwFrame, sw::BroadcastingModify, sw::IteratorMode::UnwrapMulti> aIter(*pModify);
                SwFrame* pAnchorFrameOfMaster = nullptr;
                for( SwFrame *pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
                {
                    // append drawing object, if
                    // (1) proposed anchor frame isn't a follow and...
                    const bool bFollow = pFrame->IsContentFrame() && static_cast<SwContentFrame*>(pFrame)->IsFollow();
                    if (bFollow)
                        continue;

                    // (2) drawing object isn't a control object to be anchored
                    //     in header/footer.
                    const bool bControlInHF = ::CheckControlLayer(GetMaster()) && pFrame->FindFooterOrHeader();
                    // tdf#129542 but make an exception for control objects so they can get added to just the first frame,
                    // the Master Anchor Frame and not the others
                    if (bControlInHF && pAnchorFrameOfMaster)
                        continue;

                    bool bAdd;
                    if (RndStdIds::FLY_AT_FLY == pAnch->GetAnchorId())
                        bAdd = true;
                    else
                    {
                        assert(pFrame->IsTextFrame());
                        bAdd = IsAnchoredObjShown(*static_cast<SwTextFrame*>(pFrame), *pAnch);
                    }

                    if( bAdd )
                    {
                        if ( RndStdIds::FLY_AT_FLY == pAnch->GetAnchorId() && !pFrame->IsFlyFrame() )
                        {
                            pFrame = pFrame->FindFlyFrame();
                            assert(pFrame);
                        }

                        // find correct follow for as character anchored objects
                        if ((pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR) &&
                             pFrame->IsTextFrame() )
                        {
                            pFrame = lcl_GetFlyInContentAnchor(
                                        static_cast<SwTextFrame*>(pFrame),
                                        *pAnch->GetContentAnchor());
                        }

                        if ( !pAnchorFrameOfMaster )
                        {
                            // append 'master' drawing object
                            pAnchorFrameOfMaster = pFrame;

                            const SwFrameFormat* pFlyFormat = nullptr;
                            if (!maAnchoredDrawObj.GetDrawObj()->IsGroupObject())
                            {
                                pFlyFormat = SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_DRAWFRMFMT);
                            }

                            if (pFlyFormat)
                            {
                                // This is a master draw object and it has an associated fly format.
                                // See if a fly frame is already inserted to the layout: if so, this
                                // master draw object should be ordered directly before the fly one.
                                if (const SwSortedObjs* pObjs = pFrame->GetDrawObjs())
                                {
                                    for (const SwAnchoredObject* pAnchoredObj : *pObjs)
                                    {
                                        if (pAnchoredObj->GetFrameFormat() == pFlyFormat)
                                        {
                                            SdrPage* pDrawPage = pAnchoredObj->GetDrawObj()->getSdrPageFromSdrObject();
                                            if (pDrawPage)
                                            {
                                                sal_uInt32 nOrdNum = pAnchoredObj->GetDrawObj()->GetOrdNum();
                                                if (maAnchoredDrawObj.GetDrawObj()->GetOrdNum() >= nOrdNum)
                                                {
                                                    pDrawPage->SetObjectOrdNum(maAnchoredDrawObj.GetDrawObj()->GetOrdNumDirect(), nOrdNum);
                                                }
                                                else
                                                {
                                                    pDrawPage->SetObjectOrdNum(nOrdNum, maAnchoredDrawObj.GetDrawObj()->GetOrdNumDirect() + 1);
                                                }
                                                break;
                                            }
                                        }
                                    }
                                }
                            }

                            pFrame->AppendDrawObj( maAnchoredDrawObj );
                        }
                        else
                        {
                            // append 'virtual' drawing object
                            SwDrawVirtObj* pDrawVirtObj = AddVirtObj(*pFrame);
                            if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
                            {
                                ClrContourCache( pDrawVirtObj );
                            }
                            pFrame->AppendDrawObj( pDrawVirtObj->AnchoredObj() );

                            pDrawVirtObj->ActionChanged();
                        }

                        if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
                        {
                            pFrame->InvalidatePrt();
                        }
                    }
                }
            }
            break;
        default:
            assert(!"Unknown Anchor.");
            break;
    }
    if ( GetAnchorFrame() )
    {
        ::setContextWritingMode( maAnchoredDrawObj.DrawObj(), GetAnchorFrame() );
        // #i26791# - invalidate objects instead of direct positioning
        InvalidateObjs_();
    }
}

/// insert 'master' drawing object into drawing page
void SwDrawContact::InsertMasterIntoDrawPage()
{
    if ( !GetMaster()->IsInserted() )
    {
        GetFormat()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)
                ->InsertObject( GetMaster(), GetMaster()->GetOrdNumDirect() );
    }
    GetMaster()->SetUserCall( this );
}

SwPageFrame* SwDrawContact::FindPage( const SwRect &rRect )
{
    // --> #i28701# - use method <GetPageFrame()>
    SwPageFrame* pPg = GetPageFrame();
    if ( !pPg && GetAnchorFrame() )
        pPg = GetAnchorFrame()->FindPageFrame();
    if ( pPg )
        pPg = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( rRect, pPg )));
    return pPg;
}

void SwDrawContact::ChkPage()
{
    if ( mbDisconnectInProgress )
    {
        OSL_FAIL( "<SwDrawContact::ChkPage()> called during disconnection." );
        return;
    }

    // --> #i28701#
    // tdf#156287: use anchor page, not current bound rectangle's page,
    // because an object can't move to a page other than its anchor anyway
    SwPageFrame* pPg = ( maAnchoredDrawObj.GetAnchorFrame() &&
                       maAnchoredDrawObj.GetAnchorFrame()->IsPageFrame() )
                     ? GetPageFrame()
                     : maAnchoredDrawObj.FindPageFrameOfAnchor();
    if ( GetPageFrame() == pPg )
        return;

    // if drawing object is anchor in header/footer a change of the page
    // is a dramatic change. Thus, completely re-connect to the layout
    if ( maAnchoredDrawObj.GetAnchorFrame() &&
         maAnchoredDrawObj.GetAnchorFrame()->FindFooterOrHeader() )
    {
        ConnectToLayout();
    }
    else
    {
        // --> #i28701# - use methods <GetPageFrame()> and <SetPageFrame>
        maAnchoredDrawObj.RegisterAtPage(*pPg);
        maAnchoredDrawObj.SetPageFrame( pPg );
    }
}

// Important note:
// method is called by method <SwDPage::ReplaceObject(..)>, which called its
// corresponding superclass method <FmFormPage::ReplaceObject(..)>.
// Note: 'master' drawing object *has* to be connected to layout triggered
//       by the caller of this, if method is called.
void SwDrawContact::ChangeMasterObject(SdrObject* pNewMaster)
{
    DisconnectFromLayout( false );
    // consider 'virtual' drawing objects
    RemoveAllVirtObjs();

    GetMaster()->SetUserCall( nullptr );
    if(pNewMaster)
        maAnchoredDrawObj.SetDrawObj(*pNewMaster);
    else
        mbMasterObjCleared = true;
    GetMaster()->SetUserCall( this );

    InvalidateObjs_();
}

/// get data collection of anchored objects, handled by with contact
void SwDrawContact::GetAnchoredObjs(std::vector<SwAnchoredObject*>& o_rAnchoredObjs) const
{
    o_rAnchoredObjs.push_back(const_cast<SwAnchoredDrawObject*>(&maAnchoredDrawObj));

    for(auto& rpDrawVirtObj : maDrawVirtObjs)
        o_rAnchoredObjs.push_back(&rpDrawVirtObj->AnchoredObj());
}

// AW: own sdr::contact::ViewContact (VC) sdr::contact::ViewObjectContact (VOC) needed
// since offset is defined different from SdrVirtObj's sdr::contact::ViewContactOfVirtObj.
// For paint, that offset is used by setting at the OutputDevice; for primitives this is
// not possible since we have no OutputDevice, but define the geometry itself.

namespace sdr::contact
{
        namespace {

        class VOCOfDrawVirtObj : public ViewObjectContactOfSdrObj
        {
        protected:
            /**
             * This method is responsible for creating the graphical visualisation data which is
             * stored/cached in the local primitive. Default gets view-independent Primitive from
             * the ViewContact using ViewContact::getViewIndependentPrimitive2DContainer(), takes
             * care of visibility, handles glue and ghosted.
             *
             * This method will not handle included hierarchies and not check geometric visibility.
             */

            virtual void createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;

        public:
            VOCOfDrawVirtObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
            :   ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
            {
            }
        };

        class VCOfDrawVirtObj : public ViewContactOfVirtObj
        {
        protected:
            /** Create an Object-Specific ViewObjectContact, set ViewContact and ObjectContact.
             *
             * Always needs to return something. Default is to create a standard ViewObjectContact
             * containing the given ObjectContact and *this.
             */

            virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact&&nbsp;rObjectContact) override;

        public:
            /// basic constructor, used from SdrObject.
            explicit VCOfDrawVirtObj(SwDrawVirtObj& rObj)
            :   ViewContactOfVirtObj(rObj)
            {
            }

            /// access to SwDrawVirtObj
            SwDrawVirtObj& GetSwDrawVirtObj() const
            {
                return static_cast<SwDrawVirtObj&>(mrObject);
            }
        };

        }
// end of namespace sdr::contact

namespace sdr::contact
{
        /// recursively collect primitive data from given VOC with given offset
        static void impAddPrimitivesFromGroup(const ViewObjectContact& rVOC, const basegfx::B2DHomMatrix& rOffsetMatrix, const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DContainer& rxTarget)
        {
            const sal_uInt32 nSubHierarchyCount(rVOC.GetViewContact().GetObjectCount());

            for(sal_uInt32 a(0); a < nSubHierarchyCount; a++)
            {
                const ViewObjectContact& rCandidate(rVOC.GetViewContact().GetViewContact(a).GetViewObjectContact(rVOC.GetObjectContact()));

                if(rCandidate.GetViewContact().GetObjectCount())
                {
                    // is a group object itself, call recursively
                    impAddPrimitivesFromGroup(rCandidate, rOffsetMatrix, rDisplayInfo, rxTarget);
                }
                else
                {
                    // single object, add primitives; check model-view visibility
                    if(rCandidate.isPrimitiveVisible(rDisplayInfo))
                    {
                        drawinglayer::primitive2d::Primitive2DContainer aNewSequence(rCandidate.getPrimitive2DSequence(rDisplayInfo));

                        if(!aNewSequence.empty())
                        {
                            // get ranges
                            const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(rCandidate.GetObjectContact().getViewInformation2D());
                            const basegfx::B2DRange& aViewRange(rViewInformation2D.getViewport());
                            basegfx::B2DRange aObjectRange(rCandidate.getObjectRange());

                            // correct with virtual object's offset
                            aObjectRange.transform(rOffsetMatrix);

                            // check geometrical visibility (with offset)
                            if(!aViewRange.overlaps(aObjectRange))
                            {
                                // not visible, release
                                aNewSequence.clear();
                            }
                        }

                        if(!aNewSequence.empty())
                        {
                            rxTarget.append(std::move(aNewSequence));
                        }
                    }
                }
            }
        }

        void VOCOfDrawVirtObj::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
        {
            // this may be called for painting where it's a precondition that
            // isPrimitiveVisible() is true, or for e.g. getObjectRange() (even
            // during layout) where there are no preconditions...
            // nasty corner case: override to clear page frame to disable the
            // sub-objects' anchor check, because their anchor is always on
            // the first page that the page style is applied to
            DisplayInfo aDisplayInfo(rDisplayInfo);
            aDisplayInfo.SetWriterPageFrame(basegfx::B2IRectangle());
            const VCOfDrawVirtObj& rVC = static_castconst VCOfDrawVirtObj& >(GetViewContact());
            const SdrObject& rReferencedObject = rVC.GetSwDrawVirtObj().GetReferencedObj();
            drawinglayer::primitive2d::Primitive2DContainer xRetval;

            // create offset transformation
            basegfx::B2DHomMatrix aOffsetMatrix;
            const Point aLocalOffset(rVC.GetSwDrawVirtObj().GetOffset());

            if(aLocalOffset.X() || aLocalOffset.Y())
            {
                aOffsetMatrix.set(0, 2, aLocalOffset.X());
                aOffsetMatrix.set(1, 2, aLocalOffset.Y());
            }

            if(dynamic_cast<const SdrObjGroup*>( &rReferencedObject) !=  nullptr)
            {
                // group object. Since the VOC/OC/VC hierarchy does not represent the
                // hierarchy virtual objects when they have group objects
                // (ViewContactOfVirtObj::GetObjectCount() returns null for that purpose)
                // to avoid multiple usages of VOCs (which would not work), the primitives
                // for the sub-hierarchy need to be collected here

                // Get the VOC of the referenced object (the Group) and fetch primitives from it
                const ViewObjectContact& rVOCOfRefObj = rReferencedObject.GetViewContact().GetViewObjectContact(GetObjectContact());
                impAddPrimitivesFromGroup(rVOCOfRefObj, aOffsetMatrix, aDisplayInfo, xRetval);
            }
            else
            {
                // single object, use method from referenced object to get the Primitive2DSequence
                rReferencedObject.GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
            }

            if(!xRetval.empty())
            {
                // create transform primitive
                xRetval = drawinglayer::primitive2d::Primitive2DContainer {
                    new drawinglayer::primitive2d::TransformPrimitive2D(aOffsetMatrix, std::move(xRetval))
                };
            }

            rVisitor.visit(xRetval);
        }

        ViewObjectContact& VCOfDrawVirtObj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
        {
            return *(new VOCOfDrawVirtObj(rObjectContact, *this));
        }

// end of namespace sdr::contact

/// implementation of class <SwDrawVirtObj>
std::unique_ptr<sdr::contact::ViewContact> SwDrawVirtObj::CreateObjectSpecificViewContact()
{
    return std::make_unique<sdr::contact::VCOfDrawVirtObj>(*this);
}

SwDrawVirtObj::SwDrawVirtObj(
    SdrModel& rSdrModel,
    SdrObject& _rNewObj,
    SwDrawContact& _rDrawContact)
:   SdrVirtObj(rSdrModel, _rNewObj ),
    mrDrawContact(_rDrawContact)
{
    // #i26791#
    maAnchoredDrawObj.SetDrawObj( *this );

    // #i35635# - set initial position out of sight
    NbcMove( Size( -16000, -16000 ) );
}

SwDrawVirtObj::SwDrawVirtObj(
    SdrModel& rSdrModel,
    SwDrawVirtObj const & rSource)
:   SdrVirtObj(rSdrModel, rSource),
    mrDrawContact(rSource.mrDrawContact)
{
    // #i26791#
    maAnchoredDrawObj.SetDrawObj( *this );

    // #i35635# - set initial position out of sight
    NbcMove( Size( -16000, -16000 ) );

    // Note: Members <maAnchoredDrawObj> and <mrDrawContact>
    //       haven't to be considered.
}

SwDrawVirtObj::~SwDrawVirtObj()
{
}

rtl::Reference<SdrObject> SwDrawVirtObj::CloneSdrObject(SdrModel& rTargetModel) const
{
    return new SwDrawVirtObj(rTargetModel, *this);
}

const SwFrame* SwDrawVirtObj::GetAnchorFrame() const
{
    // #i26791# - use new member <maAnchoredDrawObj>
    return maAnchoredDrawObj.GetAnchorFrame();
}

SwFrame* SwDrawVirtObj::AnchorFrame()
{
    // #i26791# - use new member <maAnchoredDrawObj>
    return maAnchoredDrawObj.AnchorFrame();
}

void SwDrawVirtObj::RemoveFromWriterLayout()
{
    // remove contact object from frame for 'virtual' drawing object
    // #i26791# - use new member <maAnchoredDrawObj>
    if ( maAnchoredDrawObj.GetAnchorFrame() )
    {
        maAnchoredDrawObj.AnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
    }
}

void SwDrawVirtObj::AddToDrawingPage(SwFrame const& rAnchorFrame)
{
    // determine 'master'
    SdrObject* pOrgMasterSdrObj = mrDrawContact.GetMaster();

    // insert 'virtual' drawing object into page, set layer and user call.
    SdrPage* pDrawPg = pOrgMasterSdrObj->getSdrPageFromSdrObject();
    // default: insert before master object
    auto nOrdNum(GetReferencedObj().GetOrdNum());

    // maintain invariant that a shape's textbox immediately follows the shape
    // also for the multiple SdrDrawVirtObj created for shapes in header/footer
    if (SwFrameFormat const*const pFlyFormat =
            SwTextBoxHelper::getOtherTextBoxFormat(mrDrawContact.GetFormat(), RES_DRAWFRMFMT))
    {
        // this is for the case when the flyframe SdrVirtObj is created before the draw one
        if (SwSortedObjs const*const pObjs = rAnchorFrame.GetDrawObjs())
        {
            for (SwAnchoredObject const*const pAnchoredObj : *pObjs)
            {
                if (pAnchoredObj->GetFrameFormat() == pFlyFormat)
                {
                    assert(dynamic_cast<SwFlyFrame const*>(pAnchoredObj));

                    if (pAnchoredObj->GetDrawObj()->GetOrdNum() >= GetReferencedObj().GetOrdNum())
                    {
                        // This virtual draw object has an associated fly one, but the fly's index
                        // is not below the masters, fix it up.
                        if (pDrawPg)
                        {
                            pDrawPg->SetObjectOrdNum(pAnchoredObj->GetDrawObj()->GetOrdNumDirect(), GetReferencedObj().GetOrdNum());
                        }
                    }

                    nOrdNum = pAnchoredObj->GetDrawObj()->GetOrdNum();
                    // the master SdrObj should have the highest index
                    assert(nOrdNum < GetReferencedObj().GetOrdNum());
                    break;
                }
            }
        }
        // this happens on initial insertion, the draw object is created first
        SAL_INFO_IF(GetReferencedObj().GetOrdNum() == nOrdNum, "sw""AddToDrawingPage: cannot find SdrObject for text box's shape");
    }

    // #i27030# - apply order number of referenced object
    if ( nullptr != pDrawPg )
    {
        // #i27030# - apply order number of referenced object
        pDrawPg->InsertObject(this, nOrdNum);
    }
    else
    {
        pDrawPg = getSdrPageFromSdrObject();
        if ( pDrawPg )
        {
            pDrawPg->SetObjectOrdNum(GetOrdNumDirect(), nOrdNum);
        }
        else
        {
            SetOrdNum(nOrdNum);
        }
    }
    SetUserCall( &mrDrawContact );
}

void SwDrawVirtObj::RemoveFromDrawingPage()
{
    SetUserCall( nullptr );
    if ( getSdrPageFromSdrObject() )
    {
        getSdrPageFromSdrObject()->RemoveObject( GetOrdNum() );
    }
}

/// Is 'virtual' drawing object connected to writer layout and to drawing layer?
bool SwDrawVirtObj::IsConnected() const
{
    bool bRetVal = GetAnchorFrame() &&
                   ( getSdrPageFromSdrObject() && GetUserCall() );

    return bRetVal;
}

void SwDrawVirtObj::NbcSetAnchorPos(const Point& rPnt)
{
    SdrObject::NbcSetAnchorPos( rPnt );
}

// #i97197#
// the methods relevant for positioning

const tools::Rectangle& SwDrawVirtObj::GetCurrentBoundRect() const
{
    if (getOutRectangle().IsEmpty())
    {
        const_cast<SwDrawVirtObj*>(this)->RecalcBoundRect();
    }

    return getOutRectangle();
}

const tools::Rectangle& SwDrawVirtObj::GetLastBoundRect() const
{
    return getOutRectangle();
}

Point SwDrawVirtObj::GetOffset() const
{
    // do NOT use IsEmpty() here, there is already a useful offset
    // in the position
    if (getOutRectangle() == tools::Rectangle())
    {
        return Point();
    }
    else
    {
        return getOutRectangle().TopLeft() - GetReferencedObj().GetCurrentBoundRect().TopLeft();
    }
}

void SwDrawVirtObj::SetBoundRectDirty()
{
    // do nothing to not lose model information in aOutRect
}

void SwDrawVirtObj::RecalcBoundRect()
{
    // #i26791# - switch order of calling <GetOffset()> and
    // <ReferencedObj().GetCurrentBoundRect()>, because <GetOffset()> calculates
    // its value by the 'BoundRect' of the referenced object.

    const Point aOffset(GetOffset());
    setOutRectangle(ReferencedObj().GetCurrentBoundRect() + aOffset);
}

basegfx::B2DPolyPolygon SwDrawVirtObj::TakeXorPoly() const
{
    basegfx::B2DPolyPolygon aRetval(mxRefObj->TakeXorPoly());
    aRetval.translate(GetOffset().X(), GetOffset().Y());

    return aRetval;
}

basegfx::B2DPolyPolygon SwDrawVirtObj::TakeContour() const
{
    basegfx::B2DPolyPolygon aRetval(mxRefObj->TakeContour());
    aRetval.translate(GetOffset().X(), GetOffset().Y());

    return aRetval;
}

void SwDrawVirtObj::AddToHdlList(SdrHdlList& rHdlList) const
{
    SdrHdlList tmpList(nullptr);
    mxRefObj->AddToHdlList(tmpList);

    size_t cnt = tmpList.GetHdlCount();
    for(size_t i=0; i < cnt; ++i)
    {
        SdrHdl* pHdl = tmpList.GetHdl(i);
        Point aP(pHdl->GetPos() + GetOffset());
        pHdl->SetPos(aP);
    }
    tmpList.MoveTo(rHdlList);
}

void SwDrawVirtObj::NbcMove(const Size& rSiz)
{
    SdrObject::NbcMove( rSiz );
}

void SwDrawVirtObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
{
    mxRefObj->NbcResize(rRef - GetOffset(), xFact, yFact);
    SetBoundAndSnapRectsDirty();
}

void SwDrawVirtObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
{
    mxRefObj->NbcRotate(rRef - GetOffset(), nAngle, sn, cs);
    SetBoundAndSnapRectsDirty();
}

void SwDrawVirtObj::NbcMirror(const Point& rRef1, const Point& rRef2)
{
    mxRefObj->NbcMirror(rRef1 - GetOffset(), rRef2 - GetOffset());
    SetBoundAndSnapRectsDirty();
}

void SwDrawVirtObj::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
{
    mxRefObj->NbcShear(rRef - GetOffset(), nAngle, tn, bVShear);
    SetBoundAndSnapRectsDirty();
}

void SwDrawVirtObj::Move(const Size& rSiz)
{
    SdrObject::Move( rSiz );
}

void SwDrawVirtObj::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative)
{
    if(xFact.GetNumerator() != xFact.GetDenominator() || yFact.GetNumerator() != yFact.GetDenominator())
    {
        tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
        mxRefObj->Resize(rRef - GetOffset(), xFact, yFact, bUnsetRelative);
        SetBoundAndSnapRectsDirty();
        SendUserCall(SdrUserCallType::Resize, aBoundRect0);
    }
}

void SwDrawVirtObj::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
{
    if(nAngle)
    {
        tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
        mxRefObj->Rotate(rRef - GetOffset(), nAngle, sn, cs);
        SetBoundAndSnapRectsDirty();
        SendUserCall(SdrUserCallType::Resize, aBoundRect0);
    }
}

void SwDrawVirtObj::Mirror(const Point& rRef1, const Point& rRef2)
{
    tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
    mxRefObj->Mirror(rRef1 - GetOffset(), rRef2 - GetOffset());
    SetBoundAndSnapRectsDirty();
    SendUserCall(SdrUserCallType::Resize, aBoundRect0);
}

void SwDrawVirtObj::Shear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
{
    if(nAngle)
    {
        tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
        mxRefObj->Shear(rRef - GetOffset(), nAngle, tn, bVShear);
        SetBoundAndSnapRectsDirty();
        SendUserCall(SdrUserCallType::Resize, aBoundRect0);
    }
}

void SwDrawVirtObj::RecalcSnapRect()
{
    maSnapRect = mxRefObj->GetSnapRect();
    maSnapRect += GetOffset();
}

const tools::Rectangle& SwDrawVirtObj::GetSnapRect() const
{
    const_cast<SwDrawVirtObj*>(this)->maSnapRect = mxRefObj->GetSnapRect();
    const_cast<SwDrawVirtObj*>(this)->maSnapRect += GetOffset();

    return maSnapRect;
}

void SwDrawVirtObj::SetSnapRect(const tools::Rectangle& rRect)
{
    tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
    tools::Rectangle aR(rRect);
    aR -= GetOffset();
    mxRefObj->SetSnapRect(aR);
    SetBoundAndSnapRectsDirty();
    SendUserCall(SdrUserCallType::Resize, aBoundRect0);
}

void SwDrawVirtObj::NbcSetSnapRect(const tools::Rectangle& rRect)
{
    tools::Rectangle aR(rRect);
    aR -= GetOffset();
    SetBoundAndSnapRectsDirty();
    mxRefObj->NbcSetSnapRect(aR);
}

const tools::Rectangle& SwDrawVirtObj::GetLogicRect() const
{
    const_cast<SwDrawVirtObj*>(this)->maSnapRect = mxRefObj->GetLogicRect();
    const_cast<SwDrawVirtObj*>(this)->maSnapRect += GetOffset();

    return maSnapRect;
}

void SwDrawVirtObj::SetLogicRect(const tools::Rectangle& rRect)
{
    tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
    tools::Rectangle aR(rRect);
    aR -= GetOffset();
    mxRefObj->SetLogicRect(aR);
    SetBoundAndSnapRectsDirty();
    SendUserCall(SdrUserCallType::Resize, aBoundRect0);
}

void SwDrawVirtObj::NbcSetLogicRect(const tools::Rectangle& rRect, bool bAdaptTextMinSize)
{
    tools::Rectangle aR(rRect);
    aR -= GetOffset();
    mxRefObj->NbcSetLogicRect(aR, bAdaptTextMinSize);
    SetBoundAndSnapRectsDirty();
}

Point SwDrawVirtObj::GetSnapPoint(sal_uInt32 i) const
{
    Point aP(mxRefObj->GetSnapPoint(i));
    aP += GetOffset();

    return aP;
}

Point SwDrawVirtObj::GetPoint(sal_uInt32 i) const
{
    return mxRefObj->GetPoint(i) + GetOffset();
}

void SwDrawVirtObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
{
    Point aP(rPnt);
    aP -= GetOffset();
    mxRefObj->SetPoint(aP, i);
    SetBoundAndSnapRectsDirty();
}

bool SwDrawVirtObj::HasTextEdit() const
{
    return mxRefObj->HasTextEdit();
}

// override 'layer' methods for 'virtual' drawing object to assure
// that layer of 'virtual' object is the layer of the referenced object.
SdrLayerID SwDrawVirtObj::GetLayer() const
{
    return GetReferencedObj().GetLayer();
}

void SwDrawVirtObj::NbcSetLayer(SdrLayerID nLayer)
{
    ReferencedObj().NbcSetLayer( nLayer );
    SdrVirtObj::NbcSetLayer( ReferencedObj().GetLayer() );
}

void SwDrawVirtObj::SetLayer(SdrLayerID nLayer)
{
    ReferencedObj().SetLayer( nLayer );
    SdrVirtObj::NbcSetLayer( ReferencedObj().GetLayer() );
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5 in Prozent
C=88 H=95 G=91

¤ Dauer der Verarbeitung: 0.42 Sekunden  (vorverarbeitet am  2026-05-06) ¤

*© 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge