Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/svx/source/svdraw/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 104 kB image not shown  

Quelle  svdobj.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 <svx/svdobj.hxx>
#include <config_features.h>

#include <sal/config.h>

#include <com/sun/star/text/RelOrientation.hpp>
#include <com/sun/star/frame/XTerminateListener.hpp>
#include <com/sun/star/frame/Desktop.hpp>

#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/range/b2drange.hxx>
#include <drawinglayer/processor2d/contourextractor2d.hxx>
#include <drawinglayer/processor2d/linegeometryextractor2d.hxx>
#include <comphelper/processfactory.hxx>
#include <editeng/editeng.hxx>
#include <editeng/outlobj.hxx>
#include <o3tl/deleter.hxx>
#include <math.h>
#include <svl/grabbagitem.hxx>
#include <tools/bigint.hxx>
#include <tools/helpers.hxx>
#include <comphelper/configuration.hxx>
#include <vcl/canvastools.hxx>
#include <vcl/ptrstyle.hxx>
#include <vector>

#include <svx/svdotable.hxx>

#include <svx/sdr/contact/displayinfo.hxx>
#include <sdr/contact/objectcontactofobjlistpainter.hxx>
#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
#include <sdr/properties/emptyproperties.hxx>
#include <svx/annotation/ObjectAnnotationData.hxx>
#include <svx/sdrhittesthelper.hxx>
#include <svx/sdrobjectuser.hxx>
#include <svx/sdrobjectfilter.hxx>
#include <svx/svddrag.hxx>
#include <svx/svdetc.hxx>
#include <svx/svdhdl.hxx>
#include <svx/svditer.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdoashp.hxx>
#include <svx/svdocapt.hxx>
#include <svx/svdocirc.hxx>
#include <svx/svdoedge.hxx>
#include <svx/svdograf.hxx>
#include <svx/svdogrp.hxx>
#include <svx/svdomeas.hxx>
#include <svx/svdomedia.hxx>
#include <svx/svdoole2.hxx>
#include <svx/svdopage.hxx>
#include <svx/svdopath.hxx>
#include <svx/svdorect.hxx>
#include <svx/svdotext.hxx>
#include <svx/svdouno.hxx>
#include <svx/svdovirt.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdpool.hxx>
#include <svx/strings.hrc>
#include <svx/dialmgr.hxx>
#include <svx/svdtrans.hxx>
#include <svx/svdundo.hxx>
#include <svx/svdview.hxx>
#include <sxlayitm.hxx>
#include <sxlogitm.hxx>
#include <sxmovitm.hxx>
#include <sxoneitm.hxx>
#include <sxopitm.hxx>
#include <sxreoitm.hxx>
#include <sxrooitm.hxx>
#include <sxsaitm.hxx>
#include <sxsoitm.hxx>
#include <sxtraitm.hxx>
#include <svx/unopage.hxx>
#include <svx/unoshape.hxx>
#include <svx/xfillit0.hxx>
#include <svx/xflclit.hxx>
#include <svx/xfltrit.hxx>
#include <svx/xlineit0.hxx>
#include <svx/xlnclit.hxx>
#include <svx/xlnedwit.hxx>
#include <svx/xlnstwit.hxx>
#include <svx/xlntrit.hxx>
#include <svx/xlnwtit.hxx>
#include <svx/svdglue.hxx>
#include <svx/svdsob.hxx>
#include <svdobjplusdata.hxx>
#include <svdobjuserdatalist.hxx>

#include <optional>
#include <libxml/xmlwriter.h>
#include <memory>

#include <svx/scene3d.hxx>
#include <rtl/character.hxx>
#include <tools/UnitConversion.hxx>
#include <o3tl/string_view.hxx>
#include <tools/lazydelete.hxx>

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


SdrObjUserCall::~SdrObjUserCall()
{
}

void SdrObjUserCall::Changed(const SdrObject& /*rObj*/, SdrUserCallType /*eType*/, const tools::Rectangle& /*rOldBoundRect*/)
{
}

void const* SdrObjUserCall::GetPDFAnchorStructureElementKey(SdrObject const&)
{
    return nullptr;
}

SdrObjMacroHitRec::SdrObjMacroHitRec() :
    pVisiLayer(nullptr),
    pPageView(nullptr),
    nTol(0) {}


SdrObjUserData::SdrObjUserData(SdrInventor nInv, sal_uInt16 nId) :
    m_nInventor(nInv),
    m_nIdentifier(nId) {}

SdrObjUserData::SdrObjUserData(const SdrObjUserData& rData) :
    m_nInventor(rData.m_nInventor),
    m_nIdentifier(rData.m_nIdentifier) {}

SdrObjUserData::~SdrObjUserData() {}

SdrObjGeoData::SdrObjGeoData():
    bMovProt(false),
    bSizProt(false),
    bNoPrint(false),
    bClosedObj(false),
    mbVisible(true),
    mnLayerID(0)
{
}

SdrObjGeoData::~SdrObjGeoData()
{
}

SdrObjTransformInfoRec::SdrObjTransformInfoRec() :
    bMoveAllowed(true),
    bResizeFreeAllowed(true),
    bResizePropAllowed(true),
    bRotateFreeAllowed(true),
    bRotate90Allowed(true),
    bMirrorFreeAllowed(true),
    bMirror45Allowed(true),
    bMirror90Allowed(true),
    bTransparenceAllowed(true),
    bShearAllowed(true),
    bEdgeRadiusAllowed(true),
    bNoOrthoDesired(true),
    bNoContortion(true),
    bCanConvToPath(true),
    bCanConvToPoly(true),
    bCanConvToContour(false),
    bCanConvToPathLineToArea(true),
    bCanConvToPolyLineToArea(true) {}

struct SdrObject::Impl
{
    sdr::ObjectUserVector maObjectUsers;
    std::optional<double> mnRelativeWidth;
    std::optional<double> mnRelativeHeight;
    sal_Int16               meRelativeWidthRelation;
    sal_Int16               meRelativeHeightRelation;

    Impl() :
        meRelativeWidthRelation(text::RelOrientation::PAGE_FRAME),
        meRelativeHeightRelation(text::RelOrientation::PAGE_FRAME) {}
};

const std::shared_ptr< svx::diagram::IDiagramHelper >& SdrObject::getDiagramHelper() const
{
    static std::shared_ptr< svx::diagram::IDiagramHelper > aEmpty;
    return aEmpty;
}

// BaseProperties section

sdr::properties::BaseProperties& SdrObject::GetProperties() const
{
    if(!mpProperties)
    {
        // CAUTION(!) Do *not* call this during SdrObject construction,
        // that will lead to wrong type-casts (dependent on constructor-level)
        // and thus eventually create the wrong sdr::properties (!). Is there
        // a way to check if on the stack is a SdrObject-constructor (?)
        const_cast< SdrObject* >(this)->mpProperties =
            const_cast< SdrObject* >(this)->CreateObjectSpecificProperties();
    }

    return *mpProperties;
}


// ObjectUser section

void SdrObject::AddObjectUser(sdr::ObjectUser& rNewUser)
{
    mpImpl->maObjectUsers.push_back(&rNewUser);
}

void SdrObject::RemoveObjectUser(sdr::ObjectUser& rOldUser)
{
    const sdr::ObjectUserVector::iterator aFindResult =
        std::find(mpImpl->maObjectUsers.begin(), mpImpl->maObjectUsers.end(), &rOldUser);
    if (aFindResult != mpImpl->maObjectUsers.end())
    {
        mpImpl->maObjectUsers.erase(aFindResult);
    }
}


// DrawContact section

std::unique_ptr<sdr::contact::ViewContact> SdrObject::CreateObjectSpecificViewContact()
{
    return std::make_unique<sdr::contact::ViewContactOfSdrObj>(*this);
}

sdr::contact::ViewContact& SdrObject::GetViewContact() const
{
    if(!mpViewContact)
    {
        const_cast< SdrObject* >(this)->mpViewContact =
            const_cast< SdrObject* >(this)->CreateObjectSpecificViewContact();
    }

    return *mpViewContact;
}

// DrawContact support: Methods for handling Object changes
void SdrObject::ActionChanged() const
{
    // Do necessary ViewContact actions
    GetViewContact().ActionChanged();
}

SdrPage* SdrObject::getSdrPageFromSdrObject() const
{
    if (SdrObjList* pParentList = getParentSdrObjListFromSdrObject())
    {
        return pParentList->getSdrPageFromSdrObjList();
    }

    return nullptr;
}

SdrModel& SdrObject::getSdrModelFromSdrObject() const
{
    return mrSdrModelFromSdrObject;
}

void SdrObject::setParentOfSdrObject(SdrObjList* pNewObjList)
{
    assert(!pNewObjList || mpParentOfSdrObject != pNewObjList);
    if(mpParentOfSdrObject == pNewObjList)
        return;
    // we need to be removed from the old parent before we are attached to the new parent
    assert(bool(mpParentOfSdrObject) != bool(pNewObjList) && "may only transition empty->full or full->empty");

    // remember current page
    SdrPage* pOldPage(getSdrPageFromSdrObject());

    // set new parent
    mpParentOfSdrObject = pNewObjList;

    // get new page
    SdrPage* pNewPage(getSdrPageFromSdrObject());

    // broadcast page change over objects if needed
    if(pOldPage != pNewPage)
    {
        handlePageChange(pOldPage, pNewPage);
    }
}

SdrObjList* SdrObject::getParentSdrObjListFromSdrObject() const
{
    return mpParentOfSdrObject;
}

SdrObjList* SdrObject::getChildrenOfSdrObject() const
{
    // default has no children
    return nullptr;
}

void SdrObject::SetBoundRectDirty()
{
    resetOutRectangle();
}

void impAddIncarnatedSdrObjectToSdrModel(SdrObject& rSdrObject, SdrModel& rSdrModel)
{
    rSdrModel.maAllIncarnatedObjects.insert(&rSdrObject);
}
void impRemoveIncarnatedSdrObjectToSdrModel(SdrObject& rSdrObject, SdrModel& ;rSdrModel)
{
    if(!rSdrModel.maAllIncarnatedObjects.erase(&rSdrObject))
    {
        assert(false && "SdrObject::~SdrObject: Destructed incarnation of SdrObject not member of this SdrModel (!)");
    }
}

SdrObject::SdrObject(SdrModel& rSdrModel)
    : mpFillGeometryDefiningShape(nullptr)
    , mrSdrModelFromSdrObject(rSdrModel)
    , m_pUserCall(nullptr)
    , mpImpl(new Impl)
    , mpParentOfSdrObject(nullptr)
    , m_nOrdNum(0)
    , mnNavigationPosition(SAL_MAX_UINT32)
    , mnLayerID(0)
    , mpSvxShape( nullptr )
    , mbDoNotInsertIntoPageAutomatically(false)
{
    m_bVirtObj         =false;
    m_bSnapRectDirty   =true;
    m_bMovProt         =false;
    m_bSizProt         =false;
    m_bNoPrint         =false;
    m_bEmptyPresObj    =false;
    m_bNotVisibleAsMaster=false;
    m_bClosedObj       =false;
    mbVisible        = true;

    // #i25616#
    mbLineIsOutsideGeometry = false;

    // #i25616#
    mbSupportTextIndentingOnLineWidthChange = false;

    m_bIsEdge=false;
    m_bIs3DObj=false;
    m_bMarkProt=false;
    m_bIsUnoObj=false;
    impAddIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject());
}

SdrObject::SdrObject(SdrModel& rSdrModel, SdrObject const & rSource)
    : mpFillGeometryDefiningShape(nullptr)
    , mrSdrModelFromSdrObject(rSdrModel)
    , m_pUserCall(nullptr)
    , mpImpl(new Impl)
    , mpParentOfSdrObject(nullptr)
    , m_nOrdNum(0)
    , mnNavigationPosition(SAL_MAX_UINT32)
    , mnLayerID(0)
    , mpSvxShape( nullptr )
    , mbDoNotInsertIntoPageAutomatically(false)
{
    m_bVirtObj         =false;
    m_bSnapRectDirty   =true;
    m_bMovProt         =false;
    m_bSizProt         =false;
    m_bNoPrint         =false;
    m_bEmptyPresObj    =false;
    m_bNotVisibleAsMaster=false;
    m_bClosedObj       =false;
    mbVisible        = true;

    // #i25616#
    mbLineIsOutsideGeometry = false;

    // #i25616#
    mbSupportTextIndentingOnLineWidthChange = false;

    m_bIsEdge=false;
    m_bIs3DObj=false;
    m_bMarkProt=false;
    m_bIsUnoObj=false;

    mpProperties.reset();
    mpViewContact.reset();

    // The CloneSdrObject() method uses the local copy constructor from the individual
    // sdr::properties::BaseProperties class. Since the target class maybe for another
    // draw object, an SdrObject needs to be provided, as in the normal constructor.
    mpProperties = rSource.GetProperties().Clone(*this);

    setOutRectangle(rSource.getOutRectangle());
    mnLayerID = rSource.mnLayerID;
    m_aAnchor =rSource.m_aAnchor;
    m_bVirtObj=rSource.m_bVirtObj;
    m_bSizProt=rSource.m_bSizProt;
    m_bMovProt=rSource.m_bMovProt;
    m_bNoPrint=rSource.m_bNoPrint;
    mbVisible=rSource.mbVisible;
    m_bMarkProt=rSource.m_bMarkProt;
    m_bEmptyPresObj =rSource.m_bEmptyPresObj;
    m_bNotVisibleAsMaster=rSource.m_bNotVisibleAsMaster;
    m_bSnapRectDirty=true;
    m_pPlusData.reset();
    if (rSource.m_pPlusData!=nullptr) {
        m_pPlusData.reset(rSource.m_pPlusData->Clone(this));
    }
    if (m_pPlusData!=nullptr && m_pPlusData->pBroadcast!=nullptr) {
        m_pPlusData->pBroadcast.reset(); // broadcaster isn't copied
    }

    m_pGrabBagItem.reset();
    if (rSource.m_pGrabBagItem!=nullptr)
        m_pGrabBagItem.reset(rSource.m_pGrabBagItem->Clone());
    impAddIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject());
}

SdrObject::~SdrObject()
{
#ifdef DBG_UTIL
    // see logic in SdrObject::release
    assert(m_refCount == -1);
#endif
    // Tell all the registered ObjectUsers that the page is in destruction.
    // And clear the vector. This means that user do not need to call RemoveObjectUser()
    // when they get called from ObjectInDestruction().
    sdr::ObjectUserVector aList;
    aList.swap(mpImpl->maObjectUsers);
    for(sdr::ObjectUser* pObjectUser : aList)
    {
        DBG_ASSERT(pObjectUser, "SdrObject::~SdrObject: corrupt ObjectUser list (!)");
        pObjectUser->ObjectInDestruction(*this);
    }

    // UserCall
    SendUserCall(SdrUserCallType::Delete, GetLastBoundRect());
    o3tl::reset_preserve_ptr_during(m_pPlusData);

    m_pGrabBagItem.reset();
    mpProperties.reset();
    mpViewContact.reset();
    impRemoveIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject());
}

void SdrObject::acquire() noexcept
{
#ifdef DBG_UTIL
    assert(m_refCount != -1);
#endif
    osl_atomic_increment( &m_refCount );
}

void SdrObject::release() noexcept
{
    oslInterlockedCount x = osl_atomic_decrement( &m_refCount );
    if ( x == 0 )
    {
        disposeWeakConnectionPoint();
#ifdef DBG_UTIL
        // make sure it doesn't accidentally come back to life, see assert in acquire()
        osl_atomic_decrement( &m_refCount );
#endif
        delete this;
    }
}

void SdrObject::SetBoundAndSnapRectsDirty(bool bNotMyself, bool bRecursive)
{
    if (!bNotMyself)
    {
        SetBoundRectDirty();
        m_bSnapRectDirty=true;
    }

    if (bRecursive && nullptr != getParentSdrObjListFromSdrObject())
    {
        getParentSdrObjListFromSdrObject()->SetSdrObjListRectsDirty();
    }
}

void SdrObject::handlePageChange(SdrPage*, SdrPage* )
{
}


// init global static itempool
SdrItemPool& SdrObject::GetGlobalDrawObjectItemPool()
{
    static tools::DeleteRtlReferenceOnDeinit<SdrItemPool> xGlobalItemPool( []() {
        rtl::Reference<SdrItemPool> xNewPool(new SdrItemPool());
        rtl::Reference<SfxItemPool> pGlobalOutlPool = EditEngine::CreatePool();
        xNewPool->SetSecondaryPool(pGlobalOutlPool.get());
        xNewPool->SetDefaultMetric(SdrEngineDefaults::GetMapUnit());
        if (comphelper::IsFuzzing())
            xNewPool->acquire();
        return xNewPool;
    }() );

    return *xGlobalItemPool.get();
}

void SdrObject::SetRelativeWidth( double nValue )
{
    mpImpl->mnRelativeWidth = nValue;
}

void SdrObject::SetRelativeWidthRelation( sal_Int16 eValue )
{
    mpImpl->meRelativeWidthRelation = eValue;
}

void SdrObject::SetRelativeHeight( double nValue )
{
    mpImpl->mnRelativeHeight = nValue;
}

void SdrObject::SetRelativeHeightRelation( sal_Int16 eValue )
{
    mpImpl->meRelativeHeightRelation = eValue;
}

const double* SdrObject::GetRelativeWidth( ) const
{
    if (!mpImpl->mnRelativeWidth)
        return nullptr;

    return &*mpImpl->mnRelativeWidth;
}

sal_Int16 SdrObject::GetRelativeWidthRelation() const
{
    return mpImpl->meRelativeWidthRelation;
}

const double* SdrObject::GetRelativeHeight( ) const
{
    if (!mpImpl->mnRelativeHeight)
        return nullptr;

    return &*mpImpl->mnRelativeHeight;
}

sal_Int16 SdrObject::GetRelativeHeightRelation() const
{
    return mpImpl->meRelativeHeightRelation;
}

SfxItemPool& SdrObject::GetObjectItemPool() const
{
    return getSdrModelFromSdrObject().GetItemPool();
}

SdrInventor SdrObject::GetObjInventor()   const
{
    return SdrInventor::Default;
}

SdrObjKind SdrObject::GetObjIdentifier() const
{
    return SdrObjKind::NONE;
}

void SdrObject::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
{
    rInfo.bRotateFreeAllowed=false;
    rInfo.bMirrorFreeAllowed=false;
    rInfo.bTransparenceAllowed = false;
    rInfo.bShearAllowed     =false;
    rInfo.bEdgeRadiusAllowed=false;
    rInfo.bCanConvToPath    =false;
    rInfo.bCanConvToPoly    =false;
    rInfo.bCanConvToContour = false;
    rInfo.bCanConvToPathLineToArea=false;
    rInfo.bCanConvToPolyLineToArea=false;
}

SdrLayerID SdrObject::GetLayer() const
{
    return mnLayerID;
}

bool SdrObject::isVisibleOnAnyOfTheseLayers(const SdrLayerIDSet& rSet) const
{
    if (rSet.IsSet(GetLayer()))
        return true;
    SdrObjList* pOL=GetSubList();
    if (!pOL)
        return false;
    for (const rtl::Reference<SdrObject>& pObject : *pOL)
        if (pObject->isVisibleOnAnyOfTheseLayers(rSet))
            return true;
    return false;
}

void SdrObject::NbcSetLayer(SdrLayerID nLayer)
{
    mnLayerID = nLayer;
}

void SdrObject::SetLayer(SdrLayerID nLayer)
{
    NbcSetLayer(nLayer);
    SetChanged();
    BroadcastObjectChange();
}

void SdrObject::AddListener(SfxListener& rListener)
{
    ImpForcePlusData();
    if (m_pPlusData->pBroadcast==nullptr) m_pPlusData->pBroadcast.reset(new SfxBroadcaster);

    // SdrEdgeObj may be connected to same SdrObject on both ends so allow it
    // to listen twice
    SdrEdgeObj const*const pEdge(dynamic_cast<SdrEdgeObj const*>(&rListener));
    rListener.StartListening(*m_pPlusData->pBroadcast, pEdge ? DuplicateHandling::Allow : DuplicateHandling::Unexpected);
}

void SdrObject::RemoveListener(SfxListener& rListener)
{
    if (m_pPlusData!=nullptr && m_pPlusData->pBroadcast!=nullptr) {
        rListener.EndListening(*m_pPlusData->pBroadcast);
        if (!m_pPlusData->pBroadcast->HasListeners()) {
            m_pPlusData->pBroadcast.reset();
        }
    }
}

SfxBroadcaster* SdrObject::GetBroadcaster() const
{
    return m_pPlusData!=nullptr ? m_pPlusData->pBroadcast.get() : nullptr;
}

void SdrObject::AddReference(SdrVirtObj& rVrtObj)
{
    AddListener(rVrtObj);
}

void SdrObject::DelReference(SdrVirtObj& rVrtObj)
{
    RemoveListener(rVrtObj);
}

bool SdrObject::IsGroupObject() const
{
    return GetSubList()!=nullptr;
}

SdrObjList* SdrObject::GetSubList() const
{
    return nullptr;
}

SdrObject* SdrObject::getParentSdrObjectFromSdrObject() const
{
    SdrObjList* pParent(getParentSdrObjListFromSdrObject());

    if(nullptr == pParent)
    {
        return nullptr;
    }

    return pParent->getSdrObjectFromSdrObjList();
}

void SdrObject::SetName(const OUString& rStr, const bool bSetChanged)
{
    if (!rStr.isEmpty() && !m_pPlusData)
    {
        ImpForcePlusData();
    }

    if(!(m_pPlusData && m_pPlusData->aObjName != rStr))
        return;

    // Undo/Redo for setting object's name (#i73249#)
    bool bUndo( false );
    if ( getSdrModelFromSdrObject().IsUndoEnabled() )
    {
        bUndo = true;
        std::unique_ptr<SdrUndoAction> pUndoAction =
                SdrUndoFactory::CreateUndoObjectStrAttr(
                                                *this,
                                                SdrUndoObjStrAttr::ObjStrAttrType::Name,
                                                GetName(),
                                                rStr );
        getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
        getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
    }
    m_pPlusData->aObjName = rStr;
    // Undo/Redo for setting object's name (#i73249#)
    if ( bUndo )
    {
        getSdrModelFromSdrObject().EndUndo();
    }
    if (bSetChanged)
    {
        SetChanged();
        BroadcastObjectChange();
    }
}

const OUString & SdrObject::GetName() const
{
    if(m_pPlusData)
    {
        return m_pPlusData->aObjName;
    }

    return EMPTY_OUSTRING;
}

void SdrObject::SetTitle(const OUString& rStr)
{
    if (!rStr.isEmpty() && !m_pPlusData)
    {
        ImpForcePlusData();
    }

    if(!(m_pPlusData && m_pPlusData->aObjTitle != rStr))
        return;

    // Undo/Redo for setting object's title (#i73249#)
    bool bUndo( false );
    if ( getSdrModelFromSdrObject().IsUndoEnabled() )
    {
        bUndo = true;
        std::unique_ptr<SdrUndoAction> pUndoAction =
                SdrUndoFactory::CreateUndoObjectStrAttr(
                                                *this,
                                                SdrUndoObjStrAttr::ObjStrAttrType::Title,
                                                GetTitle(),
                                                rStr );
        getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
        getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
    }
    m_pPlusData->aObjTitle = rStr;
    // Undo/Redo for setting object's title (#i73249#)
    if ( bUndo )
    {
        getSdrModelFromSdrObject().EndUndo();
    }
    SetChanged();
    BroadcastObjectChange();
}

OUString SdrObject::GetTitle() const
{
    if(m_pPlusData)
    {
        return m_pPlusData->aObjTitle;
    }

    return OUString();
}

void SdrObject::SetDescription(const OUString& rStr)
{
    if (!rStr.isEmpty() && !m_pPlusData)
    {
        ImpForcePlusData();
    }

    if(!(m_pPlusData && m_pPlusData->aObjDescription != rStr))
        return;

    // Undo/Redo for setting object's description (#i73249#)
    bool bUndo( false );
    if ( getSdrModelFromSdrObject().IsUndoEnabled() )
    {
        bUndo = true;
        std::unique_ptr<SdrUndoAction> pUndoAction =
                SdrUndoFactory::CreateUndoObjectStrAttr(
                                                *this,
                                                SdrUndoObjStrAttr::ObjStrAttrType::Description,
                                                GetDescription(),
                                                rStr );
        getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
        getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
    }
    m_pPlusData->aObjDescription = rStr;
    // Undo/Redo for setting object's description (#i73249#)
    if ( bUndo )
    {
        getSdrModelFromSdrObject().EndUndo();
    }
    SetChanged();
    BroadcastObjectChange();
}

OUString SdrObject::GetDescription() const
{
    if(m_pPlusData)
    {
        return m_pPlusData->aObjDescription;
    }

    return OUString();
}

void SdrObject::SetDecorative(bool const isDecorative)
{
    ImpForcePlusData();

    if (m_pPlusData->isDecorative == isDecorative)
    {
        return;
    }

    if (getSdrModelFromSdrObject().IsUndoEnabled())
    {
        std::unique_ptr<SdrUndoAction> pUndoAction(
            SdrUndoFactory::CreateUndoObjectDecorative(
                    *this, m_pPlusData->isDecorative));
        getSdrModelFromSdrObject().BegUndo(pUndoAction->GetComment());
        getSdrModelFromSdrObject().AddUndo(std::move(pUndoAction));
    }

    m_pPlusData->isDecorative = isDecorative;

    if (getSdrModelFromSdrObject().IsUndoEnabled())
    {
        getSdrModelFromSdrObject().EndUndo();
    }

    SetChanged();
    BroadcastObjectChange();
}

bool SdrObject::IsDecorative() const
{
    return m_pPlusData == nullptr ? false : m_pPlusData->isDecorative;
}

void SdrObject::setAsAnnotationObject()
{
    if (!mpAnnotationData)
        mpAnnotationData = std::make_unique<sdr::annotation::ObjectAnnotationData>();
}

std::unique_ptr<sdr::annotation::ObjectAnnotationData>& SdrObject::getAnnotationData()
{
    return mpAnnotationData;
}

sal_uInt32 SdrObject::GetOrdNum() const
{
    if (SdrObjList* pParentList = getParentSdrObjListFromSdrObject())
    {
        if (pParentList->IsObjOrdNumsDirty())
        {
            pParentList->RecalcObjOrdNums();
        }
    } else const_cast<SdrObject*>(this)->m_nOrdNum=0;
    return m_nOrdNum;
}

void SdrObject::SetOrdNum(sal_uInt32 nNum)
{
    m_nOrdNum = nNum;
}

/// Try to ensure the desired result __without__ triggering RecalcObjOrdNums
void SdrObject::ensureSortedImmediatelyAfter(const SdrObject& rFirst)
{
    SdrObjList* pParentList = getParentSdrObjListFromSdrObject();
    assert(pParentList == rFirst.getParentSdrObjListFromSdrObject());
    bool bDirty = pParentList->IsObjOrdNumsDirty();
    if (!bDirty)
    {
        pParentList->SetObjectOrdNum(GetOrdNum(), rFirst.GetOrdNum() + 1);
    }
    else
    {
        std::optional<decltype(pParentList->begin())> itFound1, itFound2;
        for (auto it = pParentList->begin(), itEnd = pParentList->end(); it != itEnd; ++it)
        {
            if (*it == this)
                itFound1 = it;
            else if (*it == &rFirst)
                itFound2 = it;
            if (itFound1 && itFound2)
            {
                auto ord1 = std::distance(pParentList->begin(), *itFound1);
                auto ord2 = std::distance(pParentList->begin(), *itFound2);
                pParentList->SetObjectOrdNum(ord1, ord2 + 1);
                break;
            }
        }
    }
}

void SdrObject::GetGrabBagItem(css::uno::Any& rVal) const
{
    if (m_pGrabBagItem != nullptr)
        m_pGrabBagItem->QueryValue(rVal);
    else
        rVal <<= uno::Sequence<beans::PropertyValue>();
}

void SdrObject::SetGrabBagItem(const css::uno::Any& rVal)
{
    if (m_pGrabBagItem == nullptr)
        m_pGrabBagItem.reset(new SfxGrabBagItem);

    m_pGrabBagItem->PutValue(rVal, 0);

    SetChanged();
    BroadcastObjectChange();
}

sal_uInt32 SdrObject::GetNavigationPosition() const
{
    if (nullptr != getParentSdrObjListFromSdrObject() && getParentSdrObjListFromSdrObject()->RecalcNavigationPositions())
    {
        return mnNavigationPosition;
    }
    else
        return GetOrdNum();
}


void SdrObject::SetNavigationPosition (const sal_uInt32 nNewPosition)
{
    mnNavigationPosition = nNewPosition;
}


// To make clearer that this method may trigger RecalcBoundRect and thus may be
// expensive and sometimes problematic (inside a bigger object change you will get
// non-useful BoundRects sometimes) I rename that method from GetBoundRect() to
// GetCurrentBoundRect().
const tools::Rectangle& SdrObject::GetCurrentBoundRect() const
{
    auto const& rRectangle = getOutRectangle();
    if (rRectangle.IsEmpty())
    {
        const_cast< SdrObject* >(this)->RecalcBoundRect();
    }

    return rRectangle;
}

// To have a possibility to get the last calculated BoundRect e.g for producing
// the first rectangle for repaints (old and new need to be used) without forcing
// a RecalcBoundRect (which may be problematical and expensive sometimes) I add here
// a new method for accessing the last BoundRect.
const tools::Rectangle& SdrObject::GetLastBoundRect() const
{
    return getOutRectangle();
}

void SdrObject::RecalcBoundRect()
{
    // #i101680# suppress BoundRect calculations on import(s)
    if ((getSdrModelFromSdrObject().isLocked()) || comphelper::IsFuzzing())
        return;


    auto const& rRectangle = getOutRectangle();
    // central new method which will calculate the BoundRect using primitive geometry
    if (!rRectangle.IsEmpty())
        return;

    // Use view-independent data - we do not want any connections
    // to e.g. GridOffset in SdrObject-level
    drawinglayer::primitive2d::Primitive2DContainer xPrimitives;
    GetViewContact().getViewIndependentPrimitive2DContainer(xPrimitives);

    if (xPrimitives.empty())
        return;

    // use neutral ViewInformation and get the range of the primitives
    const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
    const basegfx::B2DRange aRange(xPrimitives.getB2DRange(aViewInformation2D));

    if (!aRange.isEmpty())
    {
        tools::Rectangle aNewRectangle(
            tools::Long(floor(aRange.getMinX())),
            tools::Long(floor(aRange.getMinY())),
            tools::Long(ceil(aRange.getMaxX())),
            tools::Long(ceil(aRange.getMaxY())));
        setOutRectangle(aNewRectangle);
        return;
    }
}

void SdrObject::BroadcastObjectChange() const
{
    if ((getSdrModelFromSdrObject().isLocked()) || getSdrModelFromSdrObject().IsInDestruction() || comphelper::IsFuzzing())
        return;

    bool bPlusDataBroadcast(m_pPlusData && m_pPlusData->pBroadcast);
    bool bObjectChange(IsInserted());

    if(!(bPlusDataBroadcast || bObjectChange))
        return;

    SdrHint aHint(SdrHintKind::ObjectChange, *this);

    if(bPlusDataBroadcast)
    {
        m_pPlusData->pBroadcast->Broadcast(aHint);
    }

    if(bObjectChange)
    {
        getSdrModelFromSdrObject().Broadcast(aHint);
    }
}

void SdrObject::SetChanged()
{
    // For testing purposes, use the new ViewContact for change
    // notification now.
    ActionChanged();

    // TTTT Need to check meaning/usage of IsInserted in one
    // of the next changes. It should not mean to have a SdrModel
    // set (this is guaranteed now), but should be connected to
    // being added to a SdrPage (?)
    // TTTT tdf#120066 Indeed - This triggers e.g. by CustomShape
    // geometry-presenting SdrObjects that are in a SdrObjGroup,
    // but the SdrObjGroup is *by purpose* not inserted.
    // Need to check deeper and maybe identify all ::IsInserted()
    // calls by rename and let the compiler work...
    if(nullptr != getSdrPageFromSdrObject())
    {
        getSdrModelFromSdrObject().SetChanged();
    }
}

// tooling for painting a single object to an OutputDevice.
void SdrObject::SingleObjectPainter(OutputDevice& rOut) const
{
    sdr::contact::SdrObjectVector aObjectVector;
    aObjectVector.push_back(const_cast< SdrObject* >(this));

    sdr::contact::ObjectContactOfObjListPainter aPainter(rOut, std::move(aObjectVector), getSdrPageFromSdrObject());
    sdr::contact::DisplayInfo aDisplayInfo;

    aPainter.ProcessDisplay(aDisplayInfo);
}

bool SdrObject::LineGeometryUsageIsNecessary() const
{
    drawing::LineStyle eXLS = GetMergedItem(XATTR_LINESTYLE).GetValue();
    return (eXLS != drawing::LineStyle_NONE);
}

bool SdrObject::HasLimitedRotation() const
{
    // RotGrfFlyFrame: Default is false, support full rotation
    return false;
}

OUString SdrObject::TakeObjNameSingul() const
{
    OUString sName(SvxResId(STR_ObjNameSingulNONE));

    OUString aName(GetName());
    if (!aName.isEmpty())
        sName += " '" + aName + "'";
    return sName;
}

OUString SdrObject::TakeObjNamePlural() const
{
    return SvxResId(STR_ObjNamePluralNONE);
}

OUString SdrObject::ImpGetDescriptionStr(TranslateId pStrCacheID) const
{
    OUString aStr = SvxResId(pStrCacheID);
    sal_Int32 nPos = aStr.indexOf("%1");
    if (nPos >= 0)
    {
        // Replace '%1' with the object name.
        OUString aObjName(TakeObjNameSingul());
        aStr = aStr.replaceAt(nPos, 2, aObjName);
    }

    nPos = aStr.indexOf("%2");
    if (nPos >= 0)
        // Replace '%2' with the passed value.
        aStr = aStr.replaceAt(nPos, 2, u"0");
    return aStr;
}

void SdrObject::ImpForcePlusData()
{
    if (!m_pPlusData)
        m_pPlusData.reset( new SdrObjPlusData );
}

OUString SdrObject::GetMetrStr(tools::Long nVal) const
{
    return getSdrModelFromSdrObject().GetMetricString(nVal);
}

basegfx::B2DPolyPolygon SdrObject::TakeXorPoly() const
{
    basegfx::B2DPolyPolygon aRetval;
    const tools::Rectangle aR(GetCurrentBoundRect());
    aRetval.append(basegfx::utils::createPolygonFromRect(vcl::unotools::b2DRectangleFromRectangle(aR)));

    return aRetval;
}

basegfx::B2DPolyPolygon SdrObject::TakeContour() const
{
    basegfx::B2DPolyPolygon aRetval;

    // create cloned object without text, but with drawing::LineStyle_SOLID,
    // COL_BLACK as line color and drawing::FillStyle_NONE
    rtl::Reference<SdrObject> pClone(CloneSdrObject(getSdrModelFromSdrObject()));

    if(pClone)
    {
        const SdrTextObj* pTextObj = DynCastSdrTextObj(this);

        if(pTextObj)
        {
            // no text and no text animation
            pClone->SetMergedItem(SdrTextAniKindItem(SdrTextAniKind::NONE));
            pClone->SetOutlinerParaObject(std::nullopt);
        }

        const SdrEdgeObj* pEdgeObj = dynamic_castconst SdrEdgeObj* >(this);

        if(pEdgeObj)
        {
            // create connections if connector, will be cleaned up when
            // deleting the connector again
            SdrObject* pLeft = pEdgeObj->GetConnectedNode(true);
            SdrObject* pRight = pEdgeObj->GetConnectedNode(false);

            if(pLeft)
            {
                pClone->ConnectToNode(true, pLeft);
            }

            if(pRight)
            {
                pClone->ConnectToNode(false, pRight);
            }
        }

        SfxItemSet aNewSet(GetObjectItemPool());

        // #i101980# ignore LineWidth; that's what the old implementation
        // did. With line width, the result may be huge due to fat/thick
        // line decompositions
        aNewSet.Put(XLineWidthItem(0));

        // solid black lines and no fill
        aNewSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
        aNewSet.Put(XLineColorItem(OUString(), COL_BLACK));
        aNewSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
        pClone->SetMergedItemSet(aNewSet);

        // get sequence from clone
        const sdr::contact::ViewContact& rVC(pClone->GetViewContact());
        drawinglayer::primitive2d::Primitive2DContainer xSequence;
        rVC.getViewIndependentPrimitive2DContainer(xSequence);

        if(!xSequence.empty())
        {
            // use neutral ViewInformation
            const drawinglayer::geometry::ViewInformation2D aViewInformation2D;

            // create extractor, process and get result (with hairlines as opened polygons)
            drawinglayer::processor2d::ContourExtractor2D aExtractor(aViewInformation2D, false);
            aExtractor.process(xSequence);
            const basegfx::B2DPolyPolygonVector& rResult(aExtractor.getExtractedContour());
            const sal_uInt32 nSize(rResult.size());

            // when count is one, it is implied that the object has only its normal
            // contour anyways and TakeContour() is to return an empty PolyPolygon
            // (see old implementation for historical reasons)
            if(nSize > 1)
            {
                // the topology for contour is correctly a vector of PolyPolygons; for
                // historical reasons cut it back to a single tools::PolyPolygon here
                for(sal_uInt32 a(0); a < nSize; a++)
                {
                    aRetval.append(rResult[a]);
                }
            }
        }
    }

    return aRetval;
}

sal_uInt32 SdrObject::GetHdlCount() const
{
    return 8;
}

void SdrObject::AddToHdlList(SdrHdlList& rHdlList) const
{
    const tools::Rectangle& rR=GetSnapRect();
    for (sal_uInt32 nHdlNum=0; nHdlNum<8; ++nHdlNum)
    {
        std::unique_ptr<SdrHdl> pH;
        switch (nHdlNum) {
            case 0: pH.reset(new SdrHdl(rR.TopLeft(),     SdrHdlKind::UpperLeft)); break;
            case 1: pH.reset(new SdrHdl(rR.TopCenter(),   SdrHdlKind::Upper)); break;
            case 2: pH.reset(new SdrHdl(rR.TopRight(),    SdrHdlKind::UpperRight)); break;
            case 3: pH.reset(new SdrHdl(rR.LeftCenter(),  SdrHdlKind::Left )); break;
            case 4: pH.reset(new SdrHdl(rR.RightCenter(), SdrHdlKind::Right)); break;
            case 5: pH.reset(new SdrHdl(rR.BottomLeft(),  SdrHdlKind::LowerLeft)); break;
            case 6: pH.reset(new SdrHdl(rR.BottomCenter(),SdrHdlKind::Lower)); break;
            case 7: pH.reset(new SdrHdl(rR.BottomRight(), SdrHdlKind::LowerRight)); break;
        }
        rHdlList.AddHdl(std::move(pH));
    }
}

void SdrObject::AddToPlusHdlList(SdrHdlList&, SdrHdl&) const
{
}

void SdrObject::addCropHandles(SdrHdlList& /*rTarget*/) const
{
    // Default implementation, does nothing. Overloaded in
    // SdrGrafObj and SwVirtFlyDrawObj
}

tools::Rectangle SdrObject::ImpDragCalcRect(const SdrDragStat& rDrag) const
{
    tools::Rectangle aTmpRect(GetSnapRect());
    tools::Rectangle aRect(aTmpRect);
    const SdrHdl* pHdl=rDrag.GetHdl();
    SdrHdlKind eHdl=pHdl==nullptr ? SdrHdlKind::Move : pHdl->GetKind();
    bool bEcke=(eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::LowerLeft || eHdl==SdrHdlKind::LowerRight);
    bool bOrtho=rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho();
    bool bBigOrtho=bEcke && bOrtho && rDrag.GetView()->IsBigOrtho();
    Point aPos(rDrag.GetNow());
    bool bLft=(eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::Left  || eHdl==SdrHdlKind::LowerLeft);
    bool bRgt=(eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::Right || eHdl==SdrHdlKind::LowerRight);
    bool bTop=(eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::Upper || eHdl==SdrHdlKind::UpperLeft);
    bool bBtm=(eHdl==SdrHdlKind::LowerRight || eHdl==SdrHdlKind::Lower || eHdl==SdrHdlKind::LowerLeft);
    if (bLft) aTmpRect.SetLeft(aPos.X() );
    if (bRgt) aTmpRect.SetRight(aPos.X() );
    if (bTop) aTmpRect.SetTop(aPos.Y() );
    if (bBtm) aTmpRect.SetBottom(aPos.Y() );
    if (bOrtho) { // Ortho
        tools::Long nWdt0=aRect.Right() -aRect.Left();
        tools::Long nHgt0=aRect.Bottom()-aRect.Top();
        tools::Long nXMul=aTmpRect.Right() -aTmpRect.Left();
        tools::Long nYMul=aTmpRect.Bottom()-aTmpRect.Top();
        tools::Long nXDiv=nWdt0;
        tools::Long nYDiv=nHgt0;
        bool bXNeg=(nXMul<0)!=(nXDiv<0);
        bool bYNeg=(nYMul<0)!=(nYDiv<0);
        nXMul=std::abs(nXMul);
        nYMul=std::abs(nYMul);
        nXDiv=std::abs(nXDiv);
        nYDiv=std::abs(nYDiv);
        Fraction aXFact(nXMul,nXDiv); // fractions for canceling
        Fraction aYFact(nYMul,nYDiv); // and for comparing
        nXMul=aXFact.GetNumerator();
        nYMul=aYFact.GetNumerator();
        nXDiv=aXFact.GetDenominator();
        nYDiv=aYFact.GetDenominator();
        if (bEcke) { // corner point handles
            bool bUseX=(aXFact<aYFact) != bBigOrtho;
            if (bUseX) {
                tools::Long nNeed=tools::Long(BigInt(nHgt0)*BigInt(nXMul)/BigInt(nXDiv));
                if (bYNeg) nNeed=-nNeed;
                if (bTop) aTmpRect.SetTop(aTmpRect.Bottom()-nNeed );
                if (bBtm) aTmpRect.SetBottom(aTmpRect.Top()+nNeed );
            } else {
                tools::Long nNeed=tools::Long(BigInt(nWdt0)*BigInt(nYMul)/BigInt(nYDiv));
                if (bXNeg) nNeed=-nNeed;
                if (bLft) aTmpRect.SetLeft(aTmpRect.Right()-nNeed );
                if (bRgt) aTmpRect.SetRight(aTmpRect.Left()+nNeed );
            }
        } else { // apex handles
            if ((bLft || bRgt) && nXDiv!=0) {
                tools::Long nHgt0b=aRect.Bottom()-aRect.Top();
                tools::Long nNeed=tools::Long(BigInt(nHgt0b)*BigInt(nXMul)/BigInt(nXDiv));
                aTmpRect.AdjustTop( -((nNeed-nHgt0b)/2) );
                aTmpRect.SetBottom(aTmpRect.Top()+nNeed );
            }
            if ((bTop || bBtm) && nYDiv!=0) {
                tools::Long nWdt0b=aRect.Right()-aRect.Left();
                tools::Long nNeed=tools::Long(BigInt(nWdt0b)*BigInt(nYMul)/BigInt(nYDiv));
                aTmpRect.AdjustLeft( -((nNeed-nWdt0b)/2) );
                aTmpRect.SetRight(aTmpRect.Left()+nNeed );
            }
        }
    }
    aTmpRect.Normalize();
    return aTmpRect;
}


bool SdrObject::hasSpecialDrag() const
{
    return false;
}

bool SdrObject::supportsFullDrag() const
{
    return true;
}

rtl::Reference<SdrObject> SdrObject::getFullDragClone() const
{
    // default uses simple clone
    return CloneSdrObject(getSdrModelFromSdrObject());
}

bool SdrObject::beginSpecialDrag(SdrDragStat& rDrag) const
{
    const SdrHdl* pHdl = rDrag.GetHdl();

    SdrHdlKind eHdl = (pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind();

    return eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::Upper || eHdl==SdrHdlKind::UpperRight ||
        eHdl==SdrHdlKind::Left || eHdl==SdrHdlKind::Right || eHdl==SdrHdlKind::LowerLeft ||
        eHdl==SdrHdlKind::Lower || eHdl==SdrHdlKind::LowerRight;
}

bool SdrObject::applySpecialDrag(SdrDragStat& rDrag)
{
    tools::Rectangle aNewRect(ImpDragCalcRect(rDrag));

    if(aNewRect != GetSnapRect())
    {
           NbcSetSnapRect(aNewRect);
    }

    return true;
}

OUString SdrObject::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
{
    return OUString();
}

basegfx::B2DPolyPolygon SdrObject::getSpecialDragPoly(const SdrDragStat& /*rDrag*/) const
{
    // default has nothing to add
    return basegfx::B2DPolyPolygon();
}


// Create
bool SdrObject::BegCreate(SdrDragStat& rStat)
{
    rStat.SetOrtho4Possible();
    tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
    aRect1.Normalize();
    rStat.SetActionRect(aRect1);
    setOutRectangle(aRect1);
    return true;
}

bool SdrObject::MovCreate(SdrDragStat& rStat)
{
    tools::Rectangle aRectangle;
    rStat.TakeCreateRect(aRectangle);
    rStat.SetActionRect(aRectangle);
    aRectangle.Normalize();
    setOutRectangle(aRectangle);
    return true;
}

bool SdrObject::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
{
    tools::Rectangle aRectangle;
    rStat.TakeCreateRect(aRectangle);
    aRectangle.Normalize();
    setOutRectangle(aRectangle);

    return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
}

void SdrObject::BrkCreate(SdrDragStat& /*rStat*/)
{
}

bool SdrObject::BckCreate(SdrDragStat& /*rStat*/)
{
    return false;
}

basegfx::B2DPolyPolygon SdrObject::TakeCreatePoly(const SdrDragStat& rDrag) const
{
    tools::Rectangle aRect1;
    rDrag.TakeCreateRect(aRect1);
    aRect1.Normalize();

    basegfx::B2DPolyPolygon aRetval;
    aRetval.append(basegfx::utils::createPolygonFromRect(vcl::unotools::b2DRectangleFromRectangle(aRect1)));
    return aRetval;
}

PointerStyle SdrObject::GetCreatePointer() const
{
    return PointerStyle::Cross;
}

// transformations
void SdrObject::NbcMove(const Size& rSize)
{
    moveOutRectangle(rSize.Width(), rSize.Height());
    SetBoundAndSnapRectsDirty();
}

void SdrObject::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
{
    bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
    bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
    if (bXMirr || bYMirr) {
        Point aRef1(GetSnapRect().Center());
        if (bXMirr) {
            Point aRef2(aRef1);
            aRef2.AdjustY( 1 );
            NbcMirrorGluePoints(aRef1,aRef2);
        }
        if (bYMirr) {
            Point aRef2(aRef1);
            aRef2.AdjustX( 1 );
            NbcMirrorGluePoints(aRef1,aRef2);
        }
    }
    auto aRectangle = getOutRectangle();
    ResizeRect(aRectangle, rRef, xFact, yFact);
    setOutRectangle(aRectangle);

    SetBoundAndSnapRectsDirty();
}

bool SdrObject::IsSizeValid(Size /* aTargetSize */)
{
    return true;
}

void SdrObject::NbcRotate(const Point& rRef, Degree100 nAngle)
{
    if (nAngle)
    {
        double a = toRadians(nAngle);
        NbcRotate( rRef, nAngle, sin( a ), cos( a ) );
    }
}

namespace
{
tools::Rectangle lclMirrorRectangle(tools::Rectangle const& rRectangle, Point const& rRef1, Point const& rRef2)
{
    tools::Rectangle aRectangle(rRectangle);
    aRectangle.Move(-rRef1.X(),-rRef1.Y());
    tools::Rectangle R(aRectangle);
    tools::Long dx=rRef2.X()-rRef1.X();
    tools::Long dy=rRef2.Y()-rRef1.Y();
    if (dx==0) {          // vertical axis
        aRectangle.SetLeft(-R.Right() );
        aRectangle.SetRight(-R.Left() );
    } else if (dy==0) {   // horizontal axis
        aRectangle.SetTop(-R.Bottom() );
        aRectangle.SetBottom(-R.Top() );
    } else if (dx==dy) {  // 45deg axis
        aRectangle.SetLeft(R.Top() );
        aRectangle.SetRight(R.Bottom() );
        aRectangle.SetTop(R.Left() );
        aRectangle.SetBottom(R.Right() );
    } else if (dx==-dy) { // 45deg axis
        aRectangle.SetLeft(-R.Bottom() );
        aRectangle.SetRight(-R.Top() );
        aRectangle.SetTop(-R.Right() );
        aRectangle.SetBottom(-R.Left() );
    }
    aRectangle.Move(rRef1.X(),rRef1.Y());
    aRectangle.Normalize(); // just in case
    return aRectangle;
}

// end anonymous namespace

void SdrObject::NbcMirror(const Point& rRef1, const Point& rRef2)
{
    SetGlueReallyAbsolute(true);

    tools::Rectangle aRectangle = getOutRectangle();
    aRectangle = lclMirrorRectangle(aRectangle, rRef1, rRef2);
    setOutRectangle(aRectangle);

    SetBoundAndSnapRectsDirty();
    NbcMirrorGluePoints(rRef1,rRef2);
    SetGlueReallyAbsolute(false);
}

void SdrObject::NbcShear(const Point& rRef, Degree100 /*nAngle*/, double tn, bool bVShear)
{
    SetGlueReallyAbsolute(true);
    NbcShearGluePoints(rRef,tn,bVShear);
    SetGlueReallyAbsolute(false);
}

void SdrObject::Move(const Size& rSize)
{
    if (rSize.Width() == 0 && rSize.Height() == 0)
        return;

    tools::Rectangle aBoundRect0;
    if (m_pUserCall != nullptr)
        aBoundRect0 = GetLastBoundRect();
    NbcMove(rSize);
    if (isAnnotationObject())
    {
        css::geometry::RealPoint2D aNewPosition(
            GetLogicRect().Left() / 100.0,
            GetLogicRect().Top() / 100.0);

        getAnnotationData()->mxAnnotation->SetPosition(aNewPosition);
    }
    SetChanged();
    BroadcastObjectChange();
    SendUserCall(SdrUserCallType::MoveOnly, aBoundRect0);
}

void SdrObject::NbcCrop(const basegfx::B2DPoint& /*aRef*/, double /*fxFact*/, double /*fyFact*/)
{
    // Default: does nothing. Real behaviour in SwVirtFlyDrawObj and SdrDragCrop::EndSdrDrag.
    // Where SwVirtFlyDrawObj is the only real user of it to do something local
}

void SdrObject::Resize(const Point& rRef, const Fraction& xFact, const Fraction&&nbsp;yFact, bool bUnsetRelative)
{
    if (xFact.GetNumerator() == xFact.GetDenominator() && yFact.GetNumerator() == yFact.GetDenominator())
        return;

    if (bUnsetRelative)
    {
        mpImpl->mnRelativeWidth.reset();
        mpImpl->meRelativeWidthRelation = text::RelOrientation::PAGE_FRAME;
        mpImpl->meRelativeHeightRelation = text::RelOrientation::PAGE_FRAME;
        mpImpl->mnRelativeHeight.reset();
    }
    tools::Rectangle aBoundRect0;

    if (m_pUserCall != nullptr)
        aBoundRect0 = GetLastBoundRect();

    NbcResize(rRef, xFact, yFact);

    if (isAnnotationObject())
    {
        auto& rRect = GetCurrentBoundRect();
        css::geometry::RealSize2D aNewSize(rRect.GetWidth() / 100.0, rRect.GetHeight() / 100.0);
        getAnnotationData()->mxAnnotation->SetSize(aNewSize);
    }

    SetChanged();
    BroadcastObjectChange();
    SendUserCall(SdrUserCallType::Resize, aBoundRect0);
}

void SdrObject::Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
{
    tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
    NbcCrop(rRef, fxFact, fyFact);
    SetChanged();
    BroadcastObjectChange();
    SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}

void SdrObject::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
{
    if (nAngle) {
        tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
        NbcRotate(rRef,nAngle,sn,cs);
        SetChanged();
        BroadcastObjectChange();
        SendUserCall(SdrUserCallType::Resize,aBoundRect0);
    }
}

void SdrObject::Mirror(const Point& rRef1, const Point& rRef2)
{
    tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
    NbcMirror(rRef1,rRef2);
    SetChanged();
    BroadcastObjectChange();
    SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}

void SdrObject::Shear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
{
    if (nAngle) {
        tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
        NbcShear(rRef,nAngle,tn,bVShear);
        SetChanged();
        BroadcastObjectChange();
        SendUserCall(SdrUserCallType::Resize,aBoundRect0);
    }
}

void SdrObject::NbcSetRelativePos(const Point& rPnt)
{
    Point aRelPos0(GetSnapRect().TopLeft()-m_aAnchor);
    Size aSiz(rPnt.X()-aRelPos0.X(),rPnt.Y()-aRelPos0.Y());
    NbcMove(aSiz); // This also calls SetRectsDirty()
}

void SdrObject::SetRelativePos(const Point& rPnt)
{
    if (rPnt!=GetRelativePos()) {
        tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
        NbcSetRelativePos(rPnt);
        SetChanged();
        BroadcastObjectChange();
        SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
    }
}

Point SdrObject::GetRelativePos() const
{
    return GetSnapRect().TopLeft()-m_aAnchor;
}

void SdrObject::ImpSetAnchorPos(const Point& rPnt)
{
    m_aAnchor = rPnt;
}

void SdrObject::NbcSetAnchorPos(const Point& rPnt)
{
    Size aSiz(rPnt.X()-m_aAnchor.X(),rPnt.Y()-m_aAnchor.Y());
    m_aAnchor=rPnt;
    NbcMove(aSiz); // This also calls SetRectsDirty()
}

void SdrObject::SetAnchorPos(const Point& rPnt)
{
    if (rPnt!=m_aAnchor) {
        tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
        NbcSetAnchorPos(rPnt);
        SetChanged();
        BroadcastObjectChange();
        SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
    }
}

const Point& SdrObject::GetAnchorPos() const
{
    return m_aAnchor;
}

void SdrObject::RecalcSnapRect()
{
}

const tools::Rectangle& SdrObject::GetSnapRect() const
{
    return getOutRectangle();
}

void SdrObject::NbcSetSnapRect(const tools::Rectangle& rRect)
{
    setOutRectangle(rRect);
}

const tools::Rectangle& SdrObject::GetLogicRect() const
{
    return GetSnapRect();
}

void SdrObject::NbcSetLogicRect(const tools::Rectangle& rRect, bool /*bAdaptTextMinSize*/)
{
    NbcSetSnapRect(rRect);
}

void SdrObject::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool /* bShrinkOnly = false */ )
{
    SetLogicRect( rMaxRect );
}

void SdrObject::SetSnapRect(const tools::Rectangle& rRect)
{
    tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
    NbcSetSnapRect(rRect);
    SetChanged();
    BroadcastObjectChange();
    SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}

void SdrObject::SetLogicRect(const tools::Rectangle& rRect)
{
    tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
    NbcSetLogicRect(rRect);
    SetChanged();
    BroadcastObjectChange();
    SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}

Degree100 SdrObject::GetRotateAngle() const
{
    return 0_deg100;
}

Degree100 SdrObject::GetShearAngle(bool /*bVertical*/) const
{
    return 0_deg100;
}

sal_uInt32 SdrObject::GetSnapPointCount() const
{
    return GetPointCount();
}

Point SdrObject::GetSnapPoint(sal_uInt32 i) const
{
    return GetPoint(i);
}

bool SdrObject::IsPolyObj() const
{
    return false;
}

sal_uInt32 SdrObject::GetPointCount() const
{
    return 0;
}

Point SdrObject::GetPoint(sal_uInt32 /*i*/) const
{
    return Point();
}

void SdrObject::SetPoint(const Point& rPnt, sal_uInt32 i)
{
    tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
    NbcSetPoint(rPnt, i);
    SetChanged();
    BroadcastObjectChange();
    SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}

void SdrObject::NbcSetPoint(const Point& /*rPnt*/, sal_uInt32 /*i*/)
{
}

bool SdrObject::HasTextEdit() const
{
    return false;
}

bool SdrObject::Equals(const SdrObject& rOtherObj) const
{
    return (m_aAnchor.X() == rOtherObj.m_aAnchor.X() && m_aAnchor.Y() == rOtherObj.m_aAnchor.Y() &&
            m_nOrdNum == rOtherObj.m_nOrdNum && mnNavigationPosition == rOtherObj.mnNavigationPosition &&
            mbSupportTextIndentingOnLineWidthChange == rOtherObj.mbSupportTextIndentingOnLineWidthChange &&
            mbLineIsOutsideGeometry == rOtherObj.mbLineIsOutsideGeometry && m_bMarkProt == rOtherObj.m_bMarkProt &&
            m_bIs3DObj == rOtherObj.m_bIs3DObj && m_bIsEdge == rOtherObj.m_bIsEdge && m_bClosedObj == rOtherObj.m_bClosedObj &&
            m_bNotVisibleAsMaster == rOtherObj.m_bNotVisibleAsMaster && m_bEmptyPresObj == rOtherObj.m_bEmptyPresObj &&
            mbVisible == rOtherObj.mbVisible && m_bNoPrint == rOtherObj.m_bNoPrint && m_bSizProt == rOtherObj.m_bSizProt &&
            m_bMovProt == rOtherObj.m_bMovProt && m_bVirtObj == rOtherObj.m_bVirtObj &&
            mnLayerID == rOtherObj.mnLayerID && GetMergedItemSet().Equals(rOtherObj.GetMergedItemSet(), false) );
}

void SdrObject::dumpAsXml(xmlTextWriterPtr pWriter) const
{
    (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrObject"));
    (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p"this);
    (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("symbol"), "%s", BAD_CAST(typeid(*this).name()));
    (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("name"), "%s", BAD_CAST(GetName().toUtf8().getStr()));
    (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("title"), "%s", BAD_CAST(GetTitle().toUtf8().getStr()));
    (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("description"), "%s", BAD_CAST(GetDescription().toUtf8().getStr()));
    (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("nOrdNum"), "%" SAL_PRIuUINT32, GetOrdNumDirect());
    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("aOutRect"), BAD_CAST(getOutRectangle().toString().getStr()));

    if (m_pGrabBagItem)
    {
        m_pGrabBagItem->dumpAsXml(pWriter);
    }

    if (mpProperties)
    {
        mpProperties->dumpAsXml(pWriter);
    }

    if (const OutlinerParaObject* pOutliner = GetOutlinerParaObject())
        pOutliner->dumpAsXml(pWriter);

    (void)xmlTextWriterEndElement(pWriter);
}

void SdrObject::SetOutlinerParaObject(std::optional<OutlinerParaObject> pTextObject)
{
    tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
    NbcSetOutlinerParaObject(std::move(pTextObject));
    SetChanged();
    BroadcastObjectChange();
    if (GetCurrentBoundRect()!=aBoundRect0) {
        SendUserCall(SdrUserCallType::Resize,aBoundRect0);
    }

    if (!getSdrModelFromSdrObject().IsUndoEnabled())
        return;

    // Don't do this during import.
    if (SdrObject* pTopGroupObj = getParentSdrObjectFromSdrObject())
    {
        while (SdrObject* pParent = pTopGroupObj->getParentSdrObjectFromSdrObject())
            pTopGroupObj = pParent;
        // A shape was modified, which is in a group shape. Empty the group shape's grab-bag,
        // which potentially contains the old text of the shapes in case of diagrams.
        pTopGroupObj->SetGrabBagItem(uno::Any(uno::Sequence<beans::PropertyValue>()));
    }
}

void SdrObject::NbcSetOutlinerParaObject(std::optional<OutlinerParaObject> /*pTextObject*/, bool /*bAdjustTextFrameWidthAndHeight = true*/)
{
}

OutlinerParaObject* SdrObject::GetOutlinerParaObject() const
{
    return nullptr;
}

void SdrObject::NbcReformatText()
{
}

void SdrObject::BurnInStyleSheetAttributes()
{
    GetProperties().ForceStyleToHardAttributes();
}

bool SdrObject::HasMacro() const
{
    return false;
}

SdrObject* SdrObject::CheckMacroHit(const SdrObjMacroHitRec& rRec) const
{
    if(rRec.pPageView)
    {
        return SdrObjectPrimitiveHit(*this, rRec.aPos, {static_cast<double>(rRec.nTol), static_cast<double>(rRec.nTol)}, *rRec.pPageView, rRec.pVisiLayer, false);
    }

    return nullptr;
}

PointerStyle SdrObject::GetMacroPointer(const SdrObjMacroHitRec&) const
{
    return PointerStyle::RefHand;
}

void SdrObject::PaintMacro(OutputDevice& rOut, const tools::Rectangle& , const SdrObjMacroHitRec& ) const
{
    const RasterOp eRop(rOut.GetRasterOp());
    const basegfx::B2DPolyPolygon aPolyPolygon(TakeXorPoly());

    rOut.SetLineColor(COL_BLACK);
    rOut.SetFillColor();
    rOut.SetRasterOp(RasterOp::Invert);

    for(auto const& rPolygon : aPolyPolygon)
    {
        rOut.DrawPolyLine(rPolygon);
    }

    rOut.SetRasterOp(eRop);
}

bool SdrObject::DoMacro(const SdrObjMacroHitRec&)
{
    return false;
}

bool SdrObject::IsMacroHit(const SdrObjMacroHitRec& rRec) const
{
    return CheckMacroHit(rRec) != nullptr;
}


std::unique_ptr<SdrObjGeoData> SdrObject::NewGeoData() const
{
    return std::make_unique<SdrObjGeoData>();
}

void SdrObject::SaveGeoData(SdrObjGeoData& rGeo) const
{
    rGeo.aBoundRect    =GetCurrentBoundRect();
    rGeo.aAnchor       =m_aAnchor       ;
    rGeo.bMovProt      =m_bMovProt      ;
    rGeo.bSizProt      =m_bSizProt      ;
    rGeo.bNoPrint      =m_bNoPrint      ;
    rGeo.mbVisible     =mbVisible     ;
    rGeo.bClosedObj    =m_bClosedObj    ;
    rGeo.mnLayerID = mnLayerID;

    // user-defined gluepoints
    if (m_pPlusData!=nullptr && m_pPlusData->pGluePoints!=nullptr) {
        rGeo.moGluePoints = *m_pPlusData->pGluePoints;
    } else {
        rGeo.moGluePoints.reset();
    }
}

void SdrObject::RestoreGeoData(const SdrObjGeoData& rGeo)
{
    SetBoundAndSnapRectsDirty();
    setOutRectangle(rGeo.aBoundRect);
    m_aAnchor       =rGeo.aAnchor       ;
    m_bMovProt      =rGeo.bMovProt      ;
    m_bSizProt      =rGeo.bSizProt      ;
    m_bNoPrint      =rGeo.bNoPrint      ;
    mbVisible     =rGeo.mbVisible     ;
    m_bClosedObj    =rGeo.bClosedObj    ;
    mnLayerID = rGeo.mnLayerID;

    // user-defined gluepoints
    if (rGeo.moGluePoints) {
        ImpForcePlusData();
        if (m_pPlusData->pGluePoints!=nullptr) {
            *m_pPlusData->pGluePoints=*rGeo.moGluePoints;
        } else {
            m_pPlusData->pGluePoints.reset(new SdrGluePointList(*rGeo.moGluePoints));
        }
    } else {
        if (m_pPlusData!=nullptr && m_pPlusData->pGluePoints!=nullptr) {
            m_pPlusData->pGluePoints.reset();
        }
    }
}

std::unique_ptr<SdrObjGeoData> SdrObject::GetGeoData() const
{
    std::unique_ptr<SdrObjGeoData> pGeo = NewGeoData();
    SaveGeoData(*pGeo);
    return pGeo;
}

void SdrObject::SetGeoData(const SdrObjGeoData& rGeo)
{
    tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
    RestoreGeoData(rGeo);
    SetChanged();
    BroadcastObjectChange();
    SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}


// ItemSet access

const SfxItemSet& SdrObject::GetObjectItemSet() const
{
    return GetProperties().GetObjectItemSet();
}

const SfxItemSet& SdrObject::GetMergedItemSet() const
{
    return GetProperties().GetMergedItemSet();
}

void SdrObject::SetObjectItem(const SfxPoolItem& rItem)
{
    GetProperties().SetObjectItem(rItem);
}

void SdrObject::SetMergedItem(const SfxPoolItem& rItem)
{
    GetProperties().SetMergedItem(rItem);
}

void SdrObject::ClearMergedItem(const sal_uInt16 nWhich)
{
    GetProperties().ClearMergedItem(nWhich);
}

void SdrObject::SetObjectItemSet(const SfxItemSet& rSet)
{
    GetProperties().SetObjectItemSet(rSet);
}

void SdrObject::SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems, bool bAdjustTextFrameWidthAndHeight)
{
    GetProperties().SetMergedItemSet(rSet, bClearAllItems, bAdjustTextFrameWidthAndHeight);
}

const SfxPoolItem& SdrObject::GetObjectItem(const sal_uInt16 nWhich) const
{
    return GetObjectItemSet().Get(nWhich);
}

const SfxPoolItem& SdrObject::GetMergedItem(const sal_uInt16 nWhich) const
{
    return GetMergedItemSet().Get(nWhich);
}

void SdrObject::SetMergedItemSetAndBroadcast(const SfxItemSet& rSet, bool bClearAllItems)
{
    GetProperties().SetMergedItemSetAndBroadcast(rSet, bClearAllItems);
}

void SdrObject::ApplyNotPersistAttr(const SfxItemSet& rAttr)
{
    tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
    NbcApplyNotPersistAttr(rAttr);
    SetChanged();
    BroadcastObjectChange();
    SendUserCall(SdrUserCallType::Resize,aBoundRect0);
}

void SdrObject::NbcApplyNotPersistAttr(const SfxItemSet& rAttr)
{
    const tools::Rectangle& rSnap=GetSnapRect();
    const tools::Rectangle& rLogic=GetLogicRect();
    Point aRef1(rSnap.Center());

    if (const SdrTransformRef1XItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_TRANSFORMREF1X))
    {
        aRef1.setX(pPoolItem->GetValue() );
    }
    if (const SdrTransformRef1YItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_TRANSFORMREF1Y))
    {
        aRef1.setY(pPoolItem->GetValue() );
    }

    tools::Rectangle aNewSnap(rSnap);
    if (const SdrMoveXItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_MOVEX))
    {
        tools::Long n = pPoolItem->GetValue();
        aNewSnap.Move(n,0);
    }
    if (const SdrMoveYItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_MOVEY))
    {
        tools::Long n = pPoolItem->GetValue();
        aNewSnap.Move(0,n);
    }
    if (const SdrOnePositionXItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ONEPOSITIONX))
    {
        tools::Long n = pPoolItem->GetValue();
        aNewSnap.Move(n-aNewSnap.Left(),0);
    }
    if (const SdrOnePositionYItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ONEPOSITIONY))
    {
        tools::Long n = pPoolItem->GetValue();
        aNewSnap.Move(0,n-aNewSnap.Top());
    }
    if (const SdrOneSizeWidthItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ONESIZEWIDTH))
    {
        tools::Long n = pPoolItem->GetValue();
        aNewSnap.SetRight(aNewSnap.Left()+n );
    }
    if (const SdrOneSizeHeightItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ONESIZEHEIGHT))
    {
        tools::Long n = pPoolItem->GetValue();
        aNewSnap.SetBottom(aNewSnap.Top()+n );
    }
    if (aNewSnap!=rSnap) {
        if (aNewSnap.GetSize()==rSnap.GetSize()) {
            NbcMove(Size(aNewSnap.Left()-rSnap.Left(),aNewSnap.Top()-rSnap.Top()));
        } else {
            NbcSetSnapRect(aNewSnap);
        }
    }

    if (const SdrShearAngleItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_SHEARANGLE))
    {
        Degree100 n = pPoolItem->GetValue();
        n-=GetShearAngle();
        if (n) {
            double nTan = tan(toRadians(n));
            NbcShear(aRef1,n,nTan,false);
        }
    }
    if (const SdrAngleItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ROTATEANGLE))
    {
        Degree100 n = pPoolItem->GetValue();
        n-=GetRotateAngle();
        if (n) {
            NbcRotate(aRef1,n);
        }
    }
    if (const SdrRotateOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_ROTATEONE))
    {
        Degree100 n = pPoolItem->GetValue();
        NbcRotate(aRef1,n);
    }
    if (const SdrHorzShearOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_HORZSHEARONE))
    {
        Degree100 n = pPoolItem->GetValue();
        double nTan = tan(toRadians(n));
        NbcShear(aRef1,n,nTan,false);
    }
    if (const SdrVertShearOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_VERTSHEARONE))
    {
        Degree100 n = pPoolItem->GetValue();
        double nTan = tan(toRadians(n));
        NbcShear(aRef1,n,nTan,true);
    }

    if (const SdrYesNoItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJMOVEPROTECT))
    {
        bool b = pPoolItem->GetValue();
        SetMoveProtect(b);
    }
    if (const SdrYesNoItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJSIZEPROTECT))
    {
        bool b = pPoolItem->GetValue();
        SetResizeProtect(b);
    }

    /* move protect always sets size protect */
    if( IsMoveProtect() )
        SetResizeProtect( true );

    if (const SdrObjPrintableItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJPRINTABLE))
    {
        bool b = pPoolItem->GetValue();
        SetPrintable(b);
    }

    if (const SdrObjVisibleItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJVISIBLE))
    {
        bool b = pPoolItem->GetValue();
        SetVisible(b);
    }

    SdrLayerID nLayer=SDRLAYER_NOTFOUND;
    if (const SdrLayerIdItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LAYERID))
    {
        nLayer = pPoolItem->GetValue();
    }
    if (const SdrLayerNameItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LAYERNAME))
    {
        OUString aLayerName = pPoolItem->GetValue();
        const SdrLayerAdmin& rLayAd(nullptr != getSdrPageFromSdrObject()
            ? getSdrPageFromSdrObject()->GetLayerAdmin()
            : getSdrModelFromSdrObject().GetLayerAdmin());
        const SdrLayer* pLayer = rLayAd.GetLayer(aLayerName);

        if(nullptr != pLayer)
        {
            nLayer=pLayer->GetID();
        }
    }
    if (nLayer!=SDRLAYER_NOTFOUND) {
        NbcSetLayer(nLayer);
    }

    if (const SfxStringItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_OBJECTNAME))
    {
        OUString aName = pPoolItem->GetValue();
        SetName(aName);
    }
    tools::Rectangle aNewLogic(rLogic);
    if (const SdrLogicSizeWidthItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LOGICSIZEWIDTH))
    {
        tools::Long n = pPoolItem->GetValue();
        aNewLogic.SetRight(aNewLogic.Left()+n );
    }
    if (const SdrLogicSizeHeightItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_LOGICSIZEHEIGHT))
    {
        tools::Long n = pPoolItem->GetValue();
        aNewLogic.SetBottom(aNewLogic.Top()+n );
    }
    if (aNewLogic!=rLogic) {
        NbcSetLogicRect(aNewLogic);
    }
    Fraction aResizeX(1,1);
    Fraction aResizeY(1,1);
    if (const SdrResizeXOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_RESIZEXONE))
    {
        aResizeX *= pPoolItem->GetValue();
    }
    if (const SdrResizeYOneItem *pPoolItem = rAttr.GetItemIfSet(SDRATTR_RESIZEYONE))
    {
        aResizeY *= pPoolItem->GetValue();
    }
    if (aResizeX!=Fraction(1,1) || aResizeY!=Fraction(1,1)) {
        NbcResize(aRef1,aResizeX,aResizeY);
    }
}

void SdrObject::TakeNotPersistAttr(SfxItemSet& rAttr) const
{
    const tools::Rectangle& rSnap=GetSnapRect();
    const tools::Rectangle& rLogic=GetLogicRect();
    rAttr.Put(SdrYesNoItem(SDRATTR_OBJMOVEPROTECT, IsMoveProtect()));
    rAttr.Put(SdrYesNoItem(SDRATTR_OBJSIZEPROTECT, IsResizeProtect()));
    rAttr.Put(SdrObjPrintableItem(IsPrintable()));
    rAttr.Put(SdrObjVisibleItem(IsVisible()));
    rAttr.Put(SdrAngleItem(SDRATTR_ROTATEANGLE, GetRotateAngle()));
    rAttr.Put(SdrShearAngleItem(GetShearAngle()));
    rAttr.Put(SdrOneSizeWidthItem(rSnap.GetWidth()-1));
    rAttr.Put(SdrOneSizeHeightItem(rSnap.GetHeight()-1));
    rAttr.Put(SdrOnePositionXItem(rSnap.Left()));
    rAttr.Put(SdrOnePositionYItem(rSnap.Top()));
    if (rLogic.GetWidth()!=rSnap.GetWidth()) {
        rAttr.Put(SdrLogicSizeWidthItem(rLogic.GetWidth()-1));
    }
    if (rLogic.GetHeight()!=rSnap.GetHeight()) {
        rAttr.Put(SdrLogicSizeHeightItem(rLogic.GetHeight()-1));
    }
    OUString aName(GetName());

    if (!aName.isEmpty())
    {
        rAttr.Put(SfxStringItem(SDRATTR_OBJECTNAME, aName));
    }

    rAttr.Put(SdrLayerIdItem(GetLayer()));
    const SdrLayerAdmin& rLayAd(nullptr != getSdrPageFromSdrObject()
        ? getSdrPageFromSdrObject()->GetLayerAdmin()
        : getSdrModelFromSdrObject().GetLayerAdmin());
    const SdrLayer* pLayer = rLayAd.GetLayerPerID(GetLayer());
    if(nullptr != pLayer)
    {
        rAttr.Put(SdrLayerNameItem(pLayer->GetName()));
    }
    Point aRef1(rSnap.Center());
    Point aRef2(aRef1); aRef2.AdjustY( 1 );
    rAttr.Put(SdrTransformRef1XItem(aRef1.X()));
    rAttr.Put(SdrTransformRef1YItem(aRef1.Y()));
    rAttr.Put(SdrTransformRef2XItem(aRef2.X()));
    rAttr.Put(SdrTransformRef2YItem(aRef2.Y()));
}

SfxStyleSheet* SdrObject::GetStyleSheet() const
{
    return GetProperties().GetStyleSheet();
}

void SdrObject::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
{
    tools::Rectangle aBoundRect0;

    if(m_pUserCall)
        aBoundRect0 = GetLastBoundRect();

    InternalSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, true);
    SetChanged();
    BroadcastObjectChange();
    SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect0);
}

void SdrObject::NbcSetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr, bool bAdjustTextFrameWidthAndHeight)
{
    InternalSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, false, bAdjustTextFrameWidthAndHeight);
}

void SdrObject::InternalSetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr, bool bBroadcast, bool bAdjustTextFrameWidthAndHeight)
{
    GetProperties().SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast, bAdjustTextFrameWidthAndHeight);
}

// Broadcasting while setting attributes is managed by the AttrObj.


SdrGluePoint SdrObject::GetVertexGluePoint(sal_uInt16 nPosNum) const
{
    // #i41936# Use SnapRect for default GluePoints
    const tools::Rectangle aR(GetSnapRect());
    Point aPt;

    switch(nPosNum)
    {
        case 0 : aPt = aR.TopCenter();    break;
        case 1 : aPt = aR.RightCenter();  break;
        case 2 : aPt = aR.BottomCenter(); break;
        case 3 : aPt = aR.LeftCenter();   break;
    }

    aPt -= aR.Center();
    SdrGluePoint aGP(aPt);
    aGP.SetPercent(false);

    return aGP;
}

SdrGluePoint SdrObject::GetCornerGluePoint(sal_uInt16 nPosNum) const
{
    tools::Rectangle aR(GetCurrentBoundRect());
    Point aPt;
    switch (nPosNum) {
        case 0 : aPt=aR.TopLeft();     break;
        case 1 : aPt=aR.TopRight();    break;
        case 2 : aPt=aR.BottomRight(); break;
        case 3 : aPt=aR.BottomLeft();  break;
    }
    aPt-=GetSnapRect().Center();
    SdrGluePoint aGP(aPt);
    aGP.SetPercent(false);
    return aGP;
}

const SdrGluePointList* SdrObject::GetGluePointList() const
{
    if (m_pPlusData!=nullptr) return m_pPlusData->pGluePoints.get();
    return nullptr;
}


SdrGluePointList* SdrObject::ForceGluePointList()
{
    ImpForcePlusData();
    if (m_pPlusData->pGluePoints==nullptr) {
        m_pPlusData->pGluePoints.reset(new SdrGluePointList);
    }
    return m_pPlusData->pGluePoints.get();
}

void SdrObject::SetGlueReallyAbsolute(bool bOn)
{
    // First a const call to see whether there are any gluepoints.
    // Force const call!
    if (GetGluePointList()!=nullptr) {
        SdrGluePointList* pGPL=ForceGluePointList();
        pGPL->SetReallyAbsolute(bOn,*this);
    }
}

void SdrObject::NbcRotateGluePoints(const Point& rRef, Degree100 nAngle, double sn, double cs)
{
    // First a const call to see whether there are any gluepoints.
    // Force const call!
    if (GetGluePointList()!=nullptr) {
        SdrGluePointList* pGPL=ForceGluePointList();
        pGPL->Rotate(rRef,nAngle,sn,cs,this);
    }
}

void SdrObject::NbcMirrorGluePoints(const Point& rRef1, const Point& rRef2)
{
    // First a const call to see whether there are any gluepoints.
    // Force const call!
    if (GetGluePointList()!=nullptr) {
        SdrGluePointList* pGPL=ForceGluePointList();
        pGPL->Mirror(rRef1,rRef2,this);
    }
}

void SdrObject::NbcShearGluePoints(const Point& rRef, double tn, bool bVShear)
{
    // First a const call to see whether there are any gluepoints.
    // Force const call!
    if (GetGluePointList()!=nullptr) {
        SdrGluePointList* pGPL=ForceGluePointList();
        pGPL->Shear(rRef,tn,bVShear,this);
    }
}

void SdrObject::ConnectToNode(bool /*bTail1*/, SdrObject* /*pObj*/)
{
}

void SdrObject::DisconnectFromNode(bool /*bTail1*/)
{
}

SdrObject* SdrObject::GetConnectedNode(bool /*bTail1*/) const
{
    return nullptr;
}


static void extractLineContourFromPrimitive2DSequence(
    const drawinglayer::primitive2d::Primitive2DContainer& rxSequence,
    basegfx::B2DPolygonVector& rExtractedHairlines,
    basegfx::B2DPolyPolygonVector& rExtractedLineFills)
{
    rExtractedHairlines.clear();
    rExtractedLineFills.clear();

    if(rxSequence.empty())
        return;

    // use neutral ViewInformation
    const drawinglayer::geometry::ViewInformation2D aViewInformation2D;

    // create extractor, process and get result
    drawinglayer::processor2d::LineGeometryExtractor2D aExtractor(aViewInformation2D);
    aExtractor.process(rxSequence);

    // copy line results
    rExtractedHairlines = aExtractor.getExtractedHairlines();

    // copy fill rsults
    rExtractedLineFills = aExtractor.getExtractedLineFills();
}


rtl::Reference<SdrObject> SdrObject::ImpConvertToContourObj(bool bForceLineDash)
{
    rtl::Reference<SdrObject> pRetval;

    if(LineGeometryUsageIsNecessary())
    {
        basegfx::B2DPolyPolygon aMergedLineFillPolyPolygon;
        basegfx::B2DPolyPolygon aMergedHairlinePolyPolygon;
        drawinglayer::primitive2d::Primitive2DContainer xSequence;
        GetViewContact().getViewIndependentPrimitive2DContainer(xSequence);

        if(!xSequence.empty())
        {
            basegfx::B2DPolygonVector aExtractedHairlines;
            basegfx::B2DPolyPolygonVector aExtractedLineFills;

            extractLineContourFromPrimitive2DSequence(xSequence, aExtractedHairlines, aExtractedLineFills);

            // for SdrObject creation, just copy all to a single Hairline-PolyPolygon
            for(const basegfx::B2DPolygon & rExtractedHairline : aExtractedHairlines)
            {
                aMergedHairlinePolyPolygon.append(rExtractedHairline);
            }

            // check for fill rsults
            if (!aExtractedLineFills.empty() && !comphelper::IsFuzzing())
            {
                // merge to a single tools::PolyPolygon (OR)
                aMergedLineFillPolyPolygon = basegfx::utils::mergeToSinglePolyPolygon(std::move(aExtractedLineFills));
            }
        }

        if(aMergedLineFillPolyPolygon.count() || (bForceLineDash && aMergedHairlinePolyPolygon.count()))
        {
            SfxItemSet aSet(GetMergedItemSet());
            drawing::FillStyle eOldFillStyle = aSet.Get(XATTR_FILLSTYLE).GetValue();
            rtl::Reference<SdrPathObj> aLinePolygonPart;
            rtl::Reference<SdrPathObj> aLineHairlinePart;
            bool bBuildGroup(false);

            if(aMergedLineFillPolyPolygon.count())
            {
                // create SdrObject for filled line geometry
                aLinePolygonPart = new SdrPathObj(
                    getSdrModelFromSdrObject(),
                    SdrObjKind::PathFill,
                    std::move(aMergedLineFillPolyPolygon));

                // correct item properties
                aSet.Put(XLineWidthItem(0));
                aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
                Color aColorLine = aSet.Get(XATTR_LINECOLOR).GetColorValue();
                sal_uInt16 nTransLine = aSet.Get(XATTR_LINETRANSPARENCE).GetValue();
                aSet.Put(XFillColorItem(OUString(), aColorLine));
                aSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
                aSet.Put(XFillTransparenceItem(nTransLine));

                aLinePolygonPart->SetMergedItemSet(aSet);
            }

            if(aMergedHairlinePolyPolygon.count())
            {
                // create SdrObject for hairline geometry
                // OBJ_PATHLINE is necessary here, not OBJ_PATHFILL. This is intended
                // to get a non-filled object. If the poly is closed, the PathObj takes care for
                // the correct closed state.
                aLineHairlinePart = new SdrPathObj(
                    getSdrModelFromSdrObject(),
                    SdrObjKind::PathLine,
                    std::move(aMergedHairlinePolyPolygon));

                aSet.Put(XLineWidthItem(0));
                aSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
                aSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));

                // it is also necessary to switch off line start and ends here
                aSet.Put(XLineStartWidthItem(0));
                aSet.Put(XLineEndWidthItem(0));

                aLineHairlinePart->SetMergedItemSet(aSet);

                if(aLinePolygonPart)
                {
                    bBuildGroup = true;
                }
            }

            // check if original geometry should be added (e.g. filled and closed)
            bool bAddOriginalGeometry(false);
            SdrPathObj* pPath = dynamic_cast<SdrPathObj*>(this);

            if(pPath && pPath->IsClosed())
            {
                if(eOldFillStyle != drawing::FillStyle_NONE)
                {
                    bAddOriginalGeometry = true;
                }
            }

            // do we need a group?
            if(bBuildGroup || bAddOriginalGeometry)
            {
                rtl::Reference<SdrObject> xGroup = new SdrObjGroup(getSdrModelFromSdrObject());

                if(bAddOriginalGeometry)
                {
                    // Add a clone of the original geometry.
                    aSet.ClearItem();
                    aSet.Put(GetMergedItemSet());
                    aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
                    aSet.Put(XLineWidthItem(0));

                    rtl::Reference<SdrObject> pClone(CloneSdrObject(getSdrModelFromSdrObject()));
                    pClone->SetMergedItemSet(aSet);

                    xGroup->GetSubList()->NbcInsertObject(pClone.get());
                }

                if(aLinePolygonPart)
                {
                    xGroup->GetSubList()->NbcInsertObject(aLinePolygonPart.get());
                }

                if(aLineHairlinePart)
                {
                    xGroup->GetSubList()->NbcInsertObject(aLineHairlinePart.get());
                }

                pRetval = std::move(xGroup);
            }
            else
            {
                if(aLinePolygonPart)
                {
                    pRetval = aLinePolygonPart;
                }
                else if(aLineHairlinePart)
                {
                    pRetval = aLineHairlinePart;
                }
            }
        }
    }

    if(!pRetval)
    {
        // due to current method usage, create and return a clone when nothing has changed
        pRetval = CloneSdrObject(getSdrModelFromSdrObject());
    }

    return pRetval;
}


void SdrObject::SetMarkProtect(bool bProt)
{
    m_bMarkProt = bProt;
}


void SdrObject::SetEmptyPresObj(bool bEpt)
{
    m_bEmptyPresObj = bEpt;
}


void SdrObject::SetNotVisibleAsMaster(bool bFlg)
{
    m_bNotVisibleAsMaster=bFlg;
}


// convert this path object to contour object, even when it is a group
rtl::Reference<SdrObject> SdrObject::ConvertToContourObj(SdrObject* pRet1, bool bForceLineDash) const
{
    rtl::Reference<SdrObject> pRet = pRet1;
    if(dynamic_cast<const SdrObjGroup*>( pRet.get()) !=  nullptr)
    {
        SdrObjList* pObjList2 = pRet->GetSubList();
        rtl::Reference<SdrObject> pGroup = new SdrObjGroup(getSdrModelFromSdrObject());

        for (const rtl::Reference<SdrObject>& pIterObj : *pObjList2)
            pGroup->GetSubList()->NbcInsertObject(ConvertToContourObj(pIterObj.get(), bForceLineDash).get());

        pRet = std::move(pGroup);
    }
    else
    {
        if (SdrPathObj *pPathObj = dynamic_cast<SdrPathObj*>(pRet.get()))
        {
            // bezier geometry got created, even for straight edges since the given
            // object is a result of DoConvertToPolyObj. For conversion to contour
            // this is not really needed and can be reduced again AFAP
            pPathObj->SetPathPoly(basegfx::utils::simplifyCurveSegments(pPathObj->GetPathPoly()));
        }

        pRet = pRet->ImpConvertToContourObj(bForceLineDash);
    }

    // #i73441# preserve LayerID
    if(pRet && pRet->GetLayer() != GetLayer())
    {
        pRet->SetLayer(GetLayer());
    }

    return pRet;
}


rtl::Reference<SdrObject> SdrObject::ConvertToPolyObj(bool bBezier, bool bLineToArea) const
{
    rtl::Reference<SdrObject> pRet = DoConvertToPolyObj(bBezier, true);

    if(pRet && bLineToArea)
    {
        pRet = ConvertToContourObj(pRet.get());
    }

    // #i73441# preserve LayerID
    if(pRet && pRet->GetLayer() != GetLayer())
    {
        pRet->SetLayer(GetLayer());
    }

    return pRet;
}


rtl::Reference<SdrObject> SdrObject::DoConvertToPolyObj(bool /*bBezier*/, bool /*bAddText*/) const
{
    return nullptr;
}


void SdrObject::InsertedStateChange()
{
    const bool bIsInserted(nullptr != getParentSdrObjListFromSdrObject());
    const tools::Rectangle aBoundRect0(GetLastBoundRect());

    if(bIsInserted)
    {
        SendUserCall(SdrUserCallType::Inserted, aBoundRect0);
    }
    else
    {
        SendUserCall(SdrUserCallType::Removed, aBoundRect0);
    }

    if(nullptr != m_pPlusData && nullptr != m_pPlusData->pBroadcast)
    {
        SdrHint aHint(bIsInserted ? SdrHintKind::ObjectInserted : SdrHintKind::ObjectRemoved, *this);
        m_pPlusData->pBroadcast->Broadcast(aHint);
    }
}

void SdrObject::SetMoveProtect(bool bProt)
{
    if(IsMoveProtect() != bProt)
    {
        // #i77187# secured and simplified
        m_bMovProt = bProt;
        SetChanged();
        BroadcastObjectChange();
    }
}

void SdrObject::SetResizeProtect(bool bProt)
{
    if(IsResizeProtect() != bProt)
    {
        // #i77187# secured and simplified
        m_bSizProt = bProt;
        SetChanged();
        BroadcastObjectChange();
    }
}

bool SdrObject::IsPrintable() const
{
    return !m_bNoPrint;
}

void SdrObject::SetPrintable(bool bPrn)
{
    if( bPrn == m_bNoPrint )
    {
        m_bNoPrint=!bPrn;
        SetChanged();
        if (IsInserted())
        {
            SdrHint aHint(SdrHintKind::ObjectChange, *this);
            getSdrModelFromSdrObject().Broadcast(aHint);
        }
    }
}

bool SdrObject::IsVisible() const
{
    return mbVisible;
}

void SdrObject::SetVisible(bool bVisible)
{
    if( bVisible != mbVisible )
    {
        mbVisible = bVisible;
        SetChanged();
        if (IsInserted())
        {
            SdrHint aHint(SdrHintKind::ObjectChange, *this);
            getSdrModelFromSdrObject().Broadcast(aHint);
        }
    }
}


sal_uInt16 SdrObject::GetUserDataCount() const
{
    if (m_pPlusData==nullptr || m_pPlusData->pUserDataList==nullptr) return 0;
    return m_pPlusData->pUserDataList->GetUserDataCount();
}

SdrObjUserData* SdrObject::GetUserData(sal_uInt16 nNum) const
{
    if (m_pPlusData==nullptr || m_pPlusData->pUserDataList==nullptr) return nullptr;
    return &m_pPlusData->pUserDataList->GetUserData(nNum);
}

void SdrObject::AppendUserData(std::unique_ptr<SdrObjUserData> pData)
{
    if (!pData)
    {
        OSL_FAIL("SdrObject::AppendUserData(): pData is NULL pointer.");
        return;
    }

    ImpForcePlusData();
    if (!m_pPlusData->pUserDataList)
        m_pPlusData->pUserDataList.reset( new SdrObjUserDataList );

    m_pPlusData->pUserDataList->AppendUserData(std::move(pData));
}

void SdrObject::DeleteUserData(sal_uInt16 nNum)
{
    sal_uInt16 nCount=GetUserDataCount();
    if (nNum<nCount) {
        m_pPlusData->pUserDataList->DeleteUserData(nNum);
        if (nCount==1)  {
            m_pPlusData->pUserDataList.reset();
        }
    } else {
        OSL_FAIL("SdrObject::DeleteUserData(): Invalid Index.");
    }
}

void SdrObject::SetUserCall(SdrObjUserCall* pUser)
{
    m_pUserCall = pUser;
}


void SdrObject::SendUserCall(SdrUserCallType eUserCall, const tools::Rectangle& rBoundRect) const
{
    SdrObject* pGroup(getParentSdrObjectFromSdrObject());

    if ( m_pUserCall )
    {
        m_pUserCall->Changed( *this, eUserCall, rBoundRect );
    }

    if(nullptr != pGroup && pGroup->GetUserCall())
    {
        // broadcast to group
        SdrUserCallType eChildUserType = SdrUserCallType::ChildChangeAttr;

        switch( eUserCall )
        {
            case SdrUserCallType::MoveOnly:
                eChildUserType = SdrUserCallType::ChildMoveOnly;
            break;

            case SdrUserCallType::Resize:
                eChildUserType = SdrUserCallType::ChildResize;
            break;

            case SdrUserCallType::ChangeAttr:
                eChildUserType = SdrUserCallType::ChildChangeAttr;
            break;

            case SdrUserCallType::Delete:
                eChildUserType = SdrUserCallType::ChildDelete;
            break;

            case SdrUserCallType::Inserted:
                eChildUserType = SdrUserCallType::ChildInserted;
            break;

            case SdrUserCallType::Removed:
                eChildUserType = SdrUserCallType::ChildRemoved;
            break;

            defaultbreak;
        }

        pGroup->GetUserCall()->Changed( *this, eChildUserType, rBoundRect );
    }

    // notify our UNO shape listeners
    switch ( eUserCall )
    {
    case SdrUserCallType::Resize:
        notifyShapePropertyChange( u"Size"_ustr );
        [[fallthrough]]; // RESIZE might also imply a change of the position
    case SdrUserCallType::MoveOnly:
        notifyShapePropertyChange( u"Position"_ustr );
        break;
    default:
        // not interested in
        break;
    }
}

void SdrObject::setUnoShape( const uno::Reference< drawing::XShape >& _rxUnoShape )
{
    const uno::Reference< uno::XInterface> xOldUnoShape( maWeakUnoShape );
    // the UNO shape would be gutted by the following code; return early
    if ( _rxUnoShape == xOldUnoShape )
    {
        if ( !xOldUnoShape.is() )
        {
            // make sure there is no stale impl. pointer if the UNO
            // shape was destroyed meanwhile (remember we only hold weak
            // reference to it!)
            mpSvxShape = nullptr;
        }
        return;
    }

    if ( xOldUnoShape.is() )
    {
        // Remove yourself from the current UNO shape. Its destructor
        // will reset our UNO shape otherwise.
        mpSvxShape->InvalidateSdrObject();
    }

    maWeakUnoShape = _rxUnoShape;
    mpSvxShape = comphelper::getFromUnoTunnel<SvxShape>( _rxUnoShape );
}

/** only for internal use! */
SvxShape* SdrObject::getSvxShape()
{
    DBG_TESTSOLARMUTEX();
        // retrieving the impl pointer and subsequently using it is not thread-safe, of course, so it needs to be
        // guarded by the SolarMutex

    uno::Reference< uno::XInterface > xShape( maWeakUnoShape );
    //#113608#, make sure mpSvxShape is always synchronized with maWeakUnoShape
    if ( mpSvxShape && !xShape )
        mpSvxShape = nullptr;

    return mpSvxShape;
}

css::uno::Reference< css::drawing::XShape > SdrObject::getUnoShape()
{
    // try weak reference first
    uno::Reference< css::drawing::XShape > xShape = maWeakUnoShape;
    if (xShape)
        return xShape;

    // try to access SdrPage from this SdrObject. This will only exist if the SdrObject is
    // inserted in a SdrObjList (page/group/3dScene)
    SdrPage* pPageCandidate(getSdrPageFromSdrObject());

    // tdf#12152, tdf#120728
    //
    // With the paradigm change to only get a SdrPage for a SdrObject when the SdrObject
    // is *inserted*, the functionality for creating 1:1 associated UNO API implementation
    // SvxShapes was partially broken: The used ::CreateShape relies on the SvxPage being
    // derived and the CreateShape method overloaded, implementing additional SdrInventor
    // types as needed.
    //
    // The fallback to use SvxDrawPage::CreateShapeByTypeAndInventor is a trap: It's only
    // a static fallback that handles the SdrInventor types SdrInventor::E3d and
    // SdrInventor::Default. Due to that, e.g. the ReportDesigner broke in various conditions.
    //
    // That again has to do with the ReportDesigner being implemented using the UNO API
    // aspects of SdrObjects early during their construction, not just after these are
    // inserted to a SdrPage - but that is not illegal or wrong, the SdrObject exists already.
    //
    // As a current solution, use the (now always available) SdrModel and any of the
    // existing SdrPages. The only important thing is to get a SdrPage where ::CreateShape is
    // overloaded and implemented as needed.
    //
    // Note for the future:
    // In a more ideal world there would be only one factory method for creating SdrObjects (not
    // ::CreateShape and ::CreateShapeByTypeAndInventor). This also would not be placed at
    // SdrPage/SvxPage at all, but at the Model where it belongs - where else would you expect
    // objects for the current Model to be constructed? To have this at the Page only would make
    // sense if different shapes would need to be constructed for different Pages in the same Model
    // - this is never the case.
    // At that Model extended functionality for that factory (or overloads and implementations)
    // should be placed. But to be realistic, migrating the factories to Model now is too much
    // work - maybe over time when melting SdrObject/SvxObject one day...
    //
    // More Note (added by noel grandin)
    // Except that sd/ is being naughty and doing all kinds of magic during CreateShape that
    // requires knowing which page the object is being created for. Fixing that would require
    // moving a bunch of nasty logic from object creation time, to the point in time when
    // it is actually added to a page.
    if(nullptr == pPageCandidate)
    {
        // If not inserted, alternatively access a SdrPage using the SdrModel. There is
        // no reason not to create and return a UNO API XShape when the SdrObject is not
        // inserted - it may be in construction. Main paradigm is that it exists.
        if(0 != getSdrModelFromSdrObject().GetPageCount())
        {
            // Take 1st SdrPage. That may be e.g. a special page (in SD), but the
            // to-be-used method ::CreateShape will be correctly overloaded in
            // all cases
            pPageCandidate = getSdrModelFromSdrObject().GetPage(0);
        }
    }

    if(nullptr != pPageCandidate)
    {
        uno::Reference< uno::XInterface > xPage(pPageCandidate->getUnoPage());
        if( xPage.is() )
        {
            SvxDrawPage* pDrawPage = comphelper::getFromUnoTunnel<SvxDrawPage>(xPage);
            if( pDrawPage )
            {
                // create one
                xShape = pDrawPage->CreateShape( this );
                assert(xShape);
                setUnoShape( xShape );
            }
        }
    }
    else
    {
        // Fallback to static base functionality. CAUTION: This will only support
        // the most basic stuff like SdrInventor::E3d and SdrInventor::Default. All
        // the other SdrInventor enum entries are from overloads and are *not accessible*
        // using this fallback (!) - what a bad trap
        rtl::Reference<SvxShape> xNewShape = SvxDrawPage::CreateShapeByTypeAndInventor( GetObjIdentifier(), GetObjInventor(), this );
        mpSvxShape = xNewShape.get();
        maWeakUnoShape = xShape = mpSvxShape;
    }

    return xShape;
}

void SdrObject::notifyShapePropertyChange( const OUString& rPropName ) const
{
    DBG_TESTSOLARMUTEX();

    SvxShape* pSvxShape = const_cast< SdrObject* >( this )->getSvxShape();
    if ( pSvxShape )
        return pSvxShape->notifyPropertyChange( rPropName );
}

// transformation interface for StarOfficeAPI. This implements support for
// homogeneous 3x3 matrices containing the transformation of the SdrObject. At the
// moment it contains a shearX, rotation and translation, but for setting all linear
// transforms like Scale, ShearX, ShearY, Rotate and Translate are supported.


// gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon
// with the base geometry and returns TRUE. Otherwise it returns FALSE.
bool SdrObject::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
{
    // any kind of SdrObject, just use SnapRect
    tools::Rectangle aRectangle(GetSnapRect());

    // convert to transformation values
    basegfx::B2DTuple aScale(aRectangle.GetWidth(), aRectangle.GetHeight());
    basegfx::B2DTuple aTranslate(aRectangle.Left(), aRectangle.Top());

    // position maybe relative to anchorpos, convert
    if(getSdrModelFromSdrObject().IsWriter())
    {
        if(GetAnchorPos().X() || GetAnchorPos().Y())
        {
            aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
        }
    }

    // build matrix
    rMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(aScale, aTranslate);

    return false;
}

// sets the base geometry of the object using infos contained in the homogeneous 3x3 matrix.
// If it's an SdrPathObj it will use the provided geometry information. The Polygon has
// to use (0,0) as upper left and will be scaled to the given size in the matrix.
void SdrObject::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
{
    // break up matrix
    basegfx::B2DTuple aScale;
    basegfx::B2DTuple aTranslate;
    double fRotate, fShearX;
    rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);

    // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
    // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
    if(aScale.getX() < 0.0 && aScale.getY() < 0.0)
    {
        aScale.setX(fabs(aScale.getX()));
        aScale.setY(fabs(aScale.getY()));
    }

    // if anchor is used, make position relative to it
    if(getSdrModelFromSdrObject().IsWriter())
    {
        if(GetAnchorPos().X() || GetAnchorPos().Y())
        {
            aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
        }
    }

    // build BaseRect
    Point aPoint(basegfx::fround<tools::Long>(aTranslate.getX()),
                 basegfx::fround<tools::Long>(aTranslate.getY()));
    tools::Rectangle aBaseRect(aPoint, Size(basegfx::fround<tools::Long>(aScale.getX()),
                                            basegfx::fround<tools::Long>(aScale.getY())));

    // set BaseRect
    SetSnapRect(aBaseRect);
}

// Give info if object is in destruction
bool SdrObject::IsInDestruction() const
{
    return getSdrModelFromSdrObject().IsInDestruction();
}

// return if fill is != drawing::FillStyle_NONE
bool SdrObject::HasFillStyle() const
{
    return GetObjectItem(XATTR_FILLSTYLE).GetValue() != drawing::FillStyle_NONE;
}

bool SdrObject::HasLineStyle() const
{
    return GetObjectItem(XATTR_LINESTYLE).GetValue() != drawing::LineStyle_NONE;
}


// #i52224#
// on import of OLE object from MS documents the BLIP size might be retrieved,
// the following four methods are used to control it;
// usually this data makes no sense after the import is finished, since the object
// might be resized


void SdrObject::SetBLIPSizeRectangle( const tools::Rectangle& aRect )
{
    maBLIPSizeRectangle = aRect;
}

void SdrObject::SetContextWritingMode( const sal_Int16 /*_nContextWritingMode*/ )
{
    // this base class does not support different writing modes, so ignore the call
}

void SdrObject::SetDoNotInsertIntoPageAutomatically(const bool bSet)
{
    mbDoNotInsertIntoPageAutomatically = bSet;
}


// #i121917#
bool SdrObject::HasText() const
{
    return false;
}

bool SdrObject::IsTextBox() const
{
    return false;
}

void SdrObject::MakeNameUnique()
{
    if (GetName().isEmpty())
    {
        OUString aName;
        if (const E3dScene* pE3dObj = DynCastE3dScene(this))
        {
            SdrObjList* pObjList = pE3dObj->GetSubList();
            if (pObjList)
            {
                SdrObject* pObj0 = pObjList->GetObj(0);
                if (pObj0)
                    aName = pObj0->TakeObjNameSingul();
            }
        }
        else
            aName = TakeObjNameSingul();
        SetName(aName + " 1");
    }

    std::unordered_set<OUString> aNameSet;
    MakeNameUnique(aNameSet);
}

void SdrObject::MakeNameUnique(std::unordered_set<OUString>& rNameSet)
{
    if (GetName().isEmpty())
        return;

    if (rNameSet.empty())
    {
        SdrPage* pPage;
        SdrObject* pObj;
        for (sal_uInt16 nPage(0); nPage < mrSdrModelFromSdrObject.GetPageCount(); ++nPage)
        {
            pPage = mrSdrModelFromSdrObject.GetPage(nPage);
            SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
            while (aIter.IsMore())
            {
                pObj = aIter.Next();
                if (pObj != this)
                    rNameSet.insert(pObj->GetName());
            }
        }
    }

    OUString sName(GetName().trim());
    OUString sRootName(sName);

    if (!sName.isEmpty() && rtl::isAsciiDigit(sName[sName.getLength() - 1]))
    {
        sal_Int32 nPos(sName.getLength() - 1);
        while (nPos > 0 && rtl::isAsciiDigit(sName[--nPos]));
        sRootName = o3tl::trim(sName.subView(0, nPos + 1));
    }

    for (sal_uInt32 n = 1; rNameSet.find(sName) != rNameSet.end(); n++)
        sName = sRootName + " " + OUString::number(n);
    rNameSet.insert(sName);

    SetName(sName);
}

void SdrObject::ForceMetricToItemPoolMetric(basegfx::B2DPolyPolygon& rPolyPolygon) const noexcept
{
    MapUnit eMapUnit(getSdrModelFromSdrObject().GetItemPool().GetMetric(0));
    if(eMapUnit == MapUnit::Map100thMM)
        return;

    if (const auto eTo = MapToO3tlLength(eMapUnit); eTo != o3tl::Length::invalid)
    {
        const double fConvert(o3tl::convert(1.0, o3tl::Length::mm100, eTo));
        rPolyPolygon.transform(basegfx::utils::createScaleB2DHomMatrix(fConvert, fConvert));
    }
    else
    {
        OSL_FAIL("Missing unit translation to PoolMetric!");
    }
}

const tools::Rectangle& SdrObject::getOutRectangle() const
{
    return m_aOutRect;
}

void SdrObject::setOutRectangleConst(tools::Rectangle const& rRectangle) const
{
    m_aOutRect = rRectangle;
}

void SdrObject::setOutRectangle(tools::Rectangle const& rRectangle)
{
    m_aOutRect = rRectangle;
}

void SdrObject::resetOutRectangle()
{
    m_aOutRect = tools::Rectangle();
}

void SdrObject::moveOutRectangle(sal_Int32 nXDelta, sal_Int32 nYDelta)
{
    m_aOutRect.Move(nXDelta, nYDelta);
}

E3dScene* DynCastE3dScene(SdrObject* pObj)
{
    if( pObj && pObj->GetObjInventor() == SdrInventor::E3d && pObj->GetObjIdentifier() == SdrObjKind::E3D_Scene )
        return static_cast<E3dScene*>(pObj);
    return nullptr;
}

E3dObject* DynCastE3dObject(SdrObject* pObj)
{
    if( pObj && pObj->GetObjInventor() == SdrInventor::E3d )
        return static_cast<E3dObject*>(pObj);
    return nullptr;
}

SdrTextObj* DynCastSdrTextObj(SdrObject* pObj)
{
    // SdrTextObj has a lot of subclasses, with lots of SdrObjKind identifiers, so use a virtual method
    // to be safer.
    if( pObj && pObj->IsSdrTextObj() )
        return static_cast<SdrTextObj*>(pObj);
    return nullptr;
}

SdrOle2Obj* DynCastSdrOle2Obj(SdrObject* pObj)
{
    // SdrTextObj has subclasses, with lots of SdrObjKind identifiers, so use a virtual method
    // to be safer.
    if( pObj && pObj->IsSdrOle2Obj() )
        return static_cast<SdrOle2Obj*>(pObj);
    return nullptr;
}

rtl::Reference<SdrObject> SdrObjFactory::CreateObjectFromFactory(SdrModel& rSdrModel, SdrInventor nInventor, SdrObjKind nObjIdentifier)
{
    SdrObjCreatorParams aParams { nInventor, nObjIdentifier, rSdrModel };
    for (const auto & i : ImpGetUserMakeObjHdl()) {
        rtl::Reference<SdrObject> pObj = i.Call(aParams);
        if (pObj) {
            return pObj;
        }
    }
    return nullptr;
}

namespace
{

// SdrObject subclass, which represents an empty object of a
// certain type (kind).
template <SdrObjKind OBJECT_KIND, SdrInventor OBJECT_INVENTOR>
class EmptyObject final : public SdrObject
{
private:
    virtual ~EmptyObject() override
    {}

public:
    EmptyObject(SdrModel& rSdrModel)
        : SdrObject(rSdrModel)
    {
    }

    EmptyObject(SdrModel& rSdrModel, EmptyObject const& rSource)
        : SdrObject(rSdrModel, rSource)
    {
    }

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

    virtual std::unique_ptr<sdr::properties::BaseProperties> CreateObjectSpecificProperties() override
    {
        return std::make_unique<sdr::properties::EmptyProperties>(*this);
    }

    SdrInventor GetObjInventor() const override
    {
        return OBJECT_INVENTOR;
    }

    SdrObjKind GetObjIdentifier() const override
    {
        return OBJECT_KIND;
    }

    void NbcRotate(const Point& /*rRef*/, Degree100 /*nAngle*/, double /*sinAngle*/, double /*cosAngle*/) override
    {
        assert(false); // should not be called for this kind of objects
    }
};

// end anonymous namespace

rtl::Reference<SdrObject> SdrObjFactory::MakeNewObject(
    SdrModel& rSdrModel,
    SdrInventor nInventor,
    SdrObjKind nIdentifier,
    const tools::Rectangle* pSnapRect)
{
    rtl::Reference<SdrObject> pObj;
    bool bSetSnapRect(nullptr != pSnapRect);

    if (nInventor == SdrInventor::Default)
    {
        switch (nIdentifier)
        {
            case SdrObjKind::Measure:
            {
                if(nullptr != pSnapRect)
                {
                    pObj = new SdrMeasureObj(
                        rSdrModel,
                        pSnapRect->TopLeft(),
                        pSnapRect->BottomRight());
                }
                else
                {
                    pObj = new SdrMeasureObj(rSdrModel);
                }
            }
            break;
            case SdrObjKind::Line:
            {
                if(nullptr != pSnapRect)
                {
                    basegfx::B2DPolygon aPoly;

                    aPoly.append(
                        basegfx::B2DPoint(
                            pSnapRect->Left(),
                            pSnapRect->Top()));
                    aPoly.append(
                        basegfx::B2DPoint(
                            pSnapRect->Right(),
                            pSnapRect->Bottom()));
                    pObj = new SdrPathObj(
                        rSdrModel,
                        SdrObjKind::Line,
                        basegfx::B2DPolyPolygon(aPoly));
                }
                else
                {
                    pObj = new SdrPathObj(
                        rSdrModel,
                        SdrObjKind::Line);
                }
            }
            break;
            case SdrObjKind::Text:
            case SdrObjKind::TitleText:
            case SdrObjKind::OutlineText:
            {
                if(nullptr != pSnapRect)
                {
                    pObj = new SdrRectObj(
                        rSdrModel,
                        nIdentifier,
                        *pSnapRect);
                    bSetSnapRect = false;
                }
                else
                {
                    pObj = new SdrRectObj(
                        rSdrModel,
                        nIdentifier);
                }
            }
            break;
            case SdrObjKind::CircleOrEllipse:
            case SdrObjKind::CircleSection:
            case SdrObjKind::CircleArc:
            case SdrObjKind::CircleCut:
            {
                SdrCircKind eCircKind = ToSdrCircKind(nIdentifier);
                if(nullptr != pSnapRect)
                {
                    pObj = new SdrCircObj(rSdrModel, eCircKind, *pSnapRect);
                    bSetSnapRect = false;
                }
                else
                {
                    pObj = new SdrCircObj(rSdrModel, eCircKind);
                }
            }
            break;
            case SdrObjKind::NONE: pObj = nullptr; break;
            case SdrObjKind::Group       : pObj=new SdrObjGroup(rSdrModel);                 break;
            case SdrObjKind::Polygon       : pObj=new SdrPathObj(rSdrModel, SdrObjKind::Polygon       ); break;
            case SdrObjKind::PolyLine       : pObj=new SdrPathObj(rSdrModel, SdrObjKind::PolyLine       ); break;
            case SdrObjKind::PathLine   : pObj=new SdrPathObj(rSdrModel, SdrObjKind::PathLine   ); break;
            case SdrObjKind::PathFill   : pObj=new SdrPathObj(rSdrModel, SdrObjKind::PathFill   ); break;
            case SdrObjKind::FreehandLine   : pObj=new SdrPathObj(rSdrModel, SdrObjKind::FreehandLine   ); break;
            case SdrObjKind::FreehandFill   : pObj=new SdrPathObj(rSdrModel, SdrObjKind::FreehandFill   ); break;
            case SdrObjKind::PathPoly   : pObj=new SdrPathObj(rSdrModel, SdrObjKind::Polygon       ); break;
            case SdrObjKind::PathPolyLine   : pObj=new SdrPathObj(rSdrModel, SdrObjKind::PolyLine       ); break;
            case SdrObjKind::Edge       : pObj=new SdrEdgeObj(rSdrModel);                  break;
            case SdrObjKind::Rectangle       : pObj=new SdrRectObj(rSdrModel);                  break;
            case SdrObjKind::Graphic       : pObj=new SdrGrafObj(rSdrModel);                  break;
            case SdrObjKind::OLE2       : pObj=new SdrOle2Obj(rSdrModel);                  break;
            case SdrObjKind::OLEPluginFrame      : pObj=new SdrOle2Obj(rSdrModel, true);            break;
            case SdrObjKind::Caption    : pObj=new SdrCaptionObj(rSdrModel);               break;
            case SdrObjKind::Page       : pObj=new SdrPageObj(rSdrModel);                  break;
            case SdrObjKind::UNO        : pObj=new SdrUnoObj(rSdrModel, OUString());       break;
            case SdrObjKind::CustomShape: pObj=new SdrObjCustomShape(rSdrModel);       break;
#if HAVE_FEATURE_AVMEDIA
            case SdrObjKind::Media      : pObj=new SdrMediaObj(rSdrModel);               break;
#endif
            case SdrObjKind::Table      : pObj=new sdr::table::SdrTableObj(rSdrModel);   break;
            case SdrObjKind::NewFrame: // used for frame creation in writer
                pObj = new EmptyObject<SdrObjKind::NewFrame, SdrInventor::Default>(rSdrModel);
                break;
            default:
                break;
        }
    }

    if (!pObj)
    {
        pObj = CreateObjectFromFactory(rSdrModel, nInventor, nIdentifier);
    }

    if (!pObj)
    {
        // Well, if no one wants it...
        return nullptr;
    }

    if(bSetSnapRect && nullptr != pSnapRect)
    {
        pObj->NbcSetSnapRect(*pSnapRect);
    }

    return pObj;
}

void SdrObjFactory::InsertMakeObjectHdl(Link<SdrObjCreatorParams, rtl::Reference<SdrObject>> const & rLink)
{
    std::vector<Link<SdrObjCreatorParams, rtl::Reference<SdrObject>>>& rLL=ImpGetUserMakeObjHdl();
    auto it = std::find(rLL.begin(), rLL.end(), rLink);
    if (it != rLL.end()) {
        OSL_FAIL("SdrObjFactory::InsertMakeObjectHdl(): Link already in place.");
    } else {
        rLL.push_back(rLink);
    }
}

void SdrObjFactory::RemoveMakeObjectHdl(Link<SdrObjCreatorParams, rtl::Reference<SdrObject>> const & rLink)
{
    std::vector<Link<SdrObjCreatorParams, rtl::Reference<SdrObject>>>& rLL=ImpGetUserMakeObjHdl();
    auto it = std::find(rLL.begin(), rLL.end(), rLink);
    if (it != rLL.end())
        rLL.erase(it);
}

namespace svx
{
    ISdrObjectFilter::~ISdrObjectFilter()
    {
    }
}

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

Messung V0.5 in Prozent
C=93 H=96 G=94

¤ Dauer der Verarbeitung: 0.45 Sekunden  (vorverarbeitet am  2026-05-08) ¤

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