xref: /core/svx/source/svdraw/svdobj.cxx (revision 8c8d8786)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <svx/svdobj.hxx>
21 #include <config_features.h>
22 
23 #include <sal/config.h>
24 #include <sal/log.hxx>
25 #include <rtl/ustrbuf.hxx>
26 
27 #include <com/sun/star/lang/XComponent.hpp>
28 #include <com/sun/star/text/RelOrientation.hpp>
29 #include <com/sun/star/frame/XTerminateListener.hpp>
30 #include <com/sun/star/frame/Desktop.hpp>
31 
32 #include <basegfx/matrix/b2dhommatrix.hxx>
33 #include <basegfx/matrix/b2dhommatrixtools.hxx>
34 #include <basegfx/polygon/b2dpolygon.hxx>
35 #include <basegfx/polygon/b2dpolygontools.hxx>
36 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
37 #include <basegfx/polygon/b2dpolypolygontools.hxx>
38 #include <basegfx/range/b2drange.hxx>
39 #include <drawinglayer/processor2d/contourextractor2d.hxx>
40 #include <drawinglayer/processor2d/linegeometryextractor2d.hxx>
41 #include <comphelper/processfactory.hxx>
42 #include <editeng/editeng.hxx>
43 #include <editeng/outlobj.hxx>
44 #include <o3tl/deleter.hxx>
45 #include <math.h>
46 #include <svl/grabbagitem.hxx>
47 #include <tools/bigint.hxx>
48 #include <tools/diagnose_ex.h>
49 #include <tools/helpers.hxx>
50 #include <unotools/configmgr.hxx>
51 #include <vcl/canvastools.hxx>
52 #include <vcl/ptrstyle.hxx>
53 #include <vector>
54 
55 #include <svx/shapepropertynotifier.hxx>
56 #include <svx/svdotable.hxx>
57 
58 #include <svx/sdr/contact/displayinfo.hxx>
59 #include <sdr/contact/objectcontactofobjlistpainter.hxx>
60 #include <svx/sdr/contact/viewcontactofsdrobj.hxx>
61 #include <sdr/properties/emptyproperties.hxx>
62 #include <svx/sdrhittesthelper.hxx>
63 #include <svx/sdrobjectuser.hxx>
64 #include <svx/sdrobjectfilter.hxx>
65 #include <svx/svddrag.hxx>
66 #include <svx/svdetc.hxx>
67 #include <svx/svdhdl.hxx>
68 #include <svx/svditer.hxx>
69 #include <svx/svdmodel.hxx>
70 #include <svx/svdoashp.hxx>
71 #include <svx/svdocapt.hxx>
72 #include <svx/svdocirc.hxx>
73 #include <svx/svdoedge.hxx>
74 #include <svx/svdograf.hxx>
75 #include <svx/svdogrp.hxx>
76 #include <svx/svdomeas.hxx>
77 #include <svx/svdomedia.hxx>
78 #include <svx/svdoole2.hxx>
79 #include <svx/svdopage.hxx>
80 #include <svx/svdopath.hxx>
81 #include <svx/svdorect.hxx>
82 #include <svx/svdotext.hxx>
83 #include <svx/svdouno.hxx>
84 #include <svx/svdovirt.hxx>
85 #include <svx/svdpage.hxx>
86 #include <svx/svdpool.hxx>
87 #include <svx/strings.hrc>
88 #include <svx/dialmgr.hxx>
89 #include <svx/svdtrans.hxx>
90 #include <svx/svdundo.hxx>
91 #include <svx/svdview.hxx>
92 #include <sxlayitm.hxx>
93 #include <sxlogitm.hxx>
94 #include <sxmovitm.hxx>
95 #include <sxoneitm.hxx>
96 #include <sxopitm.hxx>
97 #include <sxreoitm.hxx>
98 #include <sxrooitm.hxx>
99 #include <sxsaitm.hxx>
100 #include <sxsoitm.hxx>
101 #include <sxtraitm.hxx>
102 #include <svx/unopage.hxx>
103 #include <svx/unoshape.hxx>
104 #include <svx/xfillit0.hxx>
105 #include <svx/xflclit.hxx>
106 #include <svx/xfltrit.hxx>
107 #include <svx/xlineit0.hxx>
108 #include <svx/xlnclit.hxx>
109 #include <svx/xlnedwit.hxx>
110 #include <svx/xlnstwit.hxx>
111 #include <svx/xlntrit.hxx>
112 #include <svx/xlnwtit.hxx>
113 #include <svx/svdglue.hxx>
114 #include <svx/svdsob.hxx>
115 #include <svdobjplusdata.hxx>
116 #include <svdobjuserdatalist.hxx>
117 
118 #include <unordered_set>
119 
120 #include <optional>
121 #include <libxml/xmlwriter.h>
122 #include <memory>
123 
124 #include <svx/scene3d.hxx>
125 #include <rtl/character.hxx>
126 
127 using namespace ::com::sun::star;
128 
129 
130 SdrObjUserCall::~SdrObjUserCall()
131 {
132 }
133 
134 void SdrObjUserCall::Changed(const SdrObject& /*rObj*/, SdrUserCallType /*eType*/, const tools::Rectangle& /*rOldBoundRect*/)
135 {
136 }
137 
138 SdrObjMacroHitRec::SdrObjMacroHitRec() :
139     pVisiLayer(nullptr),
140     pPageView(nullptr),
141     nTol(0) {}
142 
143 
144 SdrObjUserData::SdrObjUserData(SdrInventor nInv, sal_uInt16 nId) :
145     nInventor(nInv),
146     nIdentifier(nId) {}
147 
148 SdrObjUserData::SdrObjUserData(const SdrObjUserData& rData) :
149     nInventor(rData.nInventor),
150     nIdentifier(rData.nIdentifier) {}
151 
152 SdrObjUserData::~SdrObjUserData() {}
153 
154 SdrObjGeoData::SdrObjGeoData():
155     bMovProt(false),
156     bSizProt(false),
157     bNoPrint(false),
158     bClosedObj(false),
159     mbVisible(true),
160     mnLayerID(0)
161 {
162 }
163 
164 SdrObjGeoData::~SdrObjGeoData()
165 {
166 }
167 
168 SdrObjTransformInfoRec::SdrObjTransformInfoRec() :
169     bMoveAllowed(true),
170     bResizeFreeAllowed(true),
171     bResizePropAllowed(true),
172     bRotateFreeAllowed(true),
173     bRotate90Allowed(true),
174     bMirrorFreeAllowed(true),
175     bMirror45Allowed(true),
176     bMirror90Allowed(true),
177     bTransparenceAllowed(true),
178     bShearAllowed(true),
179     bEdgeRadiusAllowed(true),
180     bNoOrthoDesired(true),
181     bNoContortion(true),
182     bCanConvToPath(true),
183     bCanConvToPoly(true),
184     bCanConvToContour(false),
185     bCanConvToPathLineToArea(true),
186     bCanConvToPolyLineToArea(true) {}
187 
188 struct SdrObject::Impl
189 {
190     sdr::ObjectUserVector maObjectUsers;
191     std::shared_ptr<DiagramDataInterface> mpDiagramData;
192     std::optional<double> mnRelativeWidth;
193     std::optional<double> mnRelativeHeight;
194     sal_Int16               meRelativeWidthRelation;
195     sal_Int16               meRelativeHeightRelation;
196 
197     Impl() :
198         meRelativeWidthRelation(text::RelOrientation::PAGE_FRAME),
199         meRelativeHeightRelation(text::RelOrientation::PAGE_FRAME) {}
200 };
201 
202 
203 // BaseProperties section
204 
205 std::unique_ptr<sdr::properties::BaseProperties> SdrObject::CreateObjectSpecificProperties()
206 {
207     return std::make_unique<sdr::properties::EmptyProperties>(*this);
208 }
209 
210 sdr::properties::BaseProperties& SdrObject::GetProperties() const
211 {
212     if(!mpProperties)
213     {
214         // CAUTION(!) Do *not* call this during SdrObject construction,
215         // that will lead to wrong type-casts (dependent on constructor-level)
216         // and thus eventually create the wrong sdr::properties (!). Is there
217         // a way to check if on the stack is a SdrObject-constructor (?)
218         const_cast< SdrObject* >(this)->mpProperties =
219             const_cast< SdrObject* >(this)->CreateObjectSpecificProperties();
220     }
221 
222     return *mpProperties;
223 }
224 
225 
226 // ObjectUser section
227 
228 void SdrObject::AddObjectUser(sdr::ObjectUser& rNewUser)
229 {
230     mpImpl->maObjectUsers.push_back(&rNewUser);
231 }
232 
233 void SdrObject::RemoveObjectUser(sdr::ObjectUser& rOldUser)
234 {
235     const sdr::ObjectUserVector::iterator aFindResult =
236         std::find(mpImpl->maObjectUsers.begin(), mpImpl->maObjectUsers.end(), &rOldUser);
237     if (aFindResult != mpImpl->maObjectUsers.end())
238     {
239         mpImpl->maObjectUsers.erase(aFindResult);
240     }
241 }
242 
243 
244 // DrawContact section
245 
246 std::unique_ptr<sdr::contact::ViewContact> SdrObject::CreateObjectSpecificViewContact()
247 {
248     return std::make_unique<sdr::contact::ViewContactOfSdrObj>(*this);
249 }
250 
251 sdr::contact::ViewContact& SdrObject::GetViewContact() const
252 {
253     if(!mpViewContact)
254     {
255         const_cast< SdrObject* >(this)->mpViewContact =
256             const_cast< SdrObject* >(this)->CreateObjectSpecificViewContact();
257     }
258 
259     return *mpViewContact;
260 }
261 
262 // DrawContact support: Methods for handling Object changes
263 void SdrObject::ActionChanged() const
264 {
265     // Do necessary ViewContact actions
266     GetViewContact().ActionChanged();
267 }
268 
269 SdrPage* SdrObject::getSdrPageFromSdrObject() const
270 {
271     if(getParentSdrObjListFromSdrObject())
272     {
273         return getParentSdrObjListFromSdrObject()->getSdrPageFromSdrObjList();
274     }
275 
276     return nullptr;
277 }
278 
279 SdrModel& SdrObject::getSdrModelFromSdrObject() const
280 {
281     return mrSdrModelFromSdrObject;
282 }
283 
284 void SdrObject::setParentOfSdrObject(SdrObjList* pNewObjList)
285 {
286     if(getParentSdrObjListFromSdrObject() == pNewObjList)
287         return;
288 
289     // remember current page
290     SdrPage* pOldPage(getSdrPageFromSdrObject());
291 
292     // set new parent
293     mpParentOfSdrObject = pNewObjList;
294 
295     // get new page
296     SdrPage* pNewPage(getSdrPageFromSdrObject());
297 
298     // broadcast page change over objects if needed
299     if(pOldPage != pNewPage)
300     {
301         handlePageChange(pOldPage, pNewPage);
302     }
303 }
304 
305 SdrObjList* SdrObject::getParentSdrObjListFromSdrObject() const
306 {
307     return mpParentOfSdrObject;
308 }
309 
310 SdrObjList* SdrObject::getChildrenOfSdrObject() const
311 {
312     // default has no children
313     return nullptr;
314 }
315 
316 void SdrObject::SetBoundRectDirty()
317 {
318     m_aOutRect = tools::Rectangle();
319 }
320 
321 #ifdef DBG_UTIL
322 // SdrObjectLifetimeWatchDog:
323 void impAddIncarnatedSdrObjectToSdrModel(const SdrObject& rSdrObject, SdrModel& rSdrModel)
324 {
325     rSdrModel.maAllIncarnatedObjects.insert(&rSdrObject);
326 }
327 void impRemoveIncarnatedSdrObjectToSdrModel(const SdrObject& rSdrObject, SdrModel& rSdrModel)
328 {
329     if(!rSdrModel.maAllIncarnatedObjects.erase(&rSdrObject))
330     {
331         SAL_WARN("svx","SdrObject::~SdrObject: Destructed incarnation of SdrObject not member of this SdrModel (!)");
332     }
333 }
334 #endif
335 
336 SdrObject::SdrObject(SdrModel& rSdrModel)
337 :   mpFillGeometryDefiningShape(nullptr)
338     ,mrSdrModelFromSdrObject(rSdrModel)
339     ,m_pUserCall(nullptr)
340     ,mpImpl(new Impl)
341     ,mpParentOfSdrObject(nullptr)
342     ,m_nOrdNum(0)
343     ,mnNavigationPosition(SAL_MAX_UINT32)
344     ,mnLayerID(0)
345     ,mpSvxShape( nullptr )
346     ,maWeakUnoShape()
347     ,mbDoNotInsertIntoPageAutomatically(false)
348 {
349     m_bVirtObj         =false;
350     m_bSnapRectDirty   =true;
351     m_bMovProt         =false;
352     m_bSizProt         =false;
353     m_bNoPrint         =false;
354     m_bEmptyPresObj    =false;
355     m_bNotVisibleAsMaster=false;
356     m_bClosedObj       =false;
357     mbVisible        = true;
358 
359     // #i25616#
360     mbLineIsOutsideGeometry = false;
361 
362     // #i25616#
363     mbSupportTextIndentingOnLineWidthChange = false;
364 
365     m_bIsEdge=false;
366     m_bIs3DObj=false;
367     m_bMarkProt=false;
368     m_bIsUnoObj=false;
369 #ifdef DBG_UTIL
370     // SdrObjectLifetimeWatchDog:
371     impAddIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject());
372 #endif
373 }
374 
375 SdrObject::SdrObject(SdrModel& rSdrModel, SdrObject const & rSource)
376 :   mpFillGeometryDefiningShape(nullptr)
377     ,mrSdrModelFromSdrObject(rSdrModel)
378     ,m_pUserCall(nullptr)
379     ,mpImpl(new Impl)
380     ,mpParentOfSdrObject(nullptr)
381     ,m_nOrdNum(0)
382     ,mnNavigationPosition(SAL_MAX_UINT32)
383     ,mnLayerID(0)
384     ,mpSvxShape( nullptr )
385     ,maWeakUnoShape()
386     ,mbDoNotInsertIntoPageAutomatically(false)
387 {
388     m_bVirtObj         =false;
389     m_bSnapRectDirty   =true;
390     m_bMovProt         =false;
391     m_bSizProt         =false;
392     m_bNoPrint         =false;
393     m_bEmptyPresObj    =false;
394     m_bNotVisibleAsMaster=false;
395     m_bClosedObj       =false;
396     mbVisible        = true;
397 
398     // #i25616#
399     mbLineIsOutsideGeometry = false;
400 
401     // #i25616#
402     mbSupportTextIndentingOnLineWidthChange = false;
403 
404     m_bIsEdge=false;
405     m_bIs3DObj=false;
406     m_bMarkProt=false;
407     m_bIsUnoObj=false;
408 #ifdef DBG_UTIL
409     // SdrObjectLifetimeWatchDog:
410     impAddIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject());
411 #endif
412 
413     mpProperties.reset();
414     mpViewContact.reset();
415 
416     // The CloneSdrObject() method uses the local copy constructor from the individual
417     // sdr::properties::BaseProperties class. Since the target class maybe for another
418     // draw object, an SdrObject needs to be provided, as in the normal constructor.
419     mpProperties = rSource.GetProperties().Clone(*this);
420 
421     m_aOutRect=rSource.m_aOutRect;
422     mnLayerID = rSource.mnLayerID;
423     m_aAnchor =rSource.m_aAnchor;
424     m_bVirtObj=rSource.m_bVirtObj;
425     m_bSizProt=rSource.m_bSizProt;
426     m_bMovProt=rSource.m_bMovProt;
427     m_bNoPrint=rSource.m_bNoPrint;
428     mbVisible=rSource.mbVisible;
429     m_bMarkProt=rSource.m_bMarkProt;
430     m_bEmptyPresObj =rSource.m_bEmptyPresObj;
431     m_bNotVisibleAsMaster=rSource.m_bNotVisibleAsMaster;
432     m_bSnapRectDirty=true;
433     m_pPlusData.reset();
434     if (rSource.m_pPlusData!=nullptr) {
435         m_pPlusData.reset(rSource.m_pPlusData->Clone(this));
436     }
437     if (m_pPlusData!=nullptr && m_pPlusData->pBroadcast!=nullptr) {
438         m_pPlusData->pBroadcast.reset(); // broadcaster isn't copied
439     }
440 
441     m_pGrabBagItem.reset();
442     if (rSource.m_pGrabBagItem!=nullptr)
443         m_pGrabBagItem.reset(rSource.m_pGrabBagItem->Clone());
444 }
445 
446 SdrObject::~SdrObject()
447 {
448     // Tell all the registered ObjectUsers that the page is in destruction.
449     // And clear the vector. This means that user do not need to call RemoveObjectUser()
450     // when they get called from ObjectInDestruction().
451     sdr::ObjectUserVector aList;
452     aList.swap(mpImpl->maObjectUsers);
453     for(sdr::ObjectUser* pObjectUser : aList)
454     {
455         DBG_ASSERT(pObjectUser, "SdrObject::~SdrObject: corrupt ObjectUser list (!)");
456         pObjectUser->ObjectInDestruction(*this);
457     }
458 
459     // UserCall
460     SendUserCall(SdrUserCallType::Delete, GetLastBoundRect());
461     o3tl::reset_preserve_ptr_during(m_pPlusData);
462 
463     m_pGrabBagItem.reset();
464     mpProperties.reset();
465     mpViewContact.reset();
466 
467 #ifdef DBG_UTIL
468     // SdrObjectLifetimeWatchDog:
469     impRemoveIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject());
470 #endif
471 }
472 
473 void SdrObject::Free( SdrObject*& _rpObject )
474 {
475     SdrObject* pObject = _rpObject; _rpObject = nullptr;
476 
477     if(nullptr == pObject)
478     {
479         // nothing to do
480         return;
481     }
482 
483     SvxShape* pShape(pObject->getSvxShape());
484 
485     if(pShape)
486     {
487         if(pShape->HasSdrObjectOwnership())
488         {
489             // only the SvxShape is allowed to delete me, and will reset
490             // the ownership before doing so
491             return;
492         }
493         else
494         {
495             // not only delete pObject, but also need to dispose uno shape
496             try
497             {
498                 pShape->InvalidateSdrObject();
499                 uno::Reference< lang::XComponent > xShapeComp( pObject->getWeakUnoShape(), uno::UNO_QUERY_THROW );
500                 xShapeComp->dispose();
501             }
502             catch( const uno::Exception& )
503             {
504                 DBG_UNHANDLED_EXCEPTION("svx");
505             }
506         }
507     }
508 
509     delete pObject;
510 }
511 
512 void SdrObject::SetBoundAndSnapRectsDirty(bool bNotMyself, bool bRecursive)
513 {
514     if (!bNotMyself)
515     {
516         SetBoundRectDirty();
517         m_bSnapRectDirty=true;
518     }
519 
520     if (bRecursive && nullptr != getParentSdrObjListFromSdrObject())
521     {
522         getParentSdrObjListFromSdrObject()->SetSdrObjListRectsDirty();
523     }
524 }
525 
526 void SdrObject::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
527 {
528     // The creation of the UNO shape in SdrObject::getUnoShape is influenced
529     // by pPage, so when the page changes we need to discard the cached UNO
530     // shape so that a new one will be created.
531     // If the page is changing to another page with the same model, we
532     // assume they create compatible UNO shape objects so we shouldn't have
533     // to invalidate.
534     // TTTT: This causes quite some problems in SvxDrawPage::add when used
535     // e.g. from Writer - the SdrObject may be cloned to target model, and
536     // the xShape was added to it by purpose (see there). Thus it will be
537     // good to think about if this is really needed - it *seems* to be intended
538     // for a xShape being a on-demand-creatable resource - with the argument that
539     // the SdrPage/UnoPage used influences the SvxShape creation. This uses
540     // resources and would be nice to get rid of anyways.
541     if(nullptr == pOldPage || nullptr == pNewPage)
542     {
543         SvxShape* const pShape(getSvxShape());
544 
545         if (pShape && !pShape->HasSdrObjectOwnership())
546         {
547             setUnoShape(nullptr);
548         }
549     }
550 }
551 
552 
553 // global static ItemPool for not-yet-inserted items
554 static rtl::Reference<SdrItemPool> mpGlobalItemPool;
555 
556 /** If we let the libc runtime clean us up, we trigger a crash */
557 namespace
558 {
559 class TerminateListener : public ::cppu::WeakImplHelper< css::frame::XTerminateListener >
560 {
561     void SAL_CALL queryTermination( const lang::EventObject& ) override
562     {}
563     void SAL_CALL notifyTermination( const lang::EventObject& ) override
564     {
565         mpGlobalItemPool.clear();
566     }
567     virtual void SAL_CALL disposing( const ::css::lang::EventObject& ) override
568     {}
569 };
570 };
571 
572 // init global static itempool
573 SdrItemPool& SdrObject::GetGlobalDrawObjectItemPool()
574 {
575     if(!mpGlobalItemPool)
576     {
577         mpGlobalItemPool = new SdrItemPool();
578         rtl::Reference<SfxItemPool> pGlobalOutlPool = EditEngine::CreatePool();
579         mpGlobalItemPool->SetSecondaryPool(pGlobalOutlPool.get());
580         mpGlobalItemPool->SetDefaultMetric(SdrEngineDefaults::GetMapUnit());
581         mpGlobalItemPool->FreezeIdRanges();
582         if (utl::ConfigManager::IsFuzzing())
583             mpGlobalItemPool->acquire();
584         else
585         {
586             uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(comphelper::getProcessComponentContext());
587             uno::Reference< frame::XTerminateListener > xListener( new TerminateListener );
588             xDesktop->addTerminateListener( xListener );
589         }
590     }
591 
592     return *mpGlobalItemPool;
593 }
594 
595 void SdrObject::SetRelativeWidth( double nValue )
596 {
597     mpImpl->mnRelativeWidth = nValue;
598 }
599 
600 void SdrObject::SetRelativeWidthRelation( sal_Int16 eValue )
601 {
602     mpImpl->meRelativeWidthRelation = eValue;
603 }
604 
605 void SdrObject::SetRelativeHeight( double nValue )
606 {
607     mpImpl->mnRelativeHeight = nValue;
608 }
609 
610 void SdrObject::SetRelativeHeightRelation( sal_Int16 eValue )
611 {
612     mpImpl->meRelativeHeightRelation = eValue;
613 }
614 
615 const double* SdrObject::GetRelativeWidth( ) const
616 {
617     if (!mpImpl->mnRelativeWidth)
618         return nullptr;
619 
620     return &*mpImpl->mnRelativeWidth;
621 }
622 
623 sal_Int16 SdrObject::GetRelativeWidthRelation() const
624 {
625     return mpImpl->meRelativeWidthRelation;
626 }
627 
628 const double* SdrObject::GetRelativeHeight( ) const
629 {
630     if (!mpImpl->mnRelativeHeight)
631         return nullptr;
632 
633     return &*mpImpl->mnRelativeHeight;
634 }
635 
636 sal_Int16 SdrObject::GetRelativeHeightRelation() const
637 {
638     return mpImpl->meRelativeHeightRelation;
639 }
640 
641 void SdrObject::SetDiagramData(std::shared_ptr<DiagramDataInterface> pDiagramData)
642 {
643     mpImpl->mpDiagramData = pDiagramData;
644 }
645 
646 const std::shared_ptr<DiagramDataInterface> & SdrObject::GetDiagramData() const
647 {
648     return mpImpl->mpDiagramData;
649 }
650 
651 SfxItemPool& SdrObject::GetObjectItemPool() const
652 {
653     return getSdrModelFromSdrObject().GetItemPool();
654 }
655 
656 SdrInventor SdrObject::GetObjInventor()   const
657 {
658     return SdrInventor::Default;
659 }
660 
661 SdrObjKind SdrObject::GetObjIdentifier() const
662 {
663     return OBJ_NONE;
664 }
665 
666 void SdrObject::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
667 {
668     rInfo.bRotateFreeAllowed=false;
669     rInfo.bMirrorFreeAllowed=false;
670     rInfo.bTransparenceAllowed = false;
671     rInfo.bShearAllowed     =false;
672     rInfo.bEdgeRadiusAllowed=false;
673     rInfo.bCanConvToPath    =false;
674     rInfo.bCanConvToPoly    =false;
675     rInfo.bCanConvToContour = false;
676     rInfo.bCanConvToPathLineToArea=false;
677     rInfo.bCanConvToPolyLineToArea=false;
678 }
679 
680 SdrLayerID SdrObject::GetLayer() const
681 {
682     return mnLayerID;
683 }
684 
685 void SdrObject::getMergedHierarchySdrLayerIDSet(SdrLayerIDSet& rSet) const
686 {
687     rSet.Set(GetLayer());
688     SdrObjList* pOL=GetSubList();
689     if (pOL!=nullptr) {
690         const size_t nObjCount = pOL->GetObjCount();
691         for (size_t nObjNum = 0; nObjNum<nObjCount; ++nObjNum) {
692             pOL->GetObj(nObjNum)->getMergedHierarchySdrLayerIDSet(rSet);
693         }
694     }
695 }
696 
697 void SdrObject::NbcSetLayer(SdrLayerID nLayer)
698 {
699     mnLayerID = nLayer;
700 }
701 
702 void SdrObject::SetLayer(SdrLayerID nLayer)
703 {
704     NbcSetLayer(nLayer);
705     SetChanged();
706     BroadcastObjectChange();
707 }
708 
709 void SdrObject::AddListener(SfxListener& rListener)
710 {
711     ImpForcePlusData();
712     if (m_pPlusData->pBroadcast==nullptr) m_pPlusData->pBroadcast.reset(new SfxBroadcaster);
713 
714     // SdrEdgeObj may be connected to same SdrObject on both ends so allow it
715     // to listen twice
716     SdrEdgeObj const*const pEdge(dynamic_cast<SdrEdgeObj const*>(&rListener));
717     rListener.StartListening(*m_pPlusData->pBroadcast, pEdge ? DuplicateHandling::Allow : DuplicateHandling::Unexpected);
718 }
719 
720 void SdrObject::RemoveListener(SfxListener& rListener)
721 {
722     if (m_pPlusData!=nullptr && m_pPlusData->pBroadcast!=nullptr) {
723         rListener.EndListening(*m_pPlusData->pBroadcast);
724         if (!m_pPlusData->pBroadcast->HasListeners()) {
725             m_pPlusData->pBroadcast.reset();
726         }
727     }
728 }
729 
730 const SfxBroadcaster* SdrObject::GetBroadcaster() const
731 {
732     return m_pPlusData!=nullptr ? m_pPlusData->pBroadcast.get() : nullptr;
733 }
734 
735 void SdrObject::AddReference(SdrVirtObj& rVrtObj)
736 {
737     AddListener(rVrtObj);
738 }
739 
740 void SdrObject::DelReference(SdrVirtObj& rVrtObj)
741 {
742     RemoveListener(rVrtObj);
743 }
744 
745 bool SdrObject::IsGroupObject() const
746 {
747     return GetSubList()!=nullptr;
748 }
749 
750 SdrObjList* SdrObject::GetSubList() const
751 {
752     return nullptr;
753 }
754 
755 SdrObject* SdrObject::getParentSdrObjectFromSdrObject() const
756 {
757     SdrObjList* pParent(getParentSdrObjListFromSdrObject());
758 
759     if(nullptr == pParent)
760     {
761         return nullptr;
762     }
763 
764     return pParent->getSdrObjectFromSdrObjList();
765 }
766 
767 void SdrObject::SetName(const OUString& rStr, const bool bSetChanged)
768 {
769     if (!rStr.isEmpty() && !m_pPlusData)
770     {
771         ImpForcePlusData();
772     }
773 
774     if(!(m_pPlusData && m_pPlusData->aObjName != rStr))
775         return;
776 
777     // Undo/Redo for setting object's name (#i73249#)
778     bool bUndo( false );
779     if ( getSdrModelFromSdrObject().IsUndoEnabled() )
780     {
781         bUndo = true;
782         std::unique_ptr<SdrUndoAction> pUndoAction =
783                 SdrUndoFactory::CreateUndoObjectStrAttr(
784                                                 *this,
785                                                 SdrUndoObjStrAttr::ObjStrAttrType::Name,
786                                                 GetName(),
787                                                 rStr );
788         getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
789         getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
790     }
791     m_pPlusData->aObjName = rStr;
792     // Undo/Redo for setting object's name (#i73249#)
793     if ( bUndo )
794     {
795         getSdrModelFromSdrObject().EndUndo();
796     }
797     if (bSetChanged)
798     {
799         SetChanged();
800         BroadcastObjectChange();
801     }
802 }
803 
804 OUString SdrObject::GetName() const
805 {
806     if(m_pPlusData)
807     {
808         return m_pPlusData->aObjName;
809     }
810 
811     return OUString();
812 }
813 
814 void SdrObject::SetTitle(const OUString& rStr)
815 {
816     if (!rStr.isEmpty() && !m_pPlusData)
817     {
818         ImpForcePlusData();
819     }
820 
821     if(!(m_pPlusData && m_pPlusData->aObjTitle != rStr))
822         return;
823 
824     // Undo/Redo for setting object's title (#i73249#)
825     bool bUndo( false );
826     if ( getSdrModelFromSdrObject().IsUndoEnabled() )
827     {
828         bUndo = true;
829         std::unique_ptr<SdrUndoAction> pUndoAction =
830                 SdrUndoFactory::CreateUndoObjectStrAttr(
831                                                 *this,
832                                                 SdrUndoObjStrAttr::ObjStrAttrType::Title,
833                                                 GetTitle(),
834                                                 rStr );
835         getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
836         getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
837     }
838     m_pPlusData->aObjTitle = rStr;
839     // Undo/Redo for setting object's title (#i73249#)
840     if ( bUndo )
841     {
842         getSdrModelFromSdrObject().EndUndo();
843     }
844     SetChanged();
845     BroadcastObjectChange();
846 }
847 
848 OUString SdrObject::GetTitle() const
849 {
850     if(m_pPlusData)
851     {
852         return m_pPlusData->aObjTitle;
853     }
854 
855     return OUString();
856 }
857 
858 void SdrObject::SetDescription(const OUString& rStr)
859 {
860     if (!rStr.isEmpty() && !m_pPlusData)
861     {
862         ImpForcePlusData();
863     }
864 
865     if(!(m_pPlusData && m_pPlusData->aObjDescription != rStr))
866         return;
867 
868     // Undo/Redo for setting object's description (#i73249#)
869     bool bUndo( false );
870     if ( getSdrModelFromSdrObject().IsUndoEnabled() )
871     {
872         bUndo = true;
873         std::unique_ptr<SdrUndoAction> pUndoAction =
874                 SdrUndoFactory::CreateUndoObjectStrAttr(
875                                                 *this,
876                                                 SdrUndoObjStrAttr::ObjStrAttrType::Description,
877                                                 GetDescription(),
878                                                 rStr );
879         getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() );
880         getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) );
881     }
882     m_pPlusData->aObjDescription = rStr;
883     // Undo/Redo for setting object's description (#i73249#)
884     if ( bUndo )
885     {
886         getSdrModelFromSdrObject().EndUndo();
887     }
888     SetChanged();
889     BroadcastObjectChange();
890 }
891 
892 OUString SdrObject::GetDescription() const
893 {
894     if(m_pPlusData)
895     {
896         return m_pPlusData->aObjDescription;
897     }
898 
899     return OUString();
900 }
901 
902 sal_uInt32 SdrObject::GetOrdNum() const
903 {
904     if (nullptr != getParentSdrObjListFromSdrObject())
905     {
906         if (getParentSdrObjListFromSdrObject()->IsObjOrdNumsDirty())
907         {
908             getParentSdrObjListFromSdrObject()->RecalcObjOrdNums();
909         }
910     } else const_cast<SdrObject*>(this)->m_nOrdNum=0;
911     return m_nOrdNum;
912 }
913 
914 
915 void SdrObject::SetOrdNum(sal_uInt32 nNum)
916 {
917     m_nOrdNum = nNum;
918 }
919 
920 void SdrObject::GetGrabBagItem(css::uno::Any& rVal) const
921 {
922     if (m_pGrabBagItem != nullptr)
923         m_pGrabBagItem->QueryValue(rVal);
924     else
925         rVal <<= uno::Sequence<beans::PropertyValue>();
926 }
927 
928 void SdrObject::SetGrabBagItem(const css::uno::Any& rVal)
929 {
930     if (m_pGrabBagItem == nullptr)
931         m_pGrabBagItem.reset(new SfxGrabBagItem);
932 
933     m_pGrabBagItem->PutValue(rVal, 0);
934 
935     SetChanged();
936     BroadcastObjectChange();
937 }
938 
939 sal_uInt32 SdrObject::GetNavigationPosition() const
940 {
941     if (nullptr != getParentSdrObjListFromSdrObject() && getParentSdrObjListFromSdrObject()->RecalcNavigationPositions())
942     {
943         return mnNavigationPosition;
944     }
945     else
946         return GetOrdNum();
947 }
948 
949 
950 void SdrObject::SetNavigationPosition (const sal_uInt32 nNewPosition)
951 {
952     mnNavigationPosition = nNewPosition;
953 }
954 
955 
956 // To make clearer that this method may trigger RecalcBoundRect and thus may be
957 // expensive and sometimes problematic (inside a bigger object change you will get
958 // non-useful BoundRects sometimes) I rename that method from GetBoundRect() to
959 // GetCurrentBoundRect().
960 const tools::Rectangle& SdrObject::GetCurrentBoundRect() const
961 {
962     if(m_aOutRect.IsEmpty())
963     {
964         const_cast< SdrObject* >(this)->RecalcBoundRect();
965     }
966 
967     return m_aOutRect;
968 }
969 
970 // To have a possibility to get the last calculated BoundRect e.g for producing
971 // the first rectangle for repaints (old and new need to be used) without forcing
972 // a RecalcBoundRect (which may be problematical and expensive sometimes) I add here
973 // a new method for accessing the last BoundRect.
974 const tools::Rectangle& SdrObject::GetLastBoundRect() const
975 {
976     return m_aOutRect;
977 }
978 
979 void SdrObject::RecalcBoundRect()
980 {
981     // #i101680# suppress BoundRect calculations on import(s)
982     if ((getSdrModelFromSdrObject().isLocked()) || utl::ConfigManager::IsFuzzing())
983         return;
984 
985     // central new method which will calculate the BoundRect using primitive geometry
986     if(!m_aOutRect.IsEmpty())
987         return;
988 
989     // Use view-independent data - we do not want any connections
990     // to e.g. GridOffset in SdrObject-level
991     const drawinglayer::primitive2d::Primitive2DContainer& xPrimitives(GetViewContact().getViewIndependentPrimitive2DContainer());
992 
993     if(xPrimitives.empty())
994         return;
995 
996     // use neutral ViewInformation and get the range of the primitives
997     const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
998     const basegfx::B2DRange aRange(xPrimitives.getB2DRange(aViewInformation2D));
999 
1000     if(!aRange.isEmpty())
1001     {
1002         m_aOutRect = tools::Rectangle(
1003             static_cast<tools::Long>(floor(aRange.getMinX())),
1004             static_cast<tools::Long>(floor(aRange.getMinY())),
1005             static_cast<tools::Long>(ceil(aRange.getMaxX())),
1006             static_cast<tools::Long>(ceil(aRange.getMaxY())));
1007         return;
1008     }
1009 }
1010 
1011 void SdrObject::BroadcastObjectChange() const
1012 {
1013     if ((getSdrModelFromSdrObject().isLocked()) || utl::ConfigManager::IsFuzzing())
1014         return;
1015 
1016     bool bPlusDataBroadcast(m_pPlusData && m_pPlusData->pBroadcast);
1017     bool bObjectChange(IsInserted());
1018 
1019     if(!(bPlusDataBroadcast || bObjectChange))
1020         return;
1021 
1022     SdrHint aHint(SdrHintKind::ObjectChange, *this);
1023 
1024     if(bPlusDataBroadcast)
1025     {
1026         m_pPlusData->pBroadcast->Broadcast(aHint);
1027     }
1028 
1029     if(bObjectChange)
1030     {
1031         getSdrModelFromSdrObject().Broadcast(aHint);
1032     }
1033 }
1034 
1035 void SdrObject::SetChanged()
1036 {
1037     // For testing purposes, use the new ViewContact for change
1038     // notification now.
1039     ActionChanged();
1040 
1041     // TTTT Need to check meaning/usage of IsInserted in one
1042     // of the next changes. It should not mean to have a SdrModel
1043     // set (this is guaranteed now), but should be connected to
1044     // being added to a SdrPage (?)
1045     // TTTT tdf#120066 Indeed - This triggers e.g. by CustomShape
1046     // geometry-presenting SdrObjects that are in a SdrObjGroup,
1047     // but the SdrObjGroup is *by purpose* not inserted.
1048     // Need to check deeper and maybe identify all ::IsInserted()
1049     // calls by rename and let the compiler work...
1050     if(nullptr != getSdrPageFromSdrObject())
1051     {
1052         getSdrModelFromSdrObject().SetChanged();
1053     }
1054 }
1055 
1056 // tooling for painting a single object to an OutputDevice.
1057 void SdrObject::SingleObjectPainter(OutputDevice& rOut) const
1058 {
1059     sdr::contact::SdrObjectVector aObjectVector;
1060     aObjectVector.push_back(const_cast< SdrObject* >(this));
1061 
1062     sdr::contact::ObjectContactOfObjListPainter aPainter(rOut, aObjectVector, getSdrPageFromSdrObject());
1063     sdr::contact::DisplayInfo aDisplayInfo;
1064 
1065     aPainter.ProcessDisplay(aDisplayInfo);
1066 }
1067 
1068 bool SdrObject::LineGeometryUsageIsNecessary() const
1069 {
1070     drawing::LineStyle eXLS = GetMergedItem(XATTR_LINESTYLE).GetValue();
1071     return (eXLS != drawing::LineStyle_NONE);
1072 }
1073 
1074 bool SdrObject::HasLimitedRotation() const
1075 {
1076     // RotGrfFlyFrame: Default is false, support full rotation
1077     return false;
1078 }
1079 
1080 SdrObject* SdrObject::CloneSdrObject(SdrModel& rTargetModel) const
1081 {
1082     return new SdrObject(rTargetModel, *this);
1083 }
1084 
1085 OUString SdrObject::TakeObjNameSingul() const
1086 {
1087     OUString sName(SvxResId(STR_ObjNameSingulNONE));
1088 
1089     OUString aName(GetName());
1090     if (!aName.isEmpty())
1091         sName += " '" + aName + "'";
1092     return sName;
1093 }
1094 
1095 OUString SdrObject::TakeObjNamePlural() const
1096 {
1097     return SvxResId(STR_ObjNamePluralNONE);
1098 }
1099 
1100 OUString SdrObject::ImpGetDescriptionStr(TranslateId pStrCacheID) const
1101 {
1102     OUString aStr = SvxResId(pStrCacheID);
1103     sal_Int32 nPos = aStr.indexOf("%1");
1104     if (nPos >= 0)
1105     {
1106         // Replace '%1' with the object name.
1107         OUString aObjName(TakeObjNameSingul());
1108         aStr = aStr.replaceAt(nPos, 2, aObjName);
1109     }
1110 
1111     nPos = aStr.indexOf("%2");
1112     if (nPos >= 0)
1113         // Replace '%2' with the passed value.
1114         aStr = aStr.replaceAt(nPos, 2, "0");
1115     return aStr;
1116 }
1117 
1118 void SdrObject::ImpForcePlusData()
1119 {
1120     if (!m_pPlusData)
1121         m_pPlusData.reset( new SdrObjPlusData );
1122 }
1123 
1124 OUString SdrObject::GetMetrStr(tools::Long nVal) const
1125 {
1126     return getSdrModelFromSdrObject().GetMetricString(nVal);
1127 }
1128 
1129 basegfx::B2DPolyPolygon SdrObject::TakeXorPoly() const
1130 {
1131     basegfx::B2DPolyPolygon aRetval;
1132     const tools::Rectangle aR(GetCurrentBoundRect());
1133     aRetval.append(basegfx::utils::createPolygonFromRect(vcl::unotools::b2DRectangleFromRectangle(aR)));
1134 
1135     return aRetval;
1136 }
1137 
1138 basegfx::B2DPolyPolygon SdrObject::TakeContour() const
1139 {
1140     basegfx::B2DPolyPolygon aRetval;
1141 
1142     // create cloned object without text, but with drawing::LineStyle_SOLID,
1143     // COL_BLACK as line color and drawing::FillStyle_NONE
1144     SdrObject* pClone(CloneSdrObject(getSdrModelFromSdrObject()));
1145 
1146     if(pClone)
1147     {
1148         const SdrTextObj* pTextObj = dynamic_cast< const SdrTextObj* >(this);
1149 
1150         if(pTextObj)
1151         {
1152             // no text and no text animation
1153             pClone->SetMergedItem(SdrTextAniKindItem(SdrTextAniKind::NONE));
1154             pClone->SetOutlinerParaObject(std::nullopt);
1155         }
1156 
1157         const SdrEdgeObj* pEdgeObj = dynamic_cast< const SdrEdgeObj* >(this);
1158 
1159         if(pEdgeObj)
1160         {
1161             // create connections if connector, will be cleaned up when
1162             // deleting the connector again
1163             SdrObject* pLeft = pEdgeObj->GetConnectedNode(true);
1164             SdrObject* pRight = pEdgeObj->GetConnectedNode(false);
1165 
1166             if(pLeft)
1167             {
1168                 pClone->ConnectToNode(true, pLeft);
1169             }
1170 
1171             if(pRight)
1172             {
1173                 pClone->ConnectToNode(false, pRight);
1174             }
1175         }
1176 
1177         SfxItemSet aNewSet(GetObjectItemPool());
1178 
1179         // #i101980# ignore LineWidth; that's what the old implementation
1180         // did. With line width, the result may be huge due to fat/thick
1181         // line decompositions
1182         aNewSet.Put(XLineWidthItem(0));
1183 
1184         // solid black lines and no fill
1185         aNewSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
1186         aNewSet.Put(XLineColorItem(OUString(), COL_BLACK));
1187         aNewSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
1188         pClone->SetMergedItemSet(aNewSet);
1189 
1190         // get sequence from clone
1191         const sdr::contact::ViewContact& rVC(pClone->GetViewContact());
1192         const drawinglayer::primitive2d::Primitive2DContainer& xSequence(rVC.getViewIndependentPrimitive2DContainer());
1193 
1194         if(!xSequence.empty())
1195         {
1196             // use neutral ViewInformation
1197             const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
1198 
1199             // create extractor, process and get result (with hairlines as opened polygons)
1200             drawinglayer::processor2d::ContourExtractor2D aExtractor(aViewInformation2D, false);
1201             aExtractor.process(xSequence);
1202             const basegfx::B2DPolyPolygonVector& rResult(aExtractor.getExtractedContour());
1203             const sal_uInt32 nSize(rResult.size());
1204 
1205             // when count is one, it is implied that the object has only its normal
1206             // contour anyways and TakeContour() is to return an empty PolyPolygon
1207             // (see old implementation for historical reasons)
1208             if(nSize > 1)
1209             {
1210                 // the topology for contour is correctly a vector of PolyPolygons; for
1211                 // historical reasons cut it back to a single tools::PolyPolygon here
1212                 for(sal_uInt32 a(0); a < nSize; a++)
1213                 {
1214                     aRetval.append(rResult[a]);
1215                 }
1216             }
1217         }
1218 
1219         // Always use SdrObject::Free to delete SdrObjects (!)
1220         SdrObject::Free(pClone);
1221     }
1222 
1223     return aRetval;
1224 }
1225 
1226 sal_uInt32 SdrObject::GetHdlCount() const
1227 {
1228     return 8;
1229 }
1230 
1231 void SdrObject::AddToHdlList(SdrHdlList& rHdlList) const
1232 {
1233     const tools::Rectangle& rR=GetSnapRect();
1234     for (sal_uInt32 nHdlNum=0; nHdlNum<8; ++nHdlNum)
1235     {
1236         std::unique_ptr<SdrHdl> pH;
1237         switch (nHdlNum) {
1238             case 0: pH.reset(new SdrHdl(rR.TopLeft(),     SdrHdlKind::UpperLeft)); break;
1239             case 1: pH.reset(new SdrHdl(rR.TopCenter(),   SdrHdlKind::Upper)); break;
1240             case 2: pH.reset(new SdrHdl(rR.TopRight(),    SdrHdlKind::UpperRight)); break;
1241             case 3: pH.reset(new SdrHdl(rR.LeftCenter(),  SdrHdlKind::Left )); break;
1242             case 4: pH.reset(new SdrHdl(rR.RightCenter(), SdrHdlKind::Right)); break;
1243             case 5: pH.reset(new SdrHdl(rR.BottomLeft(),  SdrHdlKind::LowerLeft)); break;
1244             case 6: pH.reset(new SdrHdl(rR.BottomCenter(),SdrHdlKind::Lower)); break;
1245             case 7: pH.reset(new SdrHdl(rR.BottomRight(), SdrHdlKind::LowerRight)); break;
1246         }
1247         rHdlList.AddHdl(std::move(pH));
1248     }
1249 }
1250 
1251 void SdrObject::AddToPlusHdlList(SdrHdlList&, SdrHdl&) const
1252 {
1253 }
1254 
1255 void SdrObject::addCropHandles(SdrHdlList& /*rTarget*/) const
1256 {
1257     // Default implementation, does nothing. Overloaded in
1258     // SdrGrafObj and SwVirtFlyDrawObj
1259 }
1260 
1261 tools::Rectangle SdrObject::ImpDragCalcRect(const SdrDragStat& rDrag) const
1262 {
1263     tools::Rectangle aTmpRect(GetSnapRect());
1264     tools::Rectangle aRect(aTmpRect);
1265     const SdrHdl* pHdl=rDrag.GetHdl();
1266     SdrHdlKind eHdl=pHdl==nullptr ? SdrHdlKind::Move : pHdl->GetKind();
1267     bool bEcke=(eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::LowerLeft || eHdl==SdrHdlKind::LowerRight);
1268     bool bOrtho=rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho();
1269     bool bBigOrtho=bEcke && bOrtho && rDrag.GetView()->IsBigOrtho();
1270     Point aPos(rDrag.GetNow());
1271     bool bLft=(eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::Left  || eHdl==SdrHdlKind::LowerLeft);
1272     bool bRgt=(eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::Right || eHdl==SdrHdlKind::LowerRight);
1273     bool bTop=(eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::Upper || eHdl==SdrHdlKind::UpperLeft);
1274     bool bBtm=(eHdl==SdrHdlKind::LowerRight || eHdl==SdrHdlKind::Lower || eHdl==SdrHdlKind::LowerLeft);
1275     if (bLft) aTmpRect.SetLeft(aPos.X() );
1276     if (bRgt) aTmpRect.SetRight(aPos.X() );
1277     if (bTop) aTmpRect.SetTop(aPos.Y() );
1278     if (bBtm) aTmpRect.SetBottom(aPos.Y() );
1279     if (bOrtho) { // Ortho
1280         tools::Long nWdt0=aRect.Right() -aRect.Left();
1281         tools::Long nHgt0=aRect.Bottom()-aRect.Top();
1282         tools::Long nXMul=aTmpRect.Right() -aTmpRect.Left();
1283         tools::Long nYMul=aTmpRect.Bottom()-aTmpRect.Top();
1284         tools::Long nXDiv=nWdt0;
1285         tools::Long nYDiv=nHgt0;
1286         bool bXNeg=(nXMul<0)!=(nXDiv<0);
1287         bool bYNeg=(nYMul<0)!=(nYDiv<0);
1288         nXMul=std::abs(nXMul);
1289         nYMul=std::abs(nYMul);
1290         nXDiv=std::abs(nXDiv);
1291         nYDiv=std::abs(nYDiv);
1292         Fraction aXFact(nXMul,nXDiv); // fractions for canceling
1293         Fraction aYFact(nYMul,nYDiv); // and for comparing
1294         nXMul=aXFact.GetNumerator();
1295         nYMul=aYFact.GetNumerator();
1296         nXDiv=aXFact.GetDenominator();
1297         nYDiv=aYFact.GetDenominator();
1298         if (bEcke) { // corner point handles
1299             bool bUseX=(aXFact<aYFact) != bBigOrtho;
1300             if (bUseX) {
1301                 tools::Long nNeed=tools::Long(BigInt(nHgt0)*BigInt(nXMul)/BigInt(nXDiv));
1302                 if (bYNeg) nNeed=-nNeed;
1303                 if (bTop) aTmpRect.SetTop(aTmpRect.Bottom()-nNeed );
1304                 if (bBtm) aTmpRect.SetBottom(aTmpRect.Top()+nNeed );
1305             } else {
1306                 tools::Long nNeed=tools::Long(BigInt(nWdt0)*BigInt(nYMul)/BigInt(nYDiv));
1307                 if (bXNeg) nNeed=-nNeed;
1308                 if (bLft) aTmpRect.SetLeft(aTmpRect.Right()-nNeed );
1309                 if (bRgt) aTmpRect.SetRight(aTmpRect.Left()+nNeed );
1310             }
1311         } else { // apex handles
1312             if ((bLft || bRgt) && nXDiv!=0) {
1313                 tools::Long nHgt0b=aRect.Bottom()-aRect.Top();
1314                 tools::Long nNeed=tools::Long(BigInt(nHgt0b)*BigInt(nXMul)/BigInt(nXDiv));
1315                 aTmpRect.AdjustTop( -((nNeed-nHgt0b)/2) );
1316                 aTmpRect.SetBottom(aTmpRect.Top()+nNeed );
1317             }
1318             if ((bTop || bBtm) && nYDiv!=0) {
1319                 tools::Long nWdt0b=aRect.Right()-aRect.Left();
1320                 tools::Long nNeed=tools::Long(BigInt(nWdt0b)*BigInt(nYMul)/BigInt(nYDiv));
1321                 aTmpRect.AdjustLeft( -((nNeed-nWdt0b)/2) );
1322                 aTmpRect.SetRight(aTmpRect.Left()+nNeed );
1323             }
1324         }
1325     }
1326     aTmpRect.Justify();
1327     return aTmpRect;
1328 }
1329 
1330 
1331 bool SdrObject::hasSpecialDrag() const
1332 {
1333     return false;
1334 }
1335 
1336 bool SdrObject::supportsFullDrag() const
1337 {
1338     return true;
1339 }
1340 
1341 SdrObjectUniquePtr SdrObject::getFullDragClone() const
1342 {
1343     // default uses simple clone
1344     return SdrObjectUniquePtr(CloneSdrObject(getSdrModelFromSdrObject()));
1345 }
1346 
1347 bool SdrObject::beginSpecialDrag(SdrDragStat& rDrag) const
1348 {
1349     const SdrHdl* pHdl = rDrag.GetHdl();
1350 
1351     SdrHdlKind eHdl = (pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind();
1352 
1353     return eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::Upper || eHdl==SdrHdlKind::UpperRight ||
1354         eHdl==SdrHdlKind::Left || eHdl==SdrHdlKind::Right || eHdl==SdrHdlKind::LowerLeft ||
1355         eHdl==SdrHdlKind::Lower || eHdl==SdrHdlKind::LowerRight;
1356 }
1357 
1358 bool SdrObject::applySpecialDrag(SdrDragStat& rDrag)
1359 {
1360     tools::Rectangle aNewRect(ImpDragCalcRect(rDrag));
1361 
1362     if(aNewRect != GetSnapRect())
1363     {
1364            NbcSetSnapRect(aNewRect);
1365     }
1366 
1367     return true;
1368 }
1369 
1370 OUString SdrObject::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const
1371 {
1372     return OUString();
1373 }
1374 
1375 basegfx::B2DPolyPolygon SdrObject::getSpecialDragPoly(const SdrDragStat& /*rDrag*/) const
1376 {
1377     // default has nothing to add
1378     return basegfx::B2DPolyPolygon();
1379 }
1380 
1381 
1382 // Create
1383 bool SdrObject::BegCreate(SdrDragStat& rStat)
1384 {
1385     rStat.SetOrtho4Possible();
1386     tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
1387     aRect1.Justify();
1388     rStat.SetActionRect(aRect1);
1389     m_aOutRect = aRect1;
1390     return true;
1391 }
1392 
1393 bool SdrObject::MovCreate(SdrDragStat& rStat)
1394 {
1395     rStat.TakeCreateRect(m_aOutRect);
1396     rStat.SetActionRect(m_aOutRect);
1397     m_aOutRect.Justify();
1398 
1399     return true;
1400 }
1401 
1402 bool SdrObject::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
1403 {
1404     rStat.TakeCreateRect(m_aOutRect);
1405     m_aOutRect.Justify();
1406 
1407     return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
1408 }
1409 
1410 void SdrObject::BrkCreate(SdrDragStat& /*rStat*/)
1411 {
1412 }
1413 
1414 bool SdrObject::BckCreate(SdrDragStat& /*rStat*/)
1415 {
1416     return false;
1417 }
1418 
1419 basegfx::B2DPolyPolygon SdrObject::TakeCreatePoly(const SdrDragStat& rDrag) const
1420 {
1421     tools::Rectangle aRect1;
1422     rDrag.TakeCreateRect(aRect1);
1423     aRect1.Justify();
1424 
1425     basegfx::B2DPolyPolygon aRetval;
1426     aRetval.append(basegfx::utils::createPolygonFromRect(vcl::unotools::b2DRectangleFromRectangle(aRect1)));
1427     return aRetval;
1428 }
1429 
1430 PointerStyle SdrObject::GetCreatePointer() const
1431 {
1432     return PointerStyle::Cross;
1433 }
1434 
1435 // transformations
1436 void SdrObject::NbcMove(const Size& rSiz)
1437 {
1438     m_aOutRect.Move(rSiz);
1439     SetBoundAndSnapRectsDirty();
1440 }
1441 
1442 void SdrObject::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
1443 {
1444     bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
1445     bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
1446     if (bXMirr || bYMirr) {
1447         Point aRef1(GetSnapRect().Center());
1448         if (bXMirr) {
1449             Point aRef2(aRef1);
1450             aRef2.AdjustY( 1 );
1451             NbcMirrorGluePoints(aRef1,aRef2);
1452         }
1453         if (bYMirr) {
1454             Point aRef2(aRef1);
1455             aRef2.AdjustX( 1 );
1456             NbcMirrorGluePoints(aRef1,aRef2);
1457         }
1458     }
1459     ResizeRect(m_aOutRect,rRef,xFact,yFact);
1460     SetBoundAndSnapRectsDirty();
1461 }
1462 
1463 void SdrObject::NbcRotate(const Point& rRef, Degree100 nAngle)
1464 {
1465     if (nAngle)
1466     {
1467         double a = nAngle.get() * F_PI18000;
1468         NbcRotate( rRef, nAngle, sin( a ), cos( a ) );
1469     }
1470 }
1471 
1472 void SdrObject::NbcRotate(const Point& rRef,  Degree100 nAngle, double sn, double cs)
1473 {
1474     SetGlueReallyAbsolute(true);
1475     m_aOutRect.Move(-rRef.X(),-rRef.Y());
1476     tools::Rectangle R(m_aOutRect);
1477     if (sn==1.0 && cs==0.0) { // 90deg
1478         m_aOutRect.SetLeft(-R.Bottom() );
1479         m_aOutRect.SetRight(-R.Top() );
1480         m_aOutRect.SetTop(R.Left() );
1481         m_aOutRect.SetBottom(R.Right() );
1482     } else if (sn==0.0 && cs==-1.0) { // 180deg
1483         m_aOutRect.SetLeft(-R.Right() );
1484         m_aOutRect.SetRight(-R.Left() );
1485         m_aOutRect.SetTop(-R.Bottom() );
1486         m_aOutRect.SetBottom(-R.Top() );
1487     } else if (sn==-1.0 && cs==0.0) { // 270deg
1488         m_aOutRect.SetLeft(R.Top() );
1489         m_aOutRect.SetRight(R.Bottom() );
1490         m_aOutRect.SetTop(-R.Right() );
1491         m_aOutRect.SetBottom(-R.Left() );
1492     }
1493     m_aOutRect.Move(rRef.X(),rRef.Y());
1494     m_aOutRect.Justify(); // just in case
1495     SetBoundAndSnapRectsDirty();
1496     NbcRotateGluePoints(rRef,nAngle,sn,cs);
1497     SetGlueReallyAbsolute(false);
1498 }
1499 
1500 void SdrObject::NbcMirror(const Point& rRef1, const Point& rRef2)
1501 {
1502     SetGlueReallyAbsolute(true);
1503     m_aOutRect.Move(-rRef1.X(),-rRef1.Y());
1504     tools::Rectangle R(m_aOutRect);
1505     tools::Long dx=rRef2.X()-rRef1.X();
1506     tools::Long dy=rRef2.Y()-rRef1.Y();
1507     if (dx==0) {          // vertical axis
1508         m_aOutRect.SetLeft(-R.Right() );
1509         m_aOutRect.SetRight(-R.Left() );
1510     } else if (dy==0) {   // horizontal axis
1511         m_aOutRect.SetTop(-R.Bottom() );
1512         m_aOutRect.SetBottom(-R.Top() );
1513     } else if (dx==dy) {  // 45deg axis
1514         m_aOutRect.SetLeft(R.Top() );
1515         m_aOutRect.SetRight(R.Bottom() );
1516         m_aOutRect.SetTop(R.Left() );
1517         m_aOutRect.SetBottom(R.Right() );
1518     } else if (dx==-dy) { // 45deg axis
1519         m_aOutRect.SetLeft(-R.Bottom() );
1520         m_aOutRect.SetRight(-R.Top() );
1521         m_aOutRect.SetTop(-R.Right() );
1522         m_aOutRect.SetBottom(-R.Left() );
1523     }
1524     m_aOutRect.Move(rRef1.X(),rRef1.Y());
1525     m_aOutRect.Justify(); // just in case
1526     SetBoundAndSnapRectsDirty();
1527     NbcMirrorGluePoints(rRef1,rRef2);
1528     SetGlueReallyAbsolute(false);
1529 }
1530 
1531 void SdrObject::NbcShear(const Point& rRef, Degree100 /*nAngle*/, double tn, bool bVShear)
1532 {
1533     SetGlueReallyAbsolute(true);
1534     NbcShearGluePoints(rRef,tn,bVShear);
1535     SetGlueReallyAbsolute(false);
1536 }
1537 
1538 void SdrObject::Move(const Size& rSiz)
1539 {
1540     if (rSiz.Width()!=0 || rSiz.Height()!=0) {
1541         tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1542         NbcMove(rSiz);
1543         SetChanged();
1544         BroadcastObjectChange();
1545         SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
1546     }
1547 }
1548 
1549 void SdrObject::NbcCrop(const basegfx::B2DPoint& /*aRef*/, double /*fxFact*/, double /*fyFact*/)
1550 {
1551     // Default: does nothing. Real behaviour in SwVirtFlyDrawObj and SdrDragCrop::EndSdrDrag.
1552     // Where SwVirtFlyDrawObj is the only real user of it to do something local
1553 }
1554 
1555 void SdrObject::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative)
1556 {
1557     if (xFact.GetNumerator() == xFact.GetDenominator() && yFact.GetNumerator() == yFact.GetDenominator())
1558         return;
1559 
1560     if (bUnsetRelative)
1561     {
1562         mpImpl->mnRelativeWidth.reset();
1563         mpImpl->meRelativeWidthRelation = text::RelOrientation::PAGE_FRAME;
1564         mpImpl->meRelativeHeightRelation = text::RelOrientation::PAGE_FRAME;
1565         mpImpl->mnRelativeHeight.reset();
1566     }
1567     tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1568     NbcResize(rRef,xFact,yFact);
1569     SetChanged();
1570     BroadcastObjectChange();
1571     SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1572 }
1573 
1574 void SdrObject::Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
1575 {
1576     tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1577     NbcCrop(rRef, fxFact, fyFact);
1578     SetChanged();
1579     BroadcastObjectChange();
1580     SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1581 }
1582 
1583 void SdrObject::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
1584 {
1585     if (nAngle) {
1586         tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1587         NbcRotate(rRef,nAngle,sn,cs);
1588         SetChanged();
1589         BroadcastObjectChange();
1590         SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1591     }
1592 }
1593 
1594 void SdrObject::Mirror(const Point& rRef1, const Point& rRef2)
1595 {
1596     tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1597     NbcMirror(rRef1,rRef2);
1598     SetChanged();
1599     BroadcastObjectChange();
1600     SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1601 }
1602 
1603 void SdrObject::Shear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
1604 {
1605     if (nAngle) {
1606         tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1607         NbcShear(rRef,nAngle,tn,bVShear);
1608         SetChanged();
1609         BroadcastObjectChange();
1610         SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1611     }
1612 }
1613 
1614 void SdrObject::NbcSetRelativePos(const Point& rPnt)
1615 {
1616     Point aRelPos0(GetSnapRect().TopLeft()-m_aAnchor);
1617     Size aSiz(rPnt.X()-aRelPos0.X(),rPnt.Y()-aRelPos0.Y());
1618     NbcMove(aSiz); // This also calls SetRectsDirty()
1619 }
1620 
1621 void SdrObject::SetRelativePos(const Point& rPnt)
1622 {
1623     if (rPnt!=GetRelativePos()) {
1624         tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1625         NbcSetRelativePos(rPnt);
1626         SetChanged();
1627         BroadcastObjectChange();
1628         SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
1629     }
1630 }
1631 
1632 Point SdrObject::GetRelativePos() const
1633 {
1634     return GetSnapRect().TopLeft()-m_aAnchor;
1635 }
1636 
1637 void SdrObject::ImpSetAnchorPos(const Point& rPnt)
1638 {
1639     m_aAnchor = rPnt;
1640 }
1641 
1642 void SdrObject::NbcSetAnchorPos(const Point& rPnt)
1643 {
1644     Size aSiz(rPnt.X()-m_aAnchor.X(),rPnt.Y()-m_aAnchor.Y());
1645     m_aAnchor=rPnt;
1646     NbcMove(aSiz); // This also calls SetRectsDirty()
1647 }
1648 
1649 void SdrObject::SetAnchorPos(const Point& rPnt)
1650 {
1651     if (rPnt!=m_aAnchor) {
1652         tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1653         NbcSetAnchorPos(rPnt);
1654         SetChanged();
1655         BroadcastObjectChange();
1656         SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0);
1657     }
1658 }
1659 
1660 const Point& SdrObject::GetAnchorPos() const
1661 {
1662     return m_aAnchor;
1663 }
1664 
1665 void SdrObject::RecalcSnapRect()
1666 {
1667 }
1668 
1669 const tools::Rectangle& SdrObject::GetSnapRect() const
1670 {
1671     return m_aOutRect;
1672 }
1673 
1674 void SdrObject::NbcSetSnapRect(const tools::Rectangle& rRect)
1675 {
1676     m_aOutRect=rRect;
1677 }
1678 
1679 const tools::Rectangle& SdrObject::GetLogicRect() const
1680 {
1681     return GetSnapRect();
1682 }
1683 
1684 void SdrObject::NbcSetLogicRect(const tools::Rectangle& rRect)
1685 {
1686     NbcSetSnapRect(rRect);
1687 }
1688 
1689 void SdrObject::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool /* bShrinkOnly = false */ )
1690 {
1691     SetLogicRect( rMaxRect );
1692 }
1693 
1694 void SdrObject::SetSnapRect(const tools::Rectangle& rRect)
1695 {
1696     tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1697     NbcSetSnapRect(rRect);
1698     SetChanged();
1699     BroadcastObjectChange();
1700     SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1701 }
1702 
1703 void SdrObject::SetLogicRect(const tools::Rectangle& rRect)
1704 {
1705     tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1706     NbcSetLogicRect(rRect);
1707     SetChanged();
1708     BroadcastObjectChange();
1709     SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1710 }
1711 
1712 Degree100 SdrObject::GetRotateAngle() const
1713 {
1714     return 0_deg100;
1715 }
1716 
1717 Degree100 SdrObject::GetShearAngle(bool /*bVertical*/) const
1718 {
1719     return 0_deg100;
1720 }
1721 
1722 sal_uInt32 SdrObject::GetSnapPointCount() const
1723 {
1724     return GetPointCount();
1725 }
1726 
1727 Point SdrObject::GetSnapPoint(sal_uInt32 i) const
1728 {
1729     return GetPoint(i);
1730 }
1731 
1732 bool SdrObject::IsPolyObj() const
1733 {
1734     return false;
1735 }
1736 
1737 sal_uInt32 SdrObject::GetPointCount() const
1738 {
1739     return 0;
1740 }
1741 
1742 Point SdrObject::GetPoint(sal_uInt32 /*i*/) const
1743 {
1744     return Point();
1745 }
1746 
1747 void SdrObject::SetPoint(const Point& rPnt, sal_uInt32 i)
1748 {
1749     tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1750     NbcSetPoint(rPnt, i);
1751     SetChanged();
1752     BroadcastObjectChange();
1753     SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1754 }
1755 
1756 void SdrObject::NbcSetPoint(const Point& /*rPnt*/, sal_uInt32 /*i*/)
1757 {
1758 }
1759 
1760 bool SdrObject::HasTextEdit() const
1761 {
1762     return false;
1763 }
1764 
1765 bool SdrObject::Equals(const SdrObject& rOtherObj) const
1766 {
1767     return (m_aAnchor.X() == rOtherObj.m_aAnchor.X() && m_aAnchor.Y() == rOtherObj.m_aAnchor.Y() &&
1768             m_nOrdNum == rOtherObj.m_nOrdNum && mnNavigationPosition == rOtherObj.mnNavigationPosition &&
1769             mbSupportTextIndentingOnLineWidthChange == rOtherObj.mbSupportTextIndentingOnLineWidthChange &&
1770             mbLineIsOutsideGeometry == rOtherObj.mbLineIsOutsideGeometry && m_bMarkProt == rOtherObj.m_bMarkProt &&
1771             m_bIs3DObj == rOtherObj.m_bIs3DObj && m_bIsEdge == rOtherObj.m_bIsEdge && m_bClosedObj == rOtherObj.m_bClosedObj &&
1772             m_bNotVisibleAsMaster == rOtherObj.m_bNotVisibleAsMaster && m_bEmptyPresObj == rOtherObj.m_bEmptyPresObj &&
1773             mbVisible == rOtherObj.mbVisible && m_bNoPrint == rOtherObj.m_bNoPrint && m_bSizProt == rOtherObj.m_bSizProt &&
1774             m_bMovProt == rOtherObj.m_bMovProt && m_bVirtObj == rOtherObj.m_bVirtObj &&
1775             mnLayerID == rOtherObj.mnLayerID && GetMergedItemSet().Equals(rOtherObj.GetMergedItemSet(), false) );
1776 }
1777 
1778 void SdrObject::dumpAsXml(xmlTextWriterPtr pWriter) const
1779 {
1780     (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrObject"));
1781     (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
1782     (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("symbol"), "%s", BAD_CAST(typeid(*this).name()));
1783     (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("name"), "%s", BAD_CAST(GetName().toUtf8().getStr()));
1784     (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("title"), "%s", BAD_CAST(GetTitle().toUtf8().getStr()));
1785     (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("description"), "%s", BAD_CAST(GetDescription().toUtf8().getStr()));
1786     (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("nOrdNum"), "%" SAL_PRIuUINT32, GetOrdNumDirect());
1787     (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("aOutRect"), BAD_CAST(m_aOutRect.toString().getStr()));
1788 
1789     if (m_pGrabBagItem)
1790     {
1791         m_pGrabBagItem->dumpAsXml(pWriter);
1792     }
1793 
1794     if (mpProperties)
1795     {
1796         mpProperties->dumpAsXml(pWriter);
1797     }
1798 
1799     if (const OutlinerParaObject* pOutliner = GetOutlinerParaObject())
1800         pOutliner->dumpAsXml(pWriter);
1801 
1802     (void)xmlTextWriterEndElement(pWriter);
1803 }
1804 
1805 void SdrObject::SetOutlinerParaObject(std::optional<OutlinerParaObject> pTextObject)
1806 {
1807     tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1808     NbcSetOutlinerParaObject(std::move(pTextObject));
1809     SetChanged();
1810     BroadcastObjectChange();
1811     if (GetCurrentBoundRect()!=aBoundRect0) {
1812         SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1813     }
1814 
1815     if (!getSdrModelFromSdrObject().IsUndoEnabled())
1816         return;
1817 
1818     // Don't do this during import.
1819     SdrObject* pTopGroupObj = nullptr;
1820     if (getParentSdrObjectFromSdrObject())
1821     {
1822         pTopGroupObj = getParentSdrObjectFromSdrObject();
1823         while (pTopGroupObj->getParentSdrObjectFromSdrObject())
1824         {
1825             pTopGroupObj = pTopGroupObj->getParentSdrObjectFromSdrObject();
1826         }
1827     }
1828     if (pTopGroupObj)
1829     {
1830         // A shape was modified, which is in a group shape. Empty the group shape's grab-bag,
1831         // which potentially contains the old text of the shapes in case of diagrams.
1832         pTopGroupObj->SetGrabBagItem(uno::makeAny(uno::Sequence<beans::PropertyValue>()));
1833     }
1834 }
1835 
1836 void SdrObject::NbcSetOutlinerParaObject(std::optional<OutlinerParaObject> /*pTextObject*/)
1837 {
1838 }
1839 
1840 OutlinerParaObject* SdrObject::GetOutlinerParaObject() const
1841 {
1842     return nullptr;
1843 }
1844 
1845 void SdrObject::NbcReformatText()
1846 {
1847 }
1848 
1849 void SdrObject::BurnInStyleSheetAttributes()
1850 {
1851     GetProperties().ForceStyleToHardAttributes();
1852 }
1853 
1854 bool SdrObject::HasMacro() const
1855 {
1856     return false;
1857 }
1858 
1859 SdrObject* SdrObject::CheckMacroHit(const SdrObjMacroHitRec& rRec) const
1860 {
1861     if(rRec.pPageView)
1862     {
1863         return SdrObjectPrimitiveHit(*this, rRec.aPos, rRec.nTol, *rRec.pPageView, rRec.pVisiLayer, false);
1864     }
1865 
1866     return nullptr;
1867 }
1868 
1869 PointerStyle SdrObject::GetMacroPointer(const SdrObjMacroHitRec&) const
1870 {
1871     return PointerStyle::RefHand;
1872 }
1873 
1874 void SdrObject::PaintMacro(OutputDevice& rOut, const tools::Rectangle& , const SdrObjMacroHitRec& ) const
1875 {
1876     const RasterOp eRop(rOut.GetRasterOp());
1877     const basegfx::B2DPolyPolygon aPolyPolygon(TakeXorPoly());
1878 
1879     rOut.SetLineColor(COL_BLACK);
1880     rOut.SetFillColor();
1881     rOut.SetRasterOp(RasterOp::Invert);
1882 
1883     for(auto const& rPolygon : aPolyPolygon)
1884     {
1885         rOut.DrawPolyLine(rPolygon);
1886     }
1887 
1888     rOut.SetRasterOp(eRop);
1889 }
1890 
1891 bool SdrObject::DoMacro(const SdrObjMacroHitRec&)
1892 {
1893     return false;
1894 }
1895 
1896 bool SdrObject::IsMacroHit(const SdrObjMacroHitRec& rRec) const
1897 {
1898     return CheckMacroHit(rRec) != nullptr;
1899 }
1900 
1901 
1902 std::unique_ptr<SdrObjGeoData> SdrObject::NewGeoData() const
1903 {
1904     return std::make_unique<SdrObjGeoData>();
1905 }
1906 
1907 void SdrObject::SaveGeoData(SdrObjGeoData& rGeo) const
1908 {
1909     rGeo.aBoundRect    =GetCurrentBoundRect();
1910     rGeo.aAnchor       =m_aAnchor       ;
1911     rGeo.bMovProt      =m_bMovProt      ;
1912     rGeo.bSizProt      =m_bSizProt      ;
1913     rGeo.bNoPrint      =m_bNoPrint      ;
1914     rGeo.mbVisible     =mbVisible     ;
1915     rGeo.bClosedObj    =m_bClosedObj    ;
1916     rGeo.mnLayerID = mnLayerID;
1917 
1918     // user-defined glue points
1919     if (m_pPlusData!=nullptr && m_pPlusData->pGluePoints!=nullptr) {
1920         if (rGeo.pGPL!=nullptr) {
1921             *rGeo.pGPL=*m_pPlusData->pGluePoints;
1922         } else {
1923             rGeo.pGPL.reset( new SdrGluePointList(*m_pPlusData->pGluePoints) );
1924         }
1925     } else {
1926         rGeo.pGPL.reset();
1927     }
1928 }
1929 
1930 void SdrObject::RestoreGeoData(const SdrObjGeoData& rGeo)
1931 {
1932     SetBoundAndSnapRectsDirty();
1933     m_aOutRect      =rGeo.aBoundRect    ;
1934     m_aAnchor       =rGeo.aAnchor       ;
1935     m_bMovProt      =rGeo.bMovProt      ;
1936     m_bSizProt      =rGeo.bSizProt      ;
1937     m_bNoPrint      =rGeo.bNoPrint      ;
1938     mbVisible     =rGeo.mbVisible     ;
1939     m_bClosedObj    =rGeo.bClosedObj    ;
1940     mnLayerID = rGeo.mnLayerID;
1941 
1942     // user-defined glue points
1943     if (rGeo.pGPL!=nullptr) {
1944         ImpForcePlusData();
1945         if (m_pPlusData->pGluePoints!=nullptr) {
1946             *m_pPlusData->pGluePoints=*rGeo.pGPL;
1947         } else {
1948             m_pPlusData->pGluePoints.reset(new SdrGluePointList(*rGeo.pGPL));
1949         }
1950     } else {
1951         if (m_pPlusData!=nullptr && m_pPlusData->pGluePoints!=nullptr) {
1952             m_pPlusData->pGluePoints.reset();
1953         }
1954     }
1955 }
1956 
1957 std::unique_ptr<SdrObjGeoData> SdrObject::GetGeoData() const
1958 {
1959     std::unique_ptr<SdrObjGeoData> pGeo = NewGeoData();
1960     SaveGeoData(*pGeo);
1961     return pGeo;
1962 }
1963 
1964 void SdrObject::SetGeoData(const SdrObjGeoData& rGeo)
1965 {
1966     tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
1967     RestoreGeoData(rGeo);
1968     SetChanged();
1969     BroadcastObjectChange();
1970     SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1971 }
1972 
1973 
1974 // ItemSet access
1975 
1976 const SfxItemSet& SdrObject::GetObjectItemSet() const
1977 {
1978     return GetProperties().GetObjectItemSet();
1979 }
1980 
1981 const SfxItemSet& SdrObject::GetMergedItemSet() const
1982 {
1983     return GetProperties().GetMergedItemSet();
1984 }
1985 
1986 void SdrObject::SetObjectItem(const SfxPoolItem& rItem)
1987 {
1988     GetProperties().SetObjectItem(rItem);
1989 }
1990 
1991 void SdrObject::SetMergedItem(const SfxPoolItem& rItem)
1992 {
1993     GetProperties().SetMergedItem(rItem);
1994 }
1995 
1996 void SdrObject::ClearMergedItem(const sal_uInt16 nWhich)
1997 {
1998     GetProperties().ClearMergedItem(nWhich);
1999 }
2000 
2001 void SdrObject::SetObjectItemSet(const SfxItemSet& rSet)
2002 {
2003     GetProperties().SetObjectItemSet(rSet);
2004 }
2005 
2006 void SdrObject::SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems)
2007 {
2008     GetProperties().SetMergedItemSet(rSet, bClearAllItems);
2009 }
2010 
2011 const SfxPoolItem& SdrObject::GetObjectItem(const sal_uInt16 nWhich) const
2012 {
2013     return GetObjectItemSet().Get(nWhich);
2014 }
2015 
2016 const SfxPoolItem& SdrObject::GetMergedItem(const sal_uInt16 nWhich) const
2017 {
2018     return GetMergedItemSet().Get(nWhich);
2019 }
2020 
2021 void SdrObject::SetMergedItemSetAndBroadcast(const SfxItemSet& rSet, bool bClearAllItems)
2022 {
2023     GetProperties().SetMergedItemSetAndBroadcast(rSet, bClearAllItems);
2024 }
2025 
2026 void SdrObject::ApplyNotPersistAttr(const SfxItemSet& rAttr)
2027 {
2028     tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
2029     NbcApplyNotPersistAttr(rAttr);
2030     SetChanged();
2031     BroadcastObjectChange();
2032     SendUserCall(SdrUserCallType::Resize,aBoundRect0);
2033 }
2034 
2035 void SdrObject::NbcApplyNotPersistAttr(const SfxItemSet& rAttr)
2036 {
2037     const tools::Rectangle& rSnap=GetSnapRect();
2038     const tools::Rectangle& rLogic=GetLogicRect();
2039     Point aRef1(rSnap.Center());
2040     const SfxPoolItem *pPoolItem=nullptr;
2041     if (rAttr.GetItemState(SDRATTR_TRANSFORMREF1X,true,&pPoolItem)==SfxItemState::SET) {
2042         aRef1.setX(static_cast<const SdrTransformRef1XItem*>(pPoolItem)->GetValue() );
2043     }
2044     if (rAttr.GetItemState(SDRATTR_TRANSFORMREF1Y,true,&pPoolItem)==SfxItemState::SET) {
2045         aRef1.setY(static_cast<const SdrTransformRef1YItem*>(pPoolItem)->GetValue() );
2046     }
2047 
2048     tools::Rectangle aNewSnap(rSnap);
2049     if (rAttr.GetItemState(SDRATTR_MOVEX,true,&pPoolItem)==SfxItemState::SET) {
2050         tools::Long n=static_cast<const SdrMoveXItem*>(pPoolItem)->GetValue();
2051         aNewSnap.Move(n,0);
2052     }
2053     if (rAttr.GetItemState(SDRATTR_MOVEY,true,&pPoolItem)==SfxItemState::SET) {
2054         tools::Long n=static_cast<const SdrMoveYItem*>(pPoolItem)->GetValue();
2055         aNewSnap.Move(0,n);
2056     }
2057     if (rAttr.GetItemState(SDRATTR_ONEPOSITIONX,true,&pPoolItem)==SfxItemState::SET) {
2058         tools::Long n=static_cast<const SdrOnePositionXItem*>(pPoolItem)->GetValue();
2059         aNewSnap.Move(n-aNewSnap.Left(),0);
2060     }
2061     if (rAttr.GetItemState(SDRATTR_ONEPOSITIONY,true,&pPoolItem)==SfxItemState::SET) {
2062         tools::Long n=static_cast<const SdrOnePositionYItem*>(pPoolItem)->GetValue();
2063         aNewSnap.Move(0,n-aNewSnap.Top());
2064     }
2065     if (rAttr.GetItemState(SDRATTR_ONESIZEWIDTH,true,&pPoolItem)==SfxItemState::SET) {
2066         tools::Long n=static_cast<const SdrOneSizeWidthItem*>(pPoolItem)->GetValue();
2067         aNewSnap.SetRight(aNewSnap.Left()+n );
2068     }
2069     if (rAttr.GetItemState(SDRATTR_ONESIZEHEIGHT,true,&pPoolItem)==SfxItemState::SET) {
2070         tools::Long n=static_cast<const SdrOneSizeHeightItem*>(pPoolItem)->GetValue();
2071         aNewSnap.SetBottom(aNewSnap.Top()+n );
2072     }
2073     if (aNewSnap!=rSnap) {
2074         if (aNewSnap.GetSize()==rSnap.GetSize()) {
2075             NbcMove(Size(aNewSnap.Left()-rSnap.Left(),aNewSnap.Top()-rSnap.Top()));
2076         } else {
2077             NbcSetSnapRect(aNewSnap);
2078         }
2079     }
2080 
2081     if (rAttr.GetItemState(SDRATTR_SHEARANGLE,true,&pPoolItem)==SfxItemState::SET) {
2082         Degree100 n=static_cast<const SdrShearAngleItem*>(pPoolItem)->GetValue();
2083         n-=GetShearAngle();
2084         if (n) {
2085             double nTan = tan(n.get() * F_PI18000);
2086             NbcShear(aRef1,n,nTan,false);
2087         }
2088     }
2089     if (rAttr.GetItemState(SDRATTR_ROTATEANGLE,true,&pPoolItem)==SfxItemState::SET) {
2090         Degree100 n=static_cast<const SdrAngleItem*>(pPoolItem)->GetValue();
2091         n-=GetRotateAngle();
2092         if (n) {
2093             NbcRotate(aRef1,n);
2094         }
2095     }
2096     if (rAttr.GetItemState(SDRATTR_ROTATEONE,true,&pPoolItem)==SfxItemState::SET) {
2097         Degree100 n=static_cast<const SdrRotateOneItem*>(pPoolItem)->GetValue();
2098         NbcRotate(aRef1,n);
2099     }
2100     if (rAttr.GetItemState(SDRATTR_HORZSHEARONE,true,&pPoolItem)==SfxItemState::SET) {
2101         Degree100 n=static_cast<const SdrHorzShearOneItem*>(pPoolItem)->GetValue();
2102         double nTan = tan(n.get() * F_PI18000);
2103         NbcShear(aRef1,n,nTan,false);
2104     }
2105     if (rAttr.GetItemState(SDRATTR_VERTSHEARONE,true,&pPoolItem)==SfxItemState::SET) {
2106         Degree100 n=static_cast<const SdrVertShearOneItem*>(pPoolItem)->GetValue();
2107         double nTan = tan(n.get() * F_PI18000);
2108         NbcShear(aRef1,n,nTan,true);
2109     }
2110 
2111     if (rAttr.GetItemState(SDRATTR_OBJMOVEPROTECT,true,&pPoolItem)==SfxItemState::SET) {
2112         bool b=static_cast<const SdrYesNoItem*>(pPoolItem)->GetValue();
2113         SetMoveProtect(b);
2114     }
2115     if (rAttr.GetItemState(SDRATTR_OBJSIZEPROTECT,true,&pPoolItem)==SfxItemState::SET) {
2116         bool b=static_cast<const SdrYesNoItem*>(pPoolItem)->GetValue();
2117         SetResizeProtect(b);
2118     }
2119 
2120     /* move protect always sets size protect */
2121     if( IsMoveProtect() )
2122         SetResizeProtect( true );
2123 
2124     if (rAttr.GetItemState(SDRATTR_OBJPRINTABLE,true,&pPoolItem)==SfxItemState::SET) {
2125         bool b=static_cast<const SdrObjPrintableItem*>(pPoolItem)->GetValue();
2126         SetPrintable(b);
2127     }
2128 
2129     if (rAttr.GetItemState(SDRATTR_OBJVISIBLE,true,&pPoolItem)==SfxItemState::SET) {
2130         bool b=static_cast<const SdrObjVisibleItem*>(pPoolItem)->GetValue();
2131         SetVisible(b);
2132     }
2133 
2134     SdrLayerID nLayer=SDRLAYER_NOTFOUND;
2135     if (rAttr.GetItemState(SDRATTR_LAYERID,true,&pPoolItem)==SfxItemState::SET) {
2136         nLayer=static_cast<const SdrLayerIdItem*>(pPoolItem)->GetValue();
2137     }
2138     if (rAttr.GetItemState(SDRATTR_LAYERNAME,true,&pPoolItem)==SfxItemState::SET)
2139     {
2140         OUString aLayerName = static_cast<const SdrLayerNameItem*>(pPoolItem)->GetValue();
2141         const SdrLayerAdmin& rLayAd(nullptr != getSdrPageFromSdrObject()
2142             ? getSdrPageFromSdrObject()->GetLayerAdmin()
2143             : getSdrModelFromSdrObject().GetLayerAdmin());
2144         const SdrLayer* pLayer = rLayAd.GetLayer(aLayerName);
2145 
2146         if(nullptr != pLayer)
2147         {
2148             nLayer=pLayer->GetID();
2149         }
2150     }
2151     if (nLayer!=SDRLAYER_NOTFOUND) {
2152         NbcSetLayer(nLayer);
2153     }
2154 
2155     if (rAttr.GetItemState(SDRATTR_OBJECTNAME,true,&pPoolItem)==SfxItemState::SET) {
2156         OUString aName=static_cast<const SfxStringItem*>(pPoolItem)->GetValue();
2157         SetName(aName);
2158     }
2159     tools::Rectangle aNewLogic(rLogic);
2160     if (rAttr.GetItemState(SDRATTR_LOGICSIZEWIDTH,true,&pPoolItem)==SfxItemState::SET) {
2161         tools::Long n=static_cast<const SdrLogicSizeWidthItem*>(pPoolItem)->GetValue();
2162         aNewLogic.SetRight(aNewLogic.Left()+n );
2163     }
2164     if (rAttr.GetItemState(SDRATTR_LOGICSIZEHEIGHT,true,&pPoolItem)==SfxItemState::SET) {
2165         tools::Long n=static_cast<const SdrLogicSizeHeightItem*>(pPoolItem)->GetValue();
2166         aNewLogic.SetBottom(aNewLogic.Top()+n );
2167     }
2168     if (aNewLogic!=rLogic) {
2169         NbcSetLogicRect(aNewLogic);
2170     }
2171     Fraction aResizeX(1,1);
2172     Fraction aResizeY(1,1);
2173     if (rAttr.GetItemState(SDRATTR_RESIZEXONE,true,&pPoolItem)==SfxItemState::SET) {
2174         aResizeX*=static_cast<const SdrResizeXOneItem*>(pPoolItem)->GetValue();
2175     }
2176     if (rAttr.GetItemState(SDRATTR_RESIZEYONE,true,&pPoolItem)==SfxItemState::SET) {
2177         aResizeY*=static_cast<const SdrResizeYOneItem*>(pPoolItem)->GetValue();
2178     }
2179     if (aResizeX!=Fraction(1,1) || aResizeY!=Fraction(1,1)) {
2180         NbcResize(aRef1,aResizeX,aResizeY);
2181     }
2182 }
2183 
2184 void SdrObject::TakeNotPersistAttr(SfxItemSet& rAttr) const
2185 {
2186     const tools::Rectangle& rSnap=GetSnapRect();
2187     const tools::Rectangle& rLogic=GetLogicRect();
2188     rAttr.Put(SdrYesNoItem(SDRATTR_OBJMOVEPROTECT, IsMoveProtect()));
2189     rAttr.Put(SdrYesNoItem(SDRATTR_OBJSIZEPROTECT, IsResizeProtect()));
2190     rAttr.Put(SdrObjPrintableItem(IsPrintable()));
2191     rAttr.Put(SdrObjVisibleItem(IsVisible()));
2192     rAttr.Put(SdrAngleItem(SDRATTR_ROTATEANGLE, GetRotateAngle()));
2193     rAttr.Put(SdrShearAngleItem(GetShearAngle()));
2194     rAttr.Put(SdrOneSizeWidthItem(rSnap.GetWidth()-1));
2195     rAttr.Put(SdrOneSizeHeightItem(rSnap.GetHeight()-1));
2196     rAttr.Put(SdrOnePositionXItem(rSnap.Left()));
2197     rAttr.Put(SdrOnePositionYItem(rSnap.Top()));
2198     if (rLogic.GetWidth()!=rSnap.GetWidth()) {
2199         rAttr.Put(SdrLogicSizeWidthItem(rLogic.GetWidth()-1));
2200     }
2201     if (rLogic.GetHeight()!=rSnap.GetHeight()) {
2202         rAttr.Put(SdrLogicSizeHeightItem(rLogic.GetHeight()-1));
2203     }
2204     OUString aName(GetName());
2205 
2206     if (!aName.isEmpty())
2207     {
2208         rAttr.Put(SfxStringItem(SDRATTR_OBJECTNAME, aName));
2209     }
2210 
2211     rAttr.Put(SdrLayerIdItem(GetLayer()));
2212     const SdrLayerAdmin& rLayAd(nullptr != getSdrPageFromSdrObject()
2213         ? getSdrPageFromSdrObject()->GetLayerAdmin()
2214         : getSdrModelFromSdrObject().GetLayerAdmin());
2215     const SdrLayer* pLayer = rLayAd.GetLayerPerID(GetLayer());
2216     if(nullptr != pLayer)
2217     {
2218         rAttr.Put(SdrLayerNameItem(pLayer->GetName()));
2219     }
2220     Point aRef1(rSnap.Center());
2221     Point aRef2(aRef1); aRef2.AdjustY( 1 );
2222     rAttr.Put(SdrTransformRef1XItem(aRef1.X()));
2223     rAttr.Put(SdrTransformRef1YItem(aRef1.Y()));
2224     rAttr.Put(SdrTransformRef2XItem(aRef2.X()));
2225     rAttr.Put(SdrTransformRef2YItem(aRef2.Y()));
2226 }
2227 
2228 SfxStyleSheet* SdrObject::GetStyleSheet() const
2229 {
2230     return GetProperties().GetStyleSheet();
2231 }
2232 
2233 void SdrObject::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
2234 {
2235     tools::Rectangle aBoundRect0;
2236 
2237     if(m_pUserCall)
2238         aBoundRect0 = GetLastBoundRect();
2239 
2240     NbcSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
2241     SetChanged();
2242     BroadcastObjectChange();
2243     SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect0);
2244 }
2245 
2246 void SdrObject::NbcSetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
2247 {
2248     GetProperties().SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
2249 }
2250 
2251 // Broadcasting while setting attributes is managed by the AttrObj.
2252 
2253 
2254 SdrGluePoint SdrObject::GetVertexGluePoint(sal_uInt16 nPosNum) const
2255 {
2256     // #i41936# Use SnapRect for default GluePoints
2257     const tools::Rectangle aR(GetSnapRect());
2258     Point aPt;
2259 
2260     switch(nPosNum)
2261     {
2262         case 0 : aPt = aR.TopCenter();    break;
2263         case 1 : aPt = aR.RightCenter();  break;
2264         case 2 : aPt = aR.BottomCenter(); break;
2265         case 3 : aPt = aR.LeftCenter();   break;
2266     }
2267 
2268     aPt -= aR.Center();
2269     SdrGluePoint aGP(aPt);
2270     aGP.SetPercent(false);
2271 
2272     return aGP;
2273 }
2274 
2275 SdrGluePoint SdrObject::GetCornerGluePoint(sal_uInt16 nPosNum) const
2276 {
2277     tools::Rectangle aR(GetCurrentBoundRect());
2278     Point aPt;
2279     switch (nPosNum) {
2280         case 0 : aPt=aR.TopLeft();     break;
2281         case 1 : aPt=aR.TopRight();    break;
2282         case 2 : aPt=aR.BottomRight(); break;
2283         case 3 : aPt=aR.BottomLeft();  break;
2284     }
2285     aPt-=GetSnapRect().Center();
2286     SdrGluePoint aGP(aPt);
2287     aGP.SetPercent(false);
2288     return aGP;
2289 }
2290 
2291 const SdrGluePointList* SdrObject::GetGluePointList() const
2292 {
2293     if (m_pPlusData!=nullptr) return m_pPlusData->pGluePoints.get();
2294     return nullptr;
2295 }
2296 
2297 
2298 SdrGluePointList* SdrObject::ForceGluePointList()
2299 {
2300     ImpForcePlusData();
2301     if (m_pPlusData->pGluePoints==nullptr) {
2302         m_pPlusData->pGluePoints.reset(new SdrGluePointList);
2303     }
2304     return m_pPlusData->pGluePoints.get();
2305 }
2306 
2307 void SdrObject::SetGlueReallyAbsolute(bool bOn)
2308 {
2309     // First a const call to see whether there are any glue points.
2310     // Force const call!
2311     if (GetGluePointList()!=nullptr) {
2312         SdrGluePointList* pGPL=ForceGluePointList();
2313         pGPL->SetReallyAbsolute(bOn,*this);
2314     }
2315 }
2316 
2317 void SdrObject::NbcRotateGluePoints(const Point& rRef, Degree100 nAngle, double sn, double cs)
2318 {
2319     // First a const call to see whether there are any glue points.
2320     // Force const call!
2321     if (GetGluePointList()!=nullptr) {
2322         SdrGluePointList* pGPL=ForceGluePointList();
2323         pGPL->Rotate(rRef,nAngle,sn,cs,this);
2324     }
2325 }
2326 
2327 void SdrObject::NbcMirrorGluePoints(const Point& rRef1, const Point& rRef2)
2328 {
2329     // First a const call to see whether there are any glue points.
2330     // Force const call!
2331     if (GetGluePointList()!=nullptr) {
2332         SdrGluePointList* pGPL=ForceGluePointList();
2333         pGPL->Mirror(rRef1,rRef2,this);
2334     }
2335 }
2336 
2337 void SdrObject::NbcShearGluePoints(const Point& rRef, double tn, bool bVShear)
2338 {
2339     // First a const call to see whether there are any glue points.
2340     // Force const call!
2341     if (GetGluePointList()!=nullptr) {
2342         SdrGluePointList* pGPL=ForceGluePointList();
2343         pGPL->Shear(rRef,tn,bVShear,this);
2344     }
2345 }
2346 
2347 void SdrObject::ConnectToNode(bool /*bTail1*/, SdrObject* /*pObj*/)
2348 {
2349 }
2350 
2351 void SdrObject::DisconnectFromNode(bool /*bTail1*/)
2352 {
2353 }
2354 
2355 SdrObject* SdrObject::GetConnectedNode(bool /*bTail1*/) const
2356 {
2357     return nullptr;
2358 }
2359 
2360 
2361 static void extractLineContourFromPrimitive2DSequence(
2362     const drawinglayer::primitive2d::Primitive2DContainer& rxSequence,
2363     basegfx::B2DPolygonVector& rExtractedHairlines,
2364     basegfx::B2DPolyPolygonVector& rExtractedLineFills)
2365 {
2366     rExtractedHairlines.clear();
2367     rExtractedLineFills.clear();
2368 
2369     if(rxSequence.empty())
2370         return;
2371 
2372     // use neutral ViewInformation
2373     const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
2374 
2375     // create extractor, process and get result
2376     drawinglayer::processor2d::LineGeometryExtractor2D aExtractor(aViewInformation2D);
2377     aExtractor.process(rxSequence);
2378 
2379     // copy line results
2380     rExtractedHairlines = aExtractor.getExtractedHairlines();
2381 
2382     // copy fill rsults
2383     rExtractedLineFills = aExtractor.getExtractedLineFills();
2384 }
2385 
2386 
2387 SdrObject* SdrObject::ImpConvertToContourObj(bool bForceLineDash)
2388 {
2389     SdrObject* pRetval(nullptr);
2390 
2391     if(LineGeometryUsageIsNecessary())
2392     {
2393         basegfx::B2DPolyPolygon aMergedLineFillPolyPolygon;
2394         basegfx::B2DPolyPolygon aMergedHairlinePolyPolygon;
2395         const drawinglayer::primitive2d::Primitive2DContainer & xSequence(GetViewContact().getViewIndependentPrimitive2DContainer());
2396 
2397         if(!xSequence.empty())
2398         {
2399             basegfx::B2DPolygonVector aExtractedHairlines;
2400             basegfx::B2DPolyPolygonVector aExtractedLineFills;
2401 
2402             extractLineContourFromPrimitive2DSequence(xSequence, aExtractedHairlines, aExtractedLineFills);
2403 
2404             // for SdrObject creation, just copy all to a single Hairline-PolyPolygon
2405             for(const basegfx::B2DPolygon & rExtractedHairline : aExtractedHairlines)
2406             {
2407                 aMergedHairlinePolyPolygon.append(rExtractedHairline);
2408             }
2409 
2410             // check for fill rsults
2411             if (!aExtractedLineFills.empty() && !utl::ConfigManager::IsFuzzing())
2412             {
2413                 // merge to a single tools::PolyPolygon (OR)
2414                 aMergedLineFillPolyPolygon = basegfx::utils::mergeToSinglePolyPolygon(aExtractedLineFills);
2415             }
2416         }
2417 
2418         if(aMergedLineFillPolyPolygon.count() || (bForceLineDash && aMergedHairlinePolyPolygon.count()))
2419         {
2420             SfxItemSet aSet(GetMergedItemSet());
2421             drawing::FillStyle eOldFillStyle = aSet.Get(XATTR_FILLSTYLE).GetValue();
2422             SdrPathObj* aLinePolygonPart = nullptr;
2423             SdrPathObj* aLineHairlinePart = nullptr;
2424             bool bBuildGroup(false);
2425 
2426             if(aMergedLineFillPolyPolygon.count())
2427             {
2428                 // create SdrObject for filled line geometry
2429                 aLinePolygonPart = new SdrPathObj(
2430                     getSdrModelFromSdrObject(),
2431                     OBJ_PATHFILL,
2432                     aMergedLineFillPolyPolygon);
2433 
2434                 // correct item properties
2435                 aSet.Put(XLineWidthItem(0));
2436                 aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
2437                 Color aColorLine = aSet.Get(XATTR_LINECOLOR).GetColorValue();
2438                 sal_uInt16 nTransLine = aSet.Get(XATTR_LINETRANSPARENCE).GetValue();
2439                 aSet.Put(XFillColorItem(OUString(), aColorLine));
2440                 aSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
2441                 aSet.Put(XFillTransparenceItem(nTransLine));
2442 
2443                 aLinePolygonPart->SetMergedItemSet(aSet);
2444             }
2445 
2446             if(aMergedHairlinePolyPolygon.count())
2447             {
2448                 // create SdrObject for hairline geometry
2449                 // OBJ_PATHLINE is necessary here, not OBJ_PATHFILL. This is intended
2450                 // to get a non-filled object. If the poly is closed, the PathObj takes care for
2451                 // the correct closed state.
2452                 aLineHairlinePart = new SdrPathObj(
2453                     getSdrModelFromSdrObject(),
2454                     OBJ_PATHLINE,
2455                     aMergedHairlinePolyPolygon);
2456 
2457                 aSet.Put(XLineWidthItem(0));
2458                 aSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
2459                 aSet.Put(XLineStyleItem(drawing::LineStyle_SOLID));
2460 
2461                 // it is also necessary to switch off line start and ends here
2462                 aSet.Put(XLineStartWidthItem(0));
2463                 aSet.Put(XLineEndWidthItem(0));
2464 
2465                 aLineHairlinePart->SetMergedItemSet(aSet);
2466 
2467                 if(aLinePolygonPart)
2468                 {
2469                     bBuildGroup = true;
2470                 }
2471             }
2472 
2473             // check if original geometry should be added (e.g. filled and closed)
2474             bool bAddOriginalGeometry(false);
2475             SdrPathObj* pPath = dynamic_cast<SdrPathObj*>(this);
2476 
2477             if(pPath && pPath->IsClosed())
2478             {
2479                 if(eOldFillStyle != drawing::FillStyle_NONE)
2480                 {
2481                     bAddOriginalGeometry = true;
2482                 }
2483             }
2484 
2485             // do we need a group?
2486             if(bBuildGroup || bAddOriginalGeometry)
2487             {
2488                 SdrObject* pGroup = new SdrObjGroup(getSdrModelFromSdrObject());
2489 
2490                 if(bAddOriginalGeometry)
2491                 {
2492                     // Add a clone of the original geometry.
2493                     aSet.ClearItem();
2494                     aSet.Put(GetMergedItemSet());
2495                     aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
2496                     aSet.Put(XLineWidthItem(0));
2497 
2498                     SdrObject* pClone(CloneSdrObject(getSdrModelFromSdrObject()));
2499                     pClone->SetMergedItemSet(aSet);
2500 
2501                     pGroup->GetSubList()->NbcInsertObject(pClone);
2502                 }
2503 
2504                 if(aLinePolygonPart)
2505                 {
2506                     pGroup->GetSubList()->NbcInsertObject(aLinePolygonPart);
2507                 }
2508 
2509                 if(aLineHairlinePart)
2510                 {
2511                     pGroup->GetSubList()->NbcInsertObject(aLineHairlinePart);
2512                 }
2513 
2514                 pRetval = pGroup;
2515             }
2516             else
2517             {
2518                 if(aLinePolygonPart)
2519                 {
2520                     pRetval = aLinePolygonPart;
2521                 }
2522                 else if(aLineHairlinePart)
2523                 {
2524                     pRetval = aLineHairlinePart;
2525                 }
2526             }
2527         }
2528     }
2529 
2530     if(nullptr == pRetval)
2531     {
2532         // due to current method usage, create and return a clone when nothing has changed
2533         SdrObject* pClone(CloneSdrObject(getSdrModelFromSdrObject()));
2534         pRetval = pClone;
2535     }
2536 
2537     return pRetval;
2538 }
2539 
2540 
2541 void SdrObject::SetMarkProtect(bool bProt)
2542 {
2543     m_bMarkProt = bProt;
2544 }
2545 
2546 
2547 void SdrObject::SetEmptyPresObj(bool bEpt)
2548 {
2549     m_bEmptyPresObj = bEpt;
2550 }
2551 
2552 
2553 void SdrObject::SetNotVisibleAsMaster(bool bFlg)
2554 {
2555     m_bNotVisibleAsMaster=bFlg;
2556 }
2557 
2558 
2559 // convert this path object to contour object, even when it is a group
2560 SdrObject* SdrObject::ConvertToContourObj(SdrObject* pRet, bool bForceLineDash) const
2561 {
2562     if(dynamic_cast<const SdrObjGroup*>( pRet) !=  nullptr)
2563     {
2564         SdrObjList* pObjList2 = pRet->GetSubList();
2565         SdrObject* pGroup = new SdrObjGroup(getSdrModelFromSdrObject());
2566 
2567         for(size_t a=0; a<pObjList2->GetObjCount(); ++a)
2568         {
2569             SdrObject* pIterObj = pObjList2->GetObj(a);
2570             pGroup->GetSubList()->NbcInsertObject(ConvertToContourObj(pIterObj, bForceLineDash));
2571         }
2572 
2573         pRet = pGroup;
2574     }
2575     else
2576     {
2577         if (SdrPathObj *pPathObj = dynamic_cast<SdrPathObj*>(pRet))
2578         {
2579             // bezier geometry got created, even for straight edges since the given
2580             // object is a result of DoConvertToPolyObj. For conversion to contour
2581             // this is not really needed and can be reduced again AFAP
2582             pPathObj->SetPathPoly(basegfx::utils::simplifyCurveSegments(pPathObj->GetPathPoly()));
2583         }
2584 
2585         pRet = pRet->ImpConvertToContourObj(bForceLineDash);
2586     }
2587 
2588     // #i73441# preserve LayerID
2589     if(pRet && pRet->GetLayer() != GetLayer())
2590     {
2591         pRet->SetLayer(GetLayer());
2592     }
2593 
2594     return pRet;
2595 }
2596 
2597 
2598 SdrObjectUniquePtr SdrObject::ConvertToPolyObj(bool bBezier, bool bLineToArea) const
2599 {
2600     SdrObjectUniquePtr pRet = DoConvertToPolyObj(bBezier, true);
2601 
2602     if(pRet && bLineToArea)
2603     {
2604         SdrObject* pNewRet = ConvertToContourObj(pRet.get());
2605         pRet.reset(pNewRet);
2606     }
2607 
2608     // #i73441# preserve LayerID
2609     if(pRet && pRet->GetLayer() != GetLayer())
2610     {
2611         pRet->SetLayer(GetLayer());
2612     }
2613 
2614     return pRet;
2615 }
2616 
2617 
2618 SdrObjectUniquePtr SdrObject::DoConvertToPolyObj(bool /*bBezier*/, bool /*bAddText*/) const
2619 {
2620     return nullptr;
2621 }
2622 
2623 
2624 void SdrObject::InsertedStateChange()
2625 {
2626     const bool bIsInserted(nullptr != getParentSdrObjListFromSdrObject());
2627     const tools::Rectangle aBoundRect0(GetLastBoundRect());
2628 
2629     if(bIsInserted)
2630     {
2631         SendUserCall(SdrUserCallType::Inserted, aBoundRect0);
2632     }
2633     else
2634     {
2635         SendUserCall(SdrUserCallType::Removed, aBoundRect0);
2636     }
2637 
2638     if(nullptr != m_pPlusData && nullptr != m_pPlusData->pBroadcast)
2639     {
2640         SdrHint aHint(bIsInserted ? SdrHintKind::ObjectInserted : SdrHintKind::ObjectRemoved, *this);
2641         m_pPlusData->pBroadcast->Broadcast(aHint);
2642     }
2643 }
2644 
2645 void SdrObject::SetMoveProtect(bool bProt)
2646 {
2647     if(IsMoveProtect() != bProt)
2648     {
2649         // #i77187# secured and simplified
2650         m_bMovProt = bProt;
2651         SetChanged();
2652         BroadcastObjectChange();
2653     }
2654 }
2655 
2656 void SdrObject::SetResizeProtect(bool bProt)
2657 {
2658     if(IsResizeProtect() != bProt)
2659     {
2660         // #i77187# secured and simplified
2661         m_bSizProt = bProt;
2662         SetChanged();
2663         BroadcastObjectChange();
2664     }
2665 }
2666 
2667 void SdrObject::SetPrintable(bool bPrn)
2668 {
2669     if( bPrn == m_bNoPrint )
2670     {
2671         m_bNoPrint=!bPrn;
2672         SetChanged();
2673         if (IsInserted())
2674         {
2675             SdrHint aHint(SdrHintKind::ObjectChange, *this);
2676             getSdrModelFromSdrObject().Broadcast(aHint);
2677         }
2678     }
2679 }
2680 
2681 void SdrObject::SetVisible(bool bVisible)
2682 {
2683     if( bVisible != mbVisible )
2684     {
2685         mbVisible = bVisible;
2686         SetChanged();
2687         if (IsInserted())
2688         {
2689             SdrHint aHint(SdrHintKind::ObjectChange, *this);
2690             getSdrModelFromSdrObject().Broadcast(aHint);
2691         }
2692     }
2693 }
2694 
2695 
2696 sal_uInt16 SdrObject::GetUserDataCount() const
2697 {
2698     if (m_pPlusData==nullptr || m_pPlusData->pUserDataList==nullptr) return 0;
2699     return m_pPlusData->pUserDataList->GetUserDataCount();
2700 }
2701 
2702 SdrObjUserData* SdrObject::GetUserData(sal_uInt16 nNum) const
2703 {
2704     if (m_pPlusData==nullptr || m_pPlusData->pUserDataList==nullptr) return nullptr;
2705     return &m_pPlusData->pUserDataList->GetUserData(nNum);
2706 }
2707 
2708 void SdrObject::AppendUserData(std::unique_ptr<SdrObjUserData> pData)
2709 {
2710     if (!pData)
2711     {
2712         OSL_FAIL("SdrObject::AppendUserData(): pData is NULL pointer.");
2713         return;
2714     }
2715 
2716     ImpForcePlusData();
2717     if (!m_pPlusData->pUserDataList)
2718         m_pPlusData->pUserDataList.reset( new SdrObjUserDataList );
2719 
2720     m_pPlusData->pUserDataList->AppendUserData(std::move(pData));
2721 }
2722 
2723 void SdrObject::DeleteUserData(sal_uInt16 nNum)
2724 {
2725     sal_uInt16 nCount=GetUserDataCount();
2726     if (nNum<nCount) {
2727         m_pPlusData->pUserDataList->DeleteUserData(nNum);
2728         if (nCount==1)  {
2729             m_pPlusData->pUserDataList.reset();
2730         }
2731     } else {
2732         OSL_FAIL("SdrObject::DeleteUserData(): Invalid Index.");
2733     }
2734 }
2735 
2736 void SdrObject::SetUserCall(SdrObjUserCall* pUser)
2737 {
2738     m_pUserCall = pUser;
2739 }
2740 
2741 
2742 void SdrObject::SendUserCall(SdrUserCallType eUserCall, const tools::Rectangle& rBoundRect) const
2743 {
2744     SdrObject* pGroup(getParentSdrObjectFromSdrObject());
2745 
2746     if ( m_pUserCall )
2747     {
2748         m_pUserCall->Changed( *this, eUserCall, rBoundRect );
2749     }
2750 
2751     if(nullptr != pGroup && pGroup->GetUserCall())
2752     {
2753         // broadcast to group
2754         SdrUserCallType eChildUserType = SdrUserCallType::ChildChangeAttr;
2755 
2756         switch( eUserCall )
2757         {
2758             case SdrUserCallType::MoveOnly:
2759                 eChildUserType = SdrUserCallType::ChildMoveOnly;
2760             break;
2761 
2762             case SdrUserCallType::Resize:
2763                 eChildUserType = SdrUserCallType::ChildResize;
2764             break;
2765 
2766             case SdrUserCallType::ChangeAttr:
2767                 eChildUserType = SdrUserCallType::ChildChangeAttr;
2768             break;
2769 
2770             case SdrUserCallType::Delete:
2771                 eChildUserType = SdrUserCallType::ChildDelete;
2772             break;
2773 
2774             case SdrUserCallType::Inserted:
2775                 eChildUserType = SdrUserCallType::ChildInserted;
2776             break;
2777 
2778             case SdrUserCallType::Removed:
2779                 eChildUserType = SdrUserCallType::ChildRemoved;
2780             break;
2781 
2782             default: break;
2783         }
2784 
2785         pGroup->GetUserCall()->Changed( *this, eChildUserType, rBoundRect );
2786     }
2787 
2788     // notify our UNO shape listeners
2789     switch ( eUserCall )
2790     {
2791     case SdrUserCallType::Resize:
2792         notifyShapePropertyChange( svx::ShapeProperty::Size );
2793         [[fallthrough]]; // RESIZE might also imply a change of the position
2794     case SdrUserCallType::MoveOnly:
2795         notifyShapePropertyChange( svx::ShapeProperty::Position );
2796         break;
2797     default:
2798         // not interested in
2799         break;
2800     }
2801 }
2802 
2803 void SdrObject::impl_setUnoShape( const uno::Reference< uno::XInterface >& _rxUnoShape )
2804 {
2805     const uno::Reference< uno::XInterface>& xOldUnoShape( maWeakUnoShape );
2806     // the UNO shape would be gutted by the following code; return early
2807     if ( _rxUnoShape == xOldUnoShape )
2808     {
2809         if ( !xOldUnoShape.is() )
2810         {
2811             // make sure there is no stale impl. pointer if the UNO
2812             // shape was destroyed meanwhile (remember we only hold weak
2813             // reference to it!)
2814             mpSvxShape = nullptr;
2815         }
2816         return;
2817     }
2818 
2819     bool bTransferOwnership( false );
2820     if ( xOldUnoShape.is() )
2821     {
2822         bTransferOwnership = mpSvxShape->HasSdrObjectOwnership();
2823         // Remove yourself from the current UNO shape. Its destructor
2824         // will reset our UNO shape otherwise.
2825         mpSvxShape->InvalidateSdrObject();
2826     }
2827 
2828     maWeakUnoShape = _rxUnoShape;
2829     mpSvxShape = comphelper::getUnoTunnelImplementation<SvxShape>( _rxUnoShape );
2830 
2831     // I think this may never happen... But I am not sure enough .-)
2832     if ( bTransferOwnership )
2833     {
2834         if (mpSvxShape)
2835             mpSvxShape->TakeSdrObjectOwnership();
2836         SAL_WARN( "svx.uno", "a UNO shape took over an SdrObject previously owned by another UNO shape!");
2837     }
2838 }
2839 
2840 /** only for internal use! */
2841 SvxShape* SdrObject::getSvxShape()
2842 {
2843     DBG_TESTSOLARMUTEX();
2844         // retrieving the impl pointer and subsequently using it is not thread-safe, of course, so it needs to be
2845         // guarded by the SolarMutex
2846 
2847     uno::Reference< uno::XInterface > xShape( maWeakUnoShape );
2848 #if OSL_DEBUG_LEVEL > 0
2849     OSL_ENSURE( !( !xShape.is() && mpSvxShape ),
2850         "SdrObject::getSvxShape: still having IMPL-Pointer to dead object!" );
2851 #endif
2852     //#113608#, make sure mpSvxShape is always synchronized with maWeakUnoShape
2853     if ( mpSvxShape && !xShape.is() )
2854         mpSvxShape = nullptr;
2855 
2856     return mpSvxShape;
2857 }
2858 
2859 css::uno::Reference< css::uno::XInterface > SdrObject::getUnoShape()
2860 {
2861     // try weak reference first
2862     uno::Reference< uno::XInterface > xShape( getWeakUnoShape() );
2863     if( xShape )
2864         return xShape;
2865 
2866     OSL_ENSURE( mpSvxShape == nullptr, "SdrObject::getUnoShape: XShape already dead, but still an IMPL pointer!" );
2867 
2868     // try to access SdrPage from this SdrObject. This will only exist if the SdrObject is
2869     // inserted in a SdrObjList (page/group/3dScene)
2870     SdrPage* pPageCandidate(getSdrPageFromSdrObject());
2871 
2872     // tdf#12152, tdf#120728
2873     //
2874     // With the paradigm change to only get a SdrPage for a SdrObject when the SdrObject
2875     // is *inserted*, the functionality for creating 1:1 associated UNO API implementation
2876     // SvxShapes was partially broken: The used ::CreateShape relies on the SvxPage being
2877     // derived and the CreateShape method overloaded, implementing additional SdrInventor
2878     // types as needed.
2879     //
2880     // The fallback to use SvxDrawPage::CreateShapeByTypeAndInventor is a trap: It's only
2881     // a static fallback that handles the SdrInventor types SdrInventor::E3d and
2882     // SdrInventor::Default. Due to that, e.g. the ReportDesigner broke in various conditions.
2883     //
2884     // That again has to do with the ReportDesigner being implemented using the UNO API
2885     // aspects of SdrObjects early during their construction, not just after these are
2886     // inserted to a SdrPage - but that is not illegal or wrong, the SdrObject exists already.
2887     //
2888     // As a current solution, use the (now always available) SdrModel and any of the
2889     // existing SdrPages. The only important thing is to get a SdrPage where ::CreateShape is
2890     // overloaded and implemented as needed.
2891     //
2892     // Note for the future:
2893     // In a more ideal world there would be only one factory method for creating SdrObjects (not
2894     // ::CreateShape and ::CreateShapeByTypeAndInventor). This also would not be placed at
2895     // SdrPage/SvxPage at all, but at the Model where it belongs - where else would you expect
2896     // objects for the current Model to be constructed? To have this at the Page only would make
2897     // sense if different shapes would need to be constructed for different Pages in the same Model
2898     // - this is never the case.
2899     // At that Model extended functionality for that factory (or overloads and implementations)
2900     // should be placed. But to be realistic, migrating the factories to Model now is too much
2901     // work - maybe over time when melting SdrObject/SvxObject one day...
2902     if(nullptr == pPageCandidate)
2903     {
2904         // If not inserted, alternatively access a SdrPage using the SdrModel. There is
2905         // no reason not to create and return a UNO API XShape when the SdrObject is not
2906         // inserted - it may be in construction. Main paradigm is that it exists.
2907         if(0 != getSdrModelFromSdrObject().GetPageCount())
2908         {
2909             // Take 1st SdrPage. That may be e.g. a special page (in SD), but the
2910             // to-be-used method ::CreateShape will be correctly overloaded in
2911             // all cases
2912             pPageCandidate = getSdrModelFromSdrObject().GetPage(0);
2913         }
2914     }
2915 
2916     if(nullptr != pPageCandidate)
2917     {
2918         uno::Reference< uno::XInterface > xPage(pPageCandidate->getUnoPage());
2919         if( xPage.is() )
2920         {
2921             SvxDrawPage* pDrawPage = comphelper::getUnoTunnelImplementation<SvxDrawPage>(xPage);
2922             if( pDrawPage )
2923             {
2924                 // create one
2925                 xShape = pDrawPage->CreateShape( this );
2926                 impl_setUnoShape( xShape );
2927             }
2928         }
2929     }
2930     else
2931     {
2932         // Fallback to static base functionality. CAUTION: This will only support
2933         // the most basic stuff like SdrInventor::E3d and SdrInventor::Default. All
2934         // the other SdrInventor enum entries are from overloads and are *not accessible*
2935         // using this fallback (!) - what a bad trap
2936         rtl::Reference<SvxShape> xNewShape = SvxDrawPage::CreateShapeByTypeAndInventor( GetObjIdentifier(), GetObjInventor(), this );
2937         mpSvxShape = xNewShape.get();
2938         maWeakUnoShape = xShape = static_cast< ::cppu::OWeakObject* >( mpSvxShape );
2939     }
2940 
2941     return xShape;
2942 }
2943 
2944 void SdrObject::setUnoShape(const uno::Reference<uno::XInterface >& _rxUnoShape)
2945 {
2946     impl_setUnoShape( _rxUnoShape );
2947 }
2948 
2949 svx::PropertyChangeNotifier& SdrObject::getShapePropertyChangeNotifier()
2950 {
2951     DBG_TESTSOLARMUTEX();
2952 
2953     SvxShape* pSvxShape = getSvxShape();
2954     ENSURE_OR_THROW( pSvxShape, "no SvxShape, yet!" );
2955     return pSvxShape->getShapePropertyChangeNotifier();
2956 }
2957 
2958 void SdrObject::notifyShapePropertyChange( const svx::ShapeProperty _eProperty ) const
2959 {
2960     DBG_TESTSOLARMUTEX();
2961 
2962     SvxShape* pSvxShape = const_cast< SdrObject* >( this )->getSvxShape();
2963     if ( pSvxShape )
2964         return pSvxShape->getShapePropertyChangeNotifier().notifyPropertyChange( _eProperty );
2965 }
2966 
2967 
2968 // transformation interface for StarOfficeAPI. This implements support for
2969 // homogeneous 3x3 matrices containing the transformation of the SdrObject. At the
2970 // moment it contains a shearX, rotation and translation, but for setting all linear
2971 // transforms like Scale, ShearX, ShearY, Rotate and Translate are supported.
2972 
2973 
2974 // gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon
2975 // with the base geometry and returns TRUE. Otherwise it returns FALSE.
2976 bool SdrObject::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
2977 {
2978     // any kind of SdrObject, just use SnapRect
2979     tools::Rectangle aRectangle(GetSnapRect());
2980 
2981     // convert to transformation values
2982     basegfx::B2DTuple aScale(aRectangle.GetWidth(), aRectangle.GetHeight());
2983     basegfx::B2DTuple aTranslate(aRectangle.Left(), aRectangle.Top());
2984 
2985     // position maybe relative to anchorpos, convert
2986     if(getSdrModelFromSdrObject().IsWriter())
2987     {
2988         if(GetAnchorPos().X() || GetAnchorPos().Y())
2989         {
2990             aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
2991         }
2992     }
2993 
2994     // build matrix
2995     rMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(aScale, aTranslate);
2996 
2997     return false;
2998 }
2999 
3000 // sets the base geometry of the object using infos contained in the homogeneous 3x3 matrix.
3001 // If it's an SdrPathObj it will use the provided geometry information. The Polygon has
3002 // to use (0,0) as upper left and will be scaled to the given size in the matrix.
3003 void SdrObject::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
3004 {
3005     // break up matrix
3006     basegfx::B2DTuple aScale;
3007     basegfx::B2DTuple aTranslate;
3008     double fRotate, fShearX;
3009     rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
3010 
3011     // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
3012     // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
3013     if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
3014     {
3015         aScale.setX(fabs(aScale.getX()));
3016         aScale.setY(fabs(aScale.getY()));
3017     }
3018 
3019     // if anchor is used, make position relative to it
3020     if(getSdrModelFromSdrObject().IsWriter())
3021     {
3022         if(GetAnchorPos().X() || GetAnchorPos().Y())
3023         {
3024             aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
3025         }
3026     }
3027 
3028     // build BaseRect
3029     Point aPoint(FRound(aTranslate.getX()), FRound(aTranslate.getY()));
3030     tools::Rectangle aBaseRect(aPoint, Size(FRound(aScale.getX()), FRound(aScale.getY())));
3031 
3032     // set BaseRect
3033     SetSnapRect(aBaseRect);
3034 }
3035 
3036 // Give info if object is in destruction
3037 bool SdrObject::IsInDestruction() const
3038 {
3039     return getSdrModelFromSdrObject().IsInDestruction();
3040 }
3041 
3042 // return if fill is != drawing::FillStyle_NONE
3043 bool SdrObject::HasFillStyle() const
3044 {
3045     return GetObjectItem(XATTR_FILLSTYLE).GetValue() != drawing::FillStyle_NONE;
3046 }
3047 
3048 bool SdrObject::HasLineStyle() const
3049 {
3050     return GetObjectItem(XATTR_LINESTYLE).GetValue() != drawing::LineStyle_NONE;
3051 }
3052 
3053 
3054 // #i52224#
3055 // on import of OLE object from MS documents the BLIP size might be retrieved,
3056 // the following four methods are used to control it;
3057 // usually this data makes no sense after the import is finished, since the object
3058 // might be resized
3059 
3060 
3061 void SdrObject::SetBLIPSizeRectangle( const tools::Rectangle& aRect )
3062 {
3063     maBLIPSizeRectangle = aRect;
3064 }
3065 
3066 void SdrObject::SetContextWritingMode( const sal_Int16 /*_nContextWritingMode*/ )
3067 {
3068     // this base class does not support different writing modes, so ignore the call
3069 }
3070 
3071 void SdrObject::SetDoNotInsertIntoPageAutomatically(const bool bSet)
3072 {
3073     mbDoNotInsertIntoPageAutomatically = bSet;
3074 }
3075 
3076 
3077 // #i121917#
3078 bool SdrObject::HasText() const
3079 {
3080     return false;
3081 }
3082 
3083 bool SdrObject::IsTextBox() const
3084 {
3085     return false;
3086 }
3087 
3088 void SdrObject::MakeNameUnique()
3089 {
3090     if (GetName().isEmpty())
3091     {
3092         if (const E3dScene* pE3dObj = dynamic_cast<const E3dScene*>(this))
3093         {
3094             SdrObjList* pObjList = pE3dObj->GetSubList();
3095             if (pObjList)
3096             {
3097                 SdrObject* pObj0 = pObjList->GetObj(0);
3098                 if (pObj0)
3099                     SetName(pObj0->TakeObjNameSingul());
3100             }
3101         }
3102         else
3103             SetName(TakeObjNameSingul());
3104     }
3105 
3106     std::unordered_set<OUString> aNameSet;
3107     MakeNameUnique(aNameSet);
3108 }
3109 
3110 void SdrObject::MakeNameUnique(std::unordered_set<OUString>& rNameSet)
3111 {
3112     if (GetName().isEmpty())
3113         return;
3114 
3115     if (rNameSet.empty())
3116     {
3117         SdrPage* pPage;
3118         SdrObject* pObj;
3119         for (sal_uInt16 nPage(0); nPage < mrSdrModelFromSdrObject.GetPageCount(); ++nPage)
3120         {
3121             pPage = mrSdrModelFromSdrObject.GetPage(nPage);
3122             SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
3123             while (aIter.IsMore())
3124             {
3125                 pObj = aIter.Next();
3126                 if (pObj != this)
3127                     rNameSet.insert(pObj->GetName());
3128             }
3129         }
3130     }
3131 
3132     OUString sName(GetName().trim());
3133     OUString sRootName(sName);
3134 
3135     if (!sName.isEmpty() && rtl::isAsciiDigit(sName[sName.getLength() - 1]))
3136     {
3137         sal_Int32 nPos(sName.getLength() - 1);
3138         while (nPos > 0 && rtl::isAsciiDigit(sName[--nPos]));
3139         sRootName = sName.copy(0, nPos + 1).trim();
3140     }
3141     else
3142         sName += " 1";
3143 
3144     for (sal_uInt32 n = 1; rNameSet.find(sName) != rNameSet.end(); n++)
3145         sName = sRootName + " " + OUString::number(n);
3146     rNameSet.insert(sName);
3147 
3148     SetName(sName);
3149 }
3150 
3151 SdrObject* SdrObjFactory::CreateObjectFromFactory(SdrModel& rSdrModel, SdrInventor nInventor, SdrObjKind nObjIdentifier)
3152 {
3153     SdrObjCreatorParams aParams { nInventor, nObjIdentifier, rSdrModel };
3154     for (const auto & i : ImpGetUserMakeObjHdl()) {
3155         SdrObject* pObj = i.Call(aParams);
3156         if (pObj) {
3157             return pObj;
3158         }
3159     }
3160     return nullptr;
3161 }
3162 
3163 SdrObject* SdrObjFactory::MakeNewObject(
3164     SdrModel& rSdrModel,
3165     SdrInventor nInventor,
3166     SdrObjKind nIdentifier,
3167     const tools::Rectangle* pSnapRect)
3168 {
3169     SdrObject* pObj(nullptr);
3170     bool bSetSnapRect(nullptr != pSnapRect);
3171 
3172     if (nInventor == SdrInventor::Default)
3173     {
3174         switch (nIdentifier)
3175         {
3176             case OBJ_MEASURE:
3177             {
3178                 if(nullptr != pSnapRect)
3179                 {
3180                     pObj = new SdrMeasureObj(
3181                         rSdrModel,
3182                         pSnapRect->TopLeft(),
3183                         pSnapRect->BottomRight());
3184                 }
3185                 else
3186                 {
3187                     pObj = new SdrMeasureObj(rSdrModel);
3188                 }
3189             }
3190             break;
3191             case OBJ_LINE:
3192             {
3193                 if(nullptr != pSnapRect)
3194                 {
3195                     basegfx::B2DPolygon aPoly;
3196 
3197                     aPoly.append(
3198                         basegfx::B2DPoint(
3199                             pSnapRect->Left(),
3200                             pSnapRect->Top()));
3201                     aPoly.append(
3202                         basegfx::B2DPoint(
3203                             pSnapRect->Right(),
3204                             pSnapRect->Bottom()));
3205                     pObj = new SdrPathObj(
3206                         rSdrModel,
3207                         OBJ_LINE,
3208                         basegfx::B2DPolyPolygon(aPoly));
3209                 }
3210                 else
3211                 {
3212                     pObj = new SdrPathObj(
3213                         rSdrModel,
3214                         OBJ_LINE);
3215                 }
3216             }
3217             break;
3218             case OBJ_TEXT:
3219             case OBJ_TITLETEXT:
3220             case OBJ_OUTLINETEXT:
3221             {
3222                 if(nullptr != pSnapRect)
3223                 {
3224                     pObj = new SdrRectObj(
3225                         rSdrModel,
3226                         nIdentifier,
3227                         *pSnapRect);
3228                     bSetSnapRect = false;
3229                 }
3230                 else
3231                 {
3232                     pObj = new SdrRectObj(
3233                         rSdrModel,
3234                         nIdentifier);
3235                 }
3236             }
3237             break;
3238             case OBJ_CIRC:
3239             case OBJ_SECT:
3240             case OBJ_CARC:
3241             case OBJ_CCUT:
3242             {
3243                 SdrCircKind eCircKind = ToSdrCircKind(nIdentifier);
3244                 if(nullptr != pSnapRect)
3245                 {
3246                     pObj = new SdrCircObj(rSdrModel, eCircKind, *pSnapRect);
3247                     bSetSnapRect = false;
3248                 }
3249                 else
3250                 {
3251                     pObj = new SdrCircObj(rSdrModel, eCircKind);
3252                 }
3253             }
3254             break;
3255             case OBJ_NONE       : pObj=new SdrObject(rSdrModel);                   break;
3256             case OBJ_GRUP       : pObj=new SdrObjGroup(rSdrModel);                 break;
3257             case OBJ_POLY       : pObj=new SdrPathObj(rSdrModel, OBJ_POLY       ); break;
3258             case OBJ_PLIN       : pObj=new SdrPathObj(rSdrModel, OBJ_PLIN       ); break;
3259             case OBJ_PATHLINE   : pObj=new SdrPathObj(rSdrModel, OBJ_PATHLINE   ); break;
3260             case OBJ_PATHFILL   : pObj=new SdrPathObj(rSdrModel, OBJ_PATHFILL   ); break;
3261             case OBJ_FREELINE   : pObj=new SdrPathObj(rSdrModel, OBJ_FREELINE   ); break;
3262             case OBJ_FREEFILL   : pObj=new SdrPathObj(rSdrModel, OBJ_FREEFILL   ); break;
3263             case OBJ_PATHPOLY   : pObj=new SdrPathObj(rSdrModel, OBJ_POLY       ); break;
3264             case OBJ_PATHPLIN   : pObj=new SdrPathObj(rSdrModel, OBJ_PLIN       ); break;
3265             case OBJ_EDGE       : pObj=new SdrEdgeObj(rSdrModel);                  break;
3266             case OBJ_RECT       : pObj=new SdrRectObj(rSdrModel);                  break;
3267             case OBJ_GRAF       : pObj=new SdrGrafObj(rSdrModel);                  break;
3268             case OBJ_OLE2       : pObj=new SdrOle2Obj(rSdrModel);                  break;
3269             case OBJ_FRAME      : pObj=new SdrOle2Obj(rSdrModel, true);            break;
3270             case OBJ_CAPTION    : pObj=new SdrCaptionObj(rSdrModel);               break;
3271             case OBJ_PAGE       : pObj=new SdrPageObj(rSdrModel);                  break;
3272             case OBJ_UNO        : pObj=new SdrUnoObj(rSdrModel, OUString());       break;
3273             case OBJ_CUSTOMSHAPE: pObj=new SdrObjCustomShape(rSdrModel);       break;
3274 #if HAVE_FEATURE_AVMEDIA
3275             case OBJ_MEDIA      : pObj=new SdrMediaObj(rSdrModel);               break;
3276 #endif
3277             case OBJ_TABLE      : pObj=new sdr::table::SdrTableObj(rSdrModel);   break;
3278             default: break;
3279         }
3280     }
3281 
3282     if (!pObj)
3283     {
3284         pObj = CreateObjectFromFactory(rSdrModel, nInventor, nIdentifier);
3285     }
3286 
3287     if (!pObj)
3288     {
3289         // Well, if no one wants it...
3290         return nullptr;
3291     }
3292 
3293     if(bSetSnapRect && nullptr != pSnapRect)
3294     {
3295         pObj->SetSnapRect(*pSnapRect);
3296     }
3297 
3298     return pObj;
3299 }
3300 
3301 void SdrObjFactory::InsertMakeObjectHdl(Link<SdrObjCreatorParams, SdrObject*> const & rLink)
3302 {
3303     std::vector<Link<SdrObjCreatorParams, SdrObject*>>& rLL=ImpGetUserMakeObjHdl();
3304     auto it = std::find(rLL.begin(), rLL.end(), rLink);
3305     if (it != rLL.end()) {
3306         OSL_FAIL("SdrObjFactory::InsertMakeObjectHdl(): Link already in place.");
3307     } else {
3308         rLL.push_back(rLink);
3309     }
3310 }
3311 
3312 void SdrObjFactory::RemoveMakeObjectHdl(Link<SdrObjCreatorParams, SdrObject*> const & rLink)
3313 {
3314     std::vector<Link<SdrObjCreatorParams, SdrObject*>>& rLL=ImpGetUserMakeObjHdl();
3315     auto it = std::find(rLL.begin(), rLL.end(), rLink);
3316     if (it != rLL.end())
3317         rLL.erase(it);
3318 }
3319 
3320 namespace svx
3321 {
3322     ISdrObjectFilter::~ISdrObjectFilter()
3323     {
3324     }
3325 }
3326 
3327 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3328