summaryrefslogtreecommitdiffstats
path: root/svx/source/sdr
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /svx/source/sdr
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--svx/source/sdr/animation/animationstate.cxx130
-rw-r--r--svx/source/sdr/animation/objectanimator.cxx35
-rw-r--r--svx/source/sdr/animation/scheduler.cxx173
-rw-r--r--svx/source/sdr/attribute/sdrallfillattributeshelper.cxx244
-rw-r--r--svx/source/sdr/attribute/sdreffectstextattribute.cxx76
-rw-r--r--svx/source/sdr/attribute/sdrfilltextattribute.cxx65
-rw-r--r--svx/source/sdr/attribute/sdrformtextattribute.cxx372
-rw-r--r--svx/source/sdr/attribute/sdrformtextoutlineattribute.cxx141
-rw-r--r--svx/source/sdr/attribute/sdrlineeffectstextattribute.cxx75
-rw-r--r--svx/source/sdr/attribute/sdrlinefilleffectstextattribute.cxx77
-rw-r--r--svx/source/sdr/attribute/sdrtextattribute.cxx422
-rw-r--r--svx/source/sdr/contact/displayinfo.cxx87
-rw-r--r--svx/source/sdr/contact/objectcontact.cxx217
-rw-r--r--svx/source/sdr/contact/objectcontactofobjlistpainter.cxx198
-rw-r--r--svx/source/sdr/contact/objectcontactofpageview.cxx451
-rw-r--r--svx/source/sdr/contact/sdrmediawindow.cxx174
-rw-r--r--svx/source/sdr/contact/sdrmediawindow.hxx60
-rw-r--r--svx/source/sdr/contact/viewcontact.cxx295
-rw-r--r--svx/source/sdr/contact/viewcontactofe3d.cxx195
-rw-r--r--svx/source/sdr/contact/viewcontactofe3dcube.cxx88
-rw-r--r--svx/source/sdr/contact/viewcontactofe3dextrude.cxx83
-rw-r--r--svx/source/sdr/contact/viewcontactofe3dlathe.cxx96
-rw-r--r--svx/source/sdr/contact/viewcontactofe3dpolygon.cxx169
-rw-r--r--svx/source/sdr/contact/viewcontactofe3dscene.cxx446
-rw-r--r--svx/source/sdr/contact/viewcontactofe3dsphere.cxx80
-rw-r--r--svx/source/sdr/contact/viewcontactofgraphic.cxx391
-rw-r--r--svx/source/sdr/contact/viewcontactofgroup.cxx78
-rw-r--r--svx/source/sdr/contact/viewcontactofmasterpagedescriptor.cxx103
-rw-r--r--svx/source/sdr/contact/viewcontactofpageobj.cxx79
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrcaptionobj.cxx190
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrcircobj.cxx102
-rw-r--r--svx/source/sdr/contact/viewcontactofsdredgeobj.cxx66
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrmeasureobj.cxx127
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrmediaobj.cxx129
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrobj.cxx179
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrobjcustomshape.cxx238
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrole2obj.cxx179
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrpage.cxx598
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrpathobj.cxx210
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrrectobj.cxx88
-rw-r--r--svx/source/sdr/contact/viewcontactoftextobj.cxx33
-rw-r--r--svx/source/sdr/contact/viewcontactofunocontrol.cxx133
-rw-r--r--svx/source/sdr/contact/viewcontactofvirtobj.cxx100
-rw-r--r--svx/source/sdr/contact/viewobjectcontact.cxx570
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofe3d.cxx72
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofe3dscene.cxx137
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofgraphic.cxx57
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofgroup.cxx87
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.cxx132
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofpageobj.cxx315
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofsdrmediaobj.cxx175
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofsdrobj.cxx193
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofsdrole2obj.cxx147
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofsdrpage.cxx579
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx1777
-rw-r--r--svx/source/sdr/contact/viewobjectcontactredirector.cxx39
-rw-r--r--svx/source/sdr/misc/ImageMapInfo.cxx121
-rw-r--r--svx/source/sdr/overlay/overlayanimatedbitmapex.cxx113
-rw-r--r--svx/source/sdr/overlay/overlaybitmapex.cxx72
-rw-r--r--svx/source/sdr/overlay/overlaycrosshair.cxx67
-rw-r--r--svx/source/sdr/overlay/overlayhandle.cxx55
-rw-r--r--svx/source/sdr/overlay/overlayhelpline.cxx74
-rw-r--r--svx/source/sdr/overlay/overlayline.cxx74
-rw-r--r--svx/source/sdr/overlay/overlaymanager.cxx346
-rw-r--r--svx/source/sdr/overlay/overlaymanagerbuffered.cxx441
-rw-r--r--svx/source/sdr/overlay/overlayobject.cxx228
-rw-r--r--svx/source/sdr/overlay/overlayobjectcell.cxx81
-rw-r--r--svx/source/sdr/overlay/overlayobjectlist.cxx144
-rw-r--r--svx/source/sdr/overlay/overlaypolypolygon.cxx128
-rw-r--r--svx/source/sdr/overlay/overlayprimitive2dsequenceobject.cxx42
-rw-r--r--svx/source/sdr/overlay/overlayrectangle.cxx113
-rw-r--r--svx/source/sdr/overlay/overlayrollingrectangle.cxx117
-rw-r--r--svx/source/sdr/overlay/overlayselection.cxx218
-rw-r--r--svx/source/sdr/overlay/overlaytools.cxx601
-rw-r--r--svx/source/sdr/overlay/overlaytriangle.cxx61
-rw-r--r--svx/source/sdr/primitive2d/primitivefactory2d.cxx98
-rw-r--r--svx/source/sdr/primitive2d/sdrattributecreator.cxx1151
-rw-r--r--svx/source/sdr/primitive2d/sdrcaptionprimitive2d.cxx159
-rw-r--r--svx/source/sdr/primitive2d/sdrconnectorprimitive2d.cxx107
-rw-r--r--svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d.cxx130
-rw-r--r--svx/source/sdr/primitive2d/sdrdecompositiontools.cxx884
-rw-r--r--svx/source/sdr/primitive2d/sdrellipseprimitive2d.cxx266
-rw-r--r--svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx928
-rw-r--r--svx/source/sdr/primitive2d/sdrgrafprimitive2d.cxx167
-rw-r--r--svx/source/sdr/primitive2d/sdrmeasureprimitive2d.cxx498
-rw-r--r--svx/source/sdr/primitive2d/sdrole2primitive2d.cxx176
-rw-r--r--svx/source/sdr/primitive2d/sdrolecontentprimitive2d.cxx179
-rw-r--r--svx/source/sdr/primitive2d/sdrpathprimitive2d.cxx156
-rw-r--r--svx/source/sdr/primitive2d/sdrprimitivetools.cxx64
-rw-r--r--svx/source/sdr/primitive2d/sdrrectangleprimitive2d.cxx152
-rw-r--r--svx/source/sdr/primitive2d/sdrtextprimitive2d.cxx545
-rw-r--r--svx/source/sdr/primitive3d/sdrattributecreator3d.cxx145
-rw-r--r--svx/source/sdr/properties/attributeproperties.cxx541
-rw-r--r--svx/source/sdr/properties/captionproperties.cxx101
-rw-r--r--svx/source/sdr/properties/circleproperties.cxx125
-rw-r--r--svx/source/sdr/properties/connectorproperties.cxx89
-rw-r--r--svx/source/sdr/properties/customshapeproperties.cxx230
-rw-r--r--svx/source/sdr/properties/defaultproperties.cxx251
-rw-r--r--svx/source/sdr/properties/e3dcompoundproperties.cxx144
-rw-r--r--svx/source/sdr/properties/e3dextrudeproperties.cxx74
-rw-r--r--svx/source/sdr/properties/e3dlatheproperties.cxx84
-rw-r--r--svx/source/sdr/properties/e3dproperties.cxx75
-rw-r--r--svx/source/sdr/properties/e3dsceneproperties.cxx296
-rw-r--r--svx/source/sdr/properties/e3dsphereproperties.cxx69
-rw-r--r--svx/source/sdr/properties/emptyproperties.cxx89
-rw-r--r--svx/source/sdr/properties/graphicproperties.cxx150
-rw-r--r--svx/source/sdr/properties/groupproperties.cxx240
-rw-r--r--svx/source/sdr/properties/itemsettools.cxx87
-rw-r--r--svx/source/sdr/properties/measureproperties.cxx130
-rw-r--r--svx/source/sdr/properties/oleproperties.cxx73
-rw-r--r--svx/source/sdr/properties/pageproperties.cxx106
-rw-r--r--svx/source/sdr/properties/properties.cxx178
-rw-r--r--svx/source/sdr/properties/rectangleproperties.cxx69
-rw-r--r--svx/source/sdr/properties/textproperties.cxx631
114 files changed, 24485 insertions, 0 deletions
diff --git a/svx/source/sdr/animation/animationstate.cxx b/svx/source/sdr/animation/animationstate.cxx
new file mode 100644
index 000000000..074f2082e
--- /dev/null
+++ b/svx/source/sdr/animation/animationstate.cxx
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/animation/animationstate.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/animation/objectanimator.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
+#include <drawinglayer/animation/animationtiming.hxx>
+#include <comphelper/lok.hxx>
+
+
+namespace sdr::animation
+{
+ double PrimitiveAnimation::getSmallestNextTime(double fCurrentTime)
+ {
+ double fRetval(0.0);
+
+ if(!maAnimatedPrimitives.empty())
+ {
+ const sal_Int32 nCount(maAnimatedPrimitives.size());
+
+ for(sal_Int32 a(0); a < nCount; a++)
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xRef(maAnimatedPrimitives[a]);
+ const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D* pCandidate = static_cast< const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D* >(xRef.get());
+
+ const drawinglayer::animation::AnimationEntry& rAnimEntry = pCandidate->getAnimationEntry();
+ const double fNextTime(rAnimEntry.getNextEventTime(fCurrentTime));
+
+ if(!::basegfx::fTools::equalZero(fNextTime))
+ {
+ if(::basegfx::fTools::equalZero(fRetval))
+ {
+ fRetval = fNextTime;
+ }
+ else if(::basegfx::fTools::less(fNextTime, fRetval))
+ {
+ fRetval = fNextTime;
+ }
+ }
+ }
+ }
+
+ return fRetval;
+ }
+
+ void PrimitiveAnimation::prepareNextEvent()
+ {
+ const double fCurrentTime(mrVOContact.GetObjectContact().getPrimitiveAnimator().GetTime());
+ const double fNextTime(getSmallestNextTime(fCurrentTime));
+
+ // getSmallestNextTime will be zero when animation ended. If not zero, a next step
+ // exists
+ if(::basegfx::fTools::equalZero(fNextTime))
+ return;
+
+ // next time point exists, use it
+ sal_uInt32 nNextTime;
+
+ if(fNextTime >= double(0xffffff00))
+ {
+ // take care for very late points in time, e.g. when a text animation stops
+ // in a defined AnimationEntryFixed with endless (0xffffffff) duration
+ nNextTime = GetTime() + (1000 * 60 * 60); // one hour, works with vcl timers, 0xffffff00 was too much...
+ }
+ else
+ {
+ nNextTime = static_cast<sal_uInt32>(fNextTime);
+ }
+
+ // ensure step forward in integer timing, the floating step difference maybe smaller than 1.0. Use
+ // at least 25ms for next step
+ const sal_uInt32 nMinimumStepTime(static_cast<sal_uInt32>(fCurrentTime) + 25);
+
+ if(nNextTime <= nMinimumStepTime)
+ {
+ nNextTime = nMinimumStepTime;
+ }
+
+ // set time and reactivate by re-adding to the scheduler
+ SetTime(nNextTime);
+ mrVOContact.GetObjectContact().getPrimitiveAnimator().InsertEvent(*this);
+ }
+
+ PrimitiveAnimation::PrimitiveAnimation(sdr::contact::ViewObjectContact& rVOContact, drawinglayer::primitive2d::Primitive2DContainer&& rAnimatedPrimitives)
+ : mrVOContact(rVOContact),
+ maAnimatedPrimitives(std::move(rAnimatedPrimitives))
+ {
+ if (!comphelper::LibreOfficeKit::isActive())
+ // setup initially
+ prepareNextEvent();
+ }
+
+ PrimitiveAnimation::~PrimitiveAnimation()
+ {
+ // ensure that Event member is removed from PrimitiveAnimator
+ mrVOContact.GetObjectContact().getPrimitiveAnimator().RemoveEvent(this);
+ }
+
+ // execute event, from base class Event
+ void PrimitiveAnimation::Trigger(sal_uInt32 /*nTime*/)
+ {
+ // schedule a repaint of associated object
+ mrVOContact.ActionChanged();
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ // re-setup
+ prepareNextEvent();
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/animation/objectanimator.cxx b/svx/source/sdr/animation/objectanimator.cxx
new file mode 100644
index 000000000..aad545fd7
--- /dev/null
+++ b/svx/source/sdr/animation/objectanimator.cxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/animation/objectanimator.hxx>
+
+
+namespace sdr::animation
+{
+ primitiveAnimator::primitiveAnimator()
+ {
+ }
+
+ primitiveAnimator::~primitiveAnimator()
+ {
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/animation/scheduler.cxx b/svx/source/sdr/animation/scheduler.cxx
new file mode 100644
index 000000000..d4451c099
--- /dev/null
+++ b/svx/source/sdr/animation/scheduler.cxx
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/animation/scheduler.hxx>
+
+#include <algorithm>
+#include <vector>
+
+
+// event class
+
+namespace sdr::animation
+{
+ Event::Event() : mnTime(0)
+ {
+ }
+
+ Event::~Event()
+ {
+ }
+
+
+ void Event::SetTime(sal_uInt32 nNew)
+ {
+ if(mnTime != nNew)
+ {
+ mnTime = nNew;
+ }
+ }
+
+ Scheduler::Scheduler()
+ : Timer("sdr::animation::Scheduler"),
+ mnTime(0),
+ mnDeltaTime(0),
+ mbIsPaused(false)
+ {
+ SetPriority(TaskPriority::POST_PAINT);
+ }
+
+ Scheduler::~Scheduler()
+ {
+ Stop();
+ }
+
+ void Scheduler::Invoke()
+ {
+ // stop timer and add time
+ Stop();
+ mnTime += mnDeltaTime;
+
+ // execute events
+ triggerEvents();
+
+ // re-start or stop timer according to event list
+ checkTimeout();
+ }
+
+ void Scheduler::triggerEvents()
+ {
+ if (mvEvents.empty())
+ return;
+
+ // copy events which need to be executed to a vector. Remove them from
+ // the scheduler
+ ::std::vector< Event* > aToBeExecutedList;
+
+ while(!mvEvents.empty() && mvEvents.front()->GetTime() <= mnTime)
+ {
+ Event* pNextEvent = mvEvents.front();
+ mvEvents.erase(mvEvents.begin());
+ aToBeExecutedList.push_back(pNextEvent);
+ }
+
+ // execute events from the vector
+ for(auto& rpCandidate : aToBeExecutedList)
+ {
+ // trigger event. This may re-insert the event to the scheduler again
+ rpCandidate->Trigger(mnTime);
+ }
+ }
+
+ void Scheduler::checkTimeout()
+ {
+ // re-start or stop timer according to event list
+ if(!IsPaused() && !mvEvents.empty())
+ {
+ mnDeltaTime = mvEvents.front()->GetTime() - mnTime;
+
+ if(0 != mnDeltaTime)
+ {
+ SetTimeout(mnDeltaTime);
+ Start();
+ }
+ }
+ else
+ {
+ Stop();
+ }
+ }
+
+
+ // #i38135#
+ void Scheduler::SetTime(sal_uInt32 nTime)
+ {
+ // reset time
+ Stop();
+ mnTime = nTime;
+
+ if (mvEvents.empty())
+ return;
+
+ // reset event time points
+ for (auto & rEvent : mvEvents)
+ {
+ rEvent->SetTime(nTime);
+ }
+
+ if(!IsPaused())
+ {
+ // without delta time, init events by triggering them. This will invalidate
+ // painted objects and add them to the scheduler again
+ mnDeltaTime = 0;
+ triggerEvents();
+ checkTimeout();
+ }
+ }
+
+ void Scheduler::InsertEvent(Event& rNew)
+ {
+ // insert maintaining time ordering
+ auto it = std::find_if(mvEvents.begin(), mvEvents.end(),
+ [&rNew](const Event* pEvent) { return rNew.GetTime() < pEvent->GetTime(); });
+ mvEvents.insert(it, &rNew);
+ checkTimeout();
+ }
+
+ void Scheduler::RemoveEvent(Event* pOld)
+ {
+ if(!mvEvents.empty())
+ {
+ mvEvents.erase(std::remove(mvEvents.begin(), mvEvents.end(), pOld), mvEvents.end());
+ checkTimeout();
+ }
+ }
+
+ void Scheduler::SetPaused(bool bNew)
+ {
+ if(bNew != mbIsPaused)
+ {
+ mbIsPaused = bNew;
+ checkTimeout();
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdrallfillattributeshelper.cxx b/svx/source/sdr/attribute/sdrallfillattributeshelper.cxx
new file mode 100644
index 000000000..261eef295
--- /dev/null
+++ b/svx/source/sdr/attribute/sdrallfillattributeshelper.cxx
@@ -0,0 +1,244 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/attribute/fillhatchattribute.hxx>
+#include <drawinglayer/attribute/sdrfillgraphicattribute.hxx>
+#include <vcl/graph.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer::attribute
+{
+ void SdrAllFillAttributesHelper::createPrimitive2DSequence(
+ const basegfx::B2DRange& rPaintRange,
+ const basegfx::B2DRange& rDefineRange)
+ {
+ // reset and remember new target range for object geometry
+ maLastPaintRange = rPaintRange;
+ maLastDefineRange = rDefineRange;
+
+ if(isUsed())
+ {
+ maPrimitives.resize(1);
+ maPrimitives[0] = drawinglayer::primitive2d::createPolyPolygonFillPrimitive(
+ basegfx::B2DPolyPolygon(
+ basegfx::utils::createPolygonFromRect(
+ maLastPaintRange)),
+ maLastDefineRange,
+ maFillAttribute ? *maFillAttribute : drawinglayer::attribute::SdrFillAttribute(),
+ maFillGradientAttribute ? *maFillGradientAttribute : drawinglayer::attribute::FillGradientAttribute());
+ }
+ }
+
+ SdrAllFillAttributesHelper::SdrAllFillAttributesHelper(const Color& rColor)
+ {
+ maFillAttribute = drawinglayer::attribute::SdrFillAttribute(
+ 0.0,
+ rColor.GetRGBColor().getBColor(),
+ drawinglayer::attribute::FillGradientAttribute(),
+ drawinglayer::attribute::FillHatchAttribute(),
+ drawinglayer::attribute::SdrFillGraphicAttribute());
+ }
+
+ SdrAllFillAttributesHelper::SdrAllFillAttributesHelper(const SfxItemSet& rSet)
+ : maFillAttribute(
+ drawinglayer::primitive2d::createNewSdrFillAttribute(rSet)),
+ maFillGradientAttribute(
+ drawinglayer::primitive2d::createNewTransparenceGradientAttribute(rSet))
+ {
+ }
+
+ SdrAllFillAttributesHelper::~SdrAllFillAttributesHelper()
+ {
+ }
+
+ bool SdrAllFillAttributesHelper::isUsed() const
+ {
+ // only depends on fill, FillGradientAttribute alone defines no fill
+ return maFillAttribute && !maFillAttribute->isDefault();
+ }
+
+ bool SdrAllFillAttributesHelper::isTransparent() const
+ {
+ if(hasSdrFillAttribute() && 0.0 != maFillAttribute->getTransparence())
+ {
+ return true;
+ }
+
+ if(maFillGradientAttribute && !maFillGradientAttribute->isDefault())
+ {
+ return true;
+ }
+
+ if(hasSdrFillAttribute())
+ {
+ const Graphic& rGraphic = getFillAttribute().getFillGraphic().getFillGraphic();
+
+ return rGraphic.IsSupportedGraphic() && rGraphic.IsTransparent();
+ }
+
+ return false;
+ }
+
+ const drawinglayer::attribute::SdrFillAttribute& SdrAllFillAttributesHelper::getFillAttribute() const
+ {
+ if(!maFillAttribute)
+ {
+ const_cast< SdrAllFillAttributesHelper* >(this)->maFillAttribute.emplace();
+ }
+
+ return *maFillAttribute;
+ }
+
+ const drawinglayer::attribute::FillGradientAttribute& SdrAllFillAttributesHelper::getFillGradientAttribute() const
+ {
+ if(!maFillGradientAttribute)
+ {
+ const_cast< SdrAllFillAttributesHelper* >(this)->maFillGradientAttribute.emplace();
+ }
+
+ return *maFillGradientAttribute;
+ }
+
+ const drawinglayer::primitive2d::Primitive2DContainer& SdrAllFillAttributesHelper::getPrimitive2DSequence(
+ const basegfx::B2DRange& rPaintRange,
+ const basegfx::B2DRange& rDefineRange) const
+ {
+ if(!maPrimitives.empty() && (maLastPaintRange != rPaintRange || maLastDefineRange != rDefineRange))
+ {
+ const_cast< SdrAllFillAttributesHelper* >(this)->maPrimitives.clear();
+ }
+
+ if(maPrimitives.empty())
+ {
+ const_cast< SdrAllFillAttributesHelper* >(this)->createPrimitive2DSequence(rPaintRange, rDefineRange);
+ }
+
+ return maPrimitives;
+ }
+
+ basegfx::BColor SdrAllFillAttributesHelper::getAverageColor(const basegfx::BColor& rFallback) const
+ {
+ basegfx::BColor aRetval(rFallback);
+
+ if(maFillAttribute && !maFillAttribute->isDefault())
+ {
+ const drawinglayer::attribute::FillGradientAttribute& rFillGradientAttribute = maFillAttribute->getGradient();
+ const drawinglayer::attribute::FillHatchAttribute& rFillHatchAttribute = maFillAttribute->getHatch();
+ const drawinglayer::attribute::SdrFillGraphicAttribute& rSdrFillGraphicAttribute = maFillAttribute->getFillGraphic();
+ const drawinglayer::attribute::FillGradientAttribute& rFillTransparenceGradientAttribute = getFillGradientAttribute();
+ double fTransparence(maFillAttribute->getTransparence());
+
+ if(!rFillTransparenceGradientAttribute.isDefault())
+ {
+ const double fTransA = rFillTransparenceGradientAttribute.getStartColor().luminance();
+ const double fTransB = rFillTransparenceGradientAttribute.getEndColor().luminance();
+
+ fTransparence = (fTransA + fTransB) * 0.5;
+ }
+
+ if(!rFillGradientAttribute.isDefault())
+ {
+ // gradient fill
+ const basegfx::BColor& rStart = rFillGradientAttribute.getStartColor();
+ const basegfx::BColor& rEnd = rFillGradientAttribute.getEndColor();
+
+ aRetval = basegfx::interpolate(rStart, rEnd, 0.5);
+ }
+ else if(!rFillHatchAttribute.isDefault())
+ {
+ // hatch fill
+ const basegfx::BColor& rColor = rFillHatchAttribute.getColor();
+
+ if(rFillHatchAttribute.isFillBackground())
+ {
+ const basegfx::BColor& rBackgroundColor = maFillAttribute->getColor();
+
+ // mix colors 50%/50%
+ aRetval = basegfx::interpolate(rColor, rBackgroundColor, 0.5);
+ }
+ else
+ {
+ // mix color with fallback color
+ aRetval = basegfx::interpolate(rColor, rFallback, 0.5);
+ }
+ }
+ else if(!rSdrFillGraphicAttribute.isDefault())
+ {
+ // graphic fill
+
+ // not used yet by purpose (see SwPageFrm::GetDrawBackgrdColor()),
+ // use fallback (already set)
+ }
+ else
+ {
+ // color fill
+ aRetval = maFillAttribute->getColor();
+ }
+
+ if(!basegfx::fTools::equalZero(fTransparence))
+ {
+ // blend into transparency
+ aRetval = basegfx::interpolate(aRetval, rFallback, fTransparence);
+ }
+ }
+
+ return aRetval.clamp();
+ }
+
+ bool SdrAllFillAttributesHelper::needCompleteRepaint() const
+ {
+ if(!isUsed() || !hasSdrFillAttribute())
+ {
+ // not used or no fill
+ return false;
+ }
+
+ const drawinglayer::attribute::SdrFillAttribute& rSdrFillAttribute = getFillAttribute();
+
+ if(!rSdrFillAttribute.getHatch().isDefault())
+ {
+ // hatch is always top-left aligned, needs no full refreshes
+ return false;
+ }
+
+ if(!rSdrFillAttribute.getGradient().isDefault())
+ {
+ // gradients always scale with the object
+ return true;
+ }
+
+ if(!rSdrFillAttribute.getFillGraphic().isDefault())
+ {
+ // some graphic constellations may not need this, but since most do
+ // (stretch to fill, all but top-left aligned, ...) claim to do by default
+ return true;
+ }
+
+ // color fill
+ return false;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdreffectstextattribute.cxx b/svx/source/sdr/attribute/sdreffectstextattribute.cxx
new file mode 100644
index 000000000..3287b8c8e
--- /dev/null
+++ b/svx/source/sdr/attribute/sdreffectstextattribute.cxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/attribute/sdreffectstextattribute.hxx>
+
+
+namespace drawinglayer::attribute
+{
+ SdrEffectsTextAttribute::SdrEffectsTextAttribute(
+ const SdrShadowAttribute& rShadow,
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow,
+ sal_Int32 nSoftEdgeRadius)
+ : maShadow(rShadow),
+ maTextAttribute(rTextAttribute),
+ maGlow(rGlow),
+ mnSoftEdgeRadius(nSoftEdgeRadius)
+ {
+ }
+
+ SdrEffectsTextAttribute::SdrEffectsTextAttribute()
+ {
+ }
+
+ SdrEffectsTextAttribute::SdrEffectsTextAttribute(const SdrEffectsTextAttribute& rCandidate)
+ : maShadow(rCandidate.getShadow()),
+ maTextAttribute(rCandidate.getText()),
+ maGlow(rCandidate.maGlow),
+ mnSoftEdgeRadius(rCandidate.mnSoftEdgeRadius)
+ {
+ }
+
+ SdrEffectsTextAttribute& SdrEffectsTextAttribute::operator=(const SdrEffectsTextAttribute& rCandidate)
+ {
+ maShadow = rCandidate.getShadow();
+ maTextAttribute = rCandidate.getText();
+ maGlow = rCandidate.maGlow;
+ mnSoftEdgeRadius = rCandidate.mnSoftEdgeRadius;
+
+ return *this;
+ }
+
+ bool SdrEffectsTextAttribute::isDefault() const
+ {
+ return (getShadow().isDefault()
+ && getText().isDefault() && maGlow.isDefault() && getSoftEdgeRadius() == 0);
+ }
+
+ bool SdrEffectsTextAttribute::operator==(const SdrEffectsTextAttribute& rCandidate) const
+ {
+ return (getShadow() == rCandidate.getShadow()
+ && getText() == rCandidate.getText()
+ && getGlow() == rCandidate.getGlow()
+ && getSoftEdgeRadius() == rCandidate.getSoftEdgeRadius());
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdrfilltextattribute.cxx b/svx/source/sdr/attribute/sdrfilltextattribute.cxx
new file mode 100644
index 000000000..01593c982
--- /dev/null
+++ b/svx/source/sdr/attribute/sdrfilltextattribute.cxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/attribute/sdrfilltextattribute.hxx>
+
+
+namespace drawinglayer::attribute
+{
+ SdrFillTextAttribute::SdrFillTextAttribute(
+ const SdrFillAttribute& rFill,
+ const FillGradientAttribute& rFillFloatTransGradient,
+ const SdrTextAttribute& rTextAttribute)
+ : maFill(rFill),
+ maFillFloatTransGradient(rFillFloatTransGradient),
+ maTextAttribute(rTextAttribute)
+ {
+ }
+
+ SdrFillTextAttribute::SdrFillTextAttribute()
+ {
+ }
+
+ SdrFillTextAttribute::SdrFillTextAttribute(const SdrFillTextAttribute& rCandidate)
+ : maFill(rCandidate.getFill()),
+ maFillFloatTransGradient(rCandidate.getFillFloatTransGradient()),
+ maTextAttribute(rCandidate.getText())
+ {
+ }
+
+ SdrFillTextAttribute& SdrFillTextAttribute::operator=(const SdrFillTextAttribute& rCandidate)
+ {
+ maFill = rCandidate.getFill();
+ maFillFloatTransGradient = rCandidate.getFillFloatTransGradient();
+ maTextAttribute = rCandidate.getText();
+
+ return *this;
+ }
+
+ bool SdrFillTextAttribute::operator==(const SdrFillTextAttribute& rCandidate) const
+ {
+ return(getFill() == rCandidate.getFill()
+ && getFillFloatTransGradient() == rCandidate.getFillFloatTransGradient()
+ && getText() == rCandidate.getText());
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdrformtextattribute.cxx b/svx/source/sdr/attribute/sdrformtextattribute.cxx
new file mode 100644
index 000000000..69fff8a8d
--- /dev/null
+++ b/svx/source/sdr/attribute/sdrformtextattribute.cxx
@@ -0,0 +1,372 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/attribute/sdrformtextattribute.hxx>
+#include <basegfx/vector/b2enums.hxx>
+#include <svl/itemset.hxx>
+#include <svx/sdprcitm.hxx>
+#include <svx/svddef.hxx>
+#include <svx/xftdiit.hxx>
+#include <svx/xftstit.hxx>
+#include <svx/xftshxy.hxx>
+#include <xftshtit.hxx>
+#include <svx/xtextit0.hxx>
+#include <svx/xftadit.hxx>
+#include <svx/xftshit.hxx>
+#include <svx/xftshcit.hxx>
+#include <svx/xftmrit.hxx>
+#include <svx/xftouit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlinjoit.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xdash.hxx>
+#include <svx/xlndsit.hxx>
+#include <drawinglayer/attribute/lineattribute.hxx>
+#include <drawinglayer/attribute/strokeattribute.hxx>
+#include <sdr/attribute/sdrformtextoutlineattribute.hxx>
+#include <com/sun/star/drawing/LineCap.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+
+
+// helper to get line, stroke and transparence attributes from SfxItemSet
+
+namespace
+{
+ basegfx::B2DLineJoin impGetB2DLineJoin(css::drawing::LineJoint eLineJoint)
+ {
+ switch(eLineJoint)
+ {
+ case css::drawing::LineJoint_BEVEL :
+ {
+ return basegfx::B2DLineJoin::Bevel;
+ }
+ case css::drawing::LineJoint_MIDDLE :
+ case css::drawing::LineJoint_MITER :
+ {
+ return basegfx::B2DLineJoin::Miter;
+ }
+ case css::drawing::LineJoint_ROUND :
+ {
+ return basegfx::B2DLineJoin::Round;
+ }
+ default : // css::drawing::LineJoint_NONE
+ {
+ return basegfx::B2DLineJoin::NONE; // XLINEJOINT_NONE
+ }
+ }
+ }
+
+ sal_uInt8 impGetStrokeTransparence(bool bShadow, const SfxItemSet& rSet)
+ {
+ sal_uInt8 nRetval;
+
+ if(bShadow)
+ {
+ nRetval = static_cast<sal_uInt8>((rSet.Get(SDRATTR_SHADOWTRANSPARENCE).GetValue() * 255) / 100);
+ }
+ else
+ {
+ nRetval = static_cast<sal_uInt8>((rSet.Get(XATTR_LINETRANSPARENCE).GetValue() * 255) / 100);
+ }
+
+ return nRetval;
+ }
+
+ drawinglayer::attribute::LineAttribute impGetLineAttribute(bool bShadow, const SfxItemSet& rSet)
+ {
+ basegfx::BColor aColorAttribute;
+
+ if(bShadow)
+ {
+ const Color aShadowColor(rSet.Get(SDRATTR_SHADOWCOLOR).GetColorValue());
+ aColorAttribute = aShadowColor.getBColor();
+ }
+ else
+ {
+ const Color aLineColor(rSet.Get(XATTR_LINECOLOR).GetColorValue());
+ aColorAttribute = aLineColor.getBColor();
+ }
+
+ const sal_uInt32 nLineWidth = rSet.Get(XATTR_LINEWIDTH).GetValue();
+ const css::drawing::LineJoint eLineJoint = rSet.Get(XATTR_LINEJOINT).GetValue();
+ const css::drawing::LineCap eLineCap = rSet.Get(XATTR_LINECAP).GetValue();
+
+ return drawinglayer::attribute::LineAttribute(
+ aColorAttribute,
+ static_cast<double>(nLineWidth),
+ impGetB2DLineJoin(eLineJoint),
+ eLineCap);
+ }
+
+ drawinglayer::attribute::StrokeAttribute impGetStrokeAttribute(const SfxItemSet& rSet)
+ {
+ const css::drawing::LineStyle eLineStyle = rSet.Get(XATTR_LINESTYLE).GetValue();
+ double fFullDotDashLen(0.0);
+ ::std::vector< double > aDotDashArray;
+
+ if(css::drawing::LineStyle_DASH == eLineStyle)
+ {
+ const XDash& rDash = rSet.Get(XATTR_LINEDASH).GetDashValue();
+
+ if(rDash.GetDots() || rDash.GetDashes())
+ {
+ const sal_uInt32 nLineWidth = rSet.Get(XATTR_LINEWIDTH).GetValue();
+ fFullDotDashLen = rDash.CreateDotDashArray(aDotDashArray, static_cast<double>(nLineWidth));
+ }
+ }
+
+ return drawinglayer::attribute::StrokeAttribute(std::move(aDotDashArray), fFullDotDashLen);
+ }
+} // end of anonymous namespace
+
+
+namespace drawinglayer::attribute
+{
+ class ImpSdrFormTextAttribute
+ {
+ public:
+ // FormText (FontWork) Attributes
+ sal_Int32 mnFormTextDistance; // distance from line in upright direction
+ sal_Int32 mnFormTextStart; // shift from polygon start
+ sal_Int32 mnFormTextShdwXVal; // shadow distance or 10th degrees
+ sal_Int32 mnFormTextShdwYVal; // shadow distance or scaling
+ sal_uInt16 mnFormTextShdwTransp; // shadow transparence
+ XFormTextStyle meFormTextStyle; // on/off and char orientation
+ XFormTextAdjust meFormTextAdjust; // adjustment (left/right/center) and scale
+ XFormTextShadow meFormTextShadow; // shadow mode
+ Color maFormTextShdwColor; // shadow color
+
+ // outline attributes; used when getFormTextOutline() is true and (for
+ // shadow) when getFormTextShadow() != XFormTextShadow::NONE
+ SdrFormTextOutlineAttribute maOutline;
+ SdrFormTextOutlineAttribute maShadowOutline;
+
+ bool mbFormTextMirror : 1; // change orientation
+ bool mbFormTextOutline : 1; // show contour of objects
+
+ explicit ImpSdrFormTextAttribute(const SfxItemSet& rSet)
+ : mnFormTextDistance(rSet.Get(XATTR_FORMTXTDISTANCE).GetValue()),
+ mnFormTextStart(rSet.Get(XATTR_FORMTXTSTART).GetValue()),
+ mnFormTextShdwXVal(rSet.Get(XATTR_FORMTXTSHDWXVAL).GetValue()),
+ mnFormTextShdwYVal(rSet.Get(XATTR_FORMTXTSHDWYVAL).GetValue()),
+ mnFormTextShdwTransp(rSet.Get(XATTR_FORMTXTSHDWTRANSP).GetValue()),
+ meFormTextStyle(rSet.Get(XATTR_FORMTXTSTYLE).GetValue()),
+ meFormTextAdjust(rSet.Get(XATTR_FORMTXTADJUST).GetValue()),
+ meFormTextShadow(rSet.Get(XATTR_FORMTXTSHADOW).GetValue()),
+ maFormTextShdwColor(rSet.Get(XATTR_FORMTXTSHDWCOLOR).GetColorValue()),
+ mbFormTextMirror(rSet.Get(XATTR_FORMTXTMIRROR).GetValue()),
+ mbFormTextOutline(rSet.Get(XATTR_FORMTXTOUTLINE).GetValue())
+ {
+ if(!getFormTextOutline())
+ return;
+
+ const StrokeAttribute aStrokeAttribute(impGetStrokeAttribute(rSet));
+
+ // also need to prepare attributes for outlines
+ {
+ const LineAttribute aLineAttribute(impGetLineAttribute(false, rSet));
+ const sal_uInt8 nTransparence(impGetStrokeTransparence(false, rSet));
+
+ maOutline = SdrFormTextOutlineAttribute(
+ aLineAttribute, aStrokeAttribute, nTransparence);
+ }
+
+ if(XFormTextShadow::NONE != getFormTextShadow())
+ {
+ // also need to prepare attributes for shadow outlines
+ const LineAttribute aLineAttribute(impGetLineAttribute(true, rSet));
+ const sal_uInt8 nTransparence(impGetStrokeTransparence(true, rSet));
+
+ maShadowOutline = SdrFormTextOutlineAttribute(
+ aLineAttribute, aStrokeAttribute, nTransparence);
+ }
+ }
+
+ ImpSdrFormTextAttribute()
+ : mnFormTextDistance(0),
+ mnFormTextStart(0),
+ mnFormTextShdwXVal(0),
+ mnFormTextShdwYVal(0),
+ mnFormTextShdwTransp(0),
+ meFormTextStyle(XFormTextStyle::NONE),
+ meFormTextAdjust(XFormTextAdjust::Center),
+ meFormTextShadow(XFormTextShadow::NONE),
+ mbFormTextMirror(false),
+ mbFormTextOutline(false)
+ {
+ }
+
+ // data read access
+ sal_Int32 getFormTextDistance() const { return mnFormTextDistance; }
+ sal_Int32 getFormTextStart() const { return mnFormTextStart; }
+ sal_Int32 getFormTextShdwXVal() const { return mnFormTextShdwXVal; }
+ sal_Int32 getFormTextShdwYVal() const { return mnFormTextShdwYVal; }
+ XFormTextStyle getFormTextStyle() const { return meFormTextStyle; }
+ XFormTextAdjust getFormTextAdjust() const { return meFormTextAdjust; }
+ XFormTextShadow getFormTextShadow() const { return meFormTextShadow; }
+ const Color& getFormTextShdwColor() const { return maFormTextShdwColor; }
+ const SdrFormTextOutlineAttribute& getOutline() const { return maOutline; }
+ const SdrFormTextOutlineAttribute& getShadowOutline() const { return maShadowOutline; }
+ bool getFormTextMirror() const { return mbFormTextMirror; }
+ bool getFormTextOutline() const { return mbFormTextOutline; }
+
+ // compare operator
+ bool operator==(const ImpSdrFormTextAttribute& rCandidate) const
+ {
+ return (getFormTextDistance() == rCandidate.getFormTextDistance()
+ && getFormTextStart() == rCandidate.getFormTextStart()
+ && getFormTextShdwXVal() == rCandidate.getFormTextShdwXVal()
+ && getFormTextShdwYVal() == rCandidate.getFormTextShdwYVal()
+ && mnFormTextShdwTransp == rCandidate.mnFormTextShdwTransp
+ && getFormTextStyle() == rCandidate.getFormTextStyle()
+ && getFormTextAdjust() == rCandidate.getFormTextAdjust()
+ && getFormTextShadow() == rCandidate.getFormTextShadow()
+ && getFormTextShdwColor() == rCandidate.getFormTextShdwColor()
+ && getOutline() == rCandidate.getOutline()
+ && getShadowOutline() == rCandidate.getShadowOutline()
+ && getFormTextMirror() == rCandidate.getFormTextMirror()
+ && getFormTextOutline() == rCandidate.getFormTextOutline());
+ }
+ };
+
+ namespace
+ {
+ SdrFormTextAttribute::ImplType& theGlobalDefault()
+ {
+ static SdrFormTextAttribute::ImplType SINGLETON;
+ return SINGLETON;
+ }
+ }
+
+ SdrFormTextAttribute::SdrFormTextAttribute(const SfxItemSet& rSet)
+ : mpSdrFormTextAttribute(ImpSdrFormTextAttribute(rSet))
+ {
+ }
+
+ SdrFormTextAttribute::SdrFormTextAttribute()
+ : mpSdrFormTextAttribute(theGlobalDefault())
+ {
+ }
+
+ SdrFormTextAttribute::SdrFormTextAttribute(const SdrFormTextAttribute& rCandidate)
+ : mpSdrFormTextAttribute(rCandidate.mpSdrFormTextAttribute)
+ {
+ }
+
+ SdrFormTextAttribute::SdrFormTextAttribute(SdrFormTextAttribute&& rCandidate) noexcept
+ : mpSdrFormTextAttribute(std::move(rCandidate.mpSdrFormTextAttribute))
+ {
+ }
+
+ SdrFormTextAttribute::~SdrFormTextAttribute()
+ {
+ }
+
+ bool SdrFormTextAttribute::isDefault() const
+ {
+ return mpSdrFormTextAttribute.same_object(theGlobalDefault());
+ }
+
+ SdrFormTextAttribute& SdrFormTextAttribute::operator=(const SdrFormTextAttribute& rCandidate)
+ {
+ mpSdrFormTextAttribute = rCandidate.mpSdrFormTextAttribute;
+ return *this;
+ }
+
+ SdrFormTextAttribute& SdrFormTextAttribute::operator=(SdrFormTextAttribute&& rCandidate) noexcept
+ {
+ mpSdrFormTextAttribute = std::move(rCandidate.mpSdrFormTextAttribute);
+ return *this;
+ }
+
+ bool SdrFormTextAttribute::operator==(const SdrFormTextAttribute& rCandidate) const
+ {
+ // tdf#87509 default attr is always != non-default attr, even with same values
+ if(rCandidate.isDefault() != isDefault())
+ return false;
+
+ return rCandidate.mpSdrFormTextAttribute == mpSdrFormTextAttribute;
+ }
+
+ sal_Int32 SdrFormTextAttribute::getFormTextDistance() const
+ {
+ return mpSdrFormTextAttribute->getFormTextDistance();
+ }
+
+ sal_Int32 SdrFormTextAttribute::getFormTextStart() const
+ {
+ return mpSdrFormTextAttribute->getFormTextStart();
+ }
+
+ sal_Int32 SdrFormTextAttribute::getFormTextShdwXVal() const
+ {
+ return mpSdrFormTextAttribute->getFormTextShdwXVal();
+ }
+
+ sal_Int32 SdrFormTextAttribute::getFormTextShdwYVal() const
+ {
+ return mpSdrFormTextAttribute->getFormTextShdwYVal();
+ }
+
+ XFormTextStyle SdrFormTextAttribute::getFormTextStyle() const
+ {
+ return mpSdrFormTextAttribute->getFormTextStyle();
+ }
+
+ XFormTextAdjust SdrFormTextAttribute::getFormTextAdjust() const
+ {
+ return mpSdrFormTextAttribute->getFormTextAdjust();
+ }
+
+ XFormTextShadow SdrFormTextAttribute::getFormTextShadow() const
+ {
+ return mpSdrFormTextAttribute->getFormTextShadow();
+ }
+
+ Color const & SdrFormTextAttribute::getFormTextShdwColor() const
+ {
+ return mpSdrFormTextAttribute->getFormTextShdwColor();
+ }
+
+ const SdrFormTextOutlineAttribute& SdrFormTextAttribute::getOutline() const
+ {
+ return mpSdrFormTextAttribute->getOutline();
+ }
+
+ const SdrFormTextOutlineAttribute& SdrFormTextAttribute::getShadowOutline() const
+ {
+ return mpSdrFormTextAttribute->getShadowOutline();
+ }
+
+ bool SdrFormTextAttribute::getFormTextMirror() const
+ {
+ return mpSdrFormTextAttribute->getFormTextMirror();
+ }
+
+ bool SdrFormTextAttribute::getFormTextOutline() const
+ {
+ return mpSdrFormTextAttribute->getFormTextOutline();
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdrformtextoutlineattribute.cxx b/svx/source/sdr/attribute/sdrformtextoutlineattribute.cxx
new file mode 100644
index 000000000..ec97cf044
--- /dev/null
+++ b/svx/source/sdr/attribute/sdrformtextoutlineattribute.cxx
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/attribute/sdrformtextoutlineattribute.hxx>
+#include <drawinglayer/attribute/lineattribute.hxx>
+#include <drawinglayer/attribute/strokeattribute.hxx>
+
+
+namespace drawinglayer::attribute
+{
+ class ImpSdrFormTextOutlineAttribute
+ {
+ public:
+ // one set of attributes for FormText (FontWork) outline visualisation
+ LineAttribute maLineAttribute;
+ StrokeAttribute maStrokeAttribute;
+ sal_uInt8 mnTransparence;
+
+ ImpSdrFormTextOutlineAttribute(
+ const LineAttribute& rLineAttribute,
+ const StrokeAttribute& rStrokeAttribute,
+ sal_uInt8 nTransparence)
+ : maLineAttribute(rLineAttribute),
+ maStrokeAttribute(rStrokeAttribute),
+ mnTransparence(nTransparence)
+ {
+ }
+
+ ImpSdrFormTextOutlineAttribute()
+ : mnTransparence(0)
+ {
+ }
+
+ // data read access
+ const LineAttribute& getLineAttribute() const { return maLineAttribute; }
+ const StrokeAttribute& getStrokeAttribute() const { return maStrokeAttribute; }
+ sal_uInt8 getTransparence() const { return mnTransparence; }
+
+ // compare operator
+ bool operator==(const ImpSdrFormTextOutlineAttribute& rCandidate) const
+ {
+ return (getLineAttribute() == rCandidate.getLineAttribute()
+ && getStrokeAttribute() == rCandidate.getStrokeAttribute()
+ && getTransparence() == rCandidate.getTransparence());
+ }
+ };
+
+ namespace
+ {
+ SdrFormTextOutlineAttribute::ImplType& theGlobalDefault()
+ {
+ static SdrFormTextOutlineAttribute::ImplType SINGLETON;
+ return SINGLETON;
+ }
+ }
+
+ SdrFormTextOutlineAttribute::SdrFormTextOutlineAttribute(
+ const LineAttribute& rLineAttribute,
+ const StrokeAttribute& rStrokeAttribute,
+ sal_uInt8 nTransparence)
+ : mpSdrFormTextOutlineAttribute(
+ ImpSdrFormTextOutlineAttribute(
+ rLineAttribute, rStrokeAttribute, nTransparence))
+ {
+ }
+
+ SdrFormTextOutlineAttribute::SdrFormTextOutlineAttribute()
+ : mpSdrFormTextOutlineAttribute(theGlobalDefault())
+ {
+ }
+
+ SdrFormTextOutlineAttribute::SdrFormTextOutlineAttribute(const SdrFormTextOutlineAttribute& rCandidate)
+ : mpSdrFormTextOutlineAttribute(rCandidate.mpSdrFormTextOutlineAttribute)
+ {
+ }
+
+ SdrFormTextOutlineAttribute::~SdrFormTextOutlineAttribute()
+ {
+ }
+
+ bool SdrFormTextOutlineAttribute::isDefault() const
+ {
+ return mpSdrFormTextOutlineAttribute.same_object(theGlobalDefault());
+ }
+
+ SdrFormTextOutlineAttribute& SdrFormTextOutlineAttribute::operator=(const SdrFormTextOutlineAttribute& rCandidate)
+ {
+ mpSdrFormTextOutlineAttribute = rCandidate.mpSdrFormTextOutlineAttribute;
+ return *this;
+ }
+
+ SdrFormTextOutlineAttribute& SdrFormTextOutlineAttribute::operator=(SdrFormTextOutlineAttribute&& rCandidate) noexcept
+ {
+ mpSdrFormTextOutlineAttribute = std::move(rCandidate.mpSdrFormTextOutlineAttribute);
+ return *this;
+ }
+
+ bool SdrFormTextOutlineAttribute::operator==(const SdrFormTextOutlineAttribute& rCandidate) const
+ {
+ // tdf#87509 default attr is always != non-default attr, even with same values
+ if(rCandidate.isDefault() != isDefault())
+ return false;
+
+ return rCandidate.mpSdrFormTextOutlineAttribute == mpSdrFormTextOutlineAttribute;
+ }
+
+ const LineAttribute& SdrFormTextOutlineAttribute::getLineAttribute() const
+ {
+ return mpSdrFormTextOutlineAttribute->getLineAttribute();
+ }
+
+ const StrokeAttribute& SdrFormTextOutlineAttribute::getStrokeAttribute() const
+ {
+ return mpSdrFormTextOutlineAttribute->getStrokeAttribute();
+ }
+
+ sal_uInt8 SdrFormTextOutlineAttribute::getTransparence() const
+ {
+ return mpSdrFormTextOutlineAttribute->getTransparence();
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdrlineeffectstextattribute.cxx b/svx/source/sdr/attribute/sdrlineeffectstextattribute.cxx
new file mode 100644
index 000000000..72a3ef032
--- /dev/null
+++ b/svx/source/sdr/attribute/sdrlineeffectstextattribute.cxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/attribute/sdrlineeffectstextattribute.hxx>
+
+
+namespace drawinglayer::attribute
+{
+ SdrLineEffectsTextAttribute::SdrLineEffectsTextAttribute(
+ const SdrLineAttribute& rLine,
+ const SdrLineStartEndAttribute& rLineStartEnd,
+ const SdrShadowAttribute& rShadow,
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow,
+ sal_Int32 nSoftEdgeRadius)
+ : SdrEffectsTextAttribute(rShadow, rTextAttribute, rGlow, nSoftEdgeRadius),
+ maLine(rLine),
+ maLineStartEnd(rLineStartEnd)
+ {
+ }
+
+ SdrLineEffectsTextAttribute::SdrLineEffectsTextAttribute()
+ {
+ }
+
+ SdrLineEffectsTextAttribute::SdrLineEffectsTextAttribute(const SdrLineEffectsTextAttribute& rCandidate)
+ : SdrEffectsTextAttribute(rCandidate),
+ maLine(rCandidate.getLine()),
+ maLineStartEnd(rCandidate.getLineStartEnd())
+ {
+ }
+
+ SdrLineEffectsTextAttribute& SdrLineEffectsTextAttribute::operator=(const SdrLineEffectsTextAttribute& rCandidate)
+ {
+ SdrEffectsTextAttribute::operator=(rCandidate);
+ maLine = rCandidate.getLine();
+ maLineStartEnd = rCandidate.getLineStartEnd();
+
+ return *this;
+ }
+
+ bool SdrLineEffectsTextAttribute::isDefault() const
+ {
+ return(SdrEffectsTextAttribute::isDefault()
+ && getLine().isDefault()
+ && getLineStartEnd().isDefault());
+ }
+
+ bool SdrLineEffectsTextAttribute::operator==(const SdrLineEffectsTextAttribute& rCandidate) const
+ {
+ return(SdrEffectsTextAttribute::operator==(rCandidate)
+ && getLine() == rCandidate.getLine()
+ && getLineStartEnd() == rCandidate.getLineStartEnd());
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdrlinefilleffectstextattribute.cxx b/svx/source/sdr/attribute/sdrlinefilleffectstextattribute.cxx
new file mode 100644
index 000000000..442b51833
--- /dev/null
+++ b/svx/source/sdr/attribute/sdrlinefilleffectstextattribute.cxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/attribute/sdrlinefilleffectstextattribute.hxx>
+
+
+namespace drawinglayer::attribute
+{
+ SdrLineFillEffectsTextAttribute::SdrLineFillEffectsTextAttribute(
+ const SdrLineAttribute& rLine,
+ const SdrFillAttribute& rFill,
+ const SdrLineStartEndAttribute& rLineStartEnd,
+ const SdrShadowAttribute& rShadow,
+ const FillGradientAttribute& rFillFloatTransGradient,
+ const SdrTextAttribute& rTextAttribute,
+ const SdrGlowAttribute& rGlow,
+ sal_Int32 nSoftEdgeRadius)
+ : SdrLineEffectsTextAttribute(rLine, rLineStartEnd, rShadow, rTextAttribute, rGlow, nSoftEdgeRadius),
+ maFill(rFill),
+ maFillFloatTransGradient(rFillFloatTransGradient)
+ {
+ }
+
+ SdrLineFillEffectsTextAttribute::SdrLineFillEffectsTextAttribute()
+ {
+ }
+
+ SdrLineFillEffectsTextAttribute::SdrLineFillEffectsTextAttribute(const SdrLineFillEffectsTextAttribute& rCandidate)
+ : SdrLineEffectsTextAttribute(rCandidate),
+ maFill(rCandidate.getFill()),
+ maFillFloatTransGradient(rCandidate.getFillFloatTransGradient())
+ {
+ }
+
+ SdrLineFillEffectsTextAttribute& SdrLineFillEffectsTextAttribute::operator=(const SdrLineFillEffectsTextAttribute& rCandidate)
+ {
+ SdrLineEffectsTextAttribute::operator=(rCandidate);
+ maFill = rCandidate.getFill();
+ maFillFloatTransGradient = rCandidate.getFillFloatTransGradient();
+
+ return *this;
+ }
+
+ bool SdrLineFillEffectsTextAttribute::isDefault() const
+ {
+ return (SdrLineEffectsTextAttribute::isDefault()
+ && getFill().isDefault()
+ && getFillFloatTransGradient().isDefault());
+ }
+
+ bool SdrLineFillEffectsTextAttribute::operator==(const SdrLineFillEffectsTextAttribute& rCandidate) const
+ {
+ return(SdrLineEffectsTextAttribute::operator==(rCandidate)
+ && getFill() == rCandidate.getFill()
+ && getFillFloatTransGradient() == rCandidate.getFillFloatTransGradient());
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/attribute/sdrtextattribute.cxx b/svx/source/sdr/attribute/sdrtextattribute.cxx
new file mode 100644
index 000000000..5c9ecb34e
--- /dev/null
+++ b/svx/source/sdr/attribute/sdrtextattribute.cxx
@@ -0,0 +1,422 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/attribute/sdrtextattribute.hxx>
+#include <sdr/attribute/sdrformtextattribute.hxx>
+#include <svx/svdotext.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/sdr/properties/properties.hxx>
+
+
+namespace drawinglayer::attribute
+{
+ class ImpSdrTextAttribute
+ {
+ public:
+ // all-text attributes. The SdrText itself and a copy
+ // of the OPO
+ const SdrText* mpSdrText;
+ std::shared_ptr<OutlinerParaObject> mxOutlinerParaObject;
+
+ // Set when it's a FormText; contains all FormText attributes
+ SdrFormTextAttribute maSdrFormTextAttribute;
+
+ // text distances
+ sal_Int32 maTextLeftDistance;
+ sal_Int32 maTextUpperDistance;
+ sal_Int32 maTextRightDistance;
+ sal_Int32 maTextLowerDistance;
+
+ // #i101556# use versioning from text attributes to detect changes
+ sal_uInt32 maPropertiesVersion;
+
+ // text alignments
+ SdrTextHorzAdjust maSdrTextHorzAdjust;
+ SdrTextVertAdjust maSdrTextVertAdjust;
+
+ bool mbContour : 1;
+ bool mbFitToSize : 1;
+ bool mbAutoFit : 1;
+ bool mbHideContour : 1;
+ bool mbBlink : 1;
+ bool mbScroll : 1;
+ bool mbInEditMode : 1;
+ bool mbFixedCellHeight : 1;
+ bool mbWrongSpell : 1;
+
+ bool mbChainable : 1;
+
+
+ public:
+ ImpSdrTextAttribute(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ XFormTextStyle eFormTextStyle,
+ sal_Int32 aTextLeftDistance,
+ sal_Int32 aTextUpperDistance,
+ sal_Int32 aTextRightDistance,
+ sal_Int32 aTextLowerDistance,
+ SdrTextHorzAdjust aSdrTextHorzAdjust,
+ SdrTextVertAdjust aSdrTextVertAdjust,
+ bool bContour,
+ bool bFitToSize,
+ bool bAutoFit,
+ bool bHideContour,
+ bool bBlink,
+ bool bScroll,
+ bool bInEditMode,
+ bool bFixedCellHeight,
+ bool bWrongSpell,
+ bool bChainable)
+ : mpSdrText(pSdrText),
+ mxOutlinerParaObject(std::make_shared<OutlinerParaObject>(rOutlinerParaObject)),
+ maTextLeftDistance(aTextLeftDistance),
+ maTextUpperDistance(aTextUpperDistance),
+ maTextRightDistance(aTextRightDistance),
+ maTextLowerDistance(aTextLowerDistance),
+ maPropertiesVersion(0),
+ maSdrTextHorzAdjust(aSdrTextHorzAdjust),
+ maSdrTextVertAdjust(aSdrTextVertAdjust),
+ mbContour(bContour),
+ mbFitToSize(bFitToSize),
+ mbAutoFit(bAutoFit),
+ mbHideContour(bHideContour),
+ mbBlink(bBlink),
+ mbScroll(bScroll),
+ mbInEditMode(bInEditMode),
+ mbFixedCellHeight(bFixedCellHeight),
+ mbWrongSpell(bWrongSpell),
+ mbChainable(bChainable)
+ {
+ if(!pSdrText)
+ return;
+
+ if(XFormTextStyle::NONE != eFormTextStyle)
+ {
+ // text on path. Create FormText attribute
+ const SfxItemSet& rSet = pSdrText->GetItemSet();
+ maSdrFormTextAttribute = SdrFormTextAttribute(rSet);
+ }
+
+ // #i101556# init with version number to detect changes of single text
+ // attribute and/or style sheets in primitive data without having to
+ // copy that data locally (which would be better from principle)
+ maPropertiesVersion = pSdrText->GetObject().GetProperties().getVersion();
+ }
+
+ ImpSdrTextAttribute()
+ : mpSdrText(nullptr),
+ maTextLeftDistance(0),
+ maTextUpperDistance(0),
+ maTextRightDistance(0),
+ maTextLowerDistance(0),
+ maPropertiesVersion(0),
+ maSdrTextHorzAdjust(SDRTEXTHORZADJUST_LEFT),
+ maSdrTextVertAdjust(SDRTEXTVERTADJUST_TOP),
+ mbContour(false),
+ mbFitToSize(false),
+ mbAutoFit(false),
+ mbHideContour(false),
+ mbBlink(false),
+ mbScroll(false),
+ mbInEditMode(false),
+ mbFixedCellHeight(false),
+ mbWrongSpell(false),
+ mbChainable(false)
+ {
+ }
+
+ // data read access
+ const SdrText& getSdrText() const
+ {
+ assert(mpSdrText && "Access to text of default version of ImpSdrTextAttribute (!)");
+ return *mpSdrText;
+ }
+
+ const OutlinerParaObject& getOutlinerParaObject() const
+ {
+ assert(mxOutlinerParaObject && "Access to OutlinerParaObject of default version of ImpSdrTextAttribute (!)");
+ return *mxOutlinerParaObject;
+ }
+
+ bool isContour() const { return mbContour; }
+ bool isFitToSize() const { return mbFitToSize; }
+ bool isAutoFit() const { return mbAutoFit; }
+ bool isHideContour() const { return mbHideContour; }
+ bool isBlink() const { return mbBlink; }
+ bool isScroll() const { return mbScroll; }
+ bool isInEditMode() const { return mbInEditMode; }
+ bool isFixedCellHeight() const { return mbFixedCellHeight; }
+ bool isChainable() const { return mbChainable; }
+ const SdrFormTextAttribute& getSdrFormTextAttribute() const { return maSdrFormTextAttribute; }
+ sal_Int32 getTextLeftDistance() const { return maTextLeftDistance; }
+ sal_Int32 getTextUpperDistance() const { return maTextUpperDistance; }
+ sal_Int32 getTextRightDistance() const { return maTextRightDistance; }
+ sal_Int32 getTextLowerDistance() const { return maTextLowerDistance; }
+ SdrTextHorzAdjust getSdrTextHorzAdjust() const { return maSdrTextHorzAdjust; }
+ SdrTextVertAdjust getSdrTextVertAdjust() const { return maSdrTextVertAdjust; }
+
+ // compare operator
+ bool operator==(const ImpSdrTextAttribute& rCandidate) const
+ {
+ if (mxOutlinerParaObject.get() != rCandidate.mxOutlinerParaObject.get())
+ {
+ if (mxOutlinerParaObject && rCandidate.mxOutlinerParaObject)
+ {
+ // compares OPO and it's contents, but traditionally not the RedLining
+ // which is not seen as model, but as temporary information
+ if(getOutlinerParaObject() != rCandidate.getOutlinerParaObject())
+ {
+ return false;
+ }
+
+ // #i102062# for primitive visualisation, the WrongList (SpellChecking)
+ // is important, too, so use isWrongListEqual since there is no WrongList
+ // comparison in the regular OutlinerParaObject compare (since it's
+ // not-persistent data)
+ if(!(getOutlinerParaObject().isWrongListEqual(rCandidate.getOutlinerParaObject())))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // only one is zero; not equal
+ return false;
+ }
+ }
+
+ return (
+ getSdrFormTextAttribute() == rCandidate.getSdrFormTextAttribute()
+ && getTextLeftDistance() == rCandidate.getTextLeftDistance()
+ && getTextUpperDistance() == rCandidate.getTextUpperDistance()
+ && getTextRightDistance() == rCandidate.getTextRightDistance()
+ && getTextLowerDistance() == rCandidate.getTextLowerDistance()
+ && maPropertiesVersion == rCandidate.maPropertiesVersion
+
+ && getSdrTextHorzAdjust() == rCandidate.getSdrTextHorzAdjust()
+ && getSdrTextVertAdjust() == rCandidate.getSdrTextVertAdjust()
+
+ && isContour() == rCandidate.isContour()
+ && isFitToSize() == rCandidate.isFitToSize()
+ && isAutoFit() == rCandidate.isAutoFit()
+ && isHideContour() == rCandidate.isHideContour()
+ && isBlink() == rCandidate.isBlink()
+ && isScroll() == rCandidate.isScroll()
+ && isInEditMode() == rCandidate.isInEditMode()
+ && isFixedCellHeight() == rCandidate.isFixedCellHeight()
+ && mbWrongSpell == rCandidate.mbWrongSpell );
+ }
+ };
+
+ namespace
+ {
+ SdrTextAttribute::ImplType& theGlobalDefault()
+ {
+ static SdrTextAttribute::ImplType SINGLETON;
+ return SINGLETON;
+ }
+ }
+
+ SdrTextAttribute::SdrTextAttribute(
+ const SdrText& rSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ XFormTextStyle eFormTextStyle,
+ sal_Int32 aTextLeftDistance,
+ sal_Int32 aTextUpperDistance,
+ sal_Int32 aTextRightDistance,
+ sal_Int32 aTextLowerDistance,
+ SdrTextHorzAdjust aSdrTextHorzAdjust,
+ SdrTextVertAdjust aSdrTextVertAdjust,
+ bool bContour,
+ bool bFitToSize,
+ bool bAutoFit,
+ bool bHideContour,
+ bool bBlink,
+ bool bScroll,
+ bool bInEditMode,
+ bool bFixedCellHeight,
+ bool bWrongSpell,
+ bool bChainable)
+ : mpSdrTextAttribute(
+ ImpSdrTextAttribute(
+ &rSdrText, rOutlinerParaObject, eFormTextStyle, aTextLeftDistance,
+ aTextUpperDistance, aTextRightDistance, aTextLowerDistance,
+ aSdrTextHorzAdjust, aSdrTextVertAdjust, bContour, bFitToSize, bAutoFit,
+ bHideContour, bBlink, bScroll, bInEditMode, bFixedCellHeight, bWrongSpell,
+ bChainable))
+ {
+ }
+
+ SdrTextAttribute::SdrTextAttribute()
+ : mpSdrTextAttribute(theGlobalDefault())
+ {
+ }
+
+ SdrTextAttribute::SdrTextAttribute(const SdrTextAttribute& rCandidate)
+ : mpSdrTextAttribute(rCandidate.mpSdrTextAttribute)
+ {
+ }
+
+ SdrTextAttribute::SdrTextAttribute(SdrTextAttribute&& rCandidate) noexcept
+ : mpSdrTextAttribute(std::move(rCandidate.mpSdrTextAttribute))
+ {
+ }
+
+ SdrTextAttribute::~SdrTextAttribute()
+ {
+ }
+
+ bool SdrTextAttribute::isDefault() const
+ {
+ return mpSdrTextAttribute.same_object(theGlobalDefault());
+ }
+
+ SdrTextAttribute& SdrTextAttribute::operator=(const SdrTextAttribute& rCandidate)
+ {
+ mpSdrTextAttribute = rCandidate.mpSdrTextAttribute;
+ return *this;
+ }
+
+ SdrTextAttribute& SdrTextAttribute::operator=(SdrTextAttribute&& rCandidate) noexcept
+ {
+ mpSdrTextAttribute = std::move(rCandidate.mpSdrTextAttribute);
+ return *this;
+ }
+
+ bool SdrTextAttribute::operator==(const SdrTextAttribute& rCandidate) const
+ {
+ // tdf#87509 default attr is always != non-default attr, even with same values
+ if(rCandidate.isDefault() != isDefault())
+ return false;
+
+ return rCandidate.mpSdrTextAttribute == mpSdrTextAttribute;
+ }
+
+ const SdrText& SdrTextAttribute::getSdrText() const
+ {
+ return mpSdrTextAttribute->getSdrText();
+ }
+
+ const OutlinerParaObject& SdrTextAttribute::getOutlinerParaObject() const
+ {
+ return mpSdrTextAttribute->getOutlinerParaObject();
+ }
+
+ bool SdrTextAttribute::isContour() const
+ {
+ return mpSdrTextAttribute->isContour();
+ }
+
+ bool SdrTextAttribute::isFitToSize() const
+ {
+ return mpSdrTextAttribute->isFitToSize();
+ }
+
+ bool SdrTextAttribute::isAutoFit() const
+ {
+ return mpSdrTextAttribute->isAutoFit();
+ }
+
+ bool SdrTextAttribute::isHideContour() const
+ {
+ return mpSdrTextAttribute->isHideContour();
+ }
+
+ bool SdrTextAttribute::isBlink() const
+ {
+ return mpSdrTextAttribute->isBlink();
+ }
+
+ bool SdrTextAttribute::isScroll() const
+ {
+ return mpSdrTextAttribute->isScroll();
+ }
+
+ bool SdrTextAttribute::isInEditMode() const
+ {
+ return mpSdrTextAttribute->isInEditMode();
+ }
+
+ bool SdrTextAttribute::isChainable() const
+ {
+ return mpSdrTextAttribute->isChainable();
+ }
+
+
+ bool SdrTextAttribute::isFixedCellHeight() const
+ {
+ return mpSdrTextAttribute->isFixedCellHeight();
+ }
+
+ const SdrFormTextAttribute& SdrTextAttribute::getSdrFormTextAttribute() const
+ {
+ return mpSdrTextAttribute->getSdrFormTextAttribute();
+ }
+
+ sal_Int32 SdrTextAttribute::getTextLeftDistance() const
+ {
+ return mpSdrTextAttribute->getTextLeftDistance();
+ }
+
+ sal_Int32 SdrTextAttribute::getTextUpperDistance() const
+ {
+ return mpSdrTextAttribute->getTextUpperDistance();
+ }
+
+ sal_Int32 SdrTextAttribute::getTextRightDistance() const
+ {
+ return mpSdrTextAttribute->getTextRightDistance();
+ }
+
+ sal_Int32 SdrTextAttribute::getTextLowerDistance() const
+ {
+ return mpSdrTextAttribute->getTextLowerDistance();
+ }
+
+ SdrTextHorzAdjust SdrTextAttribute::getSdrTextHorzAdjust() const
+ {
+ return mpSdrTextAttribute->getSdrTextHorzAdjust();
+ }
+
+ SdrTextVertAdjust SdrTextAttribute::getSdrTextVertAdjust() const
+ {
+ return mpSdrTextAttribute->getSdrTextVertAdjust();
+ }
+
+ void SdrTextAttribute::getBlinkTextTiming(drawinglayer::animation::AnimationEntryList& rAnimList) const
+ {
+ if(isBlink())
+ {
+ getSdrText().GetObject().impGetBlinkTextTiming(rAnimList);
+ }
+ }
+
+ void SdrTextAttribute::getScrollTextTiming(drawinglayer::animation::AnimationEntryList& rAnimList, double fFrameLength, double fTextLength) const
+ {
+ if(isScroll())
+ {
+ getSdrText().GetObject().impGetScrollTextTiming(rAnimList, fFrameLength, fTextLength);
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/displayinfo.cxx b/svx/source/sdr/contact/displayinfo.cxx
new file mode 100644
index 000000000..405fb41a0
--- /dev/null
+++ b/svx/source/sdr/contact/displayinfo.cxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/displayinfo.hxx>
+
+
+namespace sdr::contact
+{
+ DisplayInfo::DisplayInfo()
+ : maProcessLayers(true), // init layer info with all bits set to draw everything on default
+ mbControlLayerProcessingActive(false),
+ mbPageProcessingActive(true),
+ mbGhostedDrawModeActive(false),
+ mbSubContentActive(false)
+ {
+ }
+
+ // Access to LayerInfos (which layers to process)
+ void DisplayInfo::SetProcessLayers(const SdrLayerIDSet& rSet)
+ {
+ maProcessLayers = rSet;
+ }
+
+ // access to RedrawArea
+ void DisplayInfo::SetRedrawArea(const vcl::Region& rRegion)
+ {
+ maRedrawArea = rRegion;
+ }
+
+ void DisplayInfo::SetWriterPageFrame(basegfx::B2IRectangle const& rPageFrame)
+ {
+ m_WriterPageFrame = rPageFrame;
+ }
+
+ void DisplayInfo::SetControlLayerProcessingActive(bool bDoProcess)
+ {
+ if(mbControlLayerProcessingActive != bDoProcess)
+ {
+ mbControlLayerProcessingActive = bDoProcess;
+ }
+ }
+
+ void DisplayInfo::SetPageProcessingActive(bool bDoProcess)
+ {
+ if(mbPageProcessingActive != bDoProcess)
+ {
+ mbPageProcessingActive = bDoProcess;
+ }
+ }
+
+ void DisplayInfo::ClearGhostedDrawMode()
+ {
+ mbGhostedDrawModeActive = false;
+ }
+
+ void DisplayInfo::SetGhostedDrawMode()
+ {
+ mbGhostedDrawModeActive = true;
+ }
+
+ void DisplayInfo::SetSubContentActive(bool bNew)
+ {
+ if(mbSubContentActive != bNew)
+ {
+ mbSubContentActive = bNew;
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/objectcontact.cxx b/svx/source/sdr/contact/objectcontact.cxx
new file mode 100644
index 000000000..d135a2a29
--- /dev/null
+++ b/svx/source/sdr/contact/objectcontact.cxx
@@ -0,0 +1,217 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <tools/debug.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr::contact {
+
+bool ObjectContact::supportsGridOffsets() const
+{
+ // default does not support GridOffset
+ return false;
+}
+
+void ObjectContact::calculateGridOffsetForViewOjectContact(
+ basegfx::B2DVector& /*rTarget*/,
+ const ViewObjectContact& /*rClient*/) const
+{
+ // default does not on-demand calculate GridOffset
+}
+
+void ObjectContact::calculateGridOffsetForB2DRange(
+ basegfx::B2DVector& /*rTarget*/,
+ const basegfx::B2DRange& /*rB2DRange*/) const
+{
+ // default does not on-demand calculate GridOffset
+}
+
+ObjectContact::ObjectContact()
+: mpViewObjectContactRedirector(nullptr),
+ mbIsPreviewRenderer(false)
+{
+}
+
+ObjectContact::~ObjectContact() COVERITY_NOEXCEPT_FALSE
+{
+ // get rid of all registered contacts
+ // #i84257# To avoid that each 'delete pCandidate' again uses
+ // the local RemoveViewObjectContact with a search and removal in the
+ // vector, simply copy and clear local vector.
+ std::vector< ViewObjectContact* > aLocalVOCList;
+ aLocalVOCList.swap(maViewObjectContactVector);
+
+ for (const auto & pCandidate : aLocalVOCList)
+ // ViewObjectContacts only make sense with View and Object contacts.
+ // When the contact to the SdrObject is deleted like in this case,
+ // all ViewObjectContacts can be deleted, too.
+ delete pCandidate;
+
+ // assert when there were new entries added during deletion
+ DBG_ASSERT(maViewObjectContactVector.empty(), "Corrupted ViewObjectContactList (!)");
+}
+
+// LazyInvalidate request. Default implementation directly handles
+// this by calling back triggerLazyInvalidate() at the VOC
+void ObjectContact::setLazyInvalidate(ViewObjectContact& rVOC)
+{
+ rVOC.triggerLazyInvalidate();
+}
+
+// call this to support evtl. preparations for repaint. Default does nothing
+void ObjectContact::PrepareProcessDisplay()
+{
+}
+
+// A new ViewObjectContact was created and shall be remembered.
+void ObjectContact::AddViewObjectContact(ViewObjectContact& rVOContact)
+{
+ maViewObjectContactVector.push_back(&rVOContact);
+}
+
+// A ViewObjectContact was deleted and shall be forgotten.
+void ObjectContact::RemoveViewObjectContact(ViewObjectContact& rVOContact)
+{
+ std::vector< ViewObjectContact* >::iterator aFindResult = std::find(maViewObjectContactVector.begin(), maViewObjectContactVector.end(), &rVOContact);
+
+ if(aFindResult != maViewObjectContactVector.end())
+ {
+ maViewObjectContactVector.erase(aFindResult);
+ }
+}
+
+// Process the whole displaying
+void ObjectContact::ProcessDisplay(DisplayInfo& /*rDisplayInfo*/)
+{
+ // default does nothing
+}
+
+// test if visualizing of entered groups is switched on at all
+bool ObjectContact::DoVisualizeEnteredGroup() const
+{
+ // Do not do that as default
+ return false;
+}
+
+// get active group's (the entered group) ViewContact
+const ViewContact* ObjectContact::getActiveViewContact() const
+{
+ // default has no active VC
+ return nullptr;
+}
+
+// Invalidate given rectangle at the window/output which is represented by
+// this ObjectContact.
+void ObjectContact::InvalidatePartOfView(const basegfx::B2DRange& /*rRange*/) const
+{
+ // nothing to do here in the default version
+}
+
+// Get info about the need to visualize GluePoints
+bool ObjectContact::AreGluePointsVisible() const
+{
+ return false;
+}
+
+// check if text animation is allowed. Default is sal_true.
+bool ObjectContact::IsTextAnimationAllowed() const
+{
+ return true;
+}
+
+// check if graphic animation is allowed. Default is sal_true.
+bool ObjectContact::IsGraphicAnimationAllowed() const
+{
+ return true;
+}
+
+void ObjectContact::SetViewObjectContactRedirector(ViewObjectContactRedirector* pNew)
+{
+ if(mpViewObjectContactRedirector != pNew)
+ {
+ mpViewObjectContactRedirector = pNew;
+ }
+}
+
+// print? Default is false
+bool ObjectContact::isOutputToPrinter() const
+{
+ return false;
+}
+
+// recording MetaFile? Default is false
+bool ObjectContact::isOutputToRecordingMetaFile() const
+{
+ return false;
+}
+
+// pdf export? Default is false
+bool ObjectContact::isOutputToPDFFile() const
+{
+ return false;
+}
+
+bool ObjectContact::isExportTaggedPDF() const
+{
+ return false;
+}
+
+// gray display mode
+bool ObjectContact::isDrawModeGray() const
+{
+ return false;
+}
+
+// high contrast display mode
+bool ObjectContact::isDrawModeHighContrast() const
+{
+ return false;
+}
+
+// access to SdrPageView. Default implementation returns NULL
+SdrPageView* ObjectContact::TryToGetSdrPageView() const
+{
+ return nullptr;
+}
+
+// access to OutputDevice. Default implementation returns NULL
+OutputDevice* ObjectContact::TryToGetOutputDevice() const
+{
+ return nullptr;
+}
+
+void ObjectContact::resetAllGridOffsets()
+{
+ const sal_uInt32 nVOCCount(getViewObjectContactCount());
+
+ for(sal_uInt32 a(0); a < nVOCCount; a++)
+ {
+ ViewObjectContact* pVOC(getViewObjectContact(a));
+ assert(pVOC && "ObjectContact: ViewObjectContact list Corrupt (!)");
+ pVOC->resetGridOffset();
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/objectcontactofobjlistpainter.cxx b/svx/source/sdr/contact/objectcontactofobjlistpainter.cxx
new file mode 100644
index 000000000..f666eceb1
--- /dev/null
+++ b/svx/source/sdr/contact/objectcontactofobjlistpainter.cxx
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <svx/unoapi.hxx>
+#include <tools/debug.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/pdfextoutdevdata.hxx>
+#include <memory>
+
+namespace sdr::contact {
+
+ObjectContactPainter::ObjectContactPainter()
+{
+}
+
+// The destructor.
+ObjectContactPainter::~ObjectContactPainter()
+{
+}
+
+sal_uInt32 ObjectContactOfObjListPainter::GetPaintObjectCount() const
+{
+ return maStartObjects.size();
+}
+
+ViewContact& ObjectContactOfObjListPainter::GetPaintObjectViewContact(sal_uInt32 nIndex)
+{
+ const SdrObject* pObj = maStartObjects[nIndex];
+ DBG_ASSERT(pObj, "ObjectContactOfObjListPainter: Corrupt SdrObjectVector (!)");
+ return pObj->GetViewContact();
+}
+
+ObjectContactOfObjListPainter::ObjectContactOfObjListPainter(
+ OutputDevice& rTargetDevice,
+ SdrObjectVector&& rObjects,
+ const SdrPage* pProcessedPage)
+: mrTargetOutputDevice(rTargetDevice),
+ maStartObjects(std::move(rObjects)),
+ mpProcessedPage(pProcessedPage)
+{
+}
+
+ObjectContactOfObjListPainter::~ObjectContactOfObjListPainter()
+{
+}
+
+// Process the whole displaying
+void ObjectContactOfObjListPainter::ProcessDisplay(DisplayInfo& rDisplayInfo)
+{
+ const sal_uInt32 nCount(GetPaintObjectCount());
+
+ if(!nCount)
+ return;
+
+ OutputDevice* pTargetDevice = TryToGetOutputDevice();
+
+ if(!pTargetDevice)
+ return;
+
+ // update current ViewInformation2D at the ObjectContact
+ const GDIMetaFile* pMetaFile = pTargetDevice->GetConnectMetaFile();
+ const bool bOutputToRecordingMetaFile(pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
+ basegfx::B2DRange aViewRange;
+
+ // create ViewRange
+ if(!bOutputToRecordingMetaFile)
+ {
+ // use visible pixels, but transform to world coordinates
+ const Size aOutputSizePixel(pTargetDevice->GetOutputSizePixel());
+ aViewRange = ::basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
+ aViewRange.transform(pTargetDevice->GetInverseViewTransformation());
+ }
+
+ // update local ViewInformation2D
+ const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D(
+ basegfx::B2DHomMatrix(),
+ pTargetDevice->GetViewTransformation(),
+ aViewRange,
+ GetXDrawPageForSdrPage(const_cast< SdrPage* >(mpProcessedPage)),
+ 0.0);
+ updateViewInformation2D(aNewViewInformation2D);
+
+ // collect primitive data in a sequence; this will already use the updated ViewInformation2D
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence;
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const ViewObjectContact& rViewObjectContact = GetPaintObjectViewContact(a).GetViewObjectContact(*this);
+
+ rViewObjectContact.getPrimitive2DSequenceHierarchy(rDisplayInfo, xPrimitiveSequence);
+ }
+
+ // if there is something to show, use a vclProcessor to render it
+ if(!xPrimitiveSequence.empty())
+ {
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
+ *pTargetDevice,
+ getViewInformation2D()));
+
+ pProcessor2D->process(xPrimitiveSequence);
+ }
+}
+
+// recording MetaFile?
+bool ObjectContactOfObjListPainter::isOutputToRecordingMetaFile() const
+{
+ GDIMetaFile* pMetaFile = mrTargetOutputDevice.GetConnectMetaFile();
+ return (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
+}
+
+// pdf export?
+bool ObjectContactOfObjListPainter::isOutputToPDFFile() const
+{
+ return OUTDEV_PDF == mrTargetOutputDevice.GetOutDevType();
+}
+
+bool ObjectContactOfObjListPainter::isExportTaggedPDF() const
+{
+ if (isOutputToPDFFile())
+ {
+ vcl::PDFExtOutDevData* pPDFExtOutDevData(dynamic_cast<vcl::PDFExtOutDevData*>(
+ mrTargetOutputDevice.GetExtOutDevData()));
+
+ if (nullptr != pPDFExtOutDevData)
+ {
+ return pPDFExtOutDevData->GetIsExportTaggedPDF();
+ }
+ }
+ return false;
+}
+
+OutputDevice* ObjectContactOfObjListPainter::TryToGetOutputDevice() const
+{
+ return &mrTargetOutputDevice;
+}
+
+sal_uInt32 ObjectContactOfPagePainter::GetPaintObjectCount() const
+{
+ return (GetStartPage() ? 1 : 0);
+}
+
+ViewContact& ObjectContactOfPagePainter::GetPaintObjectViewContact(sal_uInt32 /*nIndex*/)
+{
+ DBG_ASSERT(GetStartPage(), "ObjectContactOfPagePainter::GetPaintObjectViewContact: no StartPage set (!)");
+ return GetStartPage()->GetViewContact();
+}
+
+ObjectContactOfPagePainter::ObjectContactOfPagePainter(
+ ObjectContact& rOriginalObjectContact)
+: mrOriginalObjectContact(rOriginalObjectContact)
+{
+}
+
+ObjectContactOfPagePainter::~ObjectContactOfPagePainter()
+{
+}
+
+void ObjectContactOfPagePainter::SetStartPage(const SdrPage* pPage)
+{
+ if(pPage != GetStartPage())
+ {
+ mxStartPage = const_cast< SdrPage* >(pPage); // no tools::WeakReference<SdrPage> available to hold a const SdrPage*
+ }
+}
+
+OutputDevice* ObjectContactOfPagePainter::TryToGetOutputDevice() const
+{
+ return mrOriginalObjectContact.TryToGetOutputDevice();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/objectcontactofpageview.cxx b/svx/source/sdr/contact/objectcontactofpageview.cxx
new file mode 100644
index 000000000..31b8b949e
--- /dev/null
+++ b/svx/source/sdr/contact/objectcontactofpageview.cxx
@@ -0,0 +1,451 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_feature_desktop.h>
+
+#include <svx/sdr/contact/objectcontactofpageview.hxx>
+#include <sdr/contact/viewobjectcontactofunocontrol.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/animation/objectanimator.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <osl/diagnose.h>
+#include <svx/unoapi.hxx>
+#include <unotools/configmgr.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/pdfextoutdevdata.hxx>
+#include <comphelper/lok.hxx>
+
+#include <memory>
+
+using namespace com::sun::star;
+
+namespace sdr::contact
+{
+ // internal access to SdrPage of SdrPageView
+ SdrPage* ObjectContactOfPageView::GetSdrPage() const
+ {
+ return GetPageWindow().GetPageView().GetPage();
+ }
+
+ ObjectContactOfPageView::ObjectContactOfPageView(
+ SdrPageWindow& rPageWindow, const char *pDebugName)
+ : Idle(pDebugName)
+ , mrPageWindow(rPageWindow)
+ {
+ // init PreviewRenderer flag
+ setPreviewRenderer(static_cast<SdrPaintView&>(rPageWindow.GetPageView().GetView()).IsPreviewRenderer());
+
+ // init timer
+ SetPriority(TaskPriority::HIGH_IDLE);
+ Stop();
+ }
+
+ ObjectContactOfPageView::~ObjectContactOfPageView()
+ {
+ // execute missing LazyInvalidates and stop timer
+ Invoke();
+ }
+
+ // LazyInvalidate request. Take action.
+ void ObjectContactOfPageView::setLazyInvalidate(ViewObjectContact& /*rVOC*/)
+ {
+ // do NOT call parent, but remember that something is to do by
+ // starting the LazyInvalidateTimer
+ Start();
+ }
+
+ // call this to support evtl. preparations for repaint
+ void ObjectContactOfPageView::PrepareProcessDisplay()
+ {
+ if(IsActive())
+ // there are still non-triggered LazyInvalidate events, trigger these
+ Invoke();
+ }
+
+ // From baseclass Timer, the timeout call triggered by the LazyInvalidate mechanism
+ void ObjectContactOfPageView::Invoke()
+ {
+ // stop the timer
+ Stop();
+
+ // invalidate all LazyInvalidate VOCs new situations
+ const sal_uInt32 nVOCCount(getViewObjectContactCount());
+
+ for(sal_uInt32 a(0); a < nVOCCount; a++)
+ {
+ ViewObjectContact* pCandidate = getViewObjectContact(a);
+ pCandidate->triggerLazyInvalidate();
+ }
+ }
+
+ // Process the whole displaying
+ void ObjectContactOfPageView::ProcessDisplay(DisplayInfo& rDisplayInfo)
+ {
+ const SdrPage* pStartPage = GetSdrPage();
+
+ if(pStartPage && !rDisplayInfo.GetProcessLayers().IsEmpty())
+ {
+ const ViewContact& rDrawPageVC = pStartPage->GetViewContact();
+
+ if(rDrawPageVC.GetObjectCount())
+ {
+ DoProcessDisplay(rDisplayInfo);
+ }
+ }
+ }
+
+ // Process the whole displaying. Only use given DisplayInfo, do not access other
+ // OutputDevices then the given ones.
+ void ObjectContactOfPageView::DoProcessDisplay(DisplayInfo& rDisplayInfo)
+ {
+ OutputDevice& rTargetOutDev = GetPageWindow().GetPaintWindow().GetTargetOutputDevice();
+ const Size aOutputSizePixel(rTargetOutDev.GetOutputSizePixel());
+ if (!isOutputToRecordingMetaFile() // do those have outdev too?
+ && (0 == aOutputSizePixel.getWidth() ||
+ 0 == aOutputSizePixel.getHeight()))
+ {
+ return;
+ }
+
+ // visualize entered group when that feature is switched on and it's not
+ // a print output. #i29129# No ghosted display for printing.
+ bool bVisualizeEnteredGroup(DoVisualizeEnteredGroup() && !isOutputToPrinter());
+
+ // Visualize entered groups: Set to ghosted as default
+ // start. Do this only for the DrawPage, not for MasterPages
+ if(bVisualizeEnteredGroup)
+ {
+ rDisplayInfo.SetGhostedDrawMode();
+ }
+
+ // #114359# save old and set clip region
+ OutputDevice* pOutDev = TryToGetOutputDevice();
+ OSL_ENSURE(nullptr != pOutDev, "ObjectContactOfPageView without OutDev, someone has overridden TryToGetOutputDevice wrong (!)");
+ bool bClipRegionPushed(false);
+ const vcl::Region& rRedrawArea(rDisplayInfo.GetRedrawArea());
+
+ if(!rRedrawArea.IsEmpty() && !comphelper::LibreOfficeKit::isActive())
+ {
+ bClipRegionPushed = true;
+ pOutDev->Push(vcl::PushFlags::CLIPREGION);
+ pOutDev->IntersectClipRegion(rRedrawArea);
+ }
+
+ // Get start node and process DrawPage contents
+ const ViewObjectContact& rDrawPageVOContact = GetSdrPage()->GetViewContact().GetViewObjectContact(*this);
+
+ // update current ViewInformation2D at the ObjectContact
+ const double fCurrentTime(getPrimitiveAnimator().GetTime());
+ basegfx::B2DRange aViewRange;
+
+ // create ViewRange
+ if(isOutputToRecordingMetaFile())
+ {
+ if (!rDisplayInfo.GetRedrawArea().IsEmpty())
+ {
+ // #i98402# if it's a PDF export, set the ClipRegion as ViewRange. This is
+ // mainly because SW does not use DrawingLayer Page-Oriented and if not doing this,
+ // all existing objects will be collected as primitives and processed.
+ // OD 2009-03-05 #i99876# perform the same also for SW on printing.
+ // fdo#78149 same thing also needed for plain MetaFile
+ // export, so why not do it always
+ const tools::Rectangle aLogicClipRectangle(rDisplayInfo.GetRedrawArea().GetBoundRect());
+
+ aViewRange = vcl::unotools::b2DRectangleFromRectangle(aLogicClipRectangle);
+ }
+ }
+ else
+ {
+ // use visible pixels, but transform to world coordinates
+ aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
+ // if a clip region is set, use it
+ if(!rDisplayInfo.GetRedrawArea().IsEmpty())
+ {
+ // get logic clip range and create discrete one
+ const tools::Rectangle aLogicClipRectangle(rDisplayInfo.GetRedrawArea().GetBoundRect());
+ basegfx::B2DRange aDiscreteClipRange = vcl::unotools::b2DRectangleFromRectangle(aLogicClipRectangle);
+ aDiscreteClipRange.transform(rTargetOutDev.GetViewTransformation());
+
+ // align the discrete one to discrete boundaries (pixel bounds). Also
+ // expand X and Y max by one due to Rectangle definition source
+ aDiscreteClipRange.expand(basegfx::B2DTuple(
+ floor(aDiscreteClipRange.getMinX()),
+ floor(aDiscreteClipRange.getMinY())));
+ aDiscreteClipRange.expand(basegfx::B2DTuple(
+ 1.0 + ceil(aDiscreteClipRange.getMaxX()),
+ 1.0 + ceil(aDiscreteClipRange.getMaxY())));
+
+ // intersect current ViewRange with ClipRange
+ aViewRange.intersect(aDiscreteClipRange);
+ }
+
+ // transform to world coordinates
+ aViewRange.transform(rTargetOutDev.GetInverseViewTransformation());
+ }
+
+ // update local ViewInformation2D
+ const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D(
+ basegfx::B2DHomMatrix(),
+ rTargetOutDev.GetViewTransformation(),
+ aViewRange,
+ GetXDrawPageForSdrPage(GetSdrPage()),
+ fCurrentTime);
+ updateViewInformation2D(aNewViewInformation2D);
+
+ drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence;
+
+#if HAVE_FEATURE_DESKTOP || defined( ANDROID )
+ // get whole Primitive2DContainer; this will already make use of updated ViewInformation2D
+ // and may use the MapMode from the Target OutDev in the DisplayInfo
+ rDrawPageVOContact.getPrimitive2DSequenceHierarchy(rDisplayInfo, xPrimitiveSequence);
+#else
+ // Hmm, !HAVE_FEATURE_DESKTOP && !ANDROID means iOS,
+ // right? But does it makes sense to use a different code
+ // path for iOS than for Android; both use tiled rendering
+ // etc now.
+
+ // HACK: this only works when we are drawing sdr shapes via
+ // drawinglayer; but it can happen that the hierarchy contains
+ // more than just the shapes, and then it fails.
+ //
+ // This is good enough for the tiled rendering for the moment, but
+ // we need to come up with the real solution shortly.
+
+ // Only get the expensive hierarchy if we can be sure that the
+ // returned sequence won't be empty anyway.
+ bool bGetHierarchy = rRedrawArea.IsEmpty();
+ if (!bGetHierarchy)
+ {
+ // Not empty? Then not doing a full redraw, check if
+ // getPrimitive2DSequenceHierarchy() is still needed.
+ sal_Int32 nObjCount = GetSdrPage()->GetObjCount();
+ for (sal_Int32 i = 0; i < nObjCount; ++i)
+ {
+ SdrObject* pObject = GetSdrPage()->GetObj(i);
+ if (rRedrawArea.Overlaps(pObject->GetCurrentBoundRect()))
+ {
+ bGetHierarchy = true;
+ break;
+ }
+ }
+ }
+
+ if (bGetHierarchy)
+ // get whole Primitive2DContainer; this will already make use of updated ViewInformation2D
+ // and may use the MapMode from the Target OutDev in the DisplayInfo
+ rDrawPageVOContact.getPrimitive2DSequenceHierarchy(rDisplayInfo, xPrimitiveSequence);
+#endif
+
+ // if there is something to show, use a primitive processor to render it. There
+ // is a choice between VCL and Canvas processors currently. The decision is made in
+ // createProcessor2DFromOutputDevice and takes into account things like the
+ // Target is a MetaFile, a VDev or something else. The Canvas renderer is triggered
+ // currently using the shown boolean. Canvas is not yet the default.
+ if(!xPrimitiveSequence.empty())
+ {
+ // prepare OutputDevice (historical stuff, maybe soon removed)
+ rDisplayInfo.ClearGhostedDrawMode(); // reset, else the VCL-paint with the processor will not do the right thing
+ pOutDev->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::Default); // reset, default is no BiDi/RTL
+ // create renderer
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
+ drawinglayer::processor2d::createProcessor2DFromOutputDevice(
+ rTargetOutDev, getViewInformation2D()));
+ pProcessor2D->process(xPrimitiveSequence);
+ }
+
+ // #114359# restore old ClipReghion
+ if(bClipRegionPushed)
+ {
+ pOutDev->Pop();
+ }
+
+ // Visualize entered groups: Reset to original DrawMode
+ if(bVisualizeEnteredGroup)
+ {
+ rDisplayInfo.ClearGhostedDrawMode();
+ }
+ }
+
+ // test if visualizing of entered groups is switched on at all
+ bool ObjectContactOfPageView::DoVisualizeEnteredGroup() const
+ {
+ return true;
+ }
+
+ // get active group's (the entered group) ViewContact
+ const ViewContact* ObjectContactOfPageView::getActiveViewContact() const
+ {
+ SdrObjList* pActiveGroupList = GetPageWindow().GetPageView().GetObjList();
+
+ if(pActiveGroupList)
+ {
+ if(nullptr != pActiveGroupList->getSdrPageFromSdrObjList())
+ {
+ // It's a Page itself
+ return &(pActiveGroupList->getSdrPageFromSdrObjList()->GetViewContact());
+ }
+ else if(pActiveGroupList->getSdrObjectFromSdrObjList())
+ {
+ // Group object
+ return &(pActiveGroupList->getSdrObjectFromSdrObjList()->GetViewContact());
+ }
+ }
+ else if(GetSdrPage())
+ {
+ // use page of associated SdrPageView
+ return &(GetSdrPage()->GetViewContact());
+ }
+
+ return nullptr;
+ }
+
+ // Invalidate given rectangle at the window/output which is represented by
+ // this ObjectContact.
+ void ObjectContactOfPageView::InvalidatePartOfView(const basegfx::B2DRange& rRange) const
+ {
+ // invalidate at associated PageWindow
+ GetPageWindow().InvalidatePageWindow(rRange);
+ }
+
+ // Get info about the need to visualize GluePoints
+ bool ObjectContactOfPageView::AreGluePointsVisible() const
+ {
+ bool bTiledRendering = comphelper::LibreOfficeKit::isActive();
+ return !bTiledRendering && GetPageWindow().GetPageView().GetView().ImpIsGlueVisible();
+ }
+
+ // check if text animation is allowed.
+ bool ObjectContactOfPageView::IsTextAnimationAllowed() const
+ {
+ if (utl::ConfigManager::IsFuzzing())
+ return true;
+ SdrView& rView = GetPageWindow().GetPageView().GetView();
+ const SvtAccessibilityOptions& rOpt = rView.getAccessibilityOptions();
+ return rOpt.GetIsAllowAnimatedText();
+ }
+
+ // check if graphic animation is allowed.
+ bool ObjectContactOfPageView::IsGraphicAnimationAllowed() const
+ {
+ if (utl::ConfigManager::IsFuzzing())
+ return true;
+ SdrView& rView = GetPageWindow().GetPageView().GetView();
+ const SvtAccessibilityOptions& rOpt = rView.getAccessibilityOptions();
+ return rOpt.GetIsAllowAnimatedGraphics();
+ }
+
+ // print?
+ bool ObjectContactOfPageView::isOutputToPrinter() const
+ {
+ return (OUTDEV_PRINTER == mrPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType());
+ }
+
+ // recording MetaFile?
+ bool ObjectContactOfPageView::isOutputToRecordingMetaFile() const
+ {
+ GDIMetaFile* pMetaFile = mrPageWindow.GetPaintWindow().GetOutputDevice().GetConnectMetaFile();
+ return (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
+ }
+
+ // pdf export?
+ bool ObjectContactOfPageView::isOutputToPDFFile() const
+ {
+ return OUTDEV_PDF == mrPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType();
+ }
+
+ bool ObjectContactOfPageView::isExportTaggedPDF() const
+ {
+ if (isOutputToPDFFile())
+ {
+ vcl::PDFExtOutDevData* pPDFExtOutDevData(dynamic_cast<vcl::PDFExtOutDevData*>(
+ mrPageWindow.GetPaintWindow().GetOutputDevice().GetExtOutDevData()));
+
+ if (nullptr != pPDFExtOutDevData)
+ {
+ return pPDFExtOutDevData->GetIsExportTaggedPDF();
+ }
+ }
+ return false;
+ }
+
+ // gray display mode
+ bool ObjectContactOfPageView::isDrawModeGray() const
+ {
+ const DrawModeFlags nDrawMode(mrPageWindow.GetPaintWindow().GetOutputDevice().GetDrawMode());
+ return (nDrawMode == (DrawModeFlags::GrayLine|DrawModeFlags::GrayFill|DrawModeFlags::BlackText|DrawModeFlags::GrayBitmap|DrawModeFlags::GrayGradient));
+ }
+
+ // high contrast display mode
+ bool ObjectContactOfPageView::isDrawModeHighContrast() const
+ {
+ const DrawModeFlags nDrawMode(mrPageWindow.GetPaintWindow().GetOutputDevice().GetDrawMode());
+ return (nDrawMode == (DrawModeFlags::SettingsLine|DrawModeFlags::SettingsFill|DrawModeFlags::SettingsText|DrawModeFlags::SettingsGradient));
+ }
+
+ // access to SdrPageView
+ SdrPageView* ObjectContactOfPageView::TryToGetSdrPageView() const
+ {
+ return &(mrPageWindow.GetPageView());
+ }
+
+
+ // access to OutputDevice
+ OutputDevice* ObjectContactOfPageView::TryToGetOutputDevice() const
+ {
+ SdrPreRenderDevice* pPreRenderDevice = mrPageWindow.GetPaintWindow().GetPreRenderDevice();
+
+ if(pPreRenderDevice)
+ {
+ return &(pPreRenderDevice->GetPreRenderDevice());
+ }
+ else
+ {
+ return &(mrPageWindow.GetPaintWindow().GetOutputDevice());
+ }
+ }
+
+ // set all UNO controls displayed in the view to design/alive mode
+ void ObjectContactOfPageView::SetUNOControlsDesignMode( bool _bDesignMode ) const
+ {
+ const sal_uInt32 nCount(getViewObjectContactCount());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const ViewObjectContact* pVOC = getViewObjectContact(a);
+ const ViewObjectContactOfUnoControl* pUnoObjectVOC = dynamic_cast< const ViewObjectContactOfUnoControl* >(pVOC);
+
+ if(pUnoObjectVOC)
+ {
+ pUnoObjectVOC->setControlDesignMode(_bDesignMode);
+ }
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/sdrmediawindow.cxx b/svx/source/sdr/contact/sdrmediawindow.cxx
new file mode 100644
index 000000000..086e12cee
--- /dev/null
+++ b/svx/source/sdr/contact/sdrmediawindow.cxx
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "sdrmediawindow.hxx"
+#include <vcl/transfer.hxx>
+
+#include <sdr/contact/viewobjectcontactofsdrmediaobj.hxx>
+#include <vcl/window.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+
+namespace sdr::contact {
+
+
+SdrMediaWindow::SdrMediaWindow( vcl::Window* pParent, ViewObjectContactOfSdrMediaObj& rViewObjContact ) :
+ ::avmedia::MediaWindow( pParent, false ),
+ mrViewObjectContactOfSdrMediaObj( rViewObjContact )
+{
+}
+
+
+SdrMediaWindow::~SdrMediaWindow()
+{
+}
+
+
+void SdrMediaWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+
+ if( pWindow && getWindow() )
+ {
+ const MouseEvent aTransformedEvent( pWindow->ScreenToOutputPixel( getWindow()->OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
+ rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
+
+ pWindow->MouseMove( aTransformedEvent );
+ setPointer( pWindow->GetPointer() );
+ }
+}
+
+
+void SdrMediaWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+
+ if( pWindow && getWindow() )
+ {
+ const MouseEvent aTransformedEvent( pWindow->ScreenToOutputPixel( getWindow()->OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
+ rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
+
+ pWindow->MouseButtonDown( aTransformedEvent );
+ }
+}
+
+
+void SdrMediaWindow::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+
+ if( pWindow && getWindow() )
+ {
+ const MouseEvent aTransformedEvent( pWindow->ScreenToOutputPixel( getWindow()->OutputToScreenPixel( rMEvt.GetPosPixel() ) ),
+ rMEvt.GetClicks(), rMEvt.GetMode(), rMEvt.GetButtons(), rMEvt.GetModifier() );
+
+ pWindow->MouseButtonUp( aTransformedEvent );
+ }
+}
+
+
+void SdrMediaWindow::KeyInput( const KeyEvent& rKEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+
+ if( pWindow )
+ pWindow->KeyInput( rKEvt );
+}
+
+
+void SdrMediaWindow::KeyUp( const KeyEvent& rKEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+
+ if( pWindow )
+ pWindow->KeyUp( rKEvt );
+}
+
+
+void SdrMediaWindow::Command( const CommandEvent& rCEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+
+ if( pWindow && getWindow() )
+ {
+ const CommandEvent aTransformedEvent( pWindow->ScreenToOutputPixel( getWindow()->OutputToScreenPixel( rCEvt.GetMousePosPixel() ) ),
+ rCEvt.GetCommand(), rCEvt.IsMouseEvent(), rCEvt.GetEventData() );
+
+ pWindow->Command( aTransformedEvent );
+ }
+}
+
+
+sal_Int8 SdrMediaWindow::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if( pWindow )
+ {
+ DropTargetHelper* pDropTargetHelper = dynamic_cast< DropTargetHelper* >( pWindow );
+
+ if( pDropTargetHelper )
+ {
+ nRet = pDropTargetHelper->AcceptDrop( rEvt );
+ }
+ }
+
+ return nRet;
+}
+
+
+sal_Int8 SdrMediaWindow::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if( pWindow )
+ {
+ DropTargetHelper* pDropTargetHelper = dynamic_cast< DropTargetHelper* >( pWindow );
+
+ if( pDropTargetHelper )
+ {
+ nRet = pDropTargetHelper->ExecuteDrop( rEvt );
+ }
+ }
+
+ return nRet;
+}
+
+
+void SdrMediaWindow::StartDrag( sal_Int8 nAction, const Point& rPosPixel )
+{
+ vcl::Window* pWindow = mrViewObjectContactOfSdrMediaObj.getWindow();
+
+ if( pWindow )
+ {
+ DragSourceHelper* pDragSourceHelper = dynamic_cast< DragSourceHelper* >( pWindow );
+
+ if( pDragSourceHelper )
+ {
+ pDragSourceHelper->StartDrag( nAction, rPosPixel );
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/sdrmediawindow.hxx b/svx/source/sdr/contact/sdrmediawindow.hxx
new file mode 100644
index 000000000..fb3cda6fc
--- /dev/null
+++ b/svx/source/sdr/contact/sdrmediawindow.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_SDR_CONTACT_SDRMEDIAWINDOW_HXX
+#define INCLUDED_SVX_SOURCE_SDR_CONTACT_SDRMEDIAWINDOW_HXX
+
+#include <avmedia/mediawindow.hxx>
+
+namespace sdr::contact {
+
+
+class ViewObjectContactOfSdrMediaObj;
+
+class SdrMediaWindow : public ::avmedia::MediaWindow
+{
+public:
+
+ SdrMediaWindow( vcl::Window* pParent, ViewObjectContactOfSdrMediaObj& rViewObjContact );
+ virtual ~SdrMediaWindow() override;
+
+ virtual void MouseMove( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) override;
+
+ virtual void KeyInput( const KeyEvent& rKEvt ) override;
+ virtual void KeyUp( const KeyEvent& rKEvt ) override;
+
+ virtual void Command( const CommandEvent& rCEvt ) override;
+
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+
+ virtual void StartDrag( sal_Int8 nAction, const Point& rPosPixel ) override;
+
+private:
+
+ ViewObjectContactOfSdrMediaObj& mrViewObjectContactOfSdrMediaObj;
+};
+
+}
+
+#endif // INCLUDED_SVX_SOURCE_SDR_CONTACT_SDRMEDIAWINDOW_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontact.cxx b/svx/source/sdr/contact/viewcontact.cxx
new file mode 100644
index 000000000..bd79bc5ed
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontact.cxx
@@ -0,0 +1,295 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <osl/diagnose.h>
+#include <tools/debug.hxx>
+
+namespace sdr::contact
+{
+// Create an Object-Specific ViewObjectContact, set ViewContact and
+// ObjectContact. Always needs to return something. Default is to create
+// a standard ViewObjectContact containing the given ObjectContact and *this
+ViewObjectContact& ViewContact::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ return *(new ViewObjectContact(rObjectContact, *this));
+}
+
+ViewContact::ViewContact() {}
+
+ViewContact::~ViewContact() { deleteAllVOCs(); }
+
+void ViewContact::deleteAllVOCs()
+{
+ // get rid of all VOCs
+ // #i84257# To avoid that each 'delete pCandidate' again uses
+ // the local RemoveViewObjectContact with a search and removal in the
+ // vector, simply copy and clear local vector.
+ std::vector<ViewObjectContact*> aLocalVOCList;
+ aLocalVOCList.swap(maViewObjectContactVector);
+
+ for (const auto& pCandidate : aLocalVOCList)
+ // ViewObjectContacts only make sense with View and Object contacts.
+ // When the contact to the SdrObject is deleted like in this case,
+ // all ViewObjectContacts can be deleted, too.
+ delete pCandidate;
+
+ // assert when there were new entries added during deletion
+ DBG_ASSERT(maViewObjectContactVector.empty(), "Corrupted ViewObjectContactList in VC (!)");
+}
+
+// get an Object-specific ViewObjectContact for a specific
+// ObjectContact (->View). Always needs to return something.
+ViewObjectContact& ViewContact::GetViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = nullptr;
+ const sal_uInt32 nCount(maViewObjectContactVector.size());
+
+ // first search if there exists a VOC for the given OC
+ for (sal_uInt32 a(0); !pRetval && a < nCount; a++)
+ {
+ ViewObjectContact* pCandidate = maViewObjectContactVector[a];
+ DBG_ASSERT(pCandidate, "Corrupted ViewObjectContactList (!)");
+
+ if (&(pCandidate->GetObjectContact()) == &rObjectContact)
+ {
+ pRetval = pCandidate;
+ }
+ }
+
+ if (!pRetval)
+ {
+ // create a new one. It's inserted to the local list from the
+ // ViewObjectContact constructor via AddViewObjectContact()
+ pRetval = &CreateObjectSpecificViewObjectContact(rObjectContact);
+ }
+
+ return *pRetval;
+}
+
+// A new ViewObjectContact was created and shall be remembered.
+void ViewContact::AddViewObjectContact(ViewObjectContact& rVOContact)
+{
+ maViewObjectContactVector.push_back(&rVOContact);
+}
+
+// A ViewObjectContact was deleted and shall be forgotten.
+void ViewContact::RemoveViewObjectContact(ViewObjectContact& rVOContact)
+{
+ std::vector<ViewObjectContact*>::iterator aFindResult = std::find(
+ maViewObjectContactVector.begin(), maViewObjectContactVector.end(), &rVOContact);
+
+ if (aFindResult != maViewObjectContactVector.end())
+ {
+ maViewObjectContactVector.erase(aFindResult);
+ }
+}
+
+// Test if this ViewContact has ViewObjectContacts at all. This can
+// be used to test if this ViewContact is visualized ATM or not
+bool ViewContact::HasViewObjectContacts() const
+{
+ const sal_uInt32 nCount(maViewObjectContactVector.size());
+
+ for (sal_uInt32 a(0); a < nCount; a++)
+ {
+ if (!maViewObjectContactVector[a]->GetObjectContact().IsPreviewRenderer())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Test if this ViewContact has ViewObjectContacts at all. This can
+// be used to test if this ViewContact is visualized ATM or not
+bool ViewContact::isAnimatedInAnyViewObjectContact() const
+{
+ const sal_uInt32 nCount(maViewObjectContactVector.size());
+
+ for (sal_uInt32 a(0); a < nCount; a++)
+ {
+ if (maViewObjectContactVector[a]->isAnimated())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Access to possible sub-hierarchy and parent. GetObjectCount() default is 0L
+// and GetViewContact default pops up an assert since it's an error if
+// GetObjectCount has a result != 0 and it's not overridden.
+sal_uInt32 ViewContact::GetObjectCount() const
+{
+ // no sub-objects
+ return 0;
+}
+
+ViewContact& ViewContact::GetViewContact(sal_uInt32 /*nIndex*/) const
+{
+ // This is the default implementation; call would be an error
+ OSL_FAIL("ViewContact::GetViewContact: This call needs to be overridden when GetObjectCount() "
+ "can return results != 0 (!)");
+ return const_cast<ViewContact&>(*this);
+}
+
+ViewContact* ViewContact::GetParentContact() const
+{
+ // default has no parent
+ return nullptr;
+}
+
+void ViewContact::ActionChildInserted(ViewContact& rChild)
+{
+ // propagate change to all existing visualisations which
+ // will force a VOC for the new child and invalidate its range
+ const sal_uInt32 nCount(maViewObjectContactVector.size());
+
+ for (sal_uInt32 a(0); a < nCount; a++)
+ {
+ ViewObjectContact* pCandidate = maViewObjectContactVector[a];
+ DBG_ASSERT(pCandidate,
+ "ViewContact::GetViewObjectContact() invalid ViewObjectContactList (!)");
+
+ // take action at all VOCs. At the VOCs ObjectContact the initial
+ // rectangle will be invalidated at the associated OutputDevice.
+ pCandidate->ActionChildInserted(rChild);
+ }
+}
+
+// React on changes of the object of this ViewContact
+void ViewContact::ActionChanged()
+{
+ // propagate change to all existing VOCs. This will invalidate
+ // all drawn visualisations in all known views
+ const sal_uInt32 nCount(maViewObjectContactVector.size());
+
+ for (sal_uInt32 a(0); a < nCount; a++)
+ {
+ ViewObjectContact* pCandidate = maViewObjectContactVector[a];
+ DBG_ASSERT(pCandidate,
+ "ViewContact::GetViewObjectContact() invalid ViewObjectContactList (!)");
+
+ if (pCandidate)
+ {
+ pCandidate->ActionChanged();
+ }
+ }
+}
+
+// access to SdrObject and/or SdrPage. May return 0L like the default
+// implementations do. Override as needed.
+SdrObject* ViewContact::TryToGetSdrObject() const { return nullptr; }
+
+// primitive stuff
+
+void ViewContact::createViewIndependentPrimitive2DSequence(
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // This is the default implementation and should never be called (see header). If this is called,
+ // someone implemented a ViewContact (VC) visualisation object without defining the visualisation by
+ // providing a sequence of primitives -> which cannot be correct.
+ // Since we have no access to any known model data here, the default implementation creates a yellow placeholder
+ // hairline polygon with a default size of (1000, 1000, 5000, 3000)
+ OSL_FAIL("ViewContact::createViewIndependentPrimitive2DSequence(): Never call the fallback "
+ "base implementation, this is always an error (!)");
+ const basegfx::B2DPolygon aOutline(
+ basegfx::utils::createPolygonFromRect(basegfx::B2DRange(1000.0, 1000.0, 5000.0, 3000.0)));
+ const basegfx::BColor aYellow(1.0, 1.0, 0.0);
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aYellow));
+
+ rVisitor.visit(xReference);
+}
+
+void ViewContact::getViewIndependentPrimitive2DContainer(
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ /* Local up-to-date checks. Create new list and compare.
+ We cannot just always use the new data because the old data has cached bitmaps in it e.g. see the document in tdf#146108.
+ */
+ drawinglayer::primitive2d::Primitive2DContainer xNew;
+ createViewIndependentPrimitive2DSequence(xNew);
+
+ if (!xNew.empty())
+ {
+ // allow evtl. embedding in object-specific infos, e.g. Name, Title, Description
+ xNew = embedToObjectSpecificInformation(std::move(xNew));
+ }
+
+ if (mxViewIndependentPrimitive2DSequence != xNew)
+ {
+ // has changed, copy content
+ const_cast<ViewContact*>(this)->mxViewIndependentPrimitive2DSequence = std::move(xNew);
+ }
+
+ // return current Primitive2DContainer
+ rVisitor.visit(mxViewIndependentPrimitive2DSequence);
+}
+
+// add Gluepoints (if available)
+drawinglayer::primitive2d::Primitive2DContainer
+ViewContact::createGluePointPrimitive2DSequence() const
+{
+ // default returns empty reference
+ return drawinglayer::primitive2d::Primitive2DContainer();
+}
+
+drawinglayer::primitive2d::Primitive2DContainer ViewContact::embedToObjectSpecificInformation(
+ drawinglayer::primitive2d::Primitive2DContainer aSource) const
+{
+ // nothing to do for default
+ return aSource;
+}
+
+basegfx::B2DRange
+ViewContact::getRange(const drawinglayer::geometry::ViewInformation2D& /*rViewInfo2D*/) const
+{
+ // Return empty range.
+ return basegfx::B2DRange();
+}
+
+void ViewContact::flushViewObjectContacts(bool bWithHierarchy)
+{
+ if (bWithHierarchy)
+ {
+ // flush DrawingLayer hierarchy
+ const sal_uInt32 nCount(GetObjectCount());
+
+ for (sal_uInt32 a(0); a < nCount; a++)
+ {
+ ViewContact& rChild = GetViewContact(a);
+ rChild.flushViewObjectContacts(bWithHierarchy);
+ }
+ }
+
+ // delete local VOCs
+ deleteAllVOCs();
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofe3d.cxx b/svx/source/sdr/contact/viewcontactofe3d.cxx
new file mode 100644
index 000000000..a504038ce
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3d.cxx
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <sdr/contact/viewobjectcontactofe3d.hxx>
+#include <svx/obj3d.hxx>
+#include <drawinglayer/primitive2d/embedded3dprimitive2d.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <svx/scene3d.hxx>
+#include <drawinglayer/primitive3d/transformprimitive3d.hxx>
+#include <drawinglayer/attribute/sdrsceneattribute3d.hxx>
+#include <drawinglayer/attribute/sdrlightingattribute3d.hxx>
+#include <drawinglayer/attribute/sdrlightattribute3d.hxx>
+
+namespace {
+
+const sdr::contact::ViewContactOfE3dScene* tryToFindVCOfE3DScene(
+ const sdr::contact::ViewContact& rCandidate,
+ basegfx::B3DHomMatrix& o_rInBetweenObjectTransform)
+{
+ const sdr::contact::ViewContactOfE3dScene* pSceneParent =
+ dynamic_cast< const sdr::contact::ViewContactOfE3dScene* >(rCandidate.GetParentContact());
+
+ if(pSceneParent)
+ {
+ // each 3d object (including in-between scenes) should have a scene as parent
+ const sdr::contact::ViewContactOfE3dScene* pSceneParentParent =
+ dynamic_cast< const sdr::contact::ViewContactOfE3dScene* >(pSceneParent->GetParentContact());
+
+ if(pSceneParentParent)
+ {
+ // the parent scene of rCandidate is an in-between scene, call recursively and collect
+ // the in-between scene's object transformation part in o_rInBetweenObjectTransform
+ const basegfx::B3DHomMatrix& rSceneParentTransform = pSceneParent->GetE3dScene().GetTransform();
+ o_rInBetweenObjectTransform = rSceneParentTransform * o_rInBetweenObjectTransform;
+ return tryToFindVCOfE3DScene(*pSceneParent, o_rInBetweenObjectTransform);
+ }
+ else
+ {
+ // the parent scene is the outmost scene
+ return pSceneParent;
+ }
+ }
+
+ // object hierarchy structure is incorrect; no result
+ return nullptr;
+}
+
+} // end of anonymous namespace
+
+namespace sdr::contact {
+
+drawinglayer::primitive2d::Primitive2DContainer ViewContactOfE3d::impCreateWithGivenPrimitive3DContainer(
+ const drawinglayer::primitive3d::Primitive3DContainer& rxContent3D) const
+{
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+
+ if(!rxContent3D.empty())
+ {
+ // try to get the outmost ViewObjectContactOfE3dScene for this single 3d object,
+ // the ones on the way there are grouping scenes. Collect the in-between scene's
+ // transformations to build a correct object transformation for the embedded
+ // object
+ basegfx::B3DHomMatrix aInBetweenObjectTransform;
+ const ViewContactOfE3dScene* pVCOfE3DScene = tryToFindVCOfE3DScene(*this, aInBetweenObjectTransform);
+
+ if(pVCOfE3DScene)
+ {
+ basegfx::B3DVector aLightNormal;
+ const double fShadowSlant(pVCOfE3DScene->getSdrSceneAttribute().getShadowSlant());
+ const basegfx::B3DRange& rAllContentRange = pVCOfE3DScene->getAllContentRange3D();
+ drawinglayer::geometry::ViewInformation3D aViewInformation3D(pVCOfE3DScene->getViewInformation3D());
+
+ if(!pVCOfE3DScene->getSdrLightingAttribute().getLightVector().empty())
+ {
+ // get light normal from first light and normalize
+ aLightNormal = pVCOfE3DScene->getSdrLightingAttribute().getLightVector()[0].getDirection();
+ aLightNormal.normalize();
+ }
+
+ if(!aInBetweenObjectTransform.isIdentity())
+ {
+ // if aInBetweenObjectTransform is used, create combined ViewInformation3D which
+ // contains the correct object transformation for the embedded 3d object
+ aViewInformation3D = drawinglayer::geometry::ViewInformation3D(
+ aViewInformation3D.getObjectTransformation() * aInBetweenObjectTransform,
+ aViewInformation3D.getOrientation(),
+ aViewInformation3D.getProjection(),
+ aViewInformation3D.getDeviceToView(),
+ aViewInformation3D.getViewTime(),
+ aViewInformation3D.getExtendedInformationSequence());
+ }
+
+ // create embedded 2d primitive and add. LightNormal and ShadowSlant are needed for evtl.
+ // 3D shadow extraction for correct B2DRange calculation (shadow is part of the object)
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::Embedded3DPrimitive2D(
+ rxContent3D,
+ pVCOfE3DScene->getObjectTransformation(),
+ aViewInformation3D,
+ aLightNormal,
+ fShadowSlant,
+ rAllContentRange));
+
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReference };
+ }
+ }
+
+ return xRetval;
+}
+
+ViewContactOfE3d::ViewContactOfE3d(E3dObject& rSdrObject)
+: ViewContactOfSdrObj(rSdrObject)
+{
+}
+
+ViewContactOfE3d::~ViewContactOfE3d()
+{
+}
+
+drawinglayer::primitive3d::Primitive3DContainer const & ViewContactOfE3d::getVIP3DSWithoutObjectTransform() const
+{
+ // local up-to-date checks. Create new list and compare.
+ drawinglayer::primitive3d::Primitive3DContainer xNew(createViewIndependentPrimitive3DContainer());
+
+ if(mxViewIndependentPrimitive3DContainer != xNew)
+ {
+ // has changed, copy content
+ const_cast< ViewContactOfE3d* >(this)->mxViewIndependentPrimitive3DContainer = xNew;
+ }
+
+ // return current Primitive2DContainer
+ return mxViewIndependentPrimitive3DContainer;
+}
+
+drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3d::getViewIndependentPrimitive3DContainer() const
+{
+ // get sequence without object transform
+ drawinglayer::primitive3d::Primitive3DContainer xRetval(getVIP3DSWithoutObjectTransform());
+
+ if(!xRetval.empty())
+ {
+ // add object transform if it's used
+ const basegfx::B3DHomMatrix& rObjectTransform(GetE3dObject().GetTransform());
+
+ if(!rObjectTransform.isIdentity())
+ {
+ const drawinglayer::primitive3d::Primitive3DReference xReference(
+ new drawinglayer::primitive3d::TransformPrimitive3D(
+ rObjectTransform,
+ xRetval));
+
+ xRetval = { xReference };
+ }
+ }
+
+ // return current Primitive2DContainer
+ return xRetval;
+}
+
+void ViewContactOfE3d::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // also need to create a 2D embedding when the view-independent part is requested,
+ // see view-dependent part in ViewObjectContactOfE3d::createPrimitive2DSequence
+ // get 3d primitive vector, isPrimitiveVisible() is done in 3d creator
+ return rVisitor.visit(impCreateWithGivenPrimitive3DContainer(getViewIndependentPrimitive3DContainer()));
+}
+
+ViewObjectContact& ViewContactOfE3d::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfE3d(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContactOfE3d::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofe3dcube.cxx b/svx/source/sdr/contact/viewcontactofe3dcube.cxx
new file mode 100644
index 000000000..2687aab32
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3dcube.cxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofe3dcube.hxx>
+#include <svx/cube3d.hxx>
+#include <drawinglayer/primitive3d/sdrcubeprimitive3d.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive3d/sdrattributecreator3d.hxx>
+#include <basegfx/range/b3drange.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfE3dCube::ViewContactOfE3dCube(E3dCubeObj& rCubeObj)
+ : ViewContactOfE3d(rCubeObj)
+ {
+ }
+
+ ViewContactOfE3dCube::~ViewContactOfE3dCube()
+ {
+ }
+
+ drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3dCube::createViewIndependentPrimitive3DContainer() const
+ {
+ drawinglayer::primitive3d::Primitive3DContainer xRetval;
+ const SfxItemSet& rItemSet = GetE3dCubeObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillShadowAttribute3D aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillShadowAttribute(rItemSet, false));
+
+ // get cube geometry and use as translation and scaling for unit cube
+ basegfx::B3DRange aCubeRange;
+ const basegfx::B3DVector aCubeSize(GetE3dCubeObj().GetCubeSize());
+ const basegfx::B3DPoint aCubePosition(GetE3dCubeObj().GetCubePos());
+ basegfx::B3DHomMatrix aWorldTransform;
+
+ if(GetE3dCubeObj().GetPosIsCenter())
+ {
+ const basegfx::B3DVector aHalfCubeSize(aCubeSize / 2.0);
+ aCubeRange.expand(aCubePosition - aHalfCubeSize);
+ aCubeRange.expand(aCubePosition + aHalfCubeSize);
+ }
+ else
+ {
+ aCubeRange.expand(aCubePosition);
+ aCubeRange.expand(aCubePosition + aCubeSize);
+ }
+
+ // add scale and translate to world transformation
+ const basegfx::B3DVector abjectRange(aCubeRange.getRange());
+ aWorldTransform.scale(abjectRange.getX(), abjectRange.getY(), abjectRange.getZ());
+ aWorldTransform.translate(aCubeRange.getMinX(), aCubeRange.getMinY(), aCubeRange.getMinZ());
+
+ // get 3D Object Attributes
+ drawinglayer::attribute::Sdr3DObjectAttribute aSdr3DObjectAttribute(drawinglayer::primitive2d::createNewSdr3DObjectAttribute(rItemSet));
+
+ // calculate texture size to get a perfect mapping for
+ // the front/back sides
+ const basegfx::B2DVector aTextureSize(aCubeSize.getX(), aCubeSize.getY());
+
+ // create primitive and add
+ const drawinglayer::primitive3d::Primitive3DReference xReference(
+ new drawinglayer::primitive3d::SdrCubePrimitive3D(
+ aWorldTransform, aTextureSize, aAttribute, aSdr3DObjectAttribute));
+ xRetval = { xReference };
+
+ return xRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofe3dextrude.cxx b/svx/source/sdr/contact/viewcontactofe3dextrude.cxx
new file mode 100644
index 000000000..71100ae34
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3dextrude.cxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofe3dextrude.hxx>
+#include <extrud3d.hxx>
+#include <drawinglayer/primitive3d/sdrextrudeprimitive3d.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive3d/sdrattributecreator3d.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfE3dExtrude::ViewContactOfE3dExtrude(E3dExtrudeObj& rExtrude)
+ : ViewContactOfE3d(rExtrude)
+ {
+ }
+
+ ViewContactOfE3dExtrude::~ViewContactOfE3dExtrude()
+ {
+ }
+
+ drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3dExtrude::createViewIndependentPrimitive3DContainer() const
+ {
+ drawinglayer::primitive3d::Primitive3DContainer xRetval;
+ const SfxItemSet& rItemSet = GetE3dExtrudeObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillShadowAttribute3D aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillShadowAttribute(rItemSet, false));
+
+ // get extrude geometry
+ const basegfx::B2DPolyPolygon aPolyPolygon(GetE3dExtrudeObj().GetExtrudePolygon());
+
+ // get 3D Object Attributes
+ drawinglayer::attribute::Sdr3DObjectAttribute aSdr3DObjectAttribute(drawinglayer::primitive2d::createNewSdr3DObjectAttribute(rItemSet));
+
+ // calculate texture size; use size of top/bottom cap to get a perfect mapping
+ // for the caps. The in-between geometry will get a stretched size with a
+ // relative factor size of caps to extrude depth
+ const basegfx::B2DRange aRange(basegfx::utils::getRange(aPolyPolygon));
+ const basegfx::B2DVector aTextureSize(aRange.getWidth(), aRange.getHeight());
+
+ // get more data
+ const double fDepth(static_cast<double>(GetE3dExtrudeObj().GetExtrudeDepth()));
+ const double fDiagonal(static_cast<double>(GetE3dExtrudeObj().GetPercentDiagonal()) / 100.0);
+ const double fBackScale(static_cast<double>(GetE3dExtrudeObj().GetPercentBackScale()) / 100.0);
+ const bool bSmoothNormals(GetE3dExtrudeObj().GetSmoothNormals()); // Plane itself
+ const bool bSmoothLids(GetE3dExtrudeObj().GetSmoothLids()); // Front/back
+ const bool bCharacterMode(GetE3dExtrudeObj().GetCharacterMode());
+ const bool bCloseFront(GetE3dExtrudeObj().GetCloseFront());
+ const bool bCloseBack(GetE3dExtrudeObj().GetCloseBack());
+
+ // create primitive and add
+ const basegfx::B3DHomMatrix aWorldTransform;
+ const drawinglayer::primitive3d::Primitive3DReference xReference(
+ new drawinglayer::primitive3d::SdrExtrudePrimitive3D(
+ aWorldTransform, aTextureSize, aAttribute, aSdr3DObjectAttribute,
+ aPolyPolygon, fDepth, fDiagonal, fBackScale, bSmoothNormals, bSmoothLids,
+ bCharacterMode, bCloseFront, bCloseBack));
+ xRetval = { xReference };
+
+ return xRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofe3dlathe.cxx b/svx/source/sdr/contact/viewcontactofe3dlathe.cxx
new file mode 100644
index 000000000..a3e7086b8
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3dlathe.cxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofe3dlathe.hxx>
+#include <svx/lathe3d.hxx>
+#include <drawinglayer/primitive3d/sdrlatheprimitive3d.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive3d/sdrattributecreator3d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfE3dLathe::ViewContactOfE3dLathe(E3dLatheObj& rLathe)
+ : ViewContactOfE3d(rLathe)
+ {
+ }
+
+ ViewContactOfE3dLathe::~ViewContactOfE3dLathe()
+ {
+ }
+
+ drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3dLathe::createViewIndependentPrimitive3DContainer() const
+ {
+ drawinglayer::primitive3d::Primitive3DContainer xRetval;
+ const SfxItemSet& rItemSet = GetE3dLatheObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillShadowAttribute3D aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillShadowAttribute(rItemSet, false));
+
+ // get extrude geometry
+ const basegfx::B2DPolyPolygon aPolyPolygon(GetE3dLatheObj().GetPolyPoly2D());
+
+ // get 3D Object Attributes
+ drawinglayer::attribute::Sdr3DObjectAttribute aSdr3DObjectAttribute(drawinglayer::primitive2d::createNewSdr3DObjectAttribute(rItemSet));
+
+ // calculate texture size. Use the polygon length of the longest polygon for
+ // height and the rotated radius for width (using polygon center) to get a good
+ // texture mapping
+ double fPolygonMaxLength(0.0);
+
+ for(auto const& rCandidate : aPolyPolygon)
+ {
+ const double fPolygonLength(basegfx::utils::getLength(rCandidate));
+ fPolygonMaxLength = std::max(fPolygonMaxLength, fPolygonLength);
+ }
+
+ const basegfx::B2DRange aPolyPolygonRange(basegfx::utils::getRange(aPolyPolygon));
+ const basegfx::B2DVector aTextureSize(
+ M_PI * fabs(aPolyPolygonRange.getCenter().getX()), // PI * d
+ fPolygonMaxLength);
+
+ // get more data
+ const sal_uInt32 nHorizontalSegments(GetE3dLatheObj().GetHorizontalSegments());
+ const sal_uInt32 nVerticalSegments(GetE3dLatheObj().GetVerticalSegments());
+ const double fDiagonal(static_cast<double>(GetE3dLatheObj().GetPercentDiagonal()) / 100.0);
+ const double fBackScale(static_cast<double>(GetE3dLatheObj().GetBackScale()) / 100.0);
+ const double fRotation(basegfx::deg2rad<10>(GetE3dLatheObj().GetEndAngle()));
+ const bool bSmoothNormals(GetE3dLatheObj().GetSmoothNormals()); // Plane itself
+ const bool bSmoothLids(GetE3dLatheObj().GetSmoothLids()); // Front/back
+ const bool bCharacterMode(GetE3dLatheObj().GetCharacterMode());
+ const bool bCloseFront(GetE3dLatheObj().GetCloseFront());
+ const bool bCloseBack(GetE3dLatheObj().GetCloseBack());
+
+ // create primitive and add
+ const basegfx::B3DHomMatrix aWorldTransform;
+ const drawinglayer::primitive3d::Primitive3DReference xReference(
+ new drawinglayer::primitive3d::SdrLathePrimitive3D(
+ aWorldTransform, aTextureSize, aAttribute, aSdr3DObjectAttribute,
+ aPolyPolygon, nHorizontalSegments, nVerticalSegments,
+ fDiagonal, fBackScale, fRotation,
+ bSmoothNormals, bSmoothLids, bCharacterMode, bCloseFront, bCloseBack));
+ xRetval = { xReference };
+
+ return xRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofe3dpolygon.cxx b/svx/source/sdr/contact/viewcontactofe3dpolygon.cxx
new file mode 100644
index 000000000..2951ead56
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3dpolygon.cxx
@@ -0,0 +1,169 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofe3dpolygon.hxx>
+#include <polygn3d.hxx>
+#include <drawinglayer/primitive3d/sdrpolypolygonprimitive3d.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive3d/sdrattributecreator3d.hxx>
+#include <basegfx/polygon/b3dpolygon.hxx>
+#include <basegfx/polygon/b3dpolypolygontools.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfE3dPolygon::ViewContactOfE3dPolygon(E3dPolygonObj& rPolygon)
+ : ViewContactOfE3d(rPolygon)
+ {
+ }
+
+ ViewContactOfE3dPolygon::~ViewContactOfE3dPolygon()
+ {
+ }
+
+ drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3dPolygon::createViewIndependentPrimitive3DContainer() const
+ {
+ drawinglayer::primitive3d::Primitive3DContainer xRetval;
+ const SfxItemSet& rItemSet = GetE3dPolygonObj().GetMergedItemSet();
+ const bool bSuppressFill(GetE3dPolygonObj().GetLineOnly());
+ const drawinglayer::attribute::SdrLineFillShadowAttribute3D aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillShadowAttribute(rItemSet, bSuppressFill));
+
+ // get extrude geometry
+ basegfx::B3DPolyPolygon aPolyPolygon3D(GetE3dPolygonObj().GetPolyPolygon3D());
+ const basegfx::B3DPolyPolygon aPolyNormals3D(GetE3dPolygonObj().GetPolyNormals3D());
+ const basegfx::B2DPolyPolygon aPolyTexture2D(GetE3dPolygonObj().GetPolyTexture2D());
+ const bool bNormals(aPolyNormals3D.count() && aPolyNormals3D.count() == aPolyPolygon3D.count());
+ const bool bTexture(aPolyTexture2D.count() && aPolyTexture2D.count() == aPolyPolygon3D.count());
+
+ if(bNormals || bTexture)
+ {
+ for(sal_uInt32 a(0); a < aPolyPolygon3D.count(); a++)
+ {
+ basegfx::B3DPolygon aCandidate3D(aPolyPolygon3D.getB3DPolygon(a));
+ basegfx::B3DPolygon aNormals3D;
+ basegfx::B2DPolygon aTexture2D;
+
+ if(bNormals)
+ {
+ aNormals3D = aPolyNormals3D.getB3DPolygon(a);
+ }
+
+ if(bTexture)
+ {
+ aTexture2D = aPolyTexture2D.getB2DPolygon(a);
+ }
+
+ for(sal_uInt32 b(0); b < aCandidate3D.count(); b++)
+ {
+ if(bNormals)
+ {
+ sal_uInt32 nNormalCount = aNormals3D.count();
+ if( b < nNormalCount )
+ aCandidate3D.setNormal(b, aNormals3D.getB3DPoint(b));
+ else if( nNormalCount > 0 )
+ aCandidate3D.setNormal(b, aNormals3D.getB3DPoint(0));
+ }
+ if(bTexture)
+ {
+ sal_uInt32 nTextureCount = aTexture2D.count();
+ if( b < nTextureCount )
+ aCandidate3D.setTextureCoordinate(b, aTexture2D.getB2DPoint(b));
+ else if( nTextureCount > 0 )
+ aCandidate3D.setTextureCoordinate(b, aTexture2D.getB2DPoint(0));
+ }
+ }
+
+ aPolyPolygon3D.setB3DPolygon(a, aCandidate3D);
+ }
+ }
+
+ // get 3D Object Attributes
+ drawinglayer::attribute::Sdr3DObjectAttribute aSdr3DObjectAttribute(drawinglayer::primitive2d::createNewSdr3DObjectAttribute(rItemSet));
+
+ // calculate texture size
+ basegfx::B2DVector aTextureSize(1.0, 1.0);
+
+ if(bTexture)
+ {
+ // #i98314#
+ // create texture size from object's size
+ const basegfx::B3DRange aObjectRange(basegfx::utils::getRange(aPolyPolygon3D));
+
+ double fWidth(0.0);
+ double fHeight(0.0);
+
+ // this is a polygon object, so Width/Height and/or Depth may be zero (e.g. left
+ // wall of chart). Take this into account
+ if(basegfx::fTools::equalZero(aObjectRange.getWidth()))
+ {
+ // width is zero, use height and depth
+ fWidth = aObjectRange.getHeight();
+ fHeight = aObjectRange.getDepth();
+ }
+ else if(basegfx::fTools::equalZero(aObjectRange.getHeight()))
+ {
+ // height is zero, use width and depth
+ fWidth = aObjectRange.getWidth();
+ fHeight = aObjectRange.getDepth();
+ }
+ else
+ {
+ // use width and height
+ fWidth = aObjectRange.getWidth();
+ fHeight = aObjectRange.getHeight();
+ }
+
+ if(basegfx::fTools::lessOrEqual(fWidth, 0.0) ||basegfx::fTools::lessOrEqual(fHeight, 0.0))
+ {
+ // no texture; fallback to very small size
+ aTextureSize.setX(0.01);
+ aTextureSize.setY(0.01);
+ }
+ else
+ {
+ aTextureSize.setX(fWidth);
+ aTextureSize.setY(fHeight);
+ }
+ }
+
+ // #i98295#
+ // unfortunately, this SdrObject type which allows a free 3d geometry definition was defined
+ // wrong topologically in relation to its plane normal and 3D visibility when it was invented
+ // a long time ago. Since the API allows creation of this SDrObject type, it is not possible to
+ // simply change this definition. Only the chart should use it, and at least this object type
+ // only exists at Runtime (is not saved and/or loaded in any FileFormat). Still someone external
+ // may have used it in its API. To not risk wrong 3D lightings, I have to switch the orientation
+ // of the polygon here
+ aPolyPolygon3D.flip();
+
+ // create primitive and add
+ const basegfx::B3DHomMatrix aWorldTransform;
+ const drawinglayer::primitive3d::Primitive3DReference xReference(
+ new drawinglayer::primitive3d::SdrPolyPolygonPrimitive3D(
+ aPolyPolygon3D, aWorldTransform, aTextureSize, aAttribute, aSdr3DObjectAttribute));
+ xRetval = { xReference };
+
+ return xRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofe3dscene.cxx b/svx/source/sdr/contact/viewcontactofe3dscene.cxx
new file mode 100644
index 000000000..6bae55263
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3dscene.cxx
@@ -0,0 +1,446 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/contact/viewobjectcontactofe3dscene.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/range/b3drange.hxx>
+#include <drawinglayer/primitive3d/baseprimitive3d.hxx>
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <drawinglayer/primitive2d/sceneprimitive2d.hxx>
+#include <drawinglayer/primitive3d/transformprimitive3d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+
+using namespace com::sun::star;
+
+namespace {
+
+// pActiveVC is only true if ghosted is still activated and maybe needs to be switched off in this path
+void createSubPrimitive3DVector(
+ const sdr::contact::ViewContact& rCandidate,
+ drawinglayer::primitive3d::Primitive3DContainer& o_rAllTarget,
+ drawinglayer::primitive3d::Primitive3DContainer* o_pVisibleTarget,
+ const SdrLayerIDSet* pVisibleSdrLayerIDSet,
+ const bool bTestSelectedVisibility)
+{
+ const sdr::contact::ViewContactOfE3dScene* pViewContactOfE3dScene = dynamic_cast< const sdr::contact::ViewContactOfE3dScene* >(&rCandidate);
+
+ if(pViewContactOfE3dScene)
+ {
+ const sal_uInt32 nChildrenCount(rCandidate.GetObjectCount());
+
+ if(nChildrenCount)
+ {
+ // provide new collection sequences
+ drawinglayer::primitive3d::Primitive3DContainer aNewAllTarget;
+ drawinglayer::primitive3d::Primitive3DContainer aNewVisibleTarget;
+
+ // add children recursively
+ for(sal_uInt32 a(0); a < nChildrenCount; a++)
+ {
+ createSubPrimitive3DVector(
+ rCandidate.GetViewContact(a),
+ aNewAllTarget,
+ o_pVisibleTarget ? &aNewVisibleTarget : nullptr,
+ pVisibleSdrLayerIDSet,
+ bTestSelectedVisibility);
+ }
+
+ // create transform primitive for the created content combining content and transformtion
+ const drawinglayer::primitive3d::Primitive3DReference xReference(new drawinglayer::primitive3d::TransformPrimitive3D(
+ pViewContactOfE3dScene->GetE3dScene().GetTransform(),
+ aNewAllTarget));
+
+ // add created content to all target
+ o_rAllTarget.push_back(xReference);
+
+ // add created content to visible target if exists
+ if(o_pVisibleTarget)
+ {
+ o_pVisibleTarget->push_back(xReference);
+ }
+ }
+ }
+ else
+ {
+ // access view independent representation of rCandidate
+ const sdr::contact::ViewContactOfE3d* pViewContactOfE3d = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&rCandidate);
+
+ if(pViewContactOfE3d)
+ {
+ drawinglayer::primitive3d::Primitive3DContainer xPrimitive3DSeq(pViewContactOfE3d->getViewIndependentPrimitive3DContainer());
+
+ if(!xPrimitive3DSeq.empty())
+ {
+ // add to all target vector
+ o_rAllTarget.append(xPrimitive3DSeq);
+
+ if(o_pVisibleTarget)
+ {
+ // test visibility. Primitive is visible when both tests are true (AND)
+ bool bVisible(true);
+
+ if(pVisibleSdrLayerIDSet)
+ {
+ // test layer visibility
+ const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject();
+ const SdrLayerID aLayerID(rE3dObject.GetLayer());
+
+ bVisible = pVisibleSdrLayerIDSet->IsSet(aLayerID);
+ }
+
+ if(bVisible && bTestSelectedVisibility)
+ {
+ // test selected visibility (see 3D View's DrawMarkedObj implementation)
+ const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject();
+
+ bVisible = rE3dObject.GetSelected();
+ }
+
+ if (bVisible)
+ {
+ // add to visible target vector
+ o_pVisibleTarget->append(xPrimitive3DSeq);
+ }
+ }
+ }
+ }
+ }
+}
+
+}
+
+namespace sdr::contact {
+
+// Create an Object-Specific ViewObjectContact, set ViewContact and
+// ObjectContact. Always needs to return something.
+ViewObjectContact& ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfE3dScene(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+ViewContactOfE3dScene::ViewContactOfE3dScene(E3dScene& rScene)
+: ViewContactOfSdrObj(rScene)
+{
+}
+
+void ViewContactOfE3dScene::createViewInformation3D(const basegfx::B3DRange& rContentRange)
+{
+ basegfx::B3DHomMatrix aTransformation;
+ basegfx::B3DHomMatrix aOrientation;
+ basegfx::B3DHomMatrix aProjection;
+ basegfx::B3DHomMatrix aDeviceToView;
+
+ // create transformation (scene as group's transformation)
+ // For historical reasons, the outmost scene's transformation is handles as part of the
+ // view transformation. This means that the BoundRect of the contained 3D Objects is
+ // without that transformation and makes it necessary to NOT add the first scene to the
+ // Primitive3DContainer of contained objects.
+ {
+ aTransformation = GetE3dScene().GetTransform();
+ }
+
+ // create orientation (world to camera coordinate system)
+ {
+ // calculate orientation from VRP, VPN and VUV
+ const B3dCamera& rSceneCamera = GetE3dScene().GetCameraSet();
+ const basegfx::B3DPoint& aVRP(rSceneCamera.GetVRP());
+ const basegfx::B3DVector& aVPN(rSceneCamera.GetVPN());
+ const basegfx::B3DVector& aVUV(rSceneCamera.GetVUV());
+
+ aOrientation.orientation(aVRP, aVPN, aVUV);
+ }
+
+ // create projection (camera coordinate system to relative 2d where X,Y and Z are [0.0 .. 1.0])
+ {
+ const basegfx::B3DHomMatrix aWorldToCamera(aOrientation * aTransformation);
+ basegfx::B3DRange aCameraRange(rContentRange);
+ aCameraRange.transform(aWorldToCamera);
+
+ // remember Z-Values, but change orientation
+ const double fMinZ(-aCameraRange.getMaxZ());
+ const double fMaxZ(-aCameraRange.getMinZ());
+
+ // construct temporary matrix from world to device. Use unit values here to measure expansion
+ basegfx::B3DHomMatrix aWorldToDevice(aWorldToCamera);
+ const drawinglayer::attribute::SdrSceneAttribute& rSdrSceneAttribute = getSdrSceneAttribute();
+
+ if(css::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode())
+ {
+ aWorldToDevice.frustum(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ);
+ }
+ else
+ {
+ aWorldToDevice.ortho(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ);
+ }
+
+ // create B3DRange in device. This will create the real used ranges
+ // in camera space. Do not use the Z-Values, though.
+ basegfx::B3DRange aDeviceRange(rContentRange);
+ aDeviceRange.transform(aWorldToDevice);
+
+ // set projection
+ if(css::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode())
+ {
+ aProjection.frustum(
+ aDeviceRange.getMinX(), aDeviceRange.getMaxX(),
+ aDeviceRange.getMinY(), aDeviceRange.getMaxY(),
+ fMinZ, fMaxZ);
+ }
+ else
+ {
+ aProjection.ortho(
+ aDeviceRange.getMinX(), aDeviceRange.getMaxX(),
+ aDeviceRange.getMinY(), aDeviceRange.getMaxY(),
+ fMinZ, fMaxZ);
+ }
+ }
+
+ // create device to view transform
+ {
+ // create standard deviceToView projection for geometry
+ // input is [-1.0 .. 1.0] in X,Y and Z. bring to [0.0 .. 1.0]. Also
+ // necessary to flip Y due to screen orientation
+ // Z is not needed, but will also be brought to [0.0 .. 1.0]
+ aDeviceToView.scale(0.5, -0.5, 0.5);
+ aDeviceToView.translate(0.5, 0.5, 0.5);
+ }
+
+ const uno::Sequence< beans::PropertyValue > aEmptyProperties;
+ maViewInformation3D = drawinglayer::geometry::ViewInformation3D(
+ aTransformation, aOrientation, aProjection,
+ aDeviceToView, 0.0, aEmptyProperties);
+}
+
+void ViewContactOfE3dScene::createObjectTransformation()
+{
+ // create 2d Object Transformation from relative point in 2d scene to world
+ const tools::Rectangle aRectangle(GetE3dScene().GetSnapRect());
+
+ maObjectTransformation.set(0, 0, aRectangle.getWidth());
+ maObjectTransformation.set(1, 1, aRectangle.getHeight());
+ maObjectTransformation.set(0, 2, aRectangle.Left());
+ maObjectTransformation.set(1, 2, aRectangle.Top());
+}
+
+void ViewContactOfE3dScene::createSdrSceneAttribute()
+{
+ const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet();
+ maSdrSceneAttribute = drawinglayer::primitive2d::createNewSdrSceneAttribute(rItemSet);
+}
+
+void ViewContactOfE3dScene::createSdrLightingAttribute()
+{
+ const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet();
+ maSdrLightingAttribute = drawinglayer::primitive2d::createNewSdrLightingAttribute(rItemSet);
+}
+
+drawinglayer::primitive2d::Primitive2DContainer ViewContactOfE3dScene::createScenePrimitive2DSequence(
+ const SdrLayerIDSet* pLayerVisibility) const
+{
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ const sal_uInt32 nChildrenCount(GetObjectCount());
+
+ if(nChildrenCount)
+ {
+ // create 3d scene primitive with visible content tested against rLayerVisibility
+ drawinglayer::primitive3d::Primitive3DContainer aAllSequence;
+ drawinglayer::primitive3d::Primitive3DContainer aVisibleSequence;
+ const bool bTestLayerVisibility(nullptr != pLayerVisibility);
+ const bool bTestSelectedVisibility(GetE3dScene().GetDrawOnlySelected());
+ const bool bTestVisibility(bTestLayerVisibility || bTestSelectedVisibility);
+
+ // add children recursively. Do NOT start with (*this), this would create
+ // a 3D transformPrimitive for the start scene. While this is theoretically not
+ // a bad thing, for historical reasons the transformation of the outmost scene
+ // is seen as part of the ViewTransformation (see text in createViewInformation3D)
+ for(sal_uInt32 a(0); a < nChildrenCount; a++)
+ {
+ createSubPrimitive3DVector(
+ GetViewContact(a),
+ aAllSequence,
+ bTestLayerVisibility ? &aVisibleSequence : nullptr,
+ bTestLayerVisibility ? pLayerVisibility : nullptr,
+ bTestSelectedVisibility);
+ }
+
+ const size_t nAllSize(!aAllSequence.empty() ? aAllSequence.size() : 0);
+ const size_t nVisibleSize(!aVisibleSequence.empty() ? aVisibleSequence.size() : 0);
+
+ if((bTestVisibility && nVisibleSize) || nAllSize)
+ {
+ // for getting the 3D range using getB3DRangeFromPrimitive3DContainer a ViewInformation3D
+ // needs to be given for evtl. decompositions. At the same time createViewInformation3D
+ // currently is based on creating the target-ViewInformation3D using a given range. To
+ // get the true range, use a neutral ViewInformation3D here. This leaves all matrices
+ // on identity and the time on 0.0.
+ const uno::Sequence< beans::PropertyValue > aEmptyProperties;
+ const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties);
+ const basegfx::B3DRange aContentRange(aAllSequence.getB3DRange(aNeutralViewInformation3D));
+
+ // create 2d primitive 3dscene with generated sub-list from collector
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::ScenePrimitive2D(
+ bTestVisibility ? aVisibleSequence : aAllSequence,
+ getSdrSceneAttribute(),
+ getSdrLightingAttribute(),
+ getObjectTransformation(),
+ getViewInformation3D(aContentRange)));
+
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer{ xReference };
+ }
+ }
+
+ // always append an invisible outline for the cases where no visible content exists
+ xRetval.push_back(
+ drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
+ getObjectTransformation()));
+
+ return xRetval;
+}
+
+void ViewContactOfE3dScene::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ if(GetObjectCount())
+ {
+ // create a default ScenePrimitive2D (without visibility test of members)
+ rVisitor.visit(createScenePrimitive2DSequence(nullptr));
+ }
+}
+
+void ViewContactOfE3dScene::ActionChanged()
+{
+ // call parent
+ ViewContactOfSdrObj::ActionChanged();
+
+ // mark locally cached values as invalid
+ maViewInformation3D = drawinglayer::geometry::ViewInformation3D();
+ maObjectTransformation.identity();
+ maSdrSceneAttribute = drawinglayer::attribute::SdrSceneAttribute();
+ maSdrLightingAttribute = drawinglayer::attribute::SdrLightingAttribute();
+}
+
+const drawinglayer::geometry::ViewInformation3D& ViewContactOfE3dScene::getViewInformation3D() const
+{
+ if(maViewInformation3D.isDefault())
+ {
+ // this version will create the content range on demand locally and thus is less
+ // performant than the other one. Since the information is buffered the planned
+ // behaviour is that the version with the given range is used initially.
+ basegfx::B3DRange aContentRange(getAllContentRange3D());
+
+ if(aContentRange.isEmpty())
+ {
+ // empty scene, no 3d action should be necessary. Prepare some
+ // fallback size
+ OSL_FAIL("No need to get ViewInformation3D from an empty scene (!)");
+ aContentRange.expand(basegfx::B3DPoint(-100.0, -100.0, -100.0));
+ aContentRange.expand(basegfx::B3DPoint( 100.0, 100.0, 100.0));
+ }
+
+ const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(aContentRange);
+ }
+
+ return maViewInformation3D;
+}
+
+const drawinglayer::geometry::ViewInformation3D& ViewContactOfE3dScene::getViewInformation3D(const basegfx::B3DRange& rContentRange) const
+{
+ if(maViewInformation3D.isDefault())
+ {
+ const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(rContentRange);
+ }
+
+ return maViewInformation3D;
+}
+
+const basegfx::B2DHomMatrix& ViewContactOfE3dScene::getObjectTransformation() const
+{
+ if(maObjectTransformation.isIdentity())
+ {
+ const_cast < ViewContactOfE3dScene* >(this)->createObjectTransformation();
+ }
+
+ return maObjectTransformation;
+}
+
+const drawinglayer::attribute::SdrSceneAttribute& ViewContactOfE3dScene::getSdrSceneAttribute() const
+{
+ if(maSdrSceneAttribute.isDefault())
+ {
+ const_cast < ViewContactOfE3dScene* >(this)->createSdrSceneAttribute();
+ }
+
+ return maSdrSceneAttribute;
+}
+
+const drawinglayer::attribute::SdrLightingAttribute& ViewContactOfE3dScene::getSdrLightingAttribute() const
+{
+ if(maSdrLightingAttribute.isDefault())
+ {
+ const_cast < ViewContactOfE3dScene* >(this)->createSdrLightingAttribute();
+ }
+
+ return maSdrLightingAttribute;
+}
+
+drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3dScene::getAllPrimitive3DContainer() const
+{
+ drawinglayer::primitive3d::Primitive3DContainer aAllPrimitive3DContainer;
+ const sal_uInt32 nChildrenCount(GetObjectCount());
+
+ // add children recursively. Do NOT start with (*this), this would create
+ // a 3D transformPrimitive for the start scene. While this is theoretically not
+ // a bad thing, for historical reasons the transformation of the outmost scene
+ // is seen as part of the ViewTransformation (see text in createViewInformation3D)
+ for(sal_uInt32 a(0); a < nChildrenCount; a++)
+ {
+ createSubPrimitive3DVector(GetViewContact(a), aAllPrimitive3DContainer, nullptr, nullptr, false);
+ }
+
+ return aAllPrimitive3DContainer;
+}
+
+basegfx::B3DRange ViewContactOfE3dScene::getAllContentRange3D() const
+{
+ const drawinglayer::primitive3d::Primitive3DContainer xAllSequence(getAllPrimitive3DContainer());
+ basegfx::B3DRange aAllContentRange3D;
+
+ if(!xAllSequence.empty())
+ {
+ // for getting the 3D range using getB3DRangeFromPrimitive3DContainer a ViewInformation3D
+ // needs to be given for evtl. decompositions. Use a neutral ViewInformation3D here. This
+ // leaves all matrices on identity and the time on 0.0.
+ const uno::Sequence< beans::PropertyValue > aEmptyProperties;
+ const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties);
+
+ aAllContentRange3D = xAllSequence.getB3DRange(aNeutralViewInformation3D);
+ }
+
+ return aAllContentRange3D;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofe3dsphere.cxx b/svx/source/sdr/contact/viewcontactofe3dsphere.cxx
new file mode 100644
index 000000000..7a99719b8
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3dsphere.cxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofe3dsphere.hxx>
+#include <svx/sphere3d.hxx>
+#include <drawinglayer/primitive3d/sdrsphereprimitive3d.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive3d/sdrattributecreator3d.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfE3dSphere::ViewContactOfE3dSphere(E3dSphereObj& rSphere)
+ : ViewContactOfE3d(rSphere)
+ {
+ }
+
+ ViewContactOfE3dSphere::~ViewContactOfE3dSphere()
+ {
+ }
+
+ drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3dSphere::createViewIndependentPrimitive3DContainer() const
+ {
+ drawinglayer::primitive3d::Primitive3DContainer xRetval;
+ const SfxItemSet& rItemSet = GetE3dSphereObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillShadowAttribute3D aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillShadowAttribute(rItemSet, false));
+
+ // get sphere center and size for geometry
+ const basegfx::B3DPoint aSpherePosition(GetE3dSphereObj().Center());
+ const basegfx::B3DVector aSphereSize(GetE3dSphereObj().Size());
+ basegfx::B3DHomMatrix aWorldTransform;
+
+ aWorldTransform.translate(-0.5, -0.5, -0.5);
+ aWorldTransform.scale(aSphereSize.getX(), aSphereSize.getY(), aSphereSize.getZ());
+ aWorldTransform.translate(aSpherePosition.getX(), aSpherePosition.getY(), aSpherePosition.getZ());
+
+ // get 3D Object Attributes
+ drawinglayer::attribute::Sdr3DObjectAttribute aSdr3DObjectAttribute(drawinglayer::primitive2d::createNewSdr3DObjectAttribute(rItemSet));
+
+ // get segment count
+ const sal_uInt32 nHorizontalSegments(GetE3dSphereObj().GetHorizontalSegments());
+ const sal_uInt32 nVerticalSegments(GetE3dSphereObj().GetVerticalSegments());
+
+ // calculate texture size, use radii for (2 * PI * r) to get a perfect
+ // mapping on the sphere
+ const basegfx::B2DVector aTextureSize(
+ M_PI * ((aSphereSize.getX() + aSphereSize.getZ()) / 2.0), // PI * d
+ M_PI_2 * aSphereSize.getY()); // half outline, (PI * d)/2 -> PI/2 * d
+
+ // create primitive and add
+ const drawinglayer::primitive3d::Primitive3DReference xReference(
+ new drawinglayer::primitive3d::SdrSpherePrimitive3D(
+ aWorldTransform, aTextureSize, aAttribute, aSdr3DObjectAttribute,
+ nHorizontalSegments, nVerticalSegments));
+ xRetval = { xReference };
+
+ return xRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofgraphic.cxx b/svx/source/sdr/contact/viewcontactofgraphic.cxx
new file mode 100644
index 000000000..6428e5a66
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofgraphic.cxx
@@ -0,0 +1,391 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofgraphic.hxx>
+#include <sdr/contact/viewobjectcontactofgraphic.hxx>
+#include <svx/svdograf.hxx>
+#include <sdgtritm.hxx>
+#include <svx/sdgluitm.hxx>
+#include <sdgcoitm.hxx>
+#include <svx/sdggaitm.hxx>
+#include <sdginitm.hxx>
+#include <svx/sdgmoitm.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <svl/itemset.hxx>
+#include <tools/debug.hxx>
+
+#include <svx/sdgcpitm.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <sdr/primitive2d/sdrgrafprimitive2d.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <sdr/primitive2d/sdrtextprimitive2d.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/colritem.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+#include <bitmaps.hlst>
+
+namespace sdr::contact
+{
+ // Create an Object-Specific ViewObjectContact, set ViewContact and
+ // ObjectContact. Always needs to return something.
+ ViewObjectContact& ViewContactOfGraphic::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+ {
+ ViewObjectContact* pRetval = new ViewObjectContactOfGraphic(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+ }
+
+ ViewContactOfGraphic::ViewContactOfGraphic(SdrGrafObj& rGrafObj)
+ : ViewContactOfTextObj(rGrafObj)
+ {
+ }
+
+ ViewContactOfGraphic::~ViewContactOfGraphic()
+ {
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer ViewContactOfGraphic::createVIP2DSForPresObj(
+ const basegfx::B2DHomMatrix& rObjectMatrix,
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute& rAttribute) const
+ {
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ GraphicObject aEmptyGraphicObject;
+ GraphicAttr aEmptyGraphicAttr;
+
+ // SdrGrafPrimitive2D without content in original size which carries all eventual attributes and texts
+ const drawinglayer::primitive2d::Primitive2DReference xReferenceA(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
+ rObjectMatrix,
+ rAttribute,
+ aEmptyGraphicObject,
+ aEmptyGraphicAttr));
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReferenceA };
+
+ // SdrGrafPrimitive2D with content (which is the preview graphic) scaled to smaller size and
+ // without attributes
+ basegfx::B2DHomMatrix aSmallerMatrix;
+
+ // #i94431# for some reason, i forgot to take the PrefMapMode of the graphic
+ // into account. Since EmptyPresObj's are only used in Draw/Impress, it is
+ // safe to assume 100th mm as target.
+ Size aPrefSize(GetGrafObject().GetGrafPrefSize());
+
+ if(MapUnit::MapPixel == GetGrafObject().GetGrafPrefMapMode().GetMapUnit())
+ {
+ aPrefSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM));
+ }
+ else
+ {
+ aPrefSize = OutputDevice::LogicToLogic(aPrefSize, GetGrafObject().GetGrafPrefMapMode(), MapMode(MapUnit::Map100thMM));
+ }
+
+ // decompose object matrix to get single values
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ const double fOffsetX((aScale.getX() - aPrefSize.getWidth()) / 2.0);
+ const double fOffsetY((aScale.getY() - aPrefSize.getHeight()) / 2.0);
+
+ if(basegfx::fTools::moreOrEqual(fOffsetX, 0.0) && basegfx::fTools::moreOrEqual(fOffsetY, 0.0))
+ {
+ // create the EmptyPresObj fallback visualisation. The fallback graphic
+ // is already provided in rGraphicObject in this case, use it
+ aSmallerMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(aPrefSize.getWidth(), aPrefSize.getHeight(), fOffsetX, fOffsetY);
+ aSmallerMatrix = basegfx::utils::createShearXRotateTranslateB2DHomMatrix(fShearX, fRotate, aTranslate)
+ * aSmallerMatrix;
+
+ const GraphicObject& rGraphicObject = GetGrafObject().GetGraphicObject();
+ const GraphicAttr aLocalGrafInfo;
+ const drawinglayer::primitive2d::Primitive2DReference xReferenceB(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
+ aSmallerMatrix,
+ drawinglayer::attribute::SdrLineFillEffectsTextAttribute(),
+ rGraphicObject,
+ aLocalGrafInfo));
+
+ xRetval.push_back(xReferenceB);
+ }
+
+ return xRetval;
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer ViewContactOfGraphic::createVIP2DSForDraft(
+ const basegfx::B2DHomMatrix& rObjectMatrix,
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute& rAttribute) const
+ {
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ GraphicObject aEmptyGraphicObject;
+ GraphicAttr aEmptyGraphicAttr;
+
+ // SdrGrafPrimitive2D without content in original size which carries all eventual attributes and texts
+ const drawinglayer::primitive2d::Primitive2DReference xReferenceA(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
+ rObjectMatrix,
+ rAttribute,
+ aEmptyGraphicObject,
+ aEmptyGraphicAttr));
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReferenceA };
+
+ if(rAttribute.getLine().isDefault())
+ {
+ // create a surrounding frame when no linestyle given
+ const Color aColor(Application::GetSettings().GetStyleSettings().GetShadowColor());
+ const basegfx::BColor aBColor(aColor.getBColor());
+ basegfx::B2DPolygon aOutline(basegfx::utils::createUnitPolygon());
+ aOutline.transform(rObjectMatrix);
+
+ xRetval.push_back(
+ drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ aOutline,
+ aBColor)));
+ }
+
+ // decompose object matrix to get single values
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // define a distance value, used for distance from bitmap to borders and from bitmap
+ // to text, too (2 mm)
+ const double fDistance(200.0);
+
+ // consume borders from values
+ aScale.setX(std::max(0.0, aScale.getX() - (2.0 * fDistance)));
+ aScale.setY(std::max(0.0, aScale.getY() - (2.0 * fDistance)));
+ aTranslate.setX(aTranslate.getX() + fDistance);
+ aTranslate.setY(aTranslate.getY() + fDistance);
+
+ // draw a draft bitmap
+ const BitmapEx aDraftBitmap(BMAP_GrafikEi);
+
+ if(!aDraftBitmap.IsEmpty())
+ {
+ Size aPrefSize(aDraftBitmap.GetPrefSize());
+
+ if(MapUnit::MapPixel == aDraftBitmap.GetPrefMapMode().GetMapUnit())
+ {
+ aPrefSize = Application::GetDefaultDevice()->PixelToLogic(aDraftBitmap.GetSizePixel(), MapMode(MapUnit::Map100thMM));
+ }
+ else
+ {
+ aPrefSize = OutputDevice::LogicToLogic(aPrefSize, aDraftBitmap.GetPrefMapMode(), MapMode(MapUnit::Map100thMM));
+ }
+
+ const double fBitmapScaling(2.0);
+ const double fWidth(aPrefSize.getWidth() * fBitmapScaling);
+ const double fHeight(aPrefSize.getHeight() * fBitmapScaling);
+
+ if(basegfx::fTools::more(fWidth, 1.0)
+ && basegfx::fTools::more(fHeight, 1.0)
+ && basegfx::fTools::lessOrEqual(fWidth, aScale.getX())
+ && basegfx::fTools::lessOrEqual(fHeight, aScale.getY()))
+ {
+ const basegfx::B2DHomMatrix aBitmapMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ fWidth, fHeight, fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
+
+ xRetval.push_back(
+ drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::BitmapPrimitive2D(
+ VCLUnoHelper::CreateVCLXBitmap(aDraftBitmap),
+ aBitmapMatrix)));
+
+ // consume bitmap size in X
+ aScale.setX(std::max(0.0, aScale.getX() - (fWidth + fDistance)));
+ aTranslate.setX(aTranslate.getX() + fWidth + fDistance);
+ }
+ }
+
+ // Build the text for the draft object
+ OUString aDraftText = GetGrafObject().GetFileName();
+
+ if (aDraftText.isEmpty())
+ {
+ aDraftText = GetGrafObject().GetName() + " ...";
+ }
+
+ if (!aDraftText.isEmpty())
+ {
+ // #i103255# Goal is to produce TextPrimitives which hold the given text as
+ // BlockText in the available space. It would be very tricky to do
+ // an own word wrap/line layout here.
+ // Using SdrBlockTextPrimitive2D OTOH is critical since it internally
+ // uses the SdrObject it references. To solve this, create a temp
+ // SdrObject with Attributes and Text, generate a SdrBlockTextPrimitive2D
+ // directly and immediately decompose it. After that, it is no longer
+ // needed and can be deleted.
+
+ // create temp RectObj as TextObj and set needed attributes
+ SdrRectObj* pRectObj(new SdrRectObj(GetGrafObject().getSdrModelFromSdrObject(), SdrObjKind::Text));
+ pRectObj->NbcSetText(aDraftText);
+ pRectObj->SetMergedItem(SvxColorItem(COL_LIGHTRED, EE_CHAR_COLOR));
+
+ // get SdrText and OPO
+ SdrText* pSdrText(pRectObj->getText(0));
+ OutlinerParaObject* pOPO(pRectObj->GetOutlinerParaObject());
+
+ if(pSdrText && pOPO)
+ {
+ // directly use the remaining space as TextRangeTransform
+ const basegfx::B2DHomMatrix aTextRangeTransform(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aScale, fShearX, fRotate, aTranslate));
+
+ // directly create temp SdrBlockTextPrimitive2D
+ rtl::Reference< drawinglayer::primitive2d::SdrBlockTextPrimitive2D > xBlockTextPrimitive(new drawinglayer::primitive2d::SdrBlockTextPrimitive2D(
+ pSdrText,
+ *pOPO,
+ aTextRangeTransform,
+ SDRTEXTHORZADJUST_LEFT,
+ SDRTEXTVERTADJUST_TOP,
+ false,
+ false,
+ false,
+ false));
+
+ // decompose immediately with neutral ViewInformation. This will
+ // layout the text to more simple TextPrimitives from drawinglayer
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ xBlockTextPrimitive->get2DDecomposition(xRetval, aViewInformation2D);
+ }
+
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(pRectObj);
+ SdrObject::Free(pTemp);
+ }
+
+ return xRetval;
+ }
+
+ void ViewContactOfGraphic::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const SfxItemSet& rItemSet = GetGrafObject().GetMergedItemSet();
+
+ // create and fill GraphicAttr
+ GraphicAttr aLocalGrafInfo;
+ const sal_uInt16 nTrans(rItemSet.Get(SDRATTR_GRAFTRANSPARENCE).GetValue());
+ const SdrGrafCropItem& rCrop(rItemSet.Get(SDRATTR_GRAFCROP));
+ aLocalGrafInfo.SetLuminance(rItemSet.Get(SDRATTR_GRAFLUMINANCE).GetValue());
+ aLocalGrafInfo.SetContrast(rItemSet.Get(SDRATTR_GRAFCONTRAST).GetValue());
+ aLocalGrafInfo.SetChannelR(rItemSet.Get(SDRATTR_GRAFRED).GetValue());
+ aLocalGrafInfo.SetChannelG(rItemSet.Get(SDRATTR_GRAFGREEN).GetValue());
+ aLocalGrafInfo.SetChannelB(rItemSet.Get(SDRATTR_GRAFBLUE).GetValue());
+ aLocalGrafInfo.SetGamma(rItemSet.Get(SDRATTR_GRAFGAMMA).GetValue() * 0.01);
+ aLocalGrafInfo.SetAlpha(255 - static_cast<sal_uInt8>(::basegfx::fround(std::min(nTrans, sal_uInt16(100)) * 2.55)));
+ aLocalGrafInfo.SetInvert(rItemSet.Get(SDRATTR_GRAFINVERT).GetValue());
+ aLocalGrafInfo.SetDrawMode(rItemSet.Get(SDRATTR_GRAFMODE).GetValue());
+ aLocalGrafInfo.SetCrop(rCrop.GetLeft(), rCrop.GetTop(), rCrop.GetRight(), rCrop.GetBottom());
+
+ // we have content if graphic is not completely transparent
+ const bool bHasContent(0 != aLocalGrafInfo.GetAlpha());
+ drawinglayer::attribute::SdrLineFillEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
+ rItemSet,
+ GetGrafObject().getText(0),
+ bHasContent));
+
+ // take unrotated snap rect for position and size. Directly use model data, not getBoundRect() or getSnapRect()
+ // which will use the primitive data we just create in the near future
+ const ::basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(GetGrafObject().GetGeoRect());
+
+ // look for mirroring
+ const GeoStat& rGeoStat(GetGrafObject().GetGeoStat());
+ const Degree100 nRotationAngle(rGeoStat.nRotationAngle);
+ const bool bMirrored(GetGrafObject().IsMirrored());
+
+ if (bMirrored)
+ aLocalGrafInfo.SetMirrorFlags(BmpMirrorFlags::Horizontal);
+
+ // fill object matrix
+ const double fShearX(-rGeoStat.mfTanShearAngle);
+ const double fRotate(nRotationAngle ? toRadians(36000_deg100 - nRotationAngle) : 0.0);
+ const basegfx::B2DHomMatrix aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aObjectRange.getWidth(), aObjectRange.getHeight(),
+ fShearX, fRotate,
+ aObjectRange.getMinX(), aObjectRange.getMinY()));
+
+ // get the current, unchanged graphic object from SdrGrafObj
+ const GraphicObject& rGraphicObject = GetGrafObject().GetGraphicObject();
+
+ if(visualisationUsesPresObj())
+ {
+ // it's an EmptyPresObj, create the SdrGrafPrimitive2D without content and another scaled one
+ // with the content which is the placeholder graphic
+ rVisitor.visit(createVIP2DSForPresObj(aObjectMatrix, aAttribute));
+ }
+#ifndef IOS // Enforce swap-in for tiled rendering for now, while we have no delayed updating mechanism
+ else if(visualisationUsesDraft())
+ {
+ // #i102380# The graphic is swapped out. To not force a swap-in here, there is a mechanism
+ // which shows a swapped-out-visualisation (which gets created here now) and an asynchronous
+ // visual update mechanism for swapped-out graphics when they were loaded (see AsynchGraphicLoadingEvent
+ // and ViewObjectContactOfGraphic implementation). Not forcing the swap-in here allows faster
+ // (non-blocking) processing here and thus in the effect e.g. fast scrolling through pages
+ rVisitor.visit(createVIP2DSForDraft(aObjectMatrix, aAttribute));
+ }
+#endif
+ else
+ {
+ // create primitive. Info: Calling the copy-constructor of GraphicObject in this
+ // SdrGrafPrimitive2D constructor will force a full swap-in of the graphic
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrGrafPrimitive2D(
+ aObjectMatrix,
+ aAttribute,
+ rGraphicObject,
+ aLocalGrafInfo));
+
+ rVisitor.visit(xReference);
+ }
+
+ // always append an invisible outline for the cases where no visible content exists
+ rVisitor.visit(
+ drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
+ aObjectMatrix));
+ }
+
+ bool ViewContactOfGraphic::visualisationUsesPresObj() const
+ {
+ return GetGrafObject().IsEmptyPresObj();
+ }
+
+ bool ViewContactOfGraphic::visualisationUsesDraft() const
+ {
+ // no draft when already PresObj
+ if(visualisationUsesPresObj())
+ return false;
+
+ // draft when swapped out
+ const GraphicObject& rGraphicObject = GetGrafObject().GetGraphicObject();
+
+ // draft when no graphic
+ return GraphicType::NONE == rGraphicObject.GetType() || GraphicType::Default == rGraphicObject.GetType();
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofgroup.cxx b/svx/source/sdr/contact/viewcontactofgroup.cxx
new file mode 100644
index 000000000..18e5e07aa
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofgroup.cxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofgroup.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <sdr/contact/viewobjectcontactofgroup.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <tools/debug.hxx>
+#include <vcl/canvastools.hxx>
+
+
+namespace sdr::contact
+{
+ // Create an Object-Specific ViewObjectContact, set ViewContact and
+ // ObjectContact. Always needs to return something.
+ ViewObjectContact& ViewContactOfGroup::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+ {
+ ViewObjectContact* pRetval = new ViewObjectContactOfGroup(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContactOfGroup::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+ }
+
+ ViewContactOfGroup::ViewContactOfGroup(SdrObjGroup& rGroup)
+ : ViewContactOfSdrObj(rGroup)
+ {
+ }
+
+ ViewContactOfGroup::~ViewContactOfGroup()
+ {
+ }
+
+ void ViewContactOfGroup::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const sal_uInt32 nObjectCount(GetObjectCount());
+
+ if(nObjectCount)
+ {
+ // collect all sub-primitives
+ for(sal_uInt32 a(0); a < nObjectCount; a++)
+ {
+ const ViewContact& rCandidate(GetViewContact(a));
+ rCandidate.getViewIndependentPrimitive2DContainer(rVisitor);
+ }
+ }
+ else
+ {
+ // append an invisible outline for the cases where no visible content exists
+ const basegfx::B2DRange aCurrentRange = vcl::unotools::b2DRectangleFromRectangle(GetSdrObjGroup().GetLastBoundRect());
+
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
+ false, aCurrentRange));
+
+ rVisitor.visit(xReference);
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofmasterpagedescriptor.cxx b/svx/source/sdr/contact/viewcontactofmasterpagedescriptor.cxx
new file mode 100644
index 000000000..20463d0fc
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofmasterpagedescriptor.cxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofmasterpagedescriptor.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdobj.hxx>
+#include <sdr/contact/viewobjectcontactofmasterpagedescriptor.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <drawinglayer/attribute/sdrfillattribute.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/attribute/fillgradientattribute.hxx>
+
+
+namespace sdr::contact
+{
+ ViewObjectContact& ViewContactOfMasterPageDescriptor::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+ {
+ return *(new ViewObjectContactOfMasterPageDescriptor(rObjectContact, *this));
+ }
+
+ void ViewContactOfMasterPageDescriptor::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ drawinglayer::attribute::SdrFillAttribute aFill;
+ const SdrPageProperties* pCorrectProperties = GetMasterPageDescriptor().getCorrectSdrPageProperties();
+
+ if(pCorrectProperties)
+ {
+ // create page fill attributes when correct properties were identified
+ aFill = drawinglayer::primitive2d::createNewSdrFillAttribute(pCorrectProperties->GetItemSet());
+ }
+
+ if(!aFill.isDefault())
+ {
+ // direct model data is the page size, get and use it
+ const SdrPage& rOwnerPage = GetMasterPageDescriptor().GetOwnerPage();
+ const basegfx::B2DRange aInnerRange(
+ rOwnerPage.GetLeftBorder(), rOwnerPage.GetUpperBorder(),
+ rOwnerPage.GetWidth() - rOwnerPage.GetRightBorder(),
+ rOwnerPage.GetHeight() - rOwnerPage.GetLowerBorder());
+ const basegfx::B2DRange aOuterRange(
+ 0, 0, rOwnerPage.GetWidth(), rOwnerPage.GetHeight());
+ // ??? somehow only the master page's bit is used
+ bool const isFullSize(GetMasterPageDescriptor().GetUsedPage().IsBackgroundFullSize());
+ const basegfx::B2DPolygon aFillPolygon(
+ basegfx::utils::createPolygonFromRect(isFullSize ? aOuterRange : aInnerRange));
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ drawinglayer::primitive2d::createPolyPolygonFillPrimitive(
+ basegfx::B2DPolyPolygon(aFillPolygon),
+ aFill,
+ drawinglayer::attribute::FillGradientAttribute()));
+
+ rVisitor.visit(xReference);
+ }
+ }
+
+ // basic constructor
+ ViewContactOfMasterPageDescriptor::ViewContactOfMasterPageDescriptor(sdr::MasterPageDescriptor& rDescriptor)
+ : mrMasterPageDescriptor(rDescriptor)
+ {
+ }
+
+ // The destructor.
+ ViewContactOfMasterPageDescriptor::~ViewContactOfMasterPageDescriptor()
+ {
+ }
+
+ sal_uInt32 ViewContactOfMasterPageDescriptor::GetObjectCount() const
+ {
+ return GetMasterPageDescriptor().GetUsedPage().GetObjCount();
+ }
+
+ ViewContact& ViewContactOfMasterPageDescriptor::GetViewContact(sal_uInt32 nIndex) const
+ {
+ return GetMasterPageDescriptor().GetUsedPage().GetObj(nIndex)->GetViewContact();
+ }
+
+ ViewContact* ViewContactOfMasterPageDescriptor::GetParentContact() const
+ {
+ return &(GetMasterPageDescriptor().GetOwnerPage().GetViewContact());
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofpageobj.cxx b/svx/source/sdr/contact/viewcontactofpageobj.cxx
new file mode 100644
index 000000000..ffcc18fbc
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofpageobj.cxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofpageobj.hxx>
+#include <svx/svdopage.hxx>
+#include <vcl/canvastools.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <sdr/contact/viewobjectcontactofpageobj.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+
+namespace sdr::contact
+{
+ViewObjectContact&
+ViewContactOfPageObj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfPageObj(rObjectContact, *this);
+ return *pRetval;
+}
+
+ViewContactOfPageObj::ViewContactOfPageObj(SdrPageObj& rPageObj)
+ : ViewContactOfSdrObj(rPageObj)
+{
+}
+
+ViewContactOfPageObj::~ViewContactOfPageObj() {}
+
+// #i35972# React on changes of the object of this ViewContact
+void ViewContactOfPageObj::ActionChanged()
+{
+ static bool bIsInActionChange(false);
+
+ if (!bIsInActionChange)
+ {
+ // set recursion flag, see description in *.hxx
+ bIsInActionChange = true;
+
+ // call parent
+ ViewContactOfSdrObj::ActionChanged();
+
+ // reset recursion flag, see description in *.hxx
+ bIsInActionChange = false;
+ }
+}
+
+void ViewContactOfPageObj::createViewIndependentPrimitive2DSequence(
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // create graphical visualisation data. Since this is the view-independent version which should not be used,
+ // create a replacement graphic visualisation here. Use GetLastBoundRect to access the model data directly
+ // which is aOutRect for SdrPageObj.
+ const tools::Rectangle aModelRectangle(GetPageObj().GetLastBoundRect());
+ const basegfx::B2DRange aModelRange = vcl::unotools::b2DRectangleFromRectangle(aModelRectangle);
+ const basegfx::B2DPolygon aOutline(basegfx::utils::createPolygonFromRect(aModelRange));
+ const basegfx::BColor aYellow(1.0, 1.0, 0.0);
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aYellow));
+
+ rVisitor.visit(xReference);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrcaptionobj.cxx b/svx/source/sdr/contact/viewcontactofsdrcaptionobj.cxx
new file mode 100644
index 000000000..2e668b4dd
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrcaptionobj.cxx
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofsdrcaptionobj.hxx>
+#include <svx/svdocapt.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrcaptionprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+
+// includes for special text box shadow (SC)
+
+#include <svl/itemset.hxx>
+#include <svx/xhatch.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdprcitm.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <vcl/canvastools.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr::contact
+{
+ ViewContactOfSdrCaptionObj::ViewContactOfSdrCaptionObj(SdrCaptionObj& rCaptionObj)
+ : ViewContactOfSdrRectObj(rCaptionObj)
+ {
+ }
+
+ ViewContactOfSdrCaptionObj::~ViewContactOfSdrCaptionObj()
+ {
+ }
+
+ void ViewContactOfSdrCaptionObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const SdrCaptionObj& rCaptionObj(static_cast<const SdrCaptionObj&>(GetSdrObject()));
+ const SfxItemSet& rItemSet = rCaptionObj.GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
+ rItemSet,
+ rCaptionObj.getText(0),
+ false));
+
+ // take unrotated snap rect (direct model data) for position and size
+ const tools::Rectangle aRectangle(rCaptionObj.GetGeoRect());
+ const ::basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(aRectangle);
+ const GeoStat& rGeoStat(rCaptionObj.GetGeoStat());
+
+ // fill object matrix
+ basegfx::B2DHomMatrix aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aObjectRange.getWidth(), aObjectRange.getHeight(),
+ -rGeoStat.mfTanShearAngle,
+ rGeoStat.nRotationAngle ? toRadians(36000_deg100 - rGeoStat.nRotationAngle) : 0.0,
+ aObjectRange.getMinX(), aObjectRange.getMinY()));
+
+ // calculate corner radius
+ double fCornerRadiusX;
+ double fCornerRadiusY;
+ drawinglayer::primitive2d::calculateRelativeCornerRadius(
+ rCaptionObj.GetEckenradius(), aObjectRange, fCornerRadiusX, fCornerRadiusY);
+ const basegfx::B2DPolygon aTail(rCaptionObj.getTailPolygon());
+
+ // create primitive. Always create one (even if invisible) to let the decomposition
+ // of SdrCaptionPrimitive2D create needed invisible elements for HitTest and BoundRect
+ drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrCaptionPrimitive2D(
+ aObjectMatrix,
+ aAttribute,
+ aTail,
+ fCornerRadiusX,
+ fCornerRadiusY));
+
+ if(!aAttribute.isDefault() && rCaptionObj.GetSpecialTextBoxShadow())
+ {
+ // for SC, the caption object may have a specialized shadow. The usual object shadow is off
+ // and a specialized shadow gets created here (see old paint)
+ const XColorItem& rShadColItem = rItemSet.Get(SDRATTR_SHADOWCOLOR);
+ const sal_uInt16 nShadowTransparence(rItemSet.Get(SDRATTR_SHADOWTRANSPARENCE).GetValue());
+ const Color aShadowColor(rShadColItem.GetColorValue());
+ const drawing::FillStyle eShadowStyle = rItemSet.Get(XATTR_FILLSTYLE).GetValue();
+
+ // Create own ItemSet and modify as needed
+ // Always hide lines for special calc shadow
+ SfxItemSet aSet(rItemSet);
+ aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+
+ if(drawing::FillStyle_HATCH == eShadowStyle)
+ {
+ // #41666# Hatch color is set hard to shadow color
+ XHatch aHatch = rItemSet.Get(XATTR_FILLHATCH).GetHatchValue();
+ aHatch.SetColor(aShadowColor);
+ aSet.Put(XFillHatchItem(OUString(),aHatch));
+ }
+ else
+ {
+ if(drawing::FillStyle_SOLID != eShadowStyle)
+ {
+ // force fill to solid (for Gradient, Bitmap and *no* fill (#119750# not filled comments *have* shadow))
+ aSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+ }
+
+ aSet.Put(XFillColorItem(OUString(),aShadowColor));
+ aSet.Put(XFillTransparenceItem(nShadowTransparence));
+ }
+
+ // create FillAttribute from modified ItemSet
+ const drawinglayer::attribute::SdrFillAttribute aFill(
+ drawinglayer::primitive2d::createNewSdrFillAttribute(aSet));
+ drawinglayer::primitive2d::Primitive2DReference xSpecialShadow;
+
+ if(!aFill.isDefault() && 1.0 != aFill.getTransparence())
+ {
+ // add shadow offset to object matrix
+ const sal_uInt32 nXDist(rItemSet.Get(SDRATTR_SHADOWXDIST).GetValue());
+ const sal_uInt32 nYDist(rItemSet.Get(SDRATTR_SHADOWYDIST).GetValue());
+
+ if(nXDist || nYDist)
+ {
+ // #119750# create object and shadow outline, clip shadow outline
+ // on object outline. If there is a rest, create shadow. Do this to
+ // emulate that shadow is *not* visible behind the object for
+ // transparent object fill for comments in excel
+ basegfx::B2DPolygon aObjectOutline(
+ basegfx::utils::createPolygonFromRect(
+ basegfx::B2DRange(0.0, 0.0, 1.0, 1.0),
+ fCornerRadiusX,
+ fCornerRadiusY));
+ aObjectOutline.transform(aObjectMatrix);
+
+ // create shadow outline
+ basegfx::B2DPolygon aShadowOutline(aObjectOutline);
+ aShadowOutline.transform(
+ basegfx::utils::createTranslateB2DHomMatrix(nXDist, nYDist));
+
+ // clip shadow outline against object outline
+ const basegfx::B2DPolyPolygon aClippedShadow(
+ basegfx::utils::clipPolygonOnPolyPolygon(
+ aShadowOutline,
+ basegfx::B2DPolyPolygon(aObjectOutline),
+ false, // take the outside
+ false));
+
+ if(aClippedShadow.count())
+ {
+ // if there is shadow, create the specialized shadow primitive
+ xSpecialShadow = drawinglayer::primitive2d::createPolyPolygonFillPrimitive(
+ aClippedShadow,
+ aFill,
+ drawinglayer::attribute::FillGradientAttribute());
+ }
+ }
+ }
+
+ if(xSpecialShadow.is())
+ {
+ // if we really got a special shadow, create a two-element retval with the shadow
+ // behind the standard object's geometry
+ rVisitor.visit(std::move(xSpecialShadow));
+ }
+ }
+
+ rVisitor.visit(std::move(xReference));
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrcircobj.cxx b/svx/source/sdr/contact/viewcontactofsdrcircobj.cxx
new file mode 100644
index 000000000..042d2160a
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrcircobj.cxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofsdrcircobj.hxx>
+#include <svx/svdocirc.hxx>
+#include <svx/sdangitm.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrellipseprimitive2d.hxx>
+#include <svl/itemset.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <vcl/canvastools.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfSdrCircObj::ViewContactOfSdrCircObj(SdrCircObj& rCircObj)
+ : ViewContactOfSdrRectObj(rCircObj)
+ {
+ }
+
+ ViewContactOfSdrCircObj::~ViewContactOfSdrCircObj()
+ {
+ }
+
+ void ViewContactOfSdrCircObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const SfxItemSet& rItemSet = GetCircObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
+ rItemSet,
+ GetCircObj().getText(0),
+ false));
+
+ // take unrotated snap rect (direct model data) for position and size
+ const basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(GetCircObj().GetGeoRect());
+ const GeoStat& rGeoStat(GetCircObj().GetGeoStat());
+
+ // fill object matrix
+ const basegfx::B2DHomMatrix aObjectMatrix(
+ basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aObjectRange.getWidth(), aObjectRange.getHeight(),
+ -rGeoStat.mfTanShearAngle,
+ rGeoStat.nRotationAngle ? toRadians(36000_deg100 - rGeoStat.nRotationAngle) : 0.0,
+ aObjectRange.getMinX(), aObjectRange.getMinY()));
+
+ // create primitive data
+ const SdrObjKind nIdentifier(GetCircObj().GetObjIdentifier());
+
+ // always create primitives to allow the decomposition of SdrEllipsePrimitive2D
+ // or SdrEllipseSegmentPrimitive2D to create needed invisible elements for HitTest
+ // and/or BoundRect
+ if(SdrObjKind::CircleOrEllipse == nIdentifier)
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrEllipsePrimitive2D(
+ aObjectMatrix,
+ aAttribute));
+
+ rVisitor.visit(xReference);
+ }
+ else
+ {
+ const auto nNewStart(rItemSet.Get(SDRATTR_CIRCSTARTANGLE).GetValue());
+ const auto nNewEnd(rItemSet.Get(SDRATTR_CIRCENDANGLE).GetValue());
+ const double fStart(toRadians((36000_deg100 - nNewEnd) % 36000_deg100));
+ const double fEnd(toRadians((36000_deg100 - nNewStart) % 36000_deg100));
+ const bool bCloseSegment(SdrObjKind::CircleArc != nIdentifier);
+ const bool bCloseUsingCenter(SdrObjKind::CircleSection == nIdentifier);
+
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrEllipseSegmentPrimitive2D(
+ aObjectMatrix,
+ aAttribute,
+ fStart,
+ fEnd,
+ bCloseSegment,
+ bCloseUsingCenter));
+
+ rVisitor.visit(xReference);
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdredgeobj.cxx b/svx/source/sdr/contact/viewcontactofsdredgeobj.cxx
new file mode 100644
index 000000000..ab9587856
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdredgeobj.cxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofsdredgeobj.hxx>
+#include <svx/svdoedge.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrconnectorprimitive2d.hxx>
+#include <osl/diagnose.h>
+
+
+namespace sdr::contact
+{
+ ViewContactOfSdrEdgeObj::ViewContactOfSdrEdgeObj(SdrEdgeObj& rEdgeObj)
+ : ViewContactOfTextObj(rEdgeObj)
+ {
+ }
+
+ ViewContactOfSdrEdgeObj::~ViewContactOfSdrEdgeObj()
+ {
+ }
+
+ void ViewContactOfSdrEdgeObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const basegfx::B2DPolygon aEdgeTrack(GetEdgeObj().getEdgeTrack());
+
+ // what to do when no EdgeTrack is provided (HitTest and selectability) ?
+ OSL_ENSURE(0 != aEdgeTrack.count(), "Connectors with no geometry are not allowed (!)");
+
+ // ckeck attributes
+ const SfxItemSet& rItemSet = GetEdgeObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineEffectsTextAttribute(
+ rItemSet,
+ GetEdgeObj().getText(0)));
+
+ // create primitive. Always create primitives to allow the decomposition of
+ // SdrConnectorPrimitive2D to create needed invisible elements for HitTest
+ // and/or BoundRect
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrConnectorPrimitive2D(
+ aAttribute,
+ aEdgeTrack));
+
+ rVisitor.visit(xReference);
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrmeasureobj.cxx b/svx/source/sdr/contact/viewcontactofsdrmeasureobj.cxx
new file mode 100644
index 000000000..eb04efd71
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrmeasureobj.cxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofsdrmeasureobj.hxx>
+#include <svx/svdomeas.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <svl/itemset.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sxmbritm.hxx>
+#include <svx/sxmtritm.hxx>
+#include <sxmtaitm.hxx>
+#include <sdr/primitive2d/sdrmeasureprimitive2d.hxx>
+#include <svx/sxmtpitm.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfSdrMeasureObj::ViewContactOfSdrMeasureObj(SdrMeasureObj& rMeasureObj)
+ : ViewContactOfTextObj(rMeasureObj)
+ {
+ }
+
+ ViewContactOfSdrMeasureObj::~ViewContactOfSdrMeasureObj()
+ {
+ }
+
+ void ViewContactOfSdrMeasureObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const SfxItemSet& rItemSet = GetMeasureObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineEffectsTextAttribute(
+ rItemSet,
+ GetMeasureObj().getText(0)));
+
+ // take properties which are the model data.
+ const ::basegfx::B2DPoint aStart(GetMeasureObj().GetPoint(0).X(), GetMeasureObj().GetPoint(0).Y());
+ const ::basegfx::B2DPoint aEnd(GetMeasureObj().GetPoint(1).X(), GetMeasureObj().GetPoint(1).Y());
+ const double fDistance(rItemSet.Get(SDRATTR_MEASURELINEDIST).GetValue());
+ const double fUpperDistance(rItemSet.Get(SDRATTR_MEASUREHELPLINEOVERHANG).GetValue());
+ const double fLowerDistance(rItemSet.Get(SDRATTR_MEASUREHELPLINEDIST).GetValue());
+ const double fLeftDelta(rItemSet.Get(SDRATTR_MEASUREHELPLINE1LEN).GetValue());
+ const double fRightDelta(rItemSet.Get(SDRATTR_MEASUREHELPLINE2LEN).GetValue());
+ const bool bBelow(rItemSet.Get(SDRATTR_MEASUREBELOWREFEDGE).GetValue());
+ const bool bTextRotation(rItemSet.Get(SDRATTR_MEASURETEXTROTA90).GetValue());
+ const bool bTextAutoAngle(rItemSet.Get(SDRATTR_MEASURETEXTAUTOANGLE).GetValue());
+ drawinglayer::primitive2d::MeasureTextPosition aMTPHor(drawinglayer::primitive2d::MEASURETEXTPOSITION_AUTOMATIC);
+ drawinglayer::primitive2d::MeasureTextPosition aMTPVer(drawinglayer::primitive2d::MEASURETEXTPOSITION_AUTOMATIC);
+
+ switch(rItemSet.Get(SDRATTR_MEASURETEXTHPOS).GetValue())
+ {
+ case css::drawing::MeasureTextHorzPos::MeasureTextHorzPos_LEFTOUTSIDE:
+ {
+ aMTPHor = drawinglayer::primitive2d::MEASURETEXTPOSITION_NEGATIVE;
+ break;
+ }
+ case css::drawing::MeasureTextHorzPos::MeasureTextHorzPos_INSIDE:
+ {
+ aMTPHor = drawinglayer::primitive2d::MEASURETEXTPOSITION_CENTERED;
+ break;
+ }
+ case css::drawing::MeasureTextHorzPos::MeasureTextHorzPos_RIGHTOUTSIDE:
+ {
+ aMTPHor = drawinglayer::primitive2d::MEASURETEXTPOSITION_POSITIVE;
+ break;
+ }
+ default: // css::drawing::MeasureTextHorzPos::MeasureTextHorzPos_AUTO
+ {
+ break;
+ }
+ }
+
+ switch(rItemSet.Get(SDRATTR_MEASURETEXTVPOS).GetValue())
+ {
+ case css::drawing::MeasureTextVertPos_EAST:
+ {
+ aMTPVer = drawinglayer::primitive2d::MEASURETEXTPOSITION_NEGATIVE;
+ break;
+ }
+ case css::drawing::MeasureTextVertPos_CENTERED:
+ {
+ aMTPVer = drawinglayer::primitive2d::MEASURETEXTPOSITION_CENTERED;
+ break;
+ }
+ case css::drawing::MeasureTextVertPos_WEST:
+ {
+ aMTPVer = drawinglayer::primitive2d::MEASURETEXTPOSITION_POSITIVE;
+ break;
+ }
+ default : // css::drawing::MeasureTextVertPos_AUTO
+ {
+ break;
+ }
+ }
+
+ // create primitive with the model data. Always create primitives to allow the
+ // decomposition of SdrMeasurePrimitive2D to create needed invisible elements for HitTest
+ // and/or BoundRect
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrMeasurePrimitive2D(
+ aAttribute, aStart, aEnd,
+ aMTPHor, aMTPVer, fDistance,
+ fUpperDistance, fLowerDistance,
+ fLeftDelta, fRightDelta, bBelow,
+ bTextRotation, bTextAutoAngle));
+
+ rVisitor.visit(xReference);
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrmediaobj.cxx b/svx/source/sdr/contact/viewcontactofsdrmediaobj.cxx
new file mode 100644
index 000000000..7c713bc4b
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrmediaobj.cxx
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/sdr/contact/viewcontactofsdrmediaobj.hxx>
+#include <svx/svdomedia.hxx>
+#include <sdr/contact/viewobjectcontactofsdrmediaobj.hxx>
+#include <drawinglayer/primitive2d/mediaprimitive2d.hxx>
+#include <vcl/canvastools.hxx>
+
+namespace sdr::contact {
+
+ViewContactOfSdrMediaObj::ViewContactOfSdrMediaObj( SdrMediaObj& rMediaObj ) :
+ ViewContactOfSdrObj( rMediaObj )
+{
+}
+
+ViewContactOfSdrMediaObj::~ViewContactOfSdrMediaObj()
+{
+}
+
+ViewObjectContact& ViewContactOfSdrMediaObj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ return *( new ViewObjectContactOfSdrMediaObj( rObjectContact, *this, static_cast< SdrMediaObj& >( GetSdrObject() ).getMediaProperties() ) );
+}
+
+Size ViewContactOfSdrMediaObj::getPreferredSize() const
+{
+ // #i71805# Since we may have a whole bunch of VOCs here, make a loop
+ // return first useful size -> the size from the first which is visualized as a window
+ const sal_uInt32 nCount(getViewObjectContactCount());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ ViewObjectContact* pCandidate = getViewObjectContact(a);
+ Size aSize(pCandidate ? static_cast< ViewObjectContactOfSdrMediaObj* >(pCandidate)->getPreferredSize() : Size());
+
+ if(0 != aSize.getWidth() || 0 != aSize.getHeight())
+ {
+ return aSize;
+ }
+ }
+
+ return Size();
+}
+
+void ViewContactOfSdrMediaObj::updateMediaItem( ::avmedia::MediaItem& rItem ) const
+{
+ // #i71805# Since we may have a whole bunch of VOCs here, make a loop
+ const sal_uInt32 nCount(getViewObjectContactCount());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ ViewObjectContact* pCandidate = getViewObjectContact(a);
+
+ if(pCandidate)
+ {
+ static_cast< ViewObjectContactOfSdrMediaObj* >(pCandidate)->updateMediaItem(rItem);
+ }
+ }
+}
+
+void ViewContactOfSdrMediaObj::executeMediaItem( const ::avmedia::MediaItem& rItem )
+{
+ const sal_uInt32 nCount(getViewObjectContactCount());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ ViewObjectContact* pCandidate = getViewObjectContact(a);
+
+ if(pCandidate)
+ {
+ static_cast< ViewObjectContactOfSdrMediaObj* >(pCandidate)->executeMediaItem(rItem);
+ }
+ }
+}
+
+void ViewContactOfSdrMediaObj::mediaPropertiesChanged( const ::avmedia::MediaItem& rNewState )
+{
+ static_cast< SdrMediaObj& >(GetSdrObject()).mediaPropertiesChanged(rNewState);
+}
+
+void ViewContactOfSdrMediaObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // create range using the model data directly. This is in SdrTextObj::aRect which i will access using
+ // GetGeoRect() to not trigger any calculations. It's the unrotated geometry which is okay for MediaObjects ATM.
+ const tools::Rectangle aRectangle(GetSdrMediaObj().GetGeoRect());
+ const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aRectangle);
+
+ // create object transform
+ basegfx::B2DHomMatrix aTransform;
+ aTransform.set(0, 0, aRange.getWidth());
+ aTransform.set(1, 1, aRange.getHeight());
+ aTransform.set(0, 2, aRange.getMinX());
+ aTransform.set(1, 2, aRange.getMinY());
+
+ // create media primitive. Always create primitives to allow the
+ // decomposition of MediaPrimitive2D to create needed invisible elements for HitTest
+ // and/or BoundRect
+ const basegfx::BColor aBackgroundColor(67.0 / 255.0, 67.0 / 255.0, 67.0 / 255.0);
+ const OUString& rURL(GetSdrMediaObj().getURL());
+ const sal_uInt32 nPixelBorder(4);
+ const drawinglayer::primitive2d::Primitive2DReference xRetval(
+ new drawinglayer::primitive2d::MediaPrimitive2D(
+ aTransform, rURL, aBackgroundColor, nPixelBorder,
+ GetSdrMediaObj().getSnapshot()));
+
+ rVisitor.visit(xRetval);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrobj.cxx b/svx/source/sdr/contact/viewcontactofsdrobj.cxx
new file mode 100644
index 000000000..1483b5764
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrobj.cxx
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/svdobj.hxx>
+#include <tools/debug.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
+#include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx>
+#include <svx/svdhdl.hxx>
+
+namespace sdr::contact {
+
+// Create an Object-Specific ViewObjectContact, set ViewContact and
+// ObjectContact. Always needs to return something.
+ViewObjectContact& ViewContactOfSdrObj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfSdrObj(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContactOfSdrObj::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+ViewContactOfSdrObj::ViewContactOfSdrObj(SdrObject& rObj)
+: mrObject(rObj)
+{
+}
+
+ViewContactOfSdrObj::~ViewContactOfSdrObj()
+{
+}
+
+// Access to possible sub-hierarchy
+sal_uInt32 ViewContactOfSdrObj::GetObjectCount() const
+{
+ if(GetSdrObject().GetSubList())
+ {
+ return GetSdrObject().GetSubList()->GetObjCount();
+ }
+
+ return 0;
+}
+
+ViewContact& ViewContactOfSdrObj::GetViewContact(sal_uInt32 nIndex) const
+{
+ assert(GetSdrObject().GetSubList() &&
+ "ViewContactOfSdrObj::GetViewContact: Access to non-existent Sub-List (!)");
+ SdrObject* pObj = GetSdrObject().GetSubList()->GetObj(nIndex);
+ assert(pObj && "ViewContactOfSdrObj::GetViewContact: Corrupt SdrObjList (!)");
+ return pObj->GetViewContact();
+}
+
+ViewContact* ViewContactOfSdrObj::GetParentContact() const
+{
+ ViewContact* pRetval = nullptr;
+ SdrObjList* pObjList = GetSdrObject().getParentSdrObjListFromSdrObject();
+
+ if(pObjList)
+ {
+ if(auto pPage = dynamic_cast<SdrPage*>( pObjList))
+ {
+ // Is a page
+ pRetval = &(pPage->GetViewContact());
+ }
+ else
+ {
+ // Is a group?
+ if(pObjList->getSdrObjectFromSdrObjList())
+ {
+ pRetval = &(pObjList->getSdrObjectFromSdrObjList()->GetViewContact());
+ }
+ }
+ }
+
+ return pRetval;
+}
+
+// React on changes of the object of this ViewContact
+void ViewContactOfSdrObj::ActionChanged()
+{
+ // look for own changes
+ if (SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>(&GetSdrObject()))
+ {
+ // tdf#146860 no idea why, but calling this makes the text boxes render properly
+ pTextObj->GetTextAniKind();
+ }
+
+ // call parent
+ ViewContact::ActionChanged();
+}
+
+// override for accessing the SdrObject
+SdrObject* ViewContactOfSdrObj::TryToGetSdrObject() const
+{
+ return &GetSdrObject();
+}
+
+
+// primitive stuff
+
+// add Gluepoints (if available)
+drawinglayer::primitive2d::Primitive2DContainer ViewContactOfSdrObj::createGluePointPrimitive2DSequence() const
+{
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ const SdrGluePointList* pGluePointList = GetSdrObject().GetGluePointList();
+
+ if(pGluePointList)
+ {
+ const sal_uInt32 nCount(pGluePointList->GetCount());
+
+ if(nCount)
+ {
+ // prepare point vector
+ std::vector< basegfx::B2DPoint > aGluepointVector;
+
+ // create GluePoint primitives. ATM these are relative to the SnapRect
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const SdrGluePoint& rCandidate = (*pGluePointList)[static_cast<sal_uInt16>(a)];
+ const Point aPosition(rCandidate.GetAbsolutePos(GetSdrObject()));
+
+ aGluepointVector.emplace_back(aPosition.X(), aPosition.Y());
+ }
+
+ if(!aGluepointVector.empty())
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::MarkerArrayPrimitive2D(
+ std::move(aGluepointVector), SdrHdl::createGluePointBitmap()));
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer{ xReference };
+ }
+ }
+ }
+
+ return xRetval;
+}
+
+drawinglayer::primitive2d::Primitive2DContainer ViewContactOfSdrObj::embedToObjectSpecificInformation(drawinglayer::primitive2d::Primitive2DContainer aSource) const
+{
+ if(!aSource.empty() &&
+ (!GetSdrObject().GetName().isEmpty() ||
+ !GetSdrObject().GetTitle().isEmpty() ||
+ !GetSdrObject().GetDescription().isEmpty()))
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xRef(
+ new drawinglayer::primitive2d::ObjectInfoPrimitive2D(
+ std::move(aSource),
+ GetSdrObject().GetName(),
+ GetSdrObject().GetTitle(),
+ GetSdrObject().GetDescription()));
+
+ return drawinglayer::primitive2d::Primitive2DContainer { xRef };
+ }
+
+ return aSource;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrobjcustomshape.cxx b/svx/source/sdr/contact/viewcontactofsdrobjcustomshape.cxx
new file mode 100644
index 000000000..e03dfced8
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrobjcustomshape.cxx
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofsdrobjcustomshape.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/sdooitm.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrcustomshapeprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <svx/obj3d.hxx>
+#include <vcl/canvastools.hxx>
+
+
+namespace sdr::contact
+{
+ ViewContactOfSdrObjCustomShape::ViewContactOfSdrObjCustomShape(SdrObjCustomShape& rCustomShape)
+ : ViewContactOfTextObj(rCustomShape)
+ {
+ }
+
+ ViewContactOfSdrObjCustomShape::~ViewContactOfSdrObjCustomShape()
+ {
+ }
+
+ basegfx::B2DRange ViewContactOfSdrObjCustomShape::getCorrectedTextBoundRect() const
+ {
+ const tools::Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect());
+ tools::Rectangle aTextBound(aObjectBound);
+ GetCustomShapeObj().GetTextBounds(aTextBound);
+ basegfx::B2DRange aTextRange = vcl::unotools::b2DRectangleFromRectangle(aTextBound);
+ const basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(aObjectBound);
+
+ // no need to correct if no extra text range
+ if(aTextRange != aObjectRange)
+ {
+ const GeoStat& rGeoStat(GetCustomShapeObj().GetGeoStat());
+
+ // only correct when rotation and/or shear is used
+ if(rGeoStat.nShearAngle || rGeoStat.nRotationAngle )
+ {
+ // text range needs to be corrected by
+ // aObjectRange.getCenter() - aRotObjectRange.getCenter() since it's
+ // defined differently by using rotation around object center. Start
+ // with positive part
+ basegfx::B2DVector aTranslation(aObjectRange.getCenter());
+
+ // get rotated and sheared object's range
+ basegfx::B2DRange aRotObjectRange(aObjectRange);
+ basegfx::B2DHomMatrix aRotMatrix;
+
+ aRotMatrix.translate(-aObjectRange.getMinimum().getX(), -aObjectRange.getMinimum().getY());
+
+ if(rGeoStat.nShearAngle)
+ {
+ aRotMatrix.shearX(-rGeoStat.mfTanShearAngle);
+ }
+
+ if(rGeoStat.nRotationAngle)
+ {
+ aRotMatrix.rotate(toRadians(36000_deg100 - rGeoStat.nRotationAngle));
+ }
+
+ aRotMatrix.translate(aObjectRange.getMinimum().getX(), aObjectRange.getMinimum().getY());
+ aRotObjectRange.transform(aRotMatrix);
+
+ // add negative translation part
+ aTranslation -= aRotObjectRange.getCenter();
+
+ // create new range
+ aTextRange = basegfx::B2DRange(
+ aTextRange.getMinX() + aTranslation.getX(), aTextRange.getMinY() + aTranslation.getY(),
+ aTextRange.getMaxX() + aTranslation.getX(), aTextRange.getMaxY() + aTranslation.getY());
+ }
+
+ // NbcMirror() of SdrTextObj (from which SdrObjCustomShape is derived), adds a
+ // 180deg rotation around the shape center to GeoStat.nRotationAngle. So remove here the
+ // 180° rotation, which was added by GetTextBounds().
+ if(GetCustomShapeObj().IsMirroredY())
+ {
+ basegfx::B2DHomMatrix aRotMatrix(basegfx::utils::createRotateAroundPoint(
+ aObjectRange.getCenterX(), aObjectRange.getCenterY(), M_PI));
+ aTextRange.transform(aRotMatrix);
+ }
+ }
+
+ return aTextRange;
+ }
+
+ void ViewContactOfSdrObjCustomShape::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const SfxItemSet& rItemSet = GetCustomShapeObj().GetMergedItemSet();
+
+ // #i98072# Get shadow and text; eventually suppress the text if it's
+ // a TextPath FontworkGallery object
+ const drawinglayer::attribute::SdrEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrEffectsTextAttribute(
+ rItemSet,
+ GetCustomShapeObj().getText(0),
+ GetCustomShapeObj().IsTextPath()));
+ drawinglayer::primitive2d::Primitive2DContainer xGroup;
+ bool bHasText(!aAttribute.getText().isDefault());
+
+ // create Primitive2DContainer from sub-geometry
+ const SdrObject* pSdrObjRepresentation = GetCustomShapeObj().GetSdrObjectFromCustomShape();
+ bool b3DShape(false);
+
+ if(pSdrObjRepresentation)
+ {
+ // tdf#118498 The processing of SdrObjListIter for SdrIterMode::DeepNoGroups
+ // did change for 3D-Objects, it now correctly enters and iterates the
+ // SdrObjects in the E3dScene (same as for SdrObjGroup). This is more correct
+ // as the old version which just checked for dynamic_cast<const SdrObjGroup*>
+ // and *only* entered these, ignoring E3dScene as grouping-object.
+ // But how to fix that? Taking back the SdrObjListIter change would be easy, but
+ // not correct. After checking ViewContactOfE3dScene and ViewContactOfGroup
+ // I see that both traverse their children by themselves (on VC-Level,
+ // see createViewIndependentPrimitive2DSequence implementations and usage of
+ // GetObjectCount()). Thus in principle iterating here (esp. 'deep') seems to
+ // be wrong anyways, it might have even created wrong and double geometries
+ // (only with complex CustomShapes with multiple representation SdrObjects and
+ // only visible when transparency involved, but runtime-expensive).
+ // Thus: Just do not iterate, will check behaviour deeply.
+ b3DShape = (nullptr != dynamic_cast< const E3dObject* >(pSdrObjRepresentation));
+ pSdrObjRepresentation->GetViewContact().getViewIndependentPrimitive2DContainer(xGroup);
+ }
+
+ if(bHasText || !xGroup.empty())
+ {
+ // prepare text box geometry
+ basegfx::B2DHomMatrix aTextBoxMatrix;
+ bool bWordWrap(false);
+
+ // take unrotated snap rect as default, then get the
+ // unrotated text box. Rotation needs to be done centered
+ const tools::Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect());
+ const basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(aObjectBound);
+
+ if(bHasText)
+ {
+ // #i101684# get the text range unrotated and absolute to the object range
+ const basegfx::B2DRange aTextRange(getCorrectedTextBoundRect());
+
+ // Rotation before scaling
+ if(!basegfx::fTools::equalZero(GetCustomShapeObj().GetExtraTextRotation(true)))
+ {
+ basegfx::B2DVector aTranslation(0.5, 0.5);
+ aTextBoxMatrix.translate( -aTranslation.getX(), -aTranslation.getY() );
+ aTextBoxMatrix.rotate(basegfx::deg2rad(
+ 360.0 - GetCustomShapeObj().GetExtraTextRotation(true)));
+ aTextBoxMatrix.translate( aTranslation.getX(), aTranslation.getY() );
+ }
+ // give text object a size
+ aTextBoxMatrix.scale(aTextRange.getWidth(), aTextRange.getHeight());
+
+ // check if we have a rotation/shear at all to take care of
+ const double fExtraTextRotation(GetCustomShapeObj().GetExtraTextRotation());
+ const GeoStat& rGeoStat(GetCustomShapeObj().GetGeoStat());
+
+ if(rGeoStat.nShearAngle || rGeoStat.nRotationAngle || !basegfx::fTools::equalZero(fExtraTextRotation))
+ {
+ if(aObjectRange != aTextRange)
+ {
+ // move relative to unrotated object range
+ aTextBoxMatrix.translate(
+ aTextRange.getMinX() - aObjectRange.getMinimum().getX(),
+ aTextRange.getMinY() - aObjectRange.getMinimum().getY());
+ }
+
+ if(!basegfx::fTools::equalZero(fExtraTextRotation))
+ {
+ basegfx::B2DVector aTranslation(
+ ( aTextRange.getWidth() / 2 ) + ( aTextRange.getMinX() - aObjectRange.getMinimum().getX() ),
+ ( aTextRange.getHeight() / 2 ) + ( aTextRange.getMinY() - aObjectRange.getMinimum().getY() ) );
+ aTextBoxMatrix.translate( -aTranslation.getX(), -aTranslation.getY() );
+ aTextBoxMatrix.rotate(basegfx::deg2rad(360.0 - fExtraTextRotation));
+ aTextBoxMatrix.translate( aTranslation.getX(), aTranslation.getY() );
+ }
+
+ if(rGeoStat.nShearAngle)
+ {
+ aTextBoxMatrix.shearX(-rGeoStat.mfTanShearAngle);
+ }
+
+ if(rGeoStat.nRotationAngle)
+ {
+ aTextBoxMatrix.rotate(toRadians(36000_deg100 - rGeoStat.nRotationAngle));
+ }
+
+ // give text it's target position
+ aTextBoxMatrix.translate(aObjectRange.getMinimum().getX(), aObjectRange.getMinimum().getY());
+ }
+ else
+ {
+ aTextBoxMatrix.translate(aTextRange.getMinX(), aTextRange.getMinY());
+ }
+
+ // check if SdrTextWordWrapItem is set
+ bWordWrap = GetCustomShapeObj().GetMergedItem(SDRATTR_TEXT_WORDWRAP).GetValue();
+ }
+
+ // fill object matrix
+ const basegfx::B2DHomMatrix aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aObjectRange.getWidth(), aObjectRange.getHeight(),
+ /*fShearX=*/0, /*fRotate=*/0,
+ aObjectRange.getMinX(), aObjectRange.getMinY()));
+
+ // create primitive
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrCustomShapePrimitive2D(
+ aAttribute,
+ std::move(xGroup),
+ aTextBoxMatrix,
+ bWordWrap,
+ b3DShape,
+ aObjectMatrix));
+ rVisitor.visit(xReference);
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrole2obj.cxx b/svx/source/sdr/contact/viewcontactofsdrole2obj.cxx
new file mode 100644
index 000000000..c1a732786
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrole2obj.cxx
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <drawinglayer/primitive2d/Tools.hxx>
+#include <sdr/contact/viewcontactofsdrole2obj.hxx>
+#include <svx/svdoole2.hxx>
+#include <sdr/contact/viewobjectcontactofsdrole2obj.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <sdr/primitive2d/sdrole2primitive2d.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <vcl/canvastools.hxx>
+#include <tools/debug.hxx>
+#include <sdr/primitive2d/sdrolecontentprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <svx/charthelper.hxx>
+#include <svtools/embedhlp.hxx>
+
+namespace sdr::contact {
+
+// Create an Object-Specific ViewObjectContact, set ViewContact and
+// ObjectContact. Always needs to return something.
+ViewObjectContact& ViewContactOfSdrOle2Obj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfSdrOle2Obj(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+ViewContactOfSdrOle2Obj::ViewContactOfSdrOle2Obj(SdrOle2Obj& rOle2Obj)
+: ViewContactOfSdrRectObj(rOle2Obj)
+{
+}
+
+ViewContactOfSdrOle2Obj::~ViewContactOfSdrOle2Obj()
+{
+}
+
+basegfx::B2DHomMatrix ViewContactOfSdrOle2Obj::createObjectTransform() const
+{
+ // take unrotated snap rect (direct model data) for position and size
+ const tools::Rectangle aRectangle(GetOle2Obj().GetGeoRect());
+ const basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(aRectangle);
+
+ // create object matrix
+ const GeoStat& rGeoStat(GetOle2Obj().GetGeoStat());
+ const double fShearX(-rGeoStat.mfTanShearAngle);
+ const double fRotate(rGeoStat.nRotationAngle ? toRadians(36000_deg100 - rGeoStat.nRotationAngle) : 0.0);
+
+ return basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aObjectRange.getWidth(), aObjectRange.getHeight(),
+ fShearX,
+ fRotate,
+ aObjectRange.getMinX(), aObjectRange.getMinY());
+}
+
+void ViewContactOfSdrOle2Obj::createPrimitive2DSequenceWithParameters(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // get object transformation
+ const basegfx::B2DHomMatrix aObjectMatrix(createObjectTransform());
+
+ // Prepare attribute settings, will be used soon anyways
+ const SfxItemSet& rItemSet = GetOle2Obj().GetMergedItemSet();
+
+ // this may be refined more granular; if no content, attributes may get simpler
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
+ rItemSet,
+ GetOle2Obj().getText(0),
+ true));
+ drawinglayer::primitive2d::Primitive2DReference xContent;
+
+ if(GetOle2Obj().IsChart())
+ {
+ // try to get chart primitives and chart range directly from xChartModel
+ basegfx::B2DRange aChartContentRange;
+ drawinglayer::primitive2d::Primitive2DContainer aChartSequence(
+ ChartHelper::tryToGetChartContentAsPrimitive2DSequence(
+ GetOle2Obj().getXModel(),
+ aChartContentRange));
+ const double fWidth(aChartContentRange.getWidth());
+ const double fHeight(aChartContentRange.getHeight());
+
+ if(!aChartSequence.empty()
+ && basegfx::fTools::more(fWidth, 0.0)
+ && basegfx::fTools::more(fHeight, 0.0))
+ {
+ // create embedding transformation
+ basegfx::B2DHomMatrix aEmbed(
+ basegfx::utils::createTranslateB2DHomMatrix(
+ -aChartContentRange.getMinX(),
+ -aChartContentRange.getMinY()));
+
+ aEmbed.scale(1.0 / fWidth, 1.0 / fHeight);
+ aEmbed = aObjectMatrix * aEmbed;
+ xContent = new drawinglayer::primitive2d::TransformPrimitive2D(
+ aEmbed,
+ std::move(aChartSequence));
+ }
+ }
+
+ if(!xContent.is())
+ {
+ // #i102063# embed OLE content in an own primitive; this will be able to decompose accessing
+ // the weak SdrOle2 reference and will also implement getB2DRange() for fast BoundRect
+ // calculations without OLE Graphic access (which may trigger e.g. chart recalculation).
+ // It will also take care of HighContrast and ScaleContent
+ xContent = new drawinglayer::primitive2d::SdrOleContentPrimitive2D(
+ GetOle2Obj(),
+ aObjectMatrix,
+
+ // #i104867# add GraphicVersion number to be able to check for
+ // content change in the primitive later
+ GetOle2Obj().getEmbeddedObjectRef().getGraphicVersion() );
+ }
+
+ // create primitive. Use Ole2 primitive here. Prepare attribute settings, will
+ // be used soon anyways. Always create primitives to allow the decomposition of
+ // SdrOle2Primitive2D to create needed invisible elements for HitTest and/or BoundRect
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrOle2Primitive2D(
+ drawinglayer::primitive2d::Primitive2DContainer { xContent },
+ aObjectMatrix,
+ aAttribute));
+
+ rVisitor.visit(xReference);
+}
+
+basegfx::B2DRange ViewContactOfSdrOle2Obj::getRange( const drawinglayer::geometry::ViewInformation2D& rViewInfo2D ) const
+{
+ // this may be refined more granular; if no content, attributes may get simpler
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute aAttribute =
+ drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
+ GetOle2Obj().GetMergedItemSet(),
+ GetOle2Obj().getText(0),
+ true);
+
+ basegfx::B2DHomMatrix aObjectMatrix = createObjectTransform();
+
+ drawinglayer::primitive2d::Primitive2DReference xContent =
+ new drawinglayer::primitive2d::SdrOleContentPrimitive2D(
+ GetOle2Obj(),
+ aObjectMatrix,
+ GetOle2Obj().getEmbeddedObjectRef().getGraphicVersion());
+
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrOle2Primitive2D(
+ drawinglayer::primitive2d::Primitive2DContainer { xContent },
+ aObjectMatrix,
+ aAttribute));
+
+ return drawinglayer::primitive2d::getB2DRangeFromPrimitive2DReference(xReference, rViewInfo2D);
+}
+
+void ViewContactOfSdrOle2Obj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ createPrimitive2DSequenceWithParameters(rVisitor);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrpage.cxx b/svx/source/sdr/contact/viewcontactofsdrpage.cxx
new file mode 100644
index 000000000..44cccb319
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrpage.cxx
@@ -0,0 +1,598 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofsdrpage.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/svdpage.hxx>
+#include <sdr/contact/viewobjectcontactofsdrpage.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <svtools/colorcfg.hxx>
+#include <tools/debug.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <drawinglayer/primitive2d/backgroundcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/attribute/fillgradientattribute.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <vcl/lazydelete.hxx>
+#include <vcl/settings.hxx>
+#include <drawinglayer/primitive2d/discreteshadowprimitive2d.hxx>
+#include <drawinglayer/attribute/sdrfillattribute.hxx>
+#include <bitmaps.hlst>
+
+namespace sdr::contact {
+
+ViewContactOfPageSubObject::ViewContactOfPageSubObject(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: mrParentViewContactOfSdrPage(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfPageSubObject::~ViewContactOfPageSubObject()
+{
+}
+
+ViewContact* ViewContactOfPageSubObject::GetParentContact() const
+{
+ return &mrParentViewContactOfSdrPage;
+}
+
+const SdrPage& ViewContactOfPageSubObject::getPage() const
+{
+ return mrParentViewContactOfSdrPage.GetSdrPage();
+}
+
+ViewObjectContact& ViewContactOfPageBackground::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfPageBackground(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfPageBackground::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // We have only the page information, not the view information. Use the
+ // svtools::DOCCOLOR color for initialisation
+ const svtools::ColorConfig aColorConfig;
+ const Color aInitColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
+ const basegfx::BColor aRGBColor(aInitColor.getBColor());
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::BackgroundColorPrimitive2D(aRGBColor));
+
+ rVisitor.visit(xReference);
+}
+
+ViewContactOfPageBackground::ViewContactOfPageBackground(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfPageBackground::~ViewContactOfPageBackground()
+{
+}
+
+ViewObjectContact& ViewContactOfPageShadow::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfPageShadow(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfPageShadow::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ static bool bUseOldPageShadow(false); // loplugin:constvars:ignore
+ const SdrPage& rPage = getPage();
+ basegfx::B2DHomMatrix aPageMatrix;
+ aPageMatrix.set(0, 0, static_cast<double>(rPage.GetWidth()));
+ aPageMatrix.set(1, 1, static_cast<double>(rPage.GetHeight()));
+
+ if(bUseOldPageShadow)
+ {
+ // create page shadow polygon
+ const double fPageBorderFactor(1.0 / 256.0);
+ basegfx::B2DPolygon aPageShadowPolygon;
+ aPageShadowPolygon.append(basegfx::B2DPoint(1.0, fPageBorderFactor));
+ aPageShadowPolygon.append(basegfx::B2DPoint(1.0 + fPageBorderFactor, fPageBorderFactor));
+ aPageShadowPolygon.append(basegfx::B2DPoint(1.0 + fPageBorderFactor, 1.0 + fPageBorderFactor));
+ aPageShadowPolygon.append(basegfx::B2DPoint(fPageBorderFactor, 1.0 + fPageBorderFactor));
+ aPageShadowPolygon.append(basegfx::B2DPoint(fPageBorderFactor, 1.0));
+ aPageShadowPolygon.append(basegfx::B2DPoint(1.0, 1.0));
+ aPageShadowPolygon.setClosed(true);
+ aPageShadowPolygon.transform(aPageMatrix);
+
+ // We have only the page information, not the view information. Use the
+ // svtools::FONTCOLOR color for initialisation
+ const svtools::ColorConfig aColorConfig;
+ const Color aShadowColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor);
+ const basegfx::BColor aRGBShadowColor(aShadowColor.getBColor());
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aPageShadowPolygon),
+ aRGBShadowColor));
+
+ rVisitor.visit(xReference);
+ }
+ else
+ {
+ static vcl::DeleteOnDeinit< drawinglayer::primitive2d::DiscreteShadow > aDiscreteShadow((
+ BitmapEx(SIP_SA_PAGESHADOW35X35)));
+
+ if(aDiscreteShadow.get())
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::DiscreteShadowPrimitive2D(
+ aPageMatrix,
+ *aDiscreteShadow.get()));
+
+ rVisitor.visit(xReference);
+ }
+ }
+}
+
+ViewContactOfPageShadow::ViewContactOfPageShadow(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfPageShadow::~ViewContactOfPageShadow()
+{
+}
+
+ViewObjectContact& ViewContactOfMasterPage::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfMasterPage(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfMasterPage::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // this class is used when the page is a MasterPage and is responsible to
+ // create a visualisation for the MPBGO, if exists. This needs to be suppressed
+ // when a SdrPage which uses a MasterPage creates it's output. Suppression
+ // is done in the corresponding VOC since DisplayInfo data is needed
+ const SdrPage& rPage = getPage();
+
+ if(rPage.IsMasterPage())
+ {
+ if(0 == rPage.GetPageNum())
+ {
+ // #i98063#
+ // filter MasterPage 0 since it's the HandoutPage. Thus, it's a
+ // MasterPage, but has no MPBGO, so there is nothing to do here.
+ }
+ else
+ {
+ drawinglayer::attribute::SdrFillAttribute aFill;
+
+ // #i110846# Suppress SdrPage FillStyle for MasterPages without StyleSheets,
+ // else the PoolDefault (XFILL_COLOR and Blue8) will be used. Normally, all
+ // MasterPages should have a StyleSheet exactly for this reason, but historically
+ // e.g. the Notes MasterPage has no StyleSheet set (and there maybe others).
+ if(rPage.getSdrPageProperties().GetStyleSheet())
+ {
+ // create page fill attributes with correct properties
+ aFill = drawinglayer::primitive2d::createNewSdrFillAttribute(
+ rPage.getSdrPageProperties().GetItemSet());
+ }
+
+ if(!aFill.isDefault())
+ {
+ // direct model data is the page size, get and use it
+ const basegfx::B2DRange aOuterRange(
+ 0, 0, rPage.GetWidth(), rPage.GetHeight());
+ const basegfx::B2DRange aInnerRange(
+ rPage.GetLeftBorder(), rPage.GetUpperBorder(),
+ rPage.GetWidth() - rPage.GetRightBorder(), rPage.GetHeight() - rPage.GetLowerBorder());
+ bool const isFullSize(rPage.IsBackgroundFullSize());
+ const basegfx::B2DPolygon aFillPolygon(
+ basegfx::utils::createPolygonFromRect(isFullSize ? aOuterRange : aInnerRange));
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ drawinglayer::primitive2d::createPolyPolygonFillPrimitive(
+ basegfx::B2DPolyPolygon(aFillPolygon),
+ aFill,
+ drawinglayer::attribute::FillGradientAttribute()));
+
+ rVisitor.visit(xReference);
+ }
+ }
+ }
+}
+
+ViewContactOfMasterPage::ViewContactOfMasterPage(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfMasterPage::~ViewContactOfMasterPage()
+{
+}
+
+ViewObjectContact& ViewContactOfPageFill::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfPageFill(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfPageFill::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SdrPage& rPage = getPage();
+ const basegfx::B2DRange aPageFillRange(0.0, 0.0, static_cast<double>(rPage.GetWidth()), static_cast<double>(rPage.GetHeight()));
+ const basegfx::B2DPolygon aPageFillPolygon(basegfx::utils::createPolygonFromRect(aPageFillRange));
+
+ // We have only the page information, not the view information. Use the
+ // svtools::DOCCOLOR color for initialisation
+ const svtools::ColorConfig aColorConfig;
+ const Color aPageFillColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
+
+ // create and add primitive
+ const basegfx::BColor aRGBColor(aPageFillColor.getBColor());
+ rVisitor.visit(drawinglayer::primitive2d::Primitive2DReference(new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPageFillPolygon), aRGBColor)));
+}
+
+ViewContactOfPageFill::ViewContactOfPageFill(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfPageFill::~ViewContactOfPageFill()
+{
+}
+
+ViewObjectContact& ViewContactOfOuterPageBorder::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfOuterPageBorder(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfOuterPageBorder::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SdrPage& rPage = getPage();
+ const basegfx::B2DRange aPageBorderRange(0.0, 0.0, static_cast<double>(rPage.GetWidth()), static_cast<double>(rPage.GetHeight()));
+
+ // Changed to 0x949599 for renaissance, before svtools::FONTCOLOR was used.
+ // Added old case as fallback for HighContrast.
+ basegfx::BColor aRGBBorderColor(0x94 / double(0xff), 0x95 / double(0xff), 0x99 / double(0xff));
+
+ if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ const svtools::ColorConfig aColorConfig;
+ const Color aBorderColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor);
+
+ aRGBBorderColor = aBorderColor.getBColor();
+ }
+
+ if(rPage.getPageBorderOnlyLeftRight())
+ {
+ // #i93597# for Report Designer, the page border shall be only displayed right and left,
+ // but not top and bottom. Create simplified geometry.
+ basegfx::B2DPolygon aLeft, aRight;
+
+ aLeft.append(basegfx::B2DPoint(aPageBorderRange.getMinX(), aPageBorderRange.getMinY()));
+ aLeft.append(basegfx::B2DPoint(aPageBorderRange.getMinX(), aPageBorderRange.getMaxY()));
+
+ aRight.append(basegfx::B2DPoint(aPageBorderRange.getMaxX(), aPageBorderRange.getMinY()));
+ aRight.append(basegfx::B2DPoint(aPageBorderRange.getMaxX(), aPageBorderRange.getMaxY()));
+
+ rVisitor.visit(drawinglayer::primitive2d::Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aLeft, aRGBBorderColor)));
+ rVisitor.visit(drawinglayer::primitive2d::Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aRight, aRGBBorderColor)));
+ }
+ else
+ {
+ const basegfx::B2DPolygon aPageBorderPolygon(basegfx::utils::createPolygonFromRect(aPageBorderRange));
+ rVisitor.visit(drawinglayer::primitive2d::Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aPageBorderPolygon, aRGBBorderColor)));
+ }
+}
+
+ViewContactOfOuterPageBorder::ViewContactOfOuterPageBorder(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfOuterPageBorder::~ViewContactOfOuterPageBorder()
+{
+}
+
+ViewObjectContact& ViewContactOfInnerPageBorder::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfInnerPageBorder(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfInnerPageBorder::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SdrPage& rPage = getPage();
+ const basegfx::B2DRange aPageBorderRange(
+ static_cast<double>(rPage.GetLeftBorder()), static_cast<double>(rPage.GetUpperBorder()),
+ static_cast<double>(rPage.GetWidth() - rPage.GetRightBorder()), static_cast<double>(rPage.GetHeight() - rPage.GetLowerBorder()));
+ const basegfx::B2DPolygon aPageBorderPolygon(basegfx::utils::createPolygonFromRect(aPageBorderRange));
+
+ // We have only the page information, not the view information. Use the
+ // svtools::FONTCOLOR or svtools::DOCBOUNDARIES color for initialisation
+ const svtools::ColorConfig aColorConfig;
+ Color aBorderColor;
+
+ if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ aBorderColor = aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor;
+ }
+ else
+ {
+ svtools::ColorConfigValue aBorderConfig = aColorConfig.GetColorValue(svtools::DOCBOUNDARIES);
+ aBorderColor = aBorderConfig.bIsVisible ? aBorderConfig.nColor :
+ aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor;
+ }
+
+ // create page outer border primitive
+ const basegfx::BColor aRGBBorderColor(aBorderColor.getBColor());
+ rVisitor.visit(drawinglayer::primitive2d::Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aPageBorderPolygon, aRGBBorderColor)));
+}
+
+ViewContactOfInnerPageBorder::ViewContactOfInnerPageBorder(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfInnerPageBorder::~ViewContactOfInnerPageBorder()
+{
+}
+
+ViewObjectContact& ViewContactOfPageHierarchy::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfPageHierarchy(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfPageHierarchy::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // collect sub-hierarchy
+ const sal_uInt32 nObjectCount(GetObjectCount());
+
+ // collect all sub-primitives
+ for(sal_uInt32 a(0); a < nObjectCount; a++)
+ {
+ const ViewContact& rCandidate(GetViewContact(a));
+ rCandidate.getViewIndependentPrimitive2DContainer(rVisitor);
+ }
+}
+
+ViewContactOfPageHierarchy::ViewContactOfPageHierarchy(ViewContactOfSdrPage& rParentViewContactOfSdrPage)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage)
+{
+}
+
+ViewContactOfPageHierarchy::~ViewContactOfPageHierarchy()
+{
+}
+
+sal_uInt32 ViewContactOfPageHierarchy::GetObjectCount() const
+{
+ return getPage().GetObjCount();
+}
+
+ViewContact& ViewContactOfPageHierarchy::GetViewContact(sal_uInt32 nIndex) const
+{
+ SdrObject* pObj = getPage().GetObj(nIndex);
+ assert(pObj && "ViewContactOfPageHierarchy::GetViewContact: Corrupt SdrObjList (!)");
+ return pObj->GetViewContact();
+}
+
+ViewObjectContact& ViewContactOfGrid::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfPageGrid(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfGrid::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor&) const
+{
+ // We have only the page information, not the view information and thus no grid settings. Create empty
+ // default. For the view-dependent implementation, see ViewObjectContactOfPageGrid::createPrimitive2DSequence
+}
+
+ViewContactOfGrid::ViewContactOfGrid(ViewContactOfSdrPage& rParentViewContactOfSdrPage, bool bFront)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage),
+ mbFront(bFront)
+{
+}
+
+ViewContactOfGrid::~ViewContactOfGrid()
+{
+}
+
+ViewObjectContact& ViewContactOfHelplines::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfPageHelplines(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+void ViewContactOfHelplines::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor&) const
+{
+ // We have only the page information, not the view information and thus no helplines. Create empty
+ // default. For the view-dependent implementation, see ViewObjectContactOfPageHelplines::createPrimitive2DSequence
+}
+
+ViewContactOfHelplines::ViewContactOfHelplines(ViewContactOfSdrPage& rParentViewContactOfSdrPage, bool bFront)
+: ViewContactOfPageSubObject(rParentViewContactOfSdrPage),
+ mbFront(bFront)
+{
+}
+
+ViewContactOfHelplines::~ViewContactOfHelplines()
+{
+}
+
+// Create an Object-Specific ViewObjectContact, set ViewContact and
+// ObjectContact. Always needs to return something.
+ViewObjectContact& ViewContactOfSdrPage::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+{
+ ViewObjectContact* pRetval = new ViewObjectContactOfSdrPage(rObjectContact, *this);
+ DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
+
+ return *pRetval;
+}
+
+ViewContactOfSdrPage::ViewContactOfSdrPage(SdrPage& rPage)
+: mrPage(rPage),
+ maViewContactOfPageBackground(*this),
+ maViewContactOfPageShadow(*this),
+ maViewContactOfPageFill(*this),
+ maViewContactOfMasterPage(*this),
+ maViewContactOfOuterPageBorder(*this),
+ maViewContactOfInnerPageBorder(*this),
+ maViewContactOfGridBack(*this, false),
+ maViewContactOfHelplinesBack(*this, false),
+ maViewContactOfPageHierarchy(*this),
+ maViewContactOfGridFront(*this, true),
+ maViewContactOfHelplinesFront(*this, true)
+{
+}
+
+ViewContactOfSdrPage::~ViewContactOfSdrPage()
+{
+}
+
+// Access to possible sub-hierarchy
+sal_uInt32 ViewContactOfSdrPage::GetObjectCount() const
+{
+ // Fixed count of content. It contains PageBackground (Wiese), PageShadow, PageFill,
+ // then - depending on if the page has a MasterPage - either MasterPage Hierarchy
+ // or MPBGO. Also OuterPageBorder, InnerPageBorder and two pairs of Grid and Helplines
+ // (for front and back) which internally are visible or not depending on the current
+ // front/back setting for those.
+ return 11;
+}
+
+ViewContact& ViewContactOfSdrPage::GetViewContact(sal_uInt32 nIndex) const
+{
+ switch(nIndex)
+ {
+ case 0: return const_cast<ViewContactOfPageBackground&>(maViewContactOfPageBackground);
+ case 1: return const_cast<ViewContactOfPageShadow&>(maViewContactOfPageShadow);
+ case 2: return const_cast<ViewContactOfPageFill&>(maViewContactOfPageFill);
+ case 3:
+ {
+ const SdrPage& rPage = GetSdrPage();
+
+ if(rPage.TRG_HasMasterPage())
+ {
+ return rPage.TRG_GetMasterPageDescriptorViewContact();
+ }
+ else
+ {
+ return const_cast<ViewContactOfMasterPage&>(maViewContactOfMasterPage);
+ }
+ }
+ case 4: return const_cast<ViewContactOfOuterPageBorder&>(maViewContactOfOuterPageBorder);
+ case 5: return const_cast<ViewContactOfInnerPageBorder&>(maViewContactOfInnerPageBorder);
+ case 6: return const_cast<ViewContactOfGrid&>(maViewContactOfGridBack);
+ case 7: return const_cast<ViewContactOfHelplines&>(maViewContactOfHelplinesBack);
+ case 8: return const_cast<ViewContactOfPageHierarchy&>(maViewContactOfPageHierarchy);
+ case 9: return const_cast<ViewContactOfGrid&>(maViewContactOfGridFront);
+ case 10: case 11: return const_cast<ViewContactOfHelplines&>(maViewContactOfHelplinesFront);
+ default: assert(false);return const_cast<ViewContactOfHelplines&>(maViewContactOfHelplinesFront);
+ }
+}
+
+// React on changes of the object of this ViewContact
+void ViewContactOfSdrPage::ActionChanged()
+{
+ // call parent
+ ViewContact::ActionChanged();
+
+ // apply to local viewContacts, they all rely on page information. Exception
+ // is the sub hierarchy; this will not be influenced by the change
+ maViewContactOfPageBackground.ActionChanged();
+ maViewContactOfPageShadow.ActionChanged();
+ maViewContactOfPageFill.ActionChanged();
+
+ const SdrPage& rPage = GetSdrPage();
+
+ if(rPage.TRG_HasMasterPage())
+ {
+ rPage.TRG_GetMasterPageDescriptorViewContact().ActionChanged();
+ }
+ else if(rPage.IsMasterPage())
+ {
+ maViewContactOfMasterPage.ActionChanged();
+ }
+
+ maViewContactOfOuterPageBorder.ActionChanged();
+ maViewContactOfInnerPageBorder.ActionChanged();
+ maViewContactOfGridBack.ActionChanged();
+ maViewContactOfHelplinesBack.ActionChanged();
+ maViewContactOfGridFront.ActionChanged();
+ maViewContactOfHelplinesFront.ActionChanged();
+}
+
+void ViewContactOfSdrPage::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // collect all sub-sequences including sub hierarchy.
+ maViewContactOfPageBackground.getViewIndependentPrimitive2DContainer(rVisitor);
+ maViewContactOfPageShadow.getViewIndependentPrimitive2DContainer(rVisitor);
+ maViewContactOfPageFill.getViewIndependentPrimitive2DContainer(rVisitor);
+
+ const SdrPage& rPage = GetSdrPage();
+
+ if(rPage.TRG_HasMasterPage())
+ {
+ rPage.TRG_GetMasterPageDescriptorViewContact().getViewIndependentPrimitive2DContainer(rVisitor);
+ }
+ else if(rPage.IsMasterPage())
+ {
+ maViewContactOfMasterPage.getViewIndependentPrimitive2DContainer(rVisitor);
+ }
+
+ maViewContactOfOuterPageBorder.getViewIndependentPrimitive2DContainer(rVisitor);
+ maViewContactOfInnerPageBorder.getViewIndependentPrimitive2DContainer(rVisitor);
+ maViewContactOfPageHierarchy.getViewIndependentPrimitive2DContainer(rVisitor);
+
+ // Only add front versions of grid and helplines since no visibility test is done,
+ // so adding the back incarnations is not necessary. This makes the Front
+ // visualisation the default when no visibility tests are done.
+
+ // Since we have no view here, no grid and helpline definitions are available currently. The used
+ // methods at ViewContactOfHelplines and ViewContactOfGrid return only empty sequences and
+ // do not need to be called ATM. This may change later if grid or helpline info gets
+ // model data (it should not). Keeping the lines commented to hold this hint.
+
+ // drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xRetval, maViewContactOfGridFront.getViewIndependentPrimitive2DContainer());
+ // drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xRetval, maViewContactOfHelplinesFront.getViewIndependentPrimitive2DContainer());
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrpathobj.cxx b/svx/source/sdr/contact/viewcontactofsdrpathobj.cxx
new file mode 100644
index 000000000..8798d40fb
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrpathobj.cxx
@@ -0,0 +1,210 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewcontactofsdrpathobj.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdpage.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <sdr/primitive2d/sdrpathprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <osl/diagnose.h>
+#include <unotools/configmgr.hxx>
+#include <vcl/canvastools.hxx>
+
+namespace sdr::contact
+{
+ ViewContactOfSdrPathObj::ViewContactOfSdrPathObj(SdrPathObj& rPathObj)
+ : ViewContactOfTextObj(rPathObj)
+ {
+ }
+
+ ViewContactOfSdrPathObj::~ViewContactOfSdrPathObj()
+ {
+ }
+
+ /// return true if polycount == 1
+ static bool ensureGeometry(basegfx::B2DPolyPolygon& rUnitPolyPolygon)
+ {
+ sal_uInt32 nPolyCount(rUnitPolyPolygon.count());
+ sal_uInt32 nPointCount(0);
+
+ for(auto const& rPolygon : std::as_const(rUnitPolyPolygon))
+ {
+ nPointCount += rPolygon.count();
+ if (nPointCount > 1)
+ return false;
+ }
+
+ if(!nPointCount)
+ {
+ OSL_FAIL("PolyPolygon object without geometry detected, this should not be created (!)");
+ basegfx::B2DPolygon aFallbackLine;
+ aFallbackLine.append(basegfx::B2DPoint(0.0, 0.0));
+ aFallbackLine.append(basegfx::B2DPoint(1000.0, 1000.0));
+ rUnitPolyPolygon = basegfx::B2DPolyPolygon(aFallbackLine);
+
+ nPolyCount = 1;
+ }
+
+ return nPolyCount == 1;
+ }
+
+ void ViewContactOfSdrPathObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const SfxItemSet& rItemSet = GetPathObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
+ rItemSet,
+ GetPathObj().getText(0),
+ false));
+ basegfx::B2DPolyPolygon aUnitPolyPolygon(GetPathObj().GetPathPoly());
+ bool bPolyCountIsOne(ensureGeometry(aUnitPolyPolygon));
+
+ // prepare object transformation and unit polygon (direct model data)
+ basegfx::B2DHomMatrix aObjectMatrix;
+ basegfx::B2DPolyPolygon aUnitDefinitionPolyPolygon;
+ bool bIsLine(
+ !aUnitPolyPolygon.areControlPointsUsed()
+ && bPolyCountIsOne
+ && 2 == aUnitPolyPolygon.getB2DPolygon(0).count());
+
+ if(bIsLine)
+ {
+ //tdf#63955 if we have an extremely long line then clip it to a
+ //very generous range of -1 page width/height vs +1 page
+ //width/height to avoid oom and massive churn generating a huge
+ //polygon chain to cover the length in applyLineDashing if this
+ //line is dashed
+ const SdrPage* pPage(GetPathObj().getSdrPageFromSdrObject());
+ sal_Int32 nPageWidth = pPage ? pPage->GetWidth() : 0;
+ sal_Int32 nPageHeight = pPage ? pPage->GetHeight() : 0;
+
+ //But, see tdf#101187, only do this if our generous clip region
+ //would not over flow into a tiny clip region
+ if (nPageWidth < SAL_MAX_INT32/2 && nPageHeight < SAL_MAX_INT32/2 && !utl::ConfigManager::IsFuzzing())
+ {
+ //But, see tdf#97276, tdf#126184 and tdf#98366. Don't clip too much if the
+ //underlying page dimension is unknown or a paste document
+ //where the page sizes use the odd default of 10x10
+ const sal_Int32 nMaxPaperWidth = SvtOptionsDrawinglayer::GetMaximumPaperWidth() * 1000;
+ const sal_Int32 nMaxPaperHeight = SvtOptionsDrawinglayer::GetMaximumPaperHeight() * 1000;
+ nPageWidth = std::max<sal_Int32>(nPageWidth, nMaxPaperWidth);
+ nPageHeight = std::max<sal_Int32>(nPageHeight, nMaxPaperHeight);
+ basegfx::B2DRange aClipRange(-nPageWidth, -nPageHeight,
+ nPageWidth*2, nPageHeight*2);
+
+ aUnitPolyPolygon = basegfx::utils::clipPolyPolygonOnRange(aUnitPolyPolygon,
+ aClipRange, true, true);
+ bPolyCountIsOne = ensureGeometry(aUnitPolyPolygon);
+
+ // re-check that we have't been clipped out to oblivion
+ bIsLine =
+ !aUnitPolyPolygon.areControlPointsUsed()
+ && bPolyCountIsOne
+ && 2 == aUnitPolyPolygon.getB2DPolygon(0).count();
+ }
+ }
+
+ if(bIsLine)
+ {
+
+ // special handling for single line mode (2 points)
+ const basegfx::B2DPolygon aSubPolygon(aUnitPolyPolygon.getB2DPolygon(0));
+ const basegfx::B2DPoint aStart(aSubPolygon.getB2DPoint(0));
+ const basegfx::B2DPoint aEnd(aSubPolygon.getB2DPoint(1));
+ const basegfx::B2DVector aLine(aEnd - aStart);
+
+ // #i102548# create new unit polygon for line (horizontal)
+ basegfx::B2DPolygon aNewPolygon;
+ aNewPolygon.append(basegfx::B2DPoint(0.0, 0.0));
+ aNewPolygon.append(basegfx::B2DPoint(1.0, 0.0));
+ aUnitPolyPolygon.setB2DPolygon(0, aNewPolygon);
+
+ // #i102548# fill objectMatrix with rotation and offset (no shear for lines)
+ aObjectMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aLine.getLength(), 1.0,
+ 0.0,
+ atan2(aLine.getY(), aLine.getX()),
+ aStart.getX(), aStart.getY());
+ }
+ else
+ {
+ // #i102548# create unscaled, unsheared, unrotated and untranslated polygon
+ // (unit polygon) by creating the object matrix and back-transforming the polygon
+ const basegfx::B2DRange aObjectRange(basegfx::utils::getRange(aUnitPolyPolygon));
+ const GeoStat& rGeoStat(GetPathObj().GetGeoStat());
+ const double fWidth(aObjectRange.getWidth());
+ const double fHeight(aObjectRange.getHeight());
+ const double fScaleX(basegfx::fTools::equalZero(fWidth) ? 1.0 : fWidth);
+ const double fScaleY(basegfx::fTools::equalZero(fHeight) ? 1.0 : fHeight);
+
+ aObjectMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ fScaleX, fScaleY,
+ -rGeoStat.mfTanShearAngle,
+ rGeoStat.nRotationAngle ? toRadians(36000_deg100 - rGeoStat.nRotationAngle) : 0.0,
+ aObjectRange.getMinX(), aObjectRange.getMinY());
+
+ // create unit polygon from object's absolute path
+ basegfx::B2DHomMatrix aInverse(aObjectMatrix);
+ aInverse.invert();
+ aUnitPolyPolygon.transform(aInverse);
+
+ // OperationSmiley: Check if a FillGeometryDefiningShape is set
+ const SdrObject* pFillGeometryDefiningShape(GetPathObj().getFillGeometryDefiningShape());
+
+ if(nullptr != pFillGeometryDefiningShape)
+ {
+ // If yes, get it's BoundRange and use as defining Geometry for the FillStyle.
+ // If no, aUnitDefinitionPolyPolygon will just be empty and thus be interpreted
+ // as unused.
+ // Using SnapRect will make the FillDefinition to always be extended e.g.
+ // for rotated/sheared objects.
+ const tools::Rectangle& rSnapRect(pFillGeometryDefiningShape->GetSnapRect());
+
+ aUnitDefinitionPolyPolygon.append(
+ basegfx::utils::createPolygonFromRect(
+ vcl::unotools::b2DRectangleFromRectangle(rSnapRect)));
+
+ // use same coordinate system as the shape geometry -> this
+ // makes it relative to shape's unit geometry and thus freely
+ // transformable with the shape
+ aUnitDefinitionPolyPolygon.transform(aInverse);
+ }
+ }
+
+ // create primitive. Always create primitives to allow the decomposition of
+ // SdrPathPrimitive2D to create needed invisible elements for HitTest and/or BoundRect
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrPathPrimitive2D(
+ aObjectMatrix,
+ aAttribute,
+ aUnitPolyPolygon,
+ aUnitDefinitionPolyPolygon));
+
+ rVisitor.visit(xReference);
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofsdrrectobj.cxx b/svx/source/sdr/contact/viewcontactofsdrrectobj.cxx
new file mode 100644
index 000000000..6d9ed7bed
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrrectobj.cxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactofsdrrectobj.hxx>
+#include <svx/svdorect.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/primitive2d/sdrrectangleprimitive2d.hxx>
+#include <svl/itemset.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <svx/svdmodel.hxx>
+#include <vcl/canvastools.hxx>
+#include <svx/sdmetitm.hxx>
+
+namespace sdr::contact {
+
+ViewContactOfSdrRectObj::ViewContactOfSdrRectObj(SdrRectObj& rRectObj)
+: ViewContactOfTextObj(rRectObj)
+{
+}
+
+ViewContactOfSdrRectObj::~ViewContactOfSdrRectObj()
+{
+}
+
+void ViewContactOfSdrRectObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SfxItemSet& rItemSet = GetRectObj().GetMergedItemSet();
+ const drawinglayer::attribute::SdrLineFillEffectsTextAttribute aAttribute(
+ drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
+ rItemSet,
+ GetRectObj().getText(0),
+ false));
+
+ // take unrotated snap rect (direct model data) for position and size
+ const tools::Rectangle aRectangle(GetRectObj().GetGeoRect());
+ const ::basegfx::B2DRange aObjectRange = vcl::unotools::b2DRectangleFromRectangle(aRectangle);
+
+ const GeoStat& rGeoStat(GetRectObj().GetGeoStat());
+
+ // fill object matrix
+ basegfx::B2DHomMatrix aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aObjectRange.getWidth(), aObjectRange.getHeight(),
+ -rGeoStat.mfTanShearAngle,
+ rGeoStat.nRotationAngle ? toRadians(36000_deg100 - rGeoStat.nRotationAngle) : 0.0,
+ aObjectRange.getMinX(), aObjectRange.getMinY()));
+
+ // calculate corner radius
+ sal_uInt32 nCornerRadius(rItemSet.Get(SDRATTR_CORNER_RADIUS).GetValue());
+ double fCornerRadiusX;
+ double fCornerRadiusY;
+ drawinglayer::primitive2d::calculateRelativeCornerRadius(nCornerRadius, aObjectRange, fCornerRadiusX, fCornerRadiusY);
+
+ // #i105856# use knowledge about pickthrough from the model
+ const bool bPickThroughTransparentTextFrames(GetRectObj().getSdrModelFromSdrObject().IsPickThroughTransparentTextFrames());
+
+ // create primitive. Always create primitives to allow the decomposition of
+ // SdrRectanglePrimitive2D to create needed invisible elements for HitTest and/or BoundRect
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::SdrRectanglePrimitive2D(
+ aObjectMatrix,
+ aAttribute,
+ fCornerRadiusX,
+ fCornerRadiusY,
+ // #i105856# use fill for HitTest when TextFrame and not PickThrough
+ GetRectObj().IsTextFrame() && !bPickThroughTransparentTextFrames));
+
+ rVisitor.visit(xReference);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactoftextobj.cxx b/svx/source/sdr/contact/viewcontactoftextobj.cxx
new file mode 100644
index 000000000..9e10d0130
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactoftextobj.cxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewcontactoftextobj.hxx>
+#include <svx/svdotext.hxx>
+
+namespace sdr::contact
+{
+ViewContactOfTextObj::ViewContactOfTextObj(SdrTextObj& rTextObj)
+ : ViewContactOfSdrObj(rTextObj)
+{
+}
+
+ViewContactOfTextObj::~ViewContactOfTextObj() {}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofunocontrol.cxx b/svx/source/sdr/contact/viewcontactofunocontrol.cxx
new file mode 100644
index 000000000..f99b24372
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofunocontrol.cxx
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/contact/viewcontactofunocontrol.hxx>
+#include <sdr/contact/viewobjectcontactofunocontrol.hxx>
+#include <svx/sdr/contact/objectcontactofpageview.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sdrpagewindow.hxx>
+
+#include <vcl/canvastools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/primitive2d/controlprimitive2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <osl/diagnose.h>
+
+
+namespace sdr::contact {
+
+
+ using ::com::sun::star::awt::XControl;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::awt::XControlContainer;
+ using ::com::sun::star::awt::XControlModel;
+
+
+ //= ViewContactOfUnoControl
+
+ ViewContactOfUnoControl::ViewContactOfUnoControl( SdrUnoObj& _rUnoObject )
+ :ViewContactOfSdrObj( _rUnoObject )
+ {
+ }
+
+
+ ViewContactOfUnoControl::~ViewContactOfUnoControl()
+ {
+ }
+
+
+ Reference< XControl > ViewContactOfUnoControl::getTemporaryControlForWindow(
+ const vcl::Window& _rWindow, Reference< XControlContainer >& _inout_ControlContainer ) const
+ {
+ SdrUnoObj* pUnoObject = dynamic_cast< SdrUnoObj* >( TryToGetSdrObject() );
+ OSL_ENSURE( pUnoObject, "ViewContactOfUnoControl::getTemporaryControlForDevice: no SdrUnoObj!" );
+ if ( !pUnoObject )
+ return nullptr;
+ return ViewObjectContactOfUnoControl::getTemporaryControlForWindow( _rWindow, _inout_ControlContainer, *pUnoObject );
+ }
+
+
+ ViewObjectContact& ViewContactOfUnoControl::CreateObjectSpecificViewObjectContact( ObjectContact& _rObjectContact )
+ {
+ // print or print preview requires special handling
+ const OutputDevice* pDevice = _rObjectContact.TryToGetOutputDevice();
+ ObjectContactOfPageView* const pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &_rObjectContact );
+
+ const bool bPrintOrPreview = pPageViewContact
+ && ( ( ( pDevice != nullptr ) && ( pDevice->GetOutDevType() == OUTDEV_PRINTER ) )
+ || pPageViewContact->GetPageWindow().GetPageView().GetView().IsPrintPreview()
+ )
+ ;
+
+ if ( bPrintOrPreview )
+ return *new UnoControlPrintOrPreviewContact( *pPageViewContact, *this );
+
+ // all others are nowadays served by the same implementation
+ return *new ViewObjectContactOfUnoControl( _rObjectContact, *this );
+ }
+
+
+ void ViewContactOfUnoControl::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ // create range. Use model data directly, not getBoundRect()/getSnapRect; these will use
+ // the primitive data themselves in the long run. Use SdrUnoObj's (which is a SdrRectObj)
+ // call to GetGeoRect() to access SdrTextObj::aRect directly and without executing anything
+ const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(GetSdrUnoObj().GetGeoRect());
+
+ // create object transform
+ basegfx::B2DHomMatrix aTransform;
+
+ aTransform.set(0, 0, aRange.getWidth());
+ aTransform.set(1, 1, aRange.getHeight());
+ aTransform.set(0, 2, aRange.getMinX());
+ aTransform.set(1, 2, aRange.getMinY());
+
+ Reference< XControlModel > xControlModel = GetSdrUnoObj().GetUnoControlModel();
+
+ if(xControlModel.is())
+ {
+ // create control primitive WITHOUT possibly existing XControl; this would be done in
+ // the VOC in createPrimitive2DSequence()
+ const drawinglayer::primitive2d::Primitive2DReference xRetval(
+ new drawinglayer::primitive2d::ControlPrimitive2D(
+ aTransform,
+ xControlModel));
+
+ rVisitor.visit(xRetval);
+ }
+ else
+ {
+ // always append an invisible outline for the cases where no visible content exists
+ const drawinglayer::primitive2d::Primitive2DReference xRetval(
+ drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
+ aTransform));
+
+ rVisitor.visit(xRetval);
+ }
+ }
+
+
+} // namespace sdr::contact
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewcontactofvirtobj.cxx b/svx/source/sdr/contact/viewcontactofvirtobj.cxx
new file mode 100644
index 000000000..f4087d036
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofvirtobj.cxx
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/viewcontactofvirtobj.hxx>
+#include <svx/svdovirt.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+
+namespace sdr::contact {
+
+ViewContactOfVirtObj::ViewContactOfVirtObj(SdrVirtObj& rObj)
+: ViewContactOfSdrObj(rObj)
+{
+}
+
+ViewContactOfVirtObj::~ViewContactOfVirtObj()
+{
+}
+
+SdrVirtObj& ViewContactOfVirtObj::GetVirtObj() const
+{
+ return static_cast<SdrVirtObj&>(mrObject);
+}
+
+// Access to possible sub-hierarchy
+sal_uInt32 ViewContactOfVirtObj::GetObjectCount() const
+{
+ // Here, SdrVirtObj's need to return 0L to show that they have no
+ // sub-hierarchy, even when they are group objects. This is necessary
+ // to avoid that the same VOCs will be added to the draw hierarchy
+ // twice which leads to problems.
+
+ // This solution is only a first solution to get things running. Later
+ // this needs to be replaced with creating real VOCs for the objects
+ // referenced by virtual objects to avoid the 'trick' of setting the
+ // offset for painting at the destination OutputDevice.
+
+ // As can be seen, with primitives, the problem will be solved using
+ // a transformPrimitive, so this solution can stay with primitives.
+ return 0;
+}
+
+void ViewContactOfVirtObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // create displacement transformation if we have content
+ basegfx::B2DHomMatrix aObjectMatrix;
+ Point aAnchor(GetVirtObj().GetAnchorPos());
+
+ if(aAnchor.X() || aAnchor.Y())
+ {
+ aObjectMatrix.set(0, 2, aAnchor.X());
+ aObjectMatrix.set(1, 2, aAnchor.Y());
+ }
+
+ // use method from referenced object to get the Primitive2DContainer
+ drawinglayer::primitive2d::Primitive2DContainer xSequenceVirtual;
+ GetVirtObj().GetReferencedObj().GetViewContact().getViewIndependentPrimitive2DContainer(xSequenceVirtual);
+
+ if(!xSequenceVirtual.empty())
+ {
+ // create transform primitive
+ drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aObjectMatrix,
+ drawinglayer::primitive2d::Primitive2DContainer(xSequenceVirtual)));
+
+ rVisitor.visit(xReference);
+ }
+ else
+ {
+ // always append an invisible outline for the cases where no visible content exists
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
+ aObjectMatrix));
+
+ rVisitor.visit(xReference);
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/svx/source/sdr/contact/viewobjectcontact.cxx b/svx/source/sdr/contact/viewobjectcontact.cxx
new file mode 100644
index 000000000..18acd5e52
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontact.cxx
@@ -0,0 +1,570 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/animation/animationstate.hxx>
+#include <svx/sdr/contact/viewobjectcontactredirector.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdotext.hxx>
+#include <vcl/pdfwriter.hxx>
+
+using namespace com::sun::star;
+
+namespace {
+
+// animated extractor
+
+// Necessary to filter a sequence of animated primitives from
+// a sequence of primitives to find out if animated or not. The decision for
+// what to decompose is hard-coded and only done for knowingly animated primitives
+// to not decompose too deeply and unnecessarily. This implies that the list
+// which is view-specific needs to be expanded by hand when new animated objects
+// are added. This may eventually be changed to a dynamically configurable approach
+// if necessary.
+class AnimatedExtractingProcessor2D : public drawinglayer::processor2d::BaseProcessor2D
+{
+protected:
+ // the found animated primitives
+ drawinglayer::primitive2d::Primitive2DContainer maPrimitive2DSequence;
+
+ // text animation allowed?
+ bool mbTextAnimationAllowed : 1;
+
+ // graphic animation allowed?
+ bool mbGraphicAnimationAllowed : 1;
+
+ // as tooling, the process() implementation takes over API handling and calls this
+ // virtual render method when the primitive implementation is BasePrimitive2D-based.
+ virtual void processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D& rCandidate) override;
+
+public:
+ AnimatedExtractingProcessor2D(
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation,
+ bool bTextAnimationAllowed,
+ bool bGraphicAnimationAllowed);
+
+ // data access
+ const drawinglayer::primitive2d::Primitive2DContainer& getPrimitive2DSequence() const { return maPrimitive2DSequence; }
+ drawinglayer::primitive2d::Primitive2DContainer extractPrimitive2DSequence() const { return std::move(maPrimitive2DSequence); }
+};
+
+AnimatedExtractingProcessor2D::AnimatedExtractingProcessor2D(
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation,
+ bool bTextAnimationAllowed,
+ bool bGraphicAnimationAllowed)
+: drawinglayer::processor2d::BaseProcessor2D(rViewInformation),
+ mbTextAnimationAllowed(bTextAnimationAllowed),
+ mbGraphicAnimationAllowed(bGraphicAnimationAllowed)
+{
+}
+
+void AnimatedExtractingProcessor2D::processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D& rCandidate)
+{
+ // known implementation, access directly
+ switch(rCandidate.getPrimitive2DID())
+ {
+ // add and accept animated primitives directly, no need to decompose
+ case PRIMITIVE2D_ID_ANIMATEDSWITCHPRIMITIVE2D :
+ case PRIMITIVE2D_ID_ANIMATEDBLINKPRIMITIVE2D :
+ case PRIMITIVE2D_ID_ANIMATEDINTERPOLATEPRIMITIVE2D :
+ {
+ const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D& rSwitchPrimitive = static_cast< const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D& >(rCandidate);
+
+ if((rSwitchPrimitive.isTextAnimation() && mbTextAnimationAllowed)
+ || (rSwitchPrimitive.isGraphicAnimation() && mbGraphicAnimationAllowed))
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xReference(const_cast< drawinglayer::primitive2d::BasePrimitive2D* >(&rCandidate));
+ maPrimitive2DSequence.push_back(xReference);
+ }
+ break;
+ }
+
+ // decompose animated gifs where SdrGrafPrimitive2D produces a GraphicPrimitive2D
+ // which then produces the animation infos (all when used/needed)
+ case PRIMITIVE2D_ID_SDRGRAFPRIMITIVE2D :
+ case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D :
+
+ // decompose SdrObjects with evtl. animated text
+ case PRIMITIVE2D_ID_SDRCAPTIONPRIMITIVE2D :
+ case PRIMITIVE2D_ID_SDRCONNECTORPRIMITIVE2D :
+ case PRIMITIVE2D_ID_SDRCUSTOMSHAPEPRIMITIVE2D :
+ case PRIMITIVE2D_ID_SDRELLIPSEPRIMITIVE2D :
+ case PRIMITIVE2D_ID_SDRELLIPSESEGMENTPRIMITIVE2D :
+ case PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D :
+ case PRIMITIVE2D_ID_SDRPATHPRIMITIVE2D :
+ case PRIMITIVE2D_ID_SDRRECTANGLEPRIMITIVE2D :
+
+ // #121194# With Graphic as Bitmap FillStyle, also check
+ // for primitives filled with animated graphics
+ case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D:
+ case PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D:
+ case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D:
+
+ // decompose evtl. animated text contained in MaskPrimitive2D
+ // or group primitives
+ case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
+ case PRIMITIVE2D_ID_GROUPPRIMITIVE2D :
+ {
+ process(rCandidate);
+ break;
+ }
+
+ default :
+ {
+ // nothing to do for the rest
+ break;
+ }
+ }
+}
+
+} // end of anonymous namespace
+
+namespace sdr::contact {
+
+ViewObjectContact::ViewObjectContact(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: mrObjectContact(rObjectContact),
+ mrViewContact(rViewContact),
+ maGridOffset(0.0, 0.0),
+ mnActionChangedCount(0),
+ mbLazyInvalidate(false)
+{
+ // make the ViewContact remember me
+ mrViewContact.AddViewObjectContact(*this);
+
+ // make the ObjectContact remember me
+ mrObjectContact.AddViewObjectContact(*this);
+}
+
+ViewObjectContact::~ViewObjectContact()
+{
+ // invalidate in view
+ if(!getObjectRange().isEmpty())
+ {
+ GetObjectContact().InvalidatePartOfView(maObjectRange);
+ }
+
+ // delete PrimitiveAnimation
+ mpPrimitiveAnimation.reset();
+
+ // take care of remembered ObjectContact. Remove from
+ // OC first. The VC removal (below) CAN trigger a StopGettingViewed()
+ // which (depending of its implementation) may destroy other OCs. This
+ // can trigger the deletion of the helper OC of a page visualising object
+ // which IS the OC of this object. Eventually StopGettingViewed() needs
+ // to get asynchron later
+ GetObjectContact().RemoveViewObjectContact(*this);
+
+ // take care of remembered ViewContact
+ GetViewContact().RemoveViewObjectContact(*this);
+}
+
+const basegfx::B2DRange& ViewObjectContact::getObjectRange() const
+{
+ if(maObjectRange.isEmpty())
+ {
+ const drawinglayer::geometry::ViewInformation2D& rViewInfo2D = GetObjectContact().getViewInformation2D();
+ basegfx::B2DRange aTempRange = GetViewContact().getRange(rViewInfo2D);
+ if (!aTempRange.isEmpty())
+ {
+ const_cast< ViewObjectContact* >(this)->maObjectRange = aTempRange;
+ }
+ else
+ {
+ // if range is not computed (new or LazyInvalidate objects), force it
+ const DisplayInfo aDisplayInfo;
+ const drawinglayer::primitive2d::Primitive2DContainer& xSequence(getPrimitive2DSequence(aDisplayInfo));
+
+ if(!xSequence.empty())
+ {
+ const_cast< ViewObjectContact* >(this)->maObjectRange =
+ xSequence.getB2DRange(rViewInfo2D);
+ }
+ }
+ }
+
+ return maObjectRange;
+}
+
+void ViewObjectContact::ActionChanged()
+{
+ // clear cached primitives
+ mxPrimitive2DSequence.clear();
+ ++mnActionChangedCount;
+
+ if(mbLazyInvalidate)
+ return;
+
+ // set local flag
+ mbLazyInvalidate = true;
+
+ // force ObjectRange
+ getObjectRange();
+
+ if(!getObjectRange().isEmpty())
+ {
+ // invalidate current valid range
+ GetObjectContact().InvalidatePartOfView(maObjectRange);
+
+ // reset gridOffset, it needs to be recalculated
+ if (GetObjectContact().supportsGridOffsets())
+ resetGridOffset();
+ else
+ maObjectRange.reset();
+ }
+
+ // register at OC for lazy invalidate
+ GetObjectContact().setLazyInvalidate(*this);
+}
+
+void ViewObjectContact::triggerLazyInvalidate()
+{
+ if(!mbLazyInvalidate)
+ return;
+
+ // reset flag
+ mbLazyInvalidate = false;
+
+ // force ObjectRange
+ getObjectRange();
+
+ if(!getObjectRange().isEmpty())
+ {
+ // invalidate current valid range
+ GetObjectContact().InvalidatePartOfView(maObjectRange);
+ }
+}
+
+// Take some action when new objects are inserted
+void ViewObjectContact::ActionChildInserted(ViewContact& rChild)
+{
+ // force creation of the new VOC and trigger it's refresh, so it
+ // will take part in LazyInvalidate immediately
+ rChild.GetViewObjectContact(GetObjectContact()).ActionChanged();
+
+ // forward action to ObjectContact
+ // const ViewObjectContact& rChildVOC = rChild.GetViewObjectContact(GetObjectContact());
+ // GetObjectContact().InvalidatePartOfView(rChildVOC.getObjectRange());
+}
+
+void ViewObjectContact::checkForPrimitive2DAnimations()
+{
+ // remove old one
+ mpPrimitiveAnimation.reset();
+
+ // check for animated primitives
+ if(mxPrimitive2DSequence.empty())
+ return;
+
+ const bool bTextAnimationAllowed(GetObjectContact().IsTextAnimationAllowed());
+ const bool bGraphicAnimationAllowed(GetObjectContact().IsGraphicAnimationAllowed());
+
+ if(bTextAnimationAllowed || bGraphicAnimationAllowed)
+ {
+ AnimatedExtractingProcessor2D aAnimatedExtractor(GetObjectContact().getViewInformation2D(),
+ bTextAnimationAllowed, bGraphicAnimationAllowed);
+ aAnimatedExtractor.process(mxPrimitive2DSequence);
+
+ if(!aAnimatedExtractor.getPrimitive2DSequence().empty())
+ {
+ // derived primitiveList is animated, setup new PrimitiveAnimation
+ mpPrimitiveAnimation.reset( new sdr::animation::PrimitiveAnimation(*this, aAnimatedExtractor.extractPrimitive2DSequence()) );
+ }
+ }
+}
+
+void ViewObjectContact::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // get the view-independent Primitive from the viewContact
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
+
+ if(!xRetval.empty())
+ {
+ // handle GluePoint
+ if(!GetObjectContact().isOutputToPrinter() && GetObjectContact().AreGluePointsVisible())
+ {
+ const drawinglayer::primitive2d::Primitive2DContainer xGlue(GetViewContact().createGluePointPrimitive2DSequence());
+
+ if(!xGlue.empty())
+ {
+ xRetval.append(xGlue);
+ }
+ }
+
+ // handle ghosted
+ if(isPrimitiveGhosted(rDisplayInfo))
+ {
+ const basegfx::BColor aRGBWhite(1.0, 1.0, 1.0);
+ const basegfx::BColorModifierSharedPtr aBColorModifier =
+ std::make_shared<basegfx::BColorModifier_interpolate>(
+ aRGBWhite,
+ 0.5);
+ drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
+ std::move(xRetval),
+ aBColorModifier));
+
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReference };
+ }
+ }
+
+ rVisitor.visit(xRetval);
+}
+
+drawinglayer::primitive2d::Primitive2DContainer const & ViewObjectContact::getPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const
+{
+ // only some of the top-level apps are any good at reliably invalidating us (e.g. writer is not)
+ SdrObject* pSdrObj(mrViewContact.TryToGetSdrObject());
+
+ if (nullptr != pSdrObj && pSdrObj->getSdrModelFromSdrObject().IsVOCInvalidationIsReliable())
+ {
+ if (!mxPrimitive2DSequence.empty())
+ return mxPrimitive2DSequence;
+ }
+
+ // prepare new representation
+ drawinglayer::primitive2d::Primitive2DContainer xNewPrimitiveSequence;
+
+ // take care of redirectors and create new list
+ ViewObjectContactRedirector* pRedirector = GetObjectContact().GetViewObjectContactRedirector();
+
+ if(pRedirector)
+ {
+ pRedirector->createRedirectedPrimitive2DSequence(*this, rDisplayInfo, xNewPrimitiveSequence);
+ }
+ else
+ {
+ createPrimitive2DSequence(rDisplayInfo, xNewPrimitiveSequence);
+ }
+
+ // check and eventually embed to GridOffset transform primitive (calc only)
+ if(!xNewPrimitiveSequence.empty() && GetObjectContact().supportsGridOffsets())
+ {
+ const basegfx::B2DVector& rGridOffset(getGridOffset());
+
+ if(0.0 != rGridOffset.getX() || 0.0 != rGridOffset.getY())
+ {
+ const basegfx::B2DHomMatrix aTranslateGridOffset(
+ basegfx::utils::createTranslateB2DHomMatrix(
+ rGridOffset));
+ drawinglayer::primitive2d::Primitive2DReference aEmbed(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aTranslateGridOffset,
+ std::move(xNewPrimitiveSequence)));
+ xNewPrimitiveSequence = drawinglayer::primitive2d::Primitive2DContainer { aEmbed };
+ }
+ }
+
+ // Check if we need to embed to a StructureTagPrimitive2D, too. This
+ // was done at ImplRenderPaintProc::createRedirectedPrimitive2DSequence before
+ if (!xNewPrimitiveSequence.empty() && GetObjectContact().isExportTaggedPDF())
+ {
+ if (nullptr != pSdrObj)
+ {
+ vcl::PDFWriter::StructElement eElement(vcl::PDFWriter::NonStructElement);
+ const SdrInventor nInventor(pSdrObj->GetObjInventor());
+ const SdrObjKind nIdentifier(pSdrObj->GetObjIdentifier());
+ const bool bIsTextObj(nullptr != dynamic_cast<const SdrTextObj *>(pSdrObj));
+
+ // Note: SwFlyDrawObj/SwVirtFlyDrawObj have SdrInventor::Swg - these
+ // are *not* handled here because not all of them are painted
+ // completely with primitives, so a tag here does not encapsulate them.
+ // The tag must be created by SwTaggedPDFHelper until this is fixed.
+ if ( nInventor == SdrInventor::Default )
+ {
+ if ( nIdentifier == SdrObjKind::Group )
+ eElement = vcl::PDFWriter::Section;
+ else if (nIdentifier == SdrObjKind::Table)
+ eElement = vcl::PDFWriter::Table;
+ else if ( nIdentifier == SdrObjKind::TitleText )
+ eElement = vcl::PDFWriter::Heading;
+ else if ( nIdentifier == SdrObjKind::OutlineText )
+ eElement = vcl::PDFWriter::Division;
+ else if ( !bIsTextObj || !static_cast<const SdrTextObj&>(*pSdrObj).HasText() )
+ eElement = vcl::PDFWriter::Figure;
+ else
+ eElement = vcl::PDFWriter::Division;
+ }
+
+ if(vcl::PDFWriter::NonStructElement != eElement)
+ {
+ SdrPage* pSdrPage(pSdrObj->getSdrPageFromSdrObject());
+
+ if(pSdrPage)
+ {
+ const bool bBackground(pSdrPage->IsMasterPage());
+ const bool bImage(SdrObjKind::Graphic == pSdrObj->GetObjIdentifier());
+ // note: there must be output device here, in PDF export
+ sal_Int32 nAnchorId(-1);
+ if (auto const pUserCall = pSdrObj->GetUserCall())
+ {
+ nAnchorId = pUserCall->GetPDFAnchorStructureElementId(
+ *pSdrObj, *GetObjectContact().TryToGetOutputDevice());
+ }
+
+ drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::StructureTagPrimitive2D(
+ eElement,
+ bBackground,
+ bImage,
+ std::move(xNewPrimitiveSequence),
+ nAnchorId));
+ xNewPrimitiveSequence = drawinglayer::primitive2d::Primitive2DContainer { xReference };
+ }
+ }
+ }
+ else
+ {
+ // page backgrounds etc should be tagged as artifacts:
+ xNewPrimitiveSequence = drawinglayer::primitive2d::Primitive2DContainer {
+ new drawinglayer::primitive2d::StructureTagPrimitive2D(
+ // lies to force silly VclMetafileProcessor2D to emit NonStructElement
+ vcl::PDFWriter::Division,
+ true,
+ true,
+ std::move(xNewPrimitiveSequence))
+ };
+ }
+ }
+
+ // Local up-to-date checks. New list different from local one?
+ // This is the important point where it gets decided if the current or the new
+ // representation gets used. This is important for performance, since the
+ // current representation contains possible precious decompositions. That
+ // comparisons triggers exactly if something in the object visualization
+ // has changed.
+ // Note: That is the main reason for BasePrimitive2D::operator== at all. I
+ // have alternatively tried to invalidate the local representation on object
+ // change, but that is simply not reliable.
+ // Note2: I did that once in aw080, the lost CWS, and it worked well enough
+ // so that I could remove *all* operator== from all derivations of
+ // BasePrimitive2D, so it can be done again (with the needed ressources)
+ if(mxPrimitive2DSequence != xNewPrimitiveSequence)
+ {
+ // has changed, copy content
+ const_cast< ViewObjectContact* >(this)->mxPrimitive2DSequence = std::move(xNewPrimitiveSequence);
+
+ // check for animated stuff
+ const_cast< ViewObjectContact* >(this)->checkForPrimitive2DAnimations();
+
+ // always update object range when PrimitiveSequence changes
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D());
+ const_cast< ViewObjectContact* >(this)->maObjectRange = mxPrimitive2DSequence.getB2DRange(rViewInformation2D);
+ }
+
+ // return current Primitive2DContainer
+ return mxPrimitive2DSequence;
+}
+
+bool ViewObjectContact::isPrimitiveVisible(const DisplayInfo& /*rDisplayInfo*/) const
+{
+ // default: always visible
+ return true;
+}
+
+bool ViewObjectContact::isPrimitiveGhosted(const DisplayInfo& rDisplayInfo) const
+{
+ // default: standard check
+ return (GetObjectContact().DoVisualizeEnteredGroup() && !GetObjectContact().isOutputToPrinter() && rDisplayInfo.IsGhostedDrawModeActive());
+}
+
+void ViewObjectContact::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // check model-view visibility
+ if(!isPrimitiveVisible(rDisplayInfo))
+ return;
+
+ getPrimitive2DSequence(rDisplayInfo);
+ if(mxPrimitive2DSequence.empty())
+ return;
+
+ // get ranges
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D());
+ // tdf#147164 cannot use maObjectRange here, it is unreliable
+ const basegfx::B2DRange aObjectRange(mxPrimitive2DSequence.getB2DRange(rViewInformation2D));
+ const basegfx::B2DRange& aViewRange(rViewInformation2D.getViewport());
+
+ // check geometrical visibility
+ bool bVisible = aViewRange.isEmpty() || aViewRange.overlaps(aObjectRange);
+ if(!bVisible)
+ return;
+
+ // temporarily take over the mxPrimitive2DSequence, in case it gets invalidated while we want to iterate over it
+ auto tmp = std::move(const_cast<ViewObjectContact*>(this)->mxPrimitive2DSequence);
+ int nPrevCount = mnActionChangedCount;
+
+ rVisitor.visit(tmp);
+
+ // if we received ActionChanged() calls while walking the primitives, then leave it empty, otherwise move it back
+ if (mnActionChangedCount == nPrevCount)
+ const_cast<ViewObjectContact*>(this)->mxPrimitive2DSequence = std::move(tmp);
+}
+
+void ViewObjectContact::getPrimitive2DSequenceSubHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const sal_uInt32 nSubHierarchyCount(GetViewContact().GetObjectCount());
+
+ for(sal_uInt32 a(0); a < nSubHierarchyCount; a++)
+ {
+ const ViewObjectContact& rCandidate(GetViewContact().GetViewContact(a).GetViewObjectContact(GetObjectContact()));
+
+ rCandidate.getPrimitive2DSequenceHierarchy(rDisplayInfo, rVisitor);
+ }
+}
+
+// Support getting a GridOffset per object and view for non-linear ViewToDevice
+// transformation (calc). On-demand created by delegating to the ObjectContact
+// (->View) that has then all needed information
+const basegfx::B2DVector& ViewObjectContact::getGridOffset() const
+{
+ if(0.0 == maGridOffset.getX() && 0.0 == maGridOffset.getY() && GetObjectContact().supportsGridOffsets())
+ {
+ // create on-demand
+ GetObjectContact().calculateGridOffsetForViewOjectContact(const_cast<ViewObjectContact*>(this)->maGridOffset, *this);
+ }
+
+ return maGridOffset;
+}
+
+void ViewObjectContact::resetGridOffset()
+{
+ // reset buffered GridOffset itself
+ maGridOffset.setX(0.0);
+ maGridOffset.setY(0.0);
+
+ // also reset sequence to get a re-calculation when GridOffset changes
+ mxPrimitive2DSequence.clear();
+ maObjectRange.reset();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofe3d.cxx b/svx/source/sdr/contact/viewobjectcontactofe3d.cxx
new file mode 100644
index 000000000..c6d41bdc9
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofe3d.cxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewobjectcontactofe3d.hxx>
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <drawinglayer/primitive3d/modifiedcolorprimitive3d.hxx>
+
+namespace sdr::contact
+{
+ ViewObjectContactOfE3d::ViewObjectContactOfE3d(ObjectContact& rObjectContact, ViewContact& rViewContact)
+ : ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
+ {
+ }
+
+ ViewObjectContactOfE3d::~ViewObjectContactOfE3d()
+ {
+ }
+
+ drawinglayer::primitive3d::Primitive3DContainer ViewObjectContactOfE3d::getPrimitive3DContainer(const DisplayInfo& rDisplayInfo) const
+ {
+ // get the view-independent Primitive from the viewContact
+ const ViewContactOfE3d& rViewContactOfE3d(dynamic_cast< const ViewContactOfE3d& >(GetViewContact()));
+ drawinglayer::primitive3d::Primitive3DContainer xRetval(rViewContactOfE3d.getViewIndependentPrimitive3DContainer());
+
+ // handle ghosted
+ if(isPrimitiveGhosted(rDisplayInfo))
+ {
+ const ::basegfx::BColor aRGBWhite(1.0, 1.0, 1.0);
+ const ::basegfx::BColorModifierSharedPtr aBColorModifier =
+ std::make_shared<basegfx::BColorModifier_interpolate>(
+ aRGBWhite,
+ 0.5);
+ const drawinglayer::primitive3d::Primitive3DReference xReference(
+ new drawinglayer::primitive3d::ModifiedColorPrimitive3D(
+ xRetval,
+ aBColorModifier));
+
+ xRetval = { xReference };
+ }
+
+ return xRetval;
+ }
+
+ void ViewObjectContactOfE3d::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const ViewContactOfE3d& rViewContact = static_cast< const ViewContactOfE3d& >(GetViewContact());
+
+ // get 3d primitive vector, isPrimitiveVisible() is done in 3d creator
+ rVisitor.visit(rViewContact.impCreateWithGivenPrimitive3DContainer(getPrimitive3DContainer(rDisplayInfo)));
+ }
+
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofe3dscene.cxx b/svx/source/sdr/contact/viewobjectcontactofe3dscene.cxx
new file mode 100644
index 000000000..ac7ad90f1
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofe3dscene.cxx
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewobjectcontactofe3dscene.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <basegfx/color/bcolormodifier.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace
+{
+ // Helper method to recursively travel the DrawHierarchy for 3D objects contained in
+ // the 2D Scene. This will create all VOCs for the current OC which are needed
+ // for ActionChanged() functionality
+ void impInternalSubHierarchyTraveller(const sdr::contact::ViewObjectContact& rVOC)
+ {
+ const sdr::contact::ViewContact& rVC = rVOC.GetViewContact();
+ const sal_uInt32 nSubHierarchyCount(rVC.GetObjectCount());
+
+ for(sal_uInt32 a(0); a < nSubHierarchyCount; a++)
+ {
+ const sdr::contact::ViewObjectContact& rCandidate(rVC.GetViewContact(a).GetViewObjectContact(rVOC.GetObjectContact()));
+ impInternalSubHierarchyTraveller(rCandidate);
+ }
+ }
+} // end of anonymous namespace
+
+
+namespace sdr::contact
+{
+ ViewObjectContactOfE3dScene::ViewObjectContactOfE3dScene(ObjectContact& rObjectContact, ViewContact& rViewContact)
+ : ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
+ {
+ }
+
+ ViewObjectContactOfE3dScene::~ViewObjectContactOfE3dScene()
+ {
+ }
+
+ void ViewObjectContactOfE3dScene::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ // handle ghosted, else the whole 3d group will be encapsulated to a ghosted primitive set (see below)
+ const bool bHandleGhostedDisplay(GetObjectContact().DoVisualizeEnteredGroup() && !GetObjectContact().isOutputToPrinter() && rDisplayInfo.IsGhostedDrawModeActive());
+ const bool bIsActiveVC(bHandleGhostedDisplay && GetObjectContact().getActiveViewContact() == &GetViewContact());
+
+ if(bIsActiveVC)
+ {
+ // switch off ghosted, display contents normal
+ const_cast< DisplayInfo& >(rDisplayInfo).ClearGhostedDrawMode();
+ }
+
+ // create 2d primitive with content, use layer visibility test
+ // this uses no ghosted mode, so scenes in scenes and entering them will not
+ // support ghosted for now. This is no problem currently but would need to be
+ // added when sub-groups in 3d will be added one day.
+ const ViewContactOfE3dScene& rViewContact = dynamic_cast< ViewContactOfE3dScene& >(GetViewContact());
+ const SdrLayerIDSet& rVisibleLayers = rDisplayInfo.GetProcessLayers();
+ drawinglayer::primitive2d::Primitive2DContainer xRetval(rViewContact.createScenePrimitive2DSequence(&rVisibleLayers));
+
+ if(!xRetval.empty())
+ {
+ // allow evtl. embedding in object-specific infos, e.g. Name, Title, Description
+ xRetval = rViewContact.embedToObjectSpecificInformation(std::move(xRetval));
+
+ // handle GluePoint
+ if(!GetObjectContact().isOutputToPrinter() && GetObjectContact().AreGluePointsVisible())
+ {
+ const drawinglayer::primitive2d::Primitive2DContainer xGlue(GetViewContact().createGluePointPrimitive2DSequence());
+
+ if(!xGlue.empty())
+ {
+ xRetval.append(xGlue);
+ }
+ }
+
+ // handle ghosted
+ if(isPrimitiveGhosted(rDisplayInfo))
+ {
+ const ::basegfx::BColor aRGBWhite(1.0, 1.0, 1.0);
+ const ::basegfx::BColorModifierSharedPtr aBColorModifier =
+ std::make_shared<basegfx::BColorModifier_interpolate>(
+ aRGBWhite,
+ 0.5);
+ const drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
+ std::move(xRetval),
+ aBColorModifier));
+
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReference };
+ }
+ }
+
+ if(bIsActiveVC)
+ {
+ // set back, display ghosted again
+ const_cast< DisplayInfo& >(rDisplayInfo).SetGhostedDrawMode();
+ }
+
+ rVisitor.visit(xRetval);
+ }
+
+ void ViewObjectContactOfE3dScene::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ // To get the VOCs for the contained 3D objects created to get the correct
+ // Draw hierarchy and ActionChanged() working properly, travel the DrawHierarchy
+ // using a local tooling method
+ impInternalSubHierarchyTraveller(*this);
+
+ // call parent
+ ViewObjectContactOfSdrObj::getPrimitive2DSequenceHierarchy(rDisplayInfo, rVisitor);
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofgraphic.cxx b/svx/source/sdr/contact/viewobjectcontactofgraphic.cxx
new file mode 100644
index 000000000..601ec28df
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofgraphic.cxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewobjectcontactofgraphic.hxx>
+#include <sdr/contact/viewcontactofgraphic.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+
+namespace sdr::contact
+{
+ void ViewObjectContactOfGraphic::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ // #i103255# suppress when graphic needs draft visualisation and output
+ // is for PDF export/Printer
+ const ViewContactOfGraphic& rVCOfGraphic = static_cast< const ViewContactOfGraphic& >(GetViewContact());
+
+ if(rVCOfGraphic.visualisationUsesDraft())
+ {
+ const ObjectContact& rObjectContact = GetObjectContact();
+
+ if(rObjectContact.isOutputToPDFFile() || rObjectContact.isOutputToPrinter())
+ {
+ return;
+ }
+ }
+
+ // get return value by calling parent
+ ViewObjectContactOfSdrObj::createPrimitive2DSequence(rDisplayInfo, rVisitor);
+ }
+
+ ViewObjectContactOfGraphic::ViewObjectContactOfGraphic(ObjectContact& rObjectContact, ViewContact& rViewContact)
+ : ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
+ {
+ }
+
+ ViewObjectContactOfGraphic::~ViewObjectContactOfGraphic()
+ {
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofgroup.cxx b/svx/source/sdr/contact/viewobjectcontactofgroup.cxx
new file mode 100644
index 000000000..8469a00c1
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofgroup.cxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewobjectcontactofgroup.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/svdobj.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace sdr::contact
+{
+ ViewObjectContactOfGroup::ViewObjectContactOfGroup(ObjectContact& rObjectContact, ViewContact& rViewContact)
+ : ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
+ {
+ }
+
+ ViewObjectContactOfGroup::~ViewObjectContactOfGroup()
+ {
+ }
+
+ void ViewObjectContactOfGroup::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ // check model-view visibility
+ if(!isPrimitiveVisible(rDisplayInfo))
+ return;
+
+ const sal_uInt32 nSubHierarchyCount(GetViewContact().GetObjectCount());
+ if(nSubHierarchyCount)
+ {
+ const bool bDoGhostedDisplaying(
+ GetObjectContact().DoVisualizeEnteredGroup()
+ && !GetObjectContact().isOutputToPrinter()
+ && GetObjectContact().getActiveViewContact() == &GetViewContact());
+
+ if(bDoGhostedDisplaying)
+ {
+ rDisplayInfo.ClearGhostedDrawMode();
+ }
+
+ // visit object hierarchy
+ getPrimitive2DSequenceSubHierarchy(rDisplayInfo, rVisitor);
+
+ if(bDoGhostedDisplaying)
+ {
+ rDisplayInfo.SetGhostedDrawMode();
+ }
+ }
+ else
+ {
+ // draw replacement object for group. This will use ViewContactOfGroup::createViewIndependentPrimitive2DSequence
+ // which creates the replacement primitives for an empty group
+ ViewObjectContactOfSdrObj::getPrimitive2DSequenceHierarchy(rDisplayInfo, rVisitor);
+ }
+ }
+
+ bool ViewObjectContactOfGroup::isPrimitiveVisibleOnAnyLayer(const SdrLayerIDSet& aLayers) const
+ {
+ SdrLayerIDSet aObjectLayers;
+ getSdrObject().getMergedHierarchySdrLayerIDSet(aObjectLayers);
+ aObjectLayers &= aLayers;
+ return !aObjectLayers.IsEmpty();
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.cxx b/svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.cxx
new file mode 100644
index 000000000..f96ed115d
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.cxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewobjectcontactofmasterpagedescriptor.hxx>
+#include <sdr/contact/viewcontactofmasterpagedescriptor.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/svdpage.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+
+namespace sdr::contact
+{
+ ViewObjectContactOfMasterPageDescriptor::ViewObjectContactOfMasterPageDescriptor(ObjectContact& rObjectContact, ViewContact& rViewContact)
+ : ViewObjectContact(rObjectContact, rViewContact)
+ {
+ }
+
+ ViewObjectContactOfMasterPageDescriptor::~ViewObjectContactOfMasterPageDescriptor()
+ {
+ }
+
+ bool ViewObjectContactOfMasterPageDescriptor::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+ {
+ if(rDisplayInfo.GetControlLayerProcessingActive())
+ {
+ return false;
+ }
+
+ if(!rDisplayInfo.GetPageProcessingActive())
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ void ViewObjectContactOfMasterPageDescriptor::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ drawinglayer::primitive2d::Primitive2DContainer xMasterPageSequence;
+ const sdr::MasterPageDescriptor& rDescriptor = static_cast< ViewContactOfMasterPageDescriptor& >(GetViewContact()).GetMasterPageDescriptor();
+
+ // used range (retval) is fixed here, it's the MasterPage fill range
+ const SdrPage& rOwnerPage = rDescriptor.GetOwnerPage();
+ const basegfx::B2DRange aInnerRange(
+ rOwnerPage.GetLeftBorder(), rOwnerPage.GetUpperBorder(),
+ rOwnerPage.GetWidth() - rOwnerPage.GetRightBorder(), rOwnerPage.GetHeight() - rOwnerPage.GetLowerBorder());
+ const basegfx::B2DRange aOuterRange(
+ 0, 0, rOwnerPage.GetWidth(), rOwnerPage.GetHeight());
+ // ??? somehow only the master page's bit is used
+ bool const isFullSize(rDescriptor.GetUsedPage().IsBackgroundFullSize());
+ basegfx::B2DRange const& rPageFillRange(isFullSize ? aOuterRange : aInnerRange);
+
+ // Modify DisplayInfo for MasterPageContent collection; remember original layers and
+ // set combined SdrLayerIDSet; set MasterPagePaint flag
+ const SdrLayerIDSet aRememberedLayers(rDisplayInfo.GetProcessLayers());
+ SdrLayerIDSet aPreprocessedLayers(aRememberedLayers);
+ aPreprocessedLayers &= rDescriptor.GetVisibleLayers();
+ rDisplayInfo.SetProcessLayers(aPreprocessedLayers);
+ rDisplayInfo.SetSubContentActive(true);
+
+ // check layer visibility (traditionally was member of layer 1)
+ if(aPreprocessedLayers.IsSet(SdrLayerID(1)))
+ {
+ // hide PageBackground for special DrawModes; historical reasons
+ if(!GetObjectContact().isDrawModeGray() && !GetObjectContact().isDrawModeHighContrast())
+ {
+ // if visible, create the default background primitive sequence
+ static_cast< ViewContactOfMasterPageDescriptor& >(GetViewContact()).getViewIndependentPrimitive2DContainer(rVisitor);
+ }
+ }
+
+ // hide MasterPage content? Test self here for hierarchy
+ if(isPrimitiveVisible(rDisplayInfo))
+ {
+ // get the VOC of the Master-SdrPage and get its object hierarchy
+ ViewContact& rViewContactOfMasterPage(rDescriptor.GetUsedPage().GetViewContact());
+ ViewObjectContact& rVOCOfMasterPage(rViewContactOfMasterPage.GetViewObjectContact(GetObjectContact()));
+
+ rVOCOfMasterPage.getPrimitive2DSequenceHierarchy(rDisplayInfo, xMasterPageSequence);
+ }
+
+ // reset DisplayInfo changes for MasterPage paint
+ rDisplayInfo.SetProcessLayers(aRememberedLayers);
+ rDisplayInfo.SetSubContentActive(false);
+
+ if(!xMasterPageSequence.empty())
+ {
+ // get range of MasterPage sub hierarchy
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D());
+ basegfx::B2DRange aSubHierarchyRange(xMasterPageSequence.getB2DRange(rViewInformation2D));
+
+ if (rPageFillRange.isInside(aSubHierarchyRange))
+ {
+ // completely inside, just render MasterPage content. Add to target
+ rVisitor.visit(xMasterPageSequence);
+ }
+ else if (rPageFillRange.overlaps(aSubHierarchyRange))
+ {
+ // overlapping, compute common area
+ basegfx::B2DRange aCommonArea(rPageFillRange);
+ aCommonArea.intersect(aSubHierarchyRange);
+
+ // need to create a clip primitive, add clipped list to target
+ const drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::MaskPrimitive2D(
+ basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aCommonArea)), std::move(xMasterPageSequence)));
+ rVisitor.visit(xReference);
+ }
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofpageobj.cxx b/svx/source/sdr/contact/viewobjectcontactofpageobj.cxx
new file mode 100644
index 000000000..e3431da91
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofpageobj.cxx
@@ -0,0 +1,315 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/idle.hxx>
+#include <sdr/contact/viewobjectcontactofpageobj.hxx>
+#include <sdr/contact/viewcontactofpageobj.hxx>
+#include <svx/svdopage.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svtools/colorcfg.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <sdr/contact/objectcontactofobjlistpainter.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/unoapi.hxx>
+#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <vcl/canvastools.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr::contact {
+
+class PagePrimitiveExtractor : public ObjectContactOfPagePainter, public Idle
+{
+private:
+ // the ViewObjectContactOfPageObj using this painter
+ ViewObjectContactOfPageObj& mrViewObjectContactOfPageObj;
+
+public:
+ // basic constructor/destructor
+ explicit PagePrimitiveExtractor(ViewObjectContactOfPageObj& rVOC);
+ virtual ~PagePrimitiveExtractor() override;
+
+ // LazyInvalidate request. Supported here to not automatically
+ // invalidate the second interaction state all the time at the
+ // original OC
+ virtual void setLazyInvalidate(ViewObjectContact& rVOC) override;
+
+ // From baseclass Timer, the timeout call triggered by the LazyInvalidate mechanism
+ virtual void Invoke() final override;
+
+ // get primitive visualization
+ drawinglayer::primitive2d::Primitive2DContainer createPrimitive2DSequenceForPage();
+
+ // Own reaction on changes which will be forwarded to the OC of the owner-VOC
+ virtual void InvalidatePartOfView(const basegfx::B2DRange& rRange) const override;
+
+ // forward access to SdrPageView of ViewObjectContactOfPageObj
+ virtual bool isOutputToPrinter() const override;
+ virtual bool isOutputToRecordingMetaFile() const override;
+ virtual bool isOutputToPDFFile() const override;
+ virtual bool isDrawModeGray() const override;
+ virtual bool isDrawModeHighContrast() const override;
+ virtual SdrPageView* TryToGetSdrPageView() const override;
+ virtual OutputDevice* TryToGetOutputDevice() const override;
+};
+
+PagePrimitiveExtractor::PagePrimitiveExtractor(
+ ViewObjectContactOfPageObj& rVOC)
+: ObjectContactOfPagePainter(rVOC.GetObjectContact()), Idle("svx PagePrimitiveExtractor"),
+ mrViewObjectContactOfPageObj(rVOC)
+{
+ // make this renderer a preview renderer
+ setPreviewRenderer(true);
+
+ // init timer
+ SetPriority(TaskPriority::HIGH_IDLE);
+ Stop();
+}
+
+PagePrimitiveExtractor::~PagePrimitiveExtractor()
+{
+ // execute missing LazyInvalidates and stop timer
+ Invoke();
+}
+
+void PagePrimitiveExtractor::setLazyInvalidate(ViewObjectContact& /*rVOC*/)
+{
+ // do NOT call parent, but remember that something is to do by
+ // starting the LazyInvalidateTimer
+ Start();
+}
+
+// From baseclass Timer, the timeout call triggered by the LazyInvalidate mechanism
+void PagePrimitiveExtractor::Invoke()
+{
+ // stop the timer
+ Stop();
+
+ // invalidate all LazyInvalidate VOCs new situations
+ const sal_uInt32 nVOCCount(getViewObjectContactCount());
+
+ for(sal_uInt32 a(0); a < nVOCCount; a++)
+ {
+ ViewObjectContact* pCandidate = getViewObjectContact(a);
+ pCandidate->triggerLazyInvalidate();
+ }
+}
+
+drawinglayer::primitive2d::Primitive2DContainer PagePrimitiveExtractor::createPrimitive2DSequenceForPage()
+{
+ drawinglayer::primitive2d::Primitive2DContainer xRetval;
+ SdrPage* pStartPage = GetStartPage();
+
+ if(pStartPage)
+ {
+ // update own ViewInformation2D for visualized page
+ const drawinglayer::geometry::ViewInformation2D& rOriginalViewInformation = mrViewObjectContactOfPageObj.GetObjectContact().getViewInformation2D();
+ const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D(
+ rOriginalViewInformation.getObjectTransformation(),
+ rOriginalViewInformation.getViewTransformation(),
+
+ // #i101075# use empty range for page content here to force
+ // the content not to be physically clipped in any way. This
+ // would be possible, but would require the internal transformation
+ // which maps between the page visualisation object and the page
+ // content, including the aspect ratios (for details see in
+ // PagePreviewPrimitive2D::create2DDecomposition)
+ basegfx::B2DRange(),
+
+ GetXDrawPageForSdrPage(pStartPage),
+ 0.0); // no time; page previews are not animated
+ updateViewInformation2D(aNewViewInformation2D);
+
+ // create copy of DisplayInfo to set PagePainting
+ DisplayInfo aDisplayInfo;
+
+ // get page's VOC
+ ViewObjectContact& rDrawPageVOContact = pStartPage->GetViewContact().GetViewObjectContact(*this);
+
+ // get whole Primitive2DContainer
+ rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo, xRetval);
+ }
+
+ return xRetval;
+}
+
+void PagePrimitiveExtractor::InvalidatePartOfView(const basegfx::B2DRange& rRange) const
+{
+ // an invalidate is called at this view, this needs to be translated to an invalidate
+ // for the using VOC. Coordinates are in page coordinate system.
+ const SdrPage* pStartPage = GetStartPage();
+
+ if(pStartPage && !rRange.isEmpty())
+ {
+ const basegfx::B2DRange aPageRange(0.0, 0.0, static_cast<double>(pStartPage->GetWidth()), static_cast<double>(pStartPage->GetHeight()));
+
+ if(rRange.overlaps(aPageRange))
+ {
+ // if object on the page is inside or overlapping with page, create ActionChanged() for
+ // involved VOC
+ mrViewObjectContactOfPageObj.ActionChanged();
+ }
+ }
+}
+
+// forward access to SdrPageView to VOCOfPageObj
+bool PagePrimitiveExtractor::isOutputToPrinter() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToPrinter(); }
+bool PagePrimitiveExtractor::isOutputToRecordingMetaFile() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToRecordingMetaFile(); }
+bool PagePrimitiveExtractor::isOutputToPDFFile() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToPDFFile(); }
+bool PagePrimitiveExtractor::isDrawModeGray() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeGray(); }
+bool PagePrimitiveExtractor::isDrawModeHighContrast() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeHighContrast(); }
+SdrPageView* PagePrimitiveExtractor::TryToGetSdrPageView() const { return mrViewObjectContactOfPageObj.GetObjectContact().TryToGetSdrPageView(); }
+OutputDevice* PagePrimitiveExtractor::TryToGetOutputDevice() const { return mrViewObjectContactOfPageObj.GetObjectContact().TryToGetOutputDevice(); }
+
+void ViewObjectContactOfPageObj::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SdrPageObj& rPageObject(static_cast< ViewContactOfPageObj& >(GetViewContact()).GetPageObj());
+ const SdrPage* pPage = rPageObject.GetReferencedPage();
+ const svtools::ColorConfig aColorConfig;
+
+ // get PageObject's geometry
+ basegfx::B2DHomMatrix aPageObjectTransform;
+ {
+ const tools::Rectangle aPageObjectModelData(rPageObject.GetLastBoundRect());
+ const basegfx::B2DRange aPageObjectBound = vcl::unotools::b2DRectangleFromRectangle(aPageObjectModelData);
+
+ aPageObjectTransform.set(0, 0, aPageObjectBound.getWidth());
+ aPageObjectTransform.set(1, 1, aPageObjectBound.getHeight());
+ aPageObjectTransform.set(0, 2, aPageObjectBound.getMinX());
+ aPageObjectTransform.set(1, 2, aPageObjectBound.getMinY());
+ }
+
+ // #i102637# add gray frame also when printing and page exists (handout pages)
+ const bool bCreateGrayFrame(!GetObjectContact().isOutputToPrinter() || pPage);
+
+ // get displayed page's content. This is the unscaled page content
+ if(mpExtractor && pPage)
+ {
+ // get displayed page's geometry
+ drawinglayer::primitive2d::Primitive2DContainer xPageContent;
+ const Size aPageSize(pPage->GetSize());
+ const double fPageWidth(aPageSize.getWidth());
+ const double fPageHeight(aPageSize.getHeight());
+
+ // The case that a PageObject contains another PageObject which visualizes the
+ // same page again would lead to a recursion. Limit that recursion depth to one
+ // by using a local static bool
+ static bool bInCreatePrimitive2D(false);
+
+ if(bInCreatePrimitive2D)
+ {
+ // Recursion is possible. Create a replacement primitive
+ xPageContent.resize(2);
+ const Color aDocColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
+ svtools::ColorConfigValue aBorderConfig = aColorConfig.GetColorValue(svtools::DOCBOUNDARIES);
+ const Color aBorderColor = aBorderConfig.bIsVisible ? aBorderConfig.nColor : aDocColor;
+ const basegfx::B2DRange aPageBound(0.0, 0.0, fPageWidth, fPageHeight);
+ const basegfx::B2DPolygon aOutline(basegfx::utils::createPolygonFromRect(aPageBound));
+
+ // add replacement fill
+ xPageContent[0] = drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aOutline), aDocColor.getBColor()));
+
+ // add replacement border
+ xPageContent[1] = drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aBorderColor.getBColor()));
+ }
+ else
+ {
+ // set recursion flag
+ bInCreatePrimitive2D = true;
+
+ // init extractor, guarantee existence, set page there
+ mpExtractor->SetStartPage(pPage);
+
+ // #i105548# also need to copy the VOCRedirector for sub-content creation
+ mpExtractor->SetViewObjectContactRedirector(GetObjectContact().GetViewObjectContactRedirector());
+
+ // create page content
+ xPageContent = mpExtractor->createPrimitive2DSequenceForPage();
+
+ // #i105548# reset VOCRedirector to not accidentally have a pointer to a
+ // temporary class, so calls to it are avoided safely
+ mpExtractor->SetViewObjectContactRedirector(nullptr);
+
+ // reset recursion flag
+ bInCreatePrimitive2D = false;
+ }
+
+ // prepare retval
+ if(!xPageContent.empty())
+ {
+ const uno::Reference< drawing::XDrawPage > xDrawPage(GetXDrawPageForSdrPage(const_cast< SdrPage*>(pPage)));
+ const drawinglayer::primitive2d::Primitive2DReference xPagePreview(new drawinglayer::primitive2d::PagePreviewPrimitive2D(
+ xDrawPage, aPageObjectTransform, fPageWidth, fPageHeight, std::move(xPageContent)));
+ rVisitor.visit(xPagePreview);
+ }
+ }
+ else if(bCreateGrayFrame)
+ {
+ // #i105146# no content, but frame display. To make hitting the page preview objects
+ // on the handout page more simple, add hidden fill geometry
+ const drawinglayer::primitive2d::Primitive2DReference xFrameHit(
+ drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
+ aPageObjectTransform));
+ rVisitor.visit(xFrameHit);
+ }
+
+ // add a gray outline frame, except not when printing
+ if(bCreateGrayFrame)
+ {
+ const Color aFrameColor(aColorConfig.GetColorValue(svtools::OBJECTBOUNDARIES).nColor);
+ basegfx::B2DPolygon aOwnOutline(basegfx::utils::createUnitPolygon());
+ aOwnOutline.transform(aPageObjectTransform);
+
+ const drawinglayer::primitive2d::Primitive2DReference xGrayFrame(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOwnOutline, aFrameColor.getBColor()));
+
+ rVisitor.visit(xGrayFrame);
+ }
+}
+
+ViewObjectContactOfPageObj::ViewObjectContactOfPageObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfSdrObj(rObjectContact, rViewContact),
+ mpExtractor(new PagePrimitiveExtractor(*this))
+{
+}
+
+ViewObjectContactOfPageObj::~ViewObjectContactOfPageObj()
+{
+ // delete the helper OC
+ if(mpExtractor)
+ {
+ // remember candidate and reset own pointer to avoid action when createPrimitive2DSequence()
+ // would be called for any reason
+ std::unique_ptr<PagePrimitiveExtractor> pCandidate = std::move(mpExtractor);
+
+ // also reset the StartPage to avoid ActionChanged() forwardings in the
+ // PagePrimitiveExtractor::InvalidatePartOfView() implementation
+ pCandidate->SetStartPage(nullptr);
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofsdrmediaobj.cxx b/svx/source/sdr/contact/viewobjectcontactofsdrmediaobj.cxx
new file mode 100644
index 000000000..777017472
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofsdrmediaobj.cxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <sdr/contact/viewobjectcontactofsdrmediaobj.hxx>
+#include <svx/sdr/contact/viewcontactofsdrmediaobj.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/window.hxx>
+#include <avmedia/mediaitem.hxx>
+#include "sdrmediawindow.hxx"
+
+namespace sdr::contact {
+
+ViewObjectContactOfSdrMediaObj::ViewObjectContactOfSdrMediaObj( ObjectContact& rObjectContact,
+ ViewContact& rViewContact,
+ const ::avmedia::MediaItem& rMediaItem ) :
+ ViewObjectContactOfSdrObj( rObjectContact, rViewContact )
+{
+#if HAVE_FEATURE_AVMEDIA
+ vcl::Window* pWindow = getWindow();
+
+ if( pWindow )
+ {
+ mpMediaWindow.reset( new SdrMediaWindow( pWindow, *this ) );
+ mpMediaWindow->hide();
+ executeMediaItem( rMediaItem );
+ }
+#else
+ (void) rMediaItem;
+#endif
+}
+
+ViewObjectContactOfSdrMediaObj::~ViewObjectContactOfSdrMediaObj()
+{
+}
+
+
+vcl::Window* ViewObjectContactOfSdrMediaObj::getWindow() const
+{
+ vcl::Window* pRetval = nullptr;
+
+ const OutputDevice* oPageOutputDev = getPageViewOutputDevice();
+ if( oPageOutputDev )
+ {
+ if(OUTDEV_WINDOW == oPageOutputDev->GetOutDevType())
+ {
+ pRetval = oPageOutputDev->GetOwnerWindow();
+ }
+ }
+
+ return pRetval;
+}
+
+
+Size ViewObjectContactOfSdrMediaObj::getPreferredSize() const
+{
+ Size aRet;
+
+#if HAVE_FEATURE_AVMEDIA
+ if( mpMediaWindow )
+ aRet = mpMediaWindow->getPreferredSize();
+#else
+ aRet = Size(0,0);
+#endif
+
+ return aRet;
+}
+
+void ViewObjectContactOfSdrMediaObj::ActionChanged()
+{
+ ViewObjectContactOfSdrObj::ActionChanged();
+ updateMediaWindow(false);
+}
+
+void ViewObjectContactOfSdrMediaObj::updateMediaWindow(bool bShow) const
+{
+#if HAVE_FEATURE_AVMEDIA
+ if (!mpMediaWindow || (!bShow && !mpMediaWindow->isVisible()))
+ return;
+
+ basegfx::B2DRange aViewRange(getObjectRange());
+ aViewRange.transform(GetObjectContact().getViewInformation2D().getViewTransformation());
+
+ const tools::Rectangle aViewRectangle(
+ static_cast<sal_Int32>(floor(aViewRange.getMinX())), static_cast<sal_Int32>(floor(aViewRange.getMinY())),
+ static_cast<sal_Int32>(ceil(aViewRange.getMaxX())), static_cast<sal_Int32>(ceil(aViewRange.getMaxY())));
+
+ // mpMediaWindow contains a SalObject window and gtk won't accept
+ // the size until after the SalObject widget is shown but if we
+ // show it before setting a size then vcl will detect that the
+ // vcl::Window has no size and make it invisible instead. If we
+ // call setPosSize twice with the same size before and after show
+ // then the second attempt is a no-op as vcl caches the size.
+
+ // so call it initially with a size arbitrarily 1 pixel wider than
+ // we want so we have an initial size to make vcl happy
+ tools::Rectangle aInitialRect(aViewRectangle);
+ aInitialRect.AdjustRight(1);
+ mpMediaWindow->setPosSize(aInitialRect);
+
+ // then make it visible
+ mpMediaWindow->show();
+
+ // set the final desired size which is different to let vcl send it
+ // through to gtk which will now accept it as the underlying
+ // m_pSocket of GtkSalObject::SetPosSize is now visible
+ mpMediaWindow->setPosSize(aViewRectangle);
+#else
+ (void) bShow;
+#endif
+}
+
+void ViewObjectContactOfSdrMediaObj::updateMediaItem( ::avmedia::MediaItem& rItem ) const
+{
+#if HAVE_FEATURE_AVMEDIA
+ if( !mpMediaWindow )
+ return;
+
+ mpMediaWindow->updateMediaItem( rItem );
+
+ // show/hide is now dependent of play state
+ if(avmedia::MediaState::Stop == rItem.getState())
+ {
+ mpMediaWindow->hide();
+ }
+ else
+ {
+ updateMediaWindow(true);
+ }
+#else
+ (void) rItem;
+#endif
+}
+
+
+void ViewObjectContactOfSdrMediaObj::executeMediaItem( const ::avmedia::MediaItem& rItem )
+{
+#if HAVE_FEATURE_AVMEDIA
+ if( mpMediaWindow )
+ {
+ ::avmedia::MediaItem aUpdatedItem;
+
+ mpMediaWindow->executeMediaItem( rItem );
+
+ // query new properties after trying to set the new properties
+ updateMediaItem( aUpdatedItem );
+ static_cast< ViewContactOfSdrMediaObj& >( GetViewContact() ).mediaPropertiesChanged( aUpdatedItem );
+ }
+#else
+ (void) rItem;
+#endif
+}
+
+
+} // end of namespace sdr::contact
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofsdrobj.cxx b/svx/source/sdr/contact/viewobjectcontactofsdrobj.cxx
new file mode 100644
index 000000000..f87906240
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofsdrobj.cxx
@@ -0,0 +1,193 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/objectcontactofpageview.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdview.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/canvastools.hxx>
+
+#include <fmobj.hxx>
+
+namespace sdr::contact {
+
+const SdrObject& ViewObjectContactOfSdrObj::getSdrObject() const
+{
+ return static_cast< ViewContactOfSdrObj& >(GetViewContact()).GetSdrObject();
+}
+
+ViewObjectContactOfSdrObj::ViewObjectContactOfSdrObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContact(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfSdrObj::~ViewObjectContactOfSdrObj()
+{
+}
+
+bool ViewObjectContactOfSdrObj::isPrimitiveVisibleOnAnyLayer(const SdrLayerIDSet& aLayers) const
+{
+ return aLayers.IsSet(getSdrObject().GetLayer());
+}
+
+bool ViewObjectContactOfSdrObj::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ const SdrObject& rObject = getSdrObject();
+
+ // Test layer visibility
+ if(!isPrimitiveVisibleOnAnyLayer(rDisplayInfo.GetProcessLayers()))
+ {
+ return false;
+ }
+
+ if(GetObjectContact().isOutputToPrinter() )
+ {
+ // Test if print output but not printable
+ if( !rObject.IsPrintable())
+ return false;
+ }
+ else
+ {
+ // test is object is not visible on screen
+ if( !rObject.IsVisible() )
+ return false;
+ }
+
+ // Test for hidden object on MasterPage
+ if(rDisplayInfo.GetSubContentActive() && rObject.IsNotVisibleAsMaster())
+ {
+ return false;
+ }
+
+ // Test for Calc object hiding (for OLE and Graphic it's extra, see there)
+ const SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(pSdrPageView)
+ {
+ const SdrView& rSdrView = pSdrPageView->GetView();
+ const bool bHideOle(rSdrView.getHideOle());
+ const bool bHideChart(rSdrView.getHideChart());
+ const bool bHideDraw(rSdrView.getHideDraw());
+ const bool bHideFormControl(rSdrView.getHideFormControl());
+
+ if(bHideOle || bHideChart || bHideDraw || bHideFormControl)
+ {
+ if(SdrObjKind::OLE2 == rObject.GetObjIdentifier())
+ {
+ if(static_cast<const SdrOle2Obj&>(rObject).IsChart())
+ {
+ // chart
+ if(bHideChart)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // OLE
+ if(bHideOle)
+ {
+ return false;
+ }
+ }
+ }
+ else if(SdrObjKind::Graphic == rObject.GetObjIdentifier())
+ {
+ // graphic handled like OLE
+ if(bHideOle)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ const bool bIsFormControl = dynamic_cast< const FmFormObj * >( &rObject ) != nullptr;
+ if(bIsFormControl && bHideFormControl)
+ {
+ return false;
+ }
+ // any other draw object
+ if(!bIsFormControl && bHideDraw)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ // tdf#91260 check if the object is anchored on a different Writer page
+ // than the one being painted, and if so ignore it (Writer has only one
+ // SdrPage, so the part of the object that should be visible will be
+ // painted on the page where it is anchored)
+ // Note that we cannot check the ViewInformation2D ViewPort for this
+ // because it is only the part of the page that is currently visible.
+ basegfx::B2IPoint const& rAnchor(vcl::unotools::b2IPointFromPoint(getSdrObject().GetAnchorPos()));
+ if (rAnchor.getX() || rAnchor.getY()) // only Writer sets anchor position
+ {
+ if (!rDisplayInfo.GetWriterPageFrame().isEmpty() &&
+ !rDisplayInfo.GetWriterPageFrame().isInside(rAnchor))
+ {
+ return false;
+ }
+ }
+
+ // Check if this object is in the visible range.
+ const drawinglayer::geometry::ViewInformation2D& rViewInfo = GetObjectContact().getViewInformation2D();
+ basegfx::B2DRange aObjRange = GetViewContact().getRange(rViewInfo);
+ if (!aObjRange.isEmpty())
+ {
+ const basegfx::B2DRange& rViewRange = rViewInfo.getViewport();
+ bool bVisible = rViewRange.isEmpty() || rViewRange.overlaps(aObjRange);
+ if (!bVisible)
+ return false;
+ }
+
+ return true;
+}
+
+const OutputDevice* ViewObjectContactOfSdrObj::getPageViewOutputDevice() const
+{
+ ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &GetObjectContact() );
+ if ( pPageViewContact )
+ {
+ // if the PageWindow has a patched PaintWindow, use the original PaintWindow
+ // this ensures that our control is _not_ re-created just because somebody
+ // (temporarily) changed the window to paint onto.
+ // #i72429# / 2007-02-20 / frank.schoenheit (at) sun.com
+ SdrPageWindow& rPageWindow( pPageViewContact->GetPageWindow() );
+ if ( rPageWindow.GetOriginalPaintWindow() )
+ return &rPageWindow.GetOriginalPaintWindow()->GetOutputDevice();
+
+ return &rPageWindow.GetPaintWindow().GetOutputDevice();
+ }
+ return nullptr;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofsdrole2obj.cxx b/svx/source/sdr/contact/viewobjectcontactofsdrole2obj.cxx
new file mode 100644
index 000000000..66d1a6fb4
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofsdrole2obj.cxx
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/contact/viewobjectcontactofsdrole2obj.hxx>
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+#include <sdr/contact/viewcontactofsdrole2obj.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdview.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonHatchPrimitive2D.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <com/sun/star/embed/EmbedMisc.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <svtools/embedhlp.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr::contact {
+
+void ViewObjectContactOfSdrOle2Obj::createPrimitive2DSequence(
+ const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // override this method to do some things the old SdrOle2Obj::DoPaintObject did.
+ // In the future, some of these may be solved different, but ATM try to stay compatible
+ // with the old behaviour
+ const SdrOle2Obj& rSdrOle2 = static_cast< ViewContactOfSdrOle2Obj& >(GetViewContact()).GetOle2Obj();
+ sal_Int32 nState(-1);
+
+ {
+ const svt::EmbeddedObjectRef& xObjRef = rSdrOle2.getEmbeddedObjectRef();
+ if ( xObjRef.is() )
+ nState = xObjRef->getCurrentState();
+ }
+
+ const bool bIsOutplaceActive(nState == embed::EmbedStates::ACTIVE);
+ const bool bIsInplaceActive((nState == embed::EmbedStates::INPLACE_ACTIVE) || (nState == embed::EmbedStates::UI_ACTIVE));
+ bool bDone(false);
+
+ if (bIsInplaceActive)
+ {
+ if( !GetObjectContact().isOutputToPrinter() && !GetObjectContact().isOutputToRecordingMetaFile() )
+ {
+ //no need to create a primitive sequence here as the OLE object does render itself
+ //in case of charts the superfluous creation of a metafile is strongly performance relevant!
+ bDone = true;
+ }
+ }
+
+ if( !bDone )
+ {
+ //old stuff that should be reworked
+ {
+ //if no replacement image is available load the OLE object
+// if(!rSdrOle2.GetGraphic()) //try to fetch the metafile - this can lead to the actual creation of the metafile what can be extremely expensive (e.g. for big charts)!!! #i101925#
+// {
+// // try to create embedded object
+// rSdrOle2.GetObjRef(); //this loads the OLE object if it is not loaded already
+// }
+ const svt::EmbeddedObjectRef& xObjRef = rSdrOle2.getEmbeddedObjectRef();
+ if(xObjRef.is())
+ {
+ const sal_Int64 nMiscStatus(xObjRef->getStatus(rSdrOle2.GetAspect()));
+
+ // this hack (to change model data during PAINT argh(!)) should be reworked
+ if(!rSdrOle2.IsResizeProtect() && (nMiscStatus & embed::EmbedMisc::EMBED_NEVERRESIZE))
+ {
+ const_cast< SdrOle2Obj* >(&rSdrOle2)->SetResizeProtect(true);
+ }
+
+ SdrPageView* pPageView = GetObjectContact().TryToGetSdrPageView();
+ if(pPageView && (nMiscStatus & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE))
+ {
+ // connect plugin object
+ pPageView->GetView().DoConnect(const_cast< SdrOle2Obj* >(&rSdrOle2));
+ }
+ }
+ }//end old stuff to rework
+
+ // create OLE primitive stuff directly at VC with HC as parameter
+ const ViewContactOfSdrOle2Obj& rVC = static_cast< const ViewContactOfSdrOle2Obj& >(GetViewContact());
+ rVC.createPrimitive2DSequenceWithParameters(rVisitor);
+
+ if(bIsOutplaceActive)
+ {
+ // do not shade when printing or PDF exporting
+ if(!GetObjectContact().isOutputToPrinter() && !GetObjectContact().isOutputToRecordingMetaFile())
+ {
+ // get object transformation
+ const basegfx::B2DHomMatrix aObjectMatrix(static_cast< ViewContactOfSdrOle2Obj& >(GetViewContact()).createObjectTransform());
+
+ // shade the representation if the object is activated outplace
+ basegfx::B2DPolygon aObjectOutline(basegfx::utils::createUnitPolygon());
+ aObjectOutline.transform(aObjectMatrix);
+
+ // Use a FillHatchPrimitive2D with necessary attributes
+ const drawinglayer::attribute::FillHatchAttribute aFillHatch(
+ drawinglayer::attribute::HatchStyle::Single, // single hatch
+ 125.0, // 1.25 mm
+ basegfx::deg2rad(45.0), // 45 degree diagonal
+ COL_BLACK.getBColor(), // black color
+ 3, // same default as VCL, a minimum of three discrete units (pixels) offset
+ false); // no filling
+
+ const drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::PolyPolygonHatchPrimitive2D(
+ basegfx::B2DPolyPolygon(aObjectOutline),
+ COL_BLACK.getBColor(),
+ aFillHatch));
+
+ rVisitor.visit(xReference);
+ }
+ }
+
+ }
+}
+
+ViewObjectContactOfSdrOle2Obj::ViewObjectContactOfSdrOle2Obj(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfSdrOle2Obj::~ViewObjectContactOfSdrOle2Obj()
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofsdrpage.cxx b/svx/source/sdr/contact/viewobjectcontactofsdrpage.cxx
new file mode 100644
index 000000000..fe9855f4c
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofsdrpage.cxx
@@ -0,0 +1,579 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewobjectcontactofsdrpage.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <sdr/contact/viewcontactofsdrpage.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <drawinglayer/primitive2d/backgroundcolorprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/gridprimitive2d.hxx>
+#include <drawinglayer/primitive2d/helplineprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <sdr/primitive2d/sdrprimitivetools.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr::contact {
+
+const SdrPage& ViewObjectContactOfPageSubObject::getPage() const
+{
+ return static_cast< ViewContactOfPageSubObject& >(GetViewContact()).getPage();
+}
+
+ViewObjectContactOfPageSubObject::ViewObjectContactOfPageSubObject(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContact(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfPageSubObject::~ViewObjectContactOfPageSubObject()
+{
+}
+
+bool ViewObjectContactOfPageSubObject::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(rDisplayInfo.GetSubContentActive())
+ {
+ return false;
+ }
+
+ if(rDisplayInfo.GetControlLayerProcessingActive())
+ {
+ return false;
+ }
+
+ if(!rDisplayInfo.GetPageProcessingActive())
+ {
+ return false;
+ }
+
+ if(GetObjectContact().isOutputToPrinter())
+ {
+ return false;
+ }
+
+ if(!GetObjectContact().TryToGetSdrPageView())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool ViewObjectContactOfPageSubObject::isPrimitiveGhosted(const DisplayInfo& /*rDisplayInfo*/) const
+{
+ // suppress ghosted for page parts
+ return false;
+}
+
+ViewObjectContactOfPageBackground::ViewObjectContactOfPageBackground(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfPageBackground::~ViewObjectContactOfPageBackground()
+{
+}
+
+bool ViewObjectContactOfPageBackground::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ // no page background for preview renderers
+ if(GetObjectContact().IsPreviewRenderer())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void ViewObjectContactOfPageBackground::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // Initialize background. Dependent of IsPageVisible, use ApplicationBackgroundColor or ApplicationDocumentColor. Most
+ // old renderers for export (html, pdf, gallery, ...) set the page to not visible (SetPageVisible(false)). They expect the
+ // given OutputDevice to be initialized with the ApplicationDocumentColor then.
+ const SdrPageView* pPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(pPageView)
+ {
+ const SdrView& rView = pPageView->GetView();
+ Color aInitColor;
+
+ if(rView.IsPageVisible())
+ {
+ aInitColor = pPageView->GetApplicationBackgroundColor();
+ }
+ else
+ {
+ aInitColor = pPageView->GetApplicationDocumentColor();
+
+ if(COL_AUTO == aInitColor)
+ {
+ const svtools::ColorConfig aColorConfig;
+ aInitColor = aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor;
+ }
+ }
+
+ // init background with InitColor
+ const basegfx::BColor aRGBColor(aInitColor.getBColor());
+ rVisitor.visit(new drawinglayer::primitive2d::BackgroundColorPrimitive2D(aRGBColor, (255 - aInitColor.GetAlpha()) / 255.0));
+ }
+}
+
+ViewObjectContactOfMasterPage::ViewObjectContactOfMasterPage(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfMasterPage::~ViewObjectContactOfMasterPage()
+{
+}
+
+bool ViewObjectContactOfMasterPage::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ // this object is only used for MasterPages. When not the MasterPage is
+ // displayed as a page, but another page is using it as sub-object, the
+ // geometry needs to be hidden
+ if(rDisplayInfo.GetSubContentActive())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+ViewObjectContactOfPageFill::ViewObjectContactOfPageFill(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfPageFill::~ViewObjectContactOfPageFill()
+{
+}
+
+bool ViewObjectContactOfPageFill::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(!pSdrPageView)
+ {
+ return false;
+ }
+
+ if(!pSdrPageView->GetView().IsPageVisible())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void ViewObjectContactOfPageFill::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SdrPageView* pPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(pPageView)
+ {
+ const SdrPage& rPage = getPage();
+
+ const basegfx::B2DRange aPageFillRange(0.0, 0.0, static_cast<double>(rPage.GetWidth()), static_cast<double>(rPage.GetHeight()));
+ const basegfx::B2DPolygon aPageFillPolygon(basegfx::utils::createPolygonFromRect(aPageFillRange));
+ Color aPageFillColor;
+
+ if(pPageView->GetApplicationDocumentColor() != COL_AUTO)
+ {
+ aPageFillColor = pPageView->GetApplicationDocumentColor();
+ }
+ else
+ {
+ const svtools::ColorConfig aColorConfig;
+ aPageFillColor = aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor;
+ }
+
+ // create and add primitive
+ const basegfx::BColor aRGBColor(aPageFillColor.getBColor());
+ rVisitor.visit(new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPageFillPolygon), aRGBColor));
+ }
+}
+
+ViewObjectContactOfPageShadow::ViewObjectContactOfPageShadow(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfPageShadow::~ViewObjectContactOfPageShadow()
+{
+}
+
+bool ViewObjectContactOfPageShadow::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(!pSdrPageView)
+ {
+ return false;
+ }
+
+ if(!pSdrPageView->GetView().IsPageVisible())
+ {
+ return false;
+ }
+
+ if(!pSdrPageView->GetView().IsPageShadowVisible())
+ {
+ return false;
+ }
+
+ // no page shadow for preview renderers
+ if(GetObjectContact().IsPreviewRenderer())
+ {
+ return false;
+ }
+
+ // no page shadow for high contrast mode
+ if(GetObjectContact().isDrawModeHighContrast())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+ViewObjectContactOfOuterPageBorder::ViewObjectContactOfOuterPageBorder(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfOuterPageBorder::~ViewObjectContactOfOuterPageBorder()
+{
+}
+
+bool ViewObjectContactOfOuterPageBorder::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(!pSdrPageView)
+ {
+ return false;
+ }
+
+ const SdrView& rView = pSdrPageView->GetView();
+
+ return rView.IsPageVisible() || !rView.IsPageBorderVisible();
+}
+
+ViewObjectContactOfInnerPageBorder::ViewObjectContactOfInnerPageBorder(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfInnerPageBorder::~ViewObjectContactOfInnerPageBorder()
+{
+}
+
+bool ViewObjectContactOfInnerPageBorder::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(!pSdrPageView)
+ {
+ return false;
+ }
+
+ if(!pSdrPageView->GetView().IsBordVisible())
+ {
+ return false;
+ }
+
+ const SdrPage& rPage = getPage();
+
+ if(!rPage.GetLeftBorder() && !rPage.GetUpperBorder() && !rPage.GetRightBorder() && !rPage.GetLowerBorder())
+ {
+ return false;
+ }
+
+ // no inner page border for preview renderers
+ if(GetObjectContact().IsPreviewRenderer())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+ViewObjectContactOfPageHierarchy::ViewObjectContactOfPageHierarchy(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfPageHierarchy::~ViewObjectContactOfPageHierarchy()
+{
+}
+
+void ViewObjectContactOfPageHierarchy::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // process local sub-hierarchy
+ const sal_uInt32 nSubHierarchyCount(GetViewContact().GetObjectCount());
+
+ if(!nSubHierarchyCount)
+ return;
+
+ getPrimitive2DSequenceSubHierarchy(rDisplayInfo, rVisitor);
+}
+
+ViewObjectContactOfPageGrid::ViewObjectContactOfPageGrid(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfPageGrid::~ViewObjectContactOfPageGrid()
+{
+}
+
+bool ViewObjectContactOfPageGrid::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(!pSdrPageView)
+ {
+ return false;
+ }
+
+ const SdrView& rView = pSdrPageView->GetView();
+
+ if(!rView.IsGridVisible())
+ {
+ return false;
+ }
+
+ // no page grid for preview renderers
+ if(GetObjectContact().IsPreviewRenderer())
+ {
+ return false;
+ }
+
+ if(static_cast< ViewContactOfGrid& >(GetViewContact()).getFront() != rView.IsGridFront())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void ViewObjectContactOfPageGrid::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SdrPageView* pPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(pPageView)
+ {
+ const SdrView& rView = pPageView->GetView();
+ const SdrPage& rPage = getPage();
+ const Color aGridColor(rView.GetGridColor());
+ const basegfx::BColor aRGBGridColor(aGridColor.getBColor());
+
+ basegfx::B2DHomMatrix aGridMatrix;
+ aGridMatrix.set(0, 0, static_cast<double>(rPage.GetWidth() - (rPage.GetRightBorder() + rPage.GetLeftBorder())));
+ aGridMatrix.set(1, 1, static_cast<double>(rPage.GetHeight() - (rPage.GetLowerBorder() + rPage.GetUpperBorder())));
+ aGridMatrix.set(0, 2, static_cast<double>(rPage.GetLeftBorder()));
+ aGridMatrix.set(1, 2, static_cast<double>(rPage.GetUpperBorder()));
+
+ const Size aRaw(rView.GetGridCoarse());
+ const Size aFine(rView.GetGridFine());
+ const double fWidthX(aRaw.getWidth());
+ const double fWidthY(aRaw.getHeight());
+ const sal_uInt32 nSubdivisionsX(aFine.getWidth() ? aRaw.getWidth() / aFine.getWidth() : 0);
+ const sal_uInt32 nSubdivisionsY(aFine.getHeight() ? aRaw.getHeight() / aFine.getHeight() : 0);
+
+ rVisitor.visit(new drawinglayer::primitive2d::GridPrimitive2D(
+ aGridMatrix, fWidthX, fWidthY, 10.0, 3.0, nSubdivisionsX, nSubdivisionsY, aRGBGridColor,
+ drawinglayer::primitive2d::createDefaultCross_3x3(aRGBGridColor)));
+ }
+}
+
+ViewObjectContactOfPageHelplines::ViewObjectContactOfPageHelplines(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContactOfPageSubObject(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfPageHelplines::~ViewObjectContactOfPageHelplines()
+{
+}
+
+bool ViewObjectContactOfPageHelplines::isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const
+{
+ if(!ViewObjectContactOfPageSubObject::isPrimitiveVisible(rDisplayInfo))
+ {
+ return false;
+ }
+
+ SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(!pSdrPageView)
+ {
+ return false;
+ }
+
+ const SdrView& rView = pSdrPageView->GetView();
+
+ if(!rView.IsHlplVisible())
+ {
+ return false;
+ }
+
+ // no helplines for preview renderers
+ if(GetObjectContact().IsPreviewRenderer())
+ {
+ return false;
+ }
+
+ if(static_cast< ViewContactOfHelplines& >(GetViewContact()).getFront() != rView.IsHlplFront())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void ViewObjectContactOfPageHelplines::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ const SdrPageView* pPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(pPageView)
+ {
+ const SdrHelpLineList& rHelpLineList = pPageView->GetHelpLines();
+ const sal_uInt32 nCount(rHelpLineList.GetCount());
+
+ if(nCount)
+ {
+ const basegfx::BColor aRGBColorA(1.0, 1.0, 1.0);
+ const basegfx::BColor aRGBColorB(0.0, 0.0, 0.0);
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const SdrHelpLine& rHelpLine = rHelpLineList[static_cast<sal_uInt16>(a)];
+ const basegfx::B2DPoint aPosition(static_cast<double>(rHelpLine.GetPos().X()), static_cast<double>(rHelpLine.GetPos().Y()));
+ const double fDiscreteDashLength(4.0);
+
+ switch(rHelpLine.GetKind())
+ {
+ default : // SdrHelpLineKind::Point
+ {
+ rVisitor.visit(new drawinglayer::primitive2d::HelplinePrimitive2D(
+ aPosition, basegfx::B2DVector(1.0, 0.0), drawinglayer::primitive2d::HelplineStyle2D::Point,
+ aRGBColorA, aRGBColorB, fDiscreteDashLength));
+ break;
+ }
+ case SdrHelpLineKind::Vertical :
+ {
+ rVisitor.visit(new drawinglayer::primitive2d::HelplinePrimitive2D(
+ aPosition, basegfx::B2DVector(0.0, 1.0), drawinglayer::primitive2d::HelplineStyle2D::Line,
+ aRGBColorA, aRGBColorB, fDiscreteDashLength));
+ break;
+ }
+ case SdrHelpLineKind::Horizontal :
+ {
+ rVisitor.visit(new drawinglayer::primitive2d::HelplinePrimitive2D(
+ aPosition, basegfx::B2DVector(1.0, 0.0), drawinglayer::primitive2d::HelplineStyle2D::Line,
+ aRGBColorA, aRGBColorB, fDiscreteDashLength));
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+ViewObjectContactOfSdrPage::ViewObjectContactOfSdrPage(ObjectContact& rObjectContact, ViewContact& rViewContact)
+: ViewObjectContact(rObjectContact, rViewContact)
+{
+}
+
+ViewObjectContactOfSdrPage::~ViewObjectContactOfSdrPage()
+{
+}
+
+void ViewObjectContactOfSdrPage::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+{
+ // process local sub-hierarchy
+ const sal_uInt32 nSubHierarchyCount(GetViewContact().GetObjectCount());
+
+ if(!nSubHierarchyCount)
+ return;
+
+ const bool bDoGhostedDisplaying(
+ GetObjectContact().DoVisualizeEnteredGroup()
+ && !GetObjectContact().isOutputToPrinter()
+ && GetObjectContact().getActiveViewContact() == &GetViewContact());
+
+ if(bDoGhostedDisplaying)
+ {
+ rDisplayInfo.ClearGhostedDrawMode();
+ }
+
+ // visit object hierarchy
+ getPrimitive2DSequenceSubHierarchy(rDisplayInfo, rVisitor);
+
+ if(bDoGhostedDisplaying)
+ {
+ rDisplayInfo.SetGhostedDrawMode();
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx b/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
new file mode 100644
index 000000000..5ca5a32d2
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
@@ -0,0 +1,1777 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/contact/viewobjectcontactofunocontrol.hxx>
+#include <sdr/contact/viewcontactofunocontrol.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/objectcontactofpageview.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sdrpagewindow.hxx>
+
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/awt/XControlModel.hpp>
+#include <com/sun/star/awt/XControlContainer.hpp>
+#include <com/sun/star/awt/XWindow2.hpp>
+#include <com/sun/star/awt/PosSize.hpp>
+#include <com/sun/star/awt/XView.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/awt/InvalidateStyle.hpp>
+#include <com/sun/star/util/XModeChangeListener.hpp>
+#include <com/sun/star/util/XModeChangeBroadcaster.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+
+#include <vcl/canvastools.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/controlprimitive2d.hxx>
+
+/*
+
+Form controls (more precise: UNO Controls) in the drawing layer are ... prone to breakage, since they have some
+specialities which the drawing layer currently doesn't capture too well. In particular, having a living VCL
+window as child of the document window, and coupling this Window to a drawing layer object, makes things
+difficult sometimes.
+
+Below is a list of issues which existed in the past. Whenever you change code here, you're encouraged to
+verify those issues are still fixed. (Whenever you have some additional time, you're encouraged to write
+an automatic test for one or more of those issues for which this is possible :)
+
+https://bz.apache.org/ooo/show_bug.cgi?id=105992
+zooming documents containing (alive) form controls improperly positions the controls
+
+https://bz.apache.org/ooo/show_bug.cgi?id=104362
+crash when copy a control
+
+https://bz.apache.org/ooo/show_bug.cgi?id=104544
+Gridcontrol duplicated after design view on/off
+
+https://bz.apache.org/ooo/show_bug.cgi?id=102089
+print preview shows control elements with property printable=false
+
+https://bz.apache.org/ooo/show_bug.cgi?id=102090
+problem with setVisible on TextControl
+
+https://bz.apache.org/ooo/show_bug.cgi?id=103138
+loop when insert a control in draw
+
+https://bz.apache.org/ooo/show_bug.cgi?id=101398
+initially-displaying a document with many controls is very slow
+
+https://bz.apache.org/ooo/show_bug.cgi?id=72429
+repaint error in form wizard in bugdoc database
+
+https://bz.apache.org/ooo/show_bug.cgi?id=72694
+form control artifacts when scrolling a text fast
+
+*/
+
+
+namespace sdr::contact {
+
+
+ using namespace ::com::sun::star::awt::InvalidateStyle;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::awt::XControl;
+ using ::com::sun::star::awt::XControlModel;
+ using ::com::sun::star::awt::XControlContainer;
+ using ::com::sun::star::awt::XWindow2;
+ using ::com::sun::star::awt::XWindowListener;
+ using ::com::sun::star::awt::PosSize::POSSIZE;
+ using ::com::sun::star::awt::XView;
+ using ::com::sun::star::awt::WindowEvent;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::lang::XComponent;
+ using ::com::sun::star::awt::XWindowPeer;
+ using ::com::sun::star::beans::XPropertyChangeListener;
+ using ::com::sun::star::util::XModeChangeListener;
+ using ::com::sun::star::util::XModeChangeBroadcaster;
+ using ::com::sun::star::util::ModeChangeEvent;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::beans::PropertyChangeEvent;
+ using ::com::sun::star::container::XContainerListener;
+ using ::com::sun::star::container::XContainer;
+ using ::com::sun::star::container::ContainerEvent;
+ using ::com::sun::star::uno::Any;
+
+ namespace {
+
+ class ControlHolder
+ {
+ private:
+ Reference< XControl > m_xControl;
+ Reference< XWindow2 > m_xControlWindow;
+ Reference< XView > m_xControlView;
+
+ public:
+ ControlHolder()
+ {
+ }
+
+ explicit ControlHolder( const Reference< XControl >& _rxControl )
+ {
+ *this = _rxControl;
+ }
+
+ ControlHolder& operator=( const Reference< XControl >& _rxControl )
+ {
+ clear();
+
+ m_xControl = _rxControl;
+ if ( m_xControl.is() )
+ {
+ m_xControlWindow.set( m_xControl, UNO_QUERY );
+ m_xControlView.set( m_xControl, UNO_QUERY );
+ if ( !m_xControlWindow.is() || !m_xControlView.is() )
+ {
+ OSL_FAIL( "ControlHolder::operator=: invalid XControl, missing required interfaces!" );
+ clear();
+ }
+ }
+
+ return *this;
+ }
+
+ public:
+ bool is() const { return m_xControl.is() && m_xControlWindow.is() && m_xControlView.is(); }
+ void clear() { m_xControl.clear(); m_xControlWindow.clear(); m_xControlView.clear(); }
+
+ // delegators for the methods of the UNO interfaces
+ // Note all those will crash if called for a NULL object.
+ bool isDesignMode() const { return m_xControl->isDesignMode(); }
+ void setDesignMode( const bool _bDesign ) const { m_xControl->setDesignMode( _bDesign ); }
+ bool isVisible() const { return m_xControlWindow->isVisible(); }
+ void setVisible( const bool _bVisible ) const { m_xControlWindow->setVisible( _bVisible ); }
+ Reference< XControlModel >
+ getModel() const { return m_xControl->getModel(); }
+ void setModel( const Reference< XControlModel >& _m ) const { m_xControl->setModel( _m ); }
+
+ void addWindowListener( const Reference< XWindowListener >& _l ) const { m_xControlWindow->addWindowListener( _l ); }
+ void removeWindowListener( const Reference< XWindowListener >& _l ) const { m_xControlWindow->removeWindowListener( _l ); }
+ void setPosSize( const tools::Rectangle& _rPosSize ) const;
+ tools::Rectangle
+ getPosSize() const;
+ void setZoom( const ::basegfx::B2DVector& _rScale ) const;
+ ::basegfx::B2DVector
+ getZoom() const;
+
+ void invalidate() const;
+
+ public:
+ const Reference< XControl >& getControl() const { return m_xControl; }
+ };
+
+ bool operator==( const ControlHolder& _rControl, const Reference< XInterface >& _rxCompare )
+ {
+ return _rControl.getControl() == _rxCompare;
+ }
+
+ bool operator==( const ControlHolder& _rControl, const Any& _rxCompare )
+ {
+ return _rControl == Reference< XInterface >( _rxCompare, UNO_QUERY );
+ }
+
+ }
+
+ void ControlHolder::setPosSize( const tools::Rectangle& _rPosSize ) const
+ {
+ // no check whether we're valid, this is the responsibility of the caller
+
+ // don't call setPosSize when pos/size did not change #i104181#
+ ::tools::Rectangle aCurrentRect( getPosSize() );
+ if ( aCurrentRect != _rPosSize )
+ {
+ m_xControlWindow->setPosSize(
+ _rPosSize.Left(), _rPosSize.Top(), _rPosSize.GetWidth(), _rPosSize.GetHeight(),
+ POSSIZE
+ );
+ }
+ }
+
+
+ ::tools::Rectangle ControlHolder::getPosSize() const
+ {
+ // no check whether we're valid, this is the responsibility of the caller
+ return VCLUnoHelper::ConvertToVCLRect( m_xControlWindow->getPosSize() );
+ }
+
+
+ void ControlHolder::setZoom( const ::basegfx::B2DVector& _rScale ) const
+ {
+ // no check whether we're valid, this is the responsibility of the caller
+ m_xControlView->setZoom( static_cast<float>(_rScale.getX()), static_cast<float>(_rScale.getY()) );
+ }
+
+
+ void ControlHolder::invalidate() const
+ {
+ Reference< XWindowPeer > xPeer( m_xControl->getPeer() );
+ if ( xPeer.is() )
+ {
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xPeer );
+ OSL_ENSURE( pWindow, "ControlHolder::invalidate: no implementation access!" );
+ if ( pWindow )
+ pWindow->Invalidate();
+ }
+ }
+
+
+ ::basegfx::B2DVector ControlHolder::getZoom() const
+ {
+ // no check whether we're valid, this is the responsibility of the caller
+
+ // Argh. Why does XView have a setZoom only, but not a getZoom?
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( m_xControl->getPeer() );
+ OSL_ENSURE( pWindow, "ControlHolder::getZoom: no implementation access!" );
+
+ ::basegfx::B2DVector aZoom( 1, 1 );
+ if ( pWindow )
+ {
+ const Fraction& rZoom( pWindow->GetZoom() );
+ aZoom.setX( static_cast<double>(rZoom) );
+ aZoom.setY( static_cast<double>(rZoom) );
+ }
+ return aZoom;
+ }
+
+ namespace UnoControlContactHelper {
+
+ /** positions a control, and sets its zoom mode, using a given transformation and output device
+ */
+ static void adjustControlGeometry_throw( const ControlHolder& _rControl, const tools::Rectangle& _rLogicBoundingRect,
+ const basegfx::B2DHomMatrix& _rViewTransformation, const ::basegfx::B2DHomMatrix& _rZoomLevelNormalization )
+ {
+ OSL_PRECOND( _rControl.is(), "UnoControlContactHelper::adjustControlGeometry_throw: illegal control!" );
+ if ( !_rControl.is() )
+ return;
+
+ #if OSL_DEBUG_LEVEL > 0
+ ::basegfx::B2DTuple aViewScale, aViewTranslate;
+ double nViewRotate(0), nViewShearX(0);
+ _rViewTransformation.decompose( aViewScale, aViewTranslate, nViewRotate, nViewShearX );
+
+ ::basegfx::B2DTuple aZoomScale, aZoomTranslate;
+ double nZoomRotate(0), nZoomShearX(0);
+ _rZoomLevelNormalization.decompose( aZoomScale, aZoomTranslate, nZoomRotate, nZoomShearX );
+ #endif
+
+ // transform the logic bound rect, using the view transformation, to pixel coordinates
+ ::basegfx::B2DPoint aTopLeft( _rLogicBoundingRect.Left(), _rLogicBoundingRect.Top() );
+ aTopLeft *= _rViewTransformation;
+ ::basegfx::B2DPoint aBottomRight( _rLogicBoundingRect.Right(), _rLogicBoundingRect.Bottom() );
+ aBottomRight *= _rViewTransformation;
+
+ const tools::Rectangle aPaintRectPixel(static_cast<tools::Long>(std::round(aTopLeft.getX())),
+ static_cast<tools::Long>(std::round(aTopLeft.getY())),
+ static_cast<tools::Long>(std::round(aBottomRight.getX())),
+ static_cast<tools::Long>(std::round(aBottomRight.getY())));
+ _rControl.setPosSize( aPaintRectPixel );
+
+ // determine the scale from the current view transformation, and the normalization matrix
+ ::basegfx::B2DHomMatrix aObtainResolutionDependentScale( _rViewTransformation * _rZoomLevelNormalization );
+ ::basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ aObtainResolutionDependentScale.decompose( aScale, aTranslate, fRotate, fShearX );
+ _rControl.setZoom( aScale );
+ }
+
+ /** disposes the given control
+ */
+ static void disposeAndClearControl_nothrow( ControlHolder& _rControl )
+ {
+ try
+ {
+ Reference< XComponent > xControlComp = _rControl.getControl();
+ if ( xControlComp.is() )
+ xControlComp->dispose();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ _rControl.clear();
+ }
+
+ }
+
+ namespace {
+
+ /** interface encapsulating access to an SdrPageView, stripped down to the methods we really need
+ */
+ class IPageViewAccess
+ {
+ public:
+ /** determines whether the view is currently in design mode
+ */
+ virtual bool isDesignMode() const = 0;
+
+ /** retrieves the control container for a given output device
+ */
+ virtual Reference< XControlContainer >
+ getControlContainer( const OutputDevice& _rDevice ) const = 0;
+
+ /** determines whether a given layer is visible
+ */
+ virtual bool isLayerVisible( SdrLayerID _nLayerID ) const = 0;
+
+ protected:
+ ~IPageViewAccess() {}
+ };
+
+ /** is a ->IPageViewAccess implementation based on a real ->SdrPageView instance
+ */
+ class SdrPageViewAccess : public IPageViewAccess
+ {
+ const SdrPageView& m_rPageView;
+ public:
+ explicit SdrPageViewAccess( const SdrPageView& _rPageView ) : m_rPageView( _rPageView ) { }
+
+ virtual ~SdrPageViewAccess() {}
+
+ virtual bool isDesignMode() const override;
+ virtual Reference< XControlContainer >
+ getControlContainer( const OutputDevice& _rDevice ) const override;
+ virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
+ };
+
+ }
+
+ bool SdrPageViewAccess::isDesignMode() const
+ {
+ return m_rPageView.GetView().IsDesignMode();
+ }
+
+
+ Reference< XControlContainer > SdrPageViewAccess::getControlContainer( const OutputDevice& _rDevice ) const
+ {
+ Reference< XControlContainer > xControlContainer = m_rPageView.GetControlContainer( _rDevice );
+ DBG_ASSERT( xControlContainer.is() || nullptr == m_rPageView.FindPageWindow( _rDevice ),
+ "SdrPageViewAccess::getControlContainer: the output device is known, but there is no control container for it?" );
+ return xControlContainer;
+ }
+
+
+ bool SdrPageViewAccess::isLayerVisible( SdrLayerID _nLayerID ) const
+ {
+ return m_rPageView.GetVisibleLayers().IsSet( _nLayerID );
+ }
+
+ namespace {
+
+ /** is a ->IPageViewAccess implementation which can be used to create an invisible control for
+ an arbitrary window
+ */
+ class InvisibleControlViewAccess : public IPageViewAccess
+ {
+ private:
+ Reference< XControlContainer >& m_rControlContainer;
+ public:
+ explicit InvisibleControlViewAccess( Reference< XControlContainer >& _inout_ControlContainer )
+ :m_rControlContainer( _inout_ControlContainer )
+ {
+ }
+
+ virtual ~InvisibleControlViewAccess() {}
+
+ virtual bool isDesignMode() const override;
+ virtual Reference< XControlContainer >
+ getControlContainer( const OutputDevice& _rDevice ) const override;
+ virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
+ };
+
+ }
+
+ bool InvisibleControlViewAccess::isDesignMode() const
+ {
+ return true;
+ }
+
+
+ Reference< XControlContainer > InvisibleControlViewAccess::getControlContainer( const OutputDevice& _rDevice ) const
+ {
+ if ( !m_rControlContainer.is() )
+ {
+ const vcl::Window* pWindow = _rDevice.GetOwnerWindow();
+ OSL_ENSURE( pWindow, "InvisibleControlViewAccess::getControlContainer: expected to be called for a window only!" );
+ if ( pWindow )
+ m_rControlContainer = VCLUnoHelper::CreateControlContainer( const_cast< vcl::Window* >( pWindow ) );
+ }
+ return m_rControlContainer;
+ }
+
+
+ bool InvisibleControlViewAccess::isLayerVisible( SdrLayerID /*_nLayerID*/ ) const
+ {
+ return false;
+ }
+
+ namespace {
+
+ //= DummyPageViewAccess
+
+ /** is a ->IPageViewAccess implementation which can be used to create a control for an arbitrary
+ non-Window device
+
+ The implementation will report the "PageView" as being in design mode, all layers to be visible,
+ and will not return any ControlContainer, so all control container related features (notifications etc)
+ are not available.
+ */
+ class DummyPageViewAccess : public IPageViewAccess
+ {
+ public:
+ DummyPageViewAccess()
+ {
+ }
+
+ virtual ~DummyPageViewAccess() {}
+
+ virtual bool isDesignMode() const override;
+ virtual Reference< XControlContainer >
+ getControlContainer( const OutputDevice& _rDevice ) const override;
+ virtual bool isLayerVisible( SdrLayerID _nLayerID ) const override;
+ };
+
+ }
+
+ bool DummyPageViewAccess::isDesignMode() const
+ {
+ return true;
+ }
+
+
+ Reference< XControlContainer > DummyPageViewAccess::getControlContainer( const OutputDevice& /*_rDevice*/ ) const
+ {
+ return nullptr;
+ }
+
+
+ bool DummyPageViewAccess::isLayerVisible( SdrLayerID /*_nLayerID*/ ) const
+ {
+ return true;
+ }
+
+
+ //= ViewObjectContactOfUnoControl_Impl
+
+ typedef ::cppu::WeakImplHelper < XWindowListener
+ , XPropertyChangeListener
+ , XContainerListener
+ , XModeChangeListener
+ > ViewObjectContactOfUnoControl_Impl_Base;
+
+ class ViewObjectContactOfUnoControl_Impl:
+ public ViewObjectContactOfUnoControl_Impl_Base
+ {
+ private:
+ // tdf#41935 note that access to members is protected with SolarMutex;
+ // the class previously had its own mutex but that is prone to deadlock
+
+ /// the instance whose IMPL we are
+ ViewObjectContactOfUnoControl* m_pAntiImpl;
+
+ /// are we currently inside impl_ensureControl_nothrow?
+ bool m_bCreatingControl;
+
+ /// the control we're responsible for
+ ControlHolder m_aControl;
+
+ /// the ControlContainer where we inserted our control
+ Reference< XContainer > m_xContainer;
+
+ /// the output device for which the control was created
+ VclPtr<OutputDevice> m_pOutputDeviceForWindow;
+
+ /// flag indicating whether the control is currently visible
+ bool m_bControlIsVisible;
+
+ /// are we currently listening at a design mode control?
+ bool m_bIsDesignModeListening;
+
+ enum ViewControlMode
+ {
+ eDesign,
+ eAlive,
+ eUnknown
+ };
+ /// is the control currently in design mode?
+ mutable ViewControlMode m_eControlDesignMode;
+
+ ::basegfx::B2DHomMatrix m_aZoomLevelNormalization;
+
+ public:
+ explicit ViewObjectContactOfUnoControl_Impl( ViewObjectContactOfUnoControl* _pAntiImpl );
+ ViewObjectContactOfUnoControl_Impl(const ViewObjectContactOfUnoControl_Impl&) = delete;
+ ViewObjectContactOfUnoControl_Impl& operator=(const ViewObjectContactOfUnoControl_Impl&) = delete;
+
+ /** disposes the instance, which is nonfunctional afterwards
+ */
+ void dispose();
+
+ /** determines whether the instance is disposed
+ */
+ bool isDisposed() const { return impl_isDisposed_nofail(); }
+
+ /** returns the SdrUnoObject associated with the ViewContact
+
+ @precond
+ We're not disposed.
+ */
+ SdrUnoObj* getUnoObject() const;
+
+ /** ensures that we have an ->XControl
+
+ Must only be called if a control is needed when no DisplayInfo is present, yet.
+
+ For creating a control, an ->OutputDevice is needed, and an ->SdrPageView. Both will be obtained
+ from a ->ObjectContactOfPageView. So, if our (anti-impl's) object contact is not a ->ObjectContactOfPageView,
+ this method fill fail.
+
+ Failure of this method will be reported via an assertion in a non-product version.
+ */
+ void ensureControl( const basegfx::B2DHomMatrix* _pInitialViewTransformationOrNULL );
+
+ /** returns our XControl, if it already has been created
+
+ If you want to ensure that the control exists before accessing it, use ->ensureControl
+ */
+ const ControlHolder&
+ getExistentControl() const { return m_aControl; }
+
+ bool
+ hasControl() const { return m_aControl.is(); }
+
+ /** positions our XControl according to the geometry settings in the SdrUnoObj, modified by the given
+ transformation, and sets proper zoom settings according to our device
+
+ @precond
+ ->m_pOutputDeviceForWindow and ->m_aControl are not <NULL/>
+ */
+ void positionAndZoomControl( const basegfx::B2DHomMatrix& _rViewTransformation ) const;
+
+ /** determines whether or not our control is printable
+
+ Effectively, this method returns the value of the "Printable" property
+ of the control's model. If we have no control, <FALSE/> is returned.
+ */
+ bool isPrintableControl() const;
+
+ /** sets the design mode on the control, or at least remembers the flag for the
+ time the control is created
+ */
+ void setControlDesignMode( bool _bDesignMode ) const;
+
+ /** determines whether our control is currently visible
+ @nofail
+ */
+ bool isControlVisible() const { return m_bControlIsVisible; }
+
+ /// creates an XControl for the given device and SdrUnoObj
+ static bool
+ createControlForDevice(
+ IPageViewAccess const & _rPageView,
+ const OutputDevice& _rDevice,
+ const SdrUnoObj& _rUnoObject,
+ const basegfx::B2DHomMatrix& _rInitialViewTransformation,
+ const basegfx::B2DHomMatrix& _rInitialZoomNormalization,
+ ControlHolder& _out_rControl
+ );
+
+ const ViewContactOfUnoControl&
+ getViewContact() const
+ {
+ ENSURE_OR_THROW( !impl_isDisposed_nofail(), "already disposed" );
+ return static_cast< const ViewContactOfUnoControl& >( m_pAntiImpl->GetViewContact() );
+ }
+
+ protected:
+ virtual ~ViewObjectContactOfUnoControl_Impl() override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const EventObject& Source ) override;
+
+ // XWindowListener
+ virtual void SAL_CALL windowResized( const WindowEvent& e ) override;
+ virtual void SAL_CALL windowMoved( const WindowEvent& e ) override;
+ virtual void SAL_CALL windowShown( const EventObject& e ) override;
+ virtual void SAL_CALL windowHidden( const EventObject& e ) override;
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const PropertyChangeEvent& evt ) override;
+
+ // XModeChangeListener
+ virtual void SAL_CALL modeChanged( const ModeChangeEvent& _rSource ) override;
+
+ // XContainerListener
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
+
+ private:
+ /** retrieves the SdrPageView which our associated SdrPageViewWindow belongs to
+
+ @param out_rpPageView
+ a reference to a pointer holding, upon return, the desired SdrPageView
+
+ @return
+ <TRUE/> if and only if a ->SdrPageView could be obtained
+
+ @precond
+ We really belong to an SdrPageViewWindow. Perhaps (I'm not sure ATM :)
+ there are instance for which this might not be true, but those instances
+ should never have a need to call this method.
+
+ @precond
+ We're not disposed.
+
+ @postcond
+ The method expects success, if it returns with <FALSE/>, this will have been
+ asserted.
+
+ @nothrow
+ */
+ bool impl_getPageView_nothrow( SdrPageView*& _out_rpPageView );
+
+ /** adjusts the control visibility so it respects its layer's visibility
+
+ @precond
+ ->m_aControl is not <NULL/>
+
+ @precond
+ We're not disposed.
+
+ @precond
+ We really belong to an SdrPageViewWindow. There are instance for which this
+ might not be true, but those instances should never have a need to call
+ this method.
+ */
+ void impl_adjustControlVisibilityToLayerVisibility_throw();
+
+ /** adjusts the control visibility so it respects its layer's visibility
+
+ The control must never be visible if it's in design mode.
+ In alive mode, it must be visibility if and only it's on a visible layer.
+
+ @param _rxControl
+ the control whose visibility is to be adjusted
+
+ @param _rPageView
+ provides access to the attributes of the SdrPageView which the control finally belongs to
+
+ @param _rUnoObject
+ our SdrUnoObj
+
+ @param _bIsCurrentlyVisible
+ determines whether the control is currently visible. Note that this is only a shortcut for
+ querying _rxControl for the XWindow2 interface, and calling isVisible at this interface.
+ This shortcut has been chosen since the caller usually already has this information.
+ If _bForce is <TRUE/>, _bIsCurrentlyVisible is ignored.
+
+ @param _bForce
+ set to <TRUE/> if you want to force a ->XWindow::setVisible call,
+ no matter if the control visibility is already correct
+
+ @precond
+ We're not disposed.
+ */
+ static void impl_adjustControlVisibilityToLayerVisibility_throw( const ControlHolder& _rxControl, const SdrUnoObj& _rUnoObject,
+ IPageViewAccess const & _rPageView, bool _bIsCurrentlyVisible, bool _bForce );
+
+ /** starts or stops listening at various aspects of our control
+
+ @precond
+ ->m_aControl is not <NULL/>
+ */
+ void impl_switchControlListening_nothrow( bool _bStart );
+
+ /** starts or stops listening at our control container
+
+ @precond
+ ->m_xContainer is not <NULL/>
+ */
+ void impl_switchContainerListening_nothrow( bool _bStart );
+
+ /** starts or stops listening at the control for design-mode relevant facets
+ */
+ void impl_switchDesignModeListening_nothrow( bool _bStart );
+
+ /** starts or stops listening for all properties at our control
+
+ @param _bStart
+ determines whether to start or to stop listening
+
+ @precond
+ ->m_aControl is not <NULL/>
+ */
+ void impl_switchPropertyListening_nothrow( bool _bStart );
+
+ /** disposes the instance
+ @param _bAlsoDisposeControl
+ determines whether the XControl should be disposed, too
+ */
+ void impl_dispose_nothrow( bool _bAlsoDisposeControl );
+
+ /** determines whether the instance is disposed
+ @nofail
+ */
+ bool impl_isDisposed_nofail() const { return m_pAntiImpl == nullptr; }
+
+ /** determines whether the control currently is in design mode
+
+ @precond
+ The design mode must already be known. It is known when we first had access to
+ an SdrPageView (which carries this flag), or somebody explicitly set it from
+ outside.
+ */
+ bool impl_isControlDesignMode_nothrow() const
+ {
+ DBG_ASSERT( m_eControlDesignMode != eUnknown, "ViewObjectContactOfUnoControl_Impl::impl_isControlDesignMode_nothrow: mode is still unknown!" );
+ return m_eControlDesignMode == eDesign;
+ }
+
+ /** ensures that we have a control for the given PageView/OutputDevice
+ */
+ bool impl_ensureControl_nothrow(
+ IPageViewAccess const & _rPageView,
+ const OutputDevice& _rDevice,
+ const basegfx::B2DHomMatrix& _rInitialViewTransformation
+ );
+
+ const OutputDevice& impl_getOutputDevice_throw() const;
+ };
+
+ namespace {
+
+ class LazyControlCreationPrimitive2D : public ::drawinglayer::primitive2d::BufferedDecompositionPrimitive2D
+ {
+ private:
+ typedef ::drawinglayer::primitive2d::BufferedDecompositionPrimitive2D BufferedDecompositionPrimitive2D;
+
+ protected:
+ virtual void
+ get2DDecomposition(
+ ::drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor,
+ const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
+ ) const override;
+
+ virtual void create2DDecomposition(
+ ::drawinglayer::primitive2d::Primitive2DContainer& rContainer,
+ const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
+ ) const override;
+
+ virtual ::basegfx::B2DRange
+ getB2DRange(
+ const ::drawinglayer::geometry::ViewInformation2D& rViewInformation
+ ) const override;
+
+ public:
+ explicit LazyControlCreationPrimitive2D( const ::rtl::Reference< ViewObjectContactOfUnoControl_Impl >& _pVOCImpl )
+ :m_pVOCImpl( _pVOCImpl )
+ {
+ ENSURE_OR_THROW( m_pVOCImpl.is(), "Illegal argument." );
+ getTransformation( m_pVOCImpl->getViewContact(), m_aTransformation );
+ }
+
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ // declare unique ID for this primitive class
+ virtual sal_uInt32 getPrimitive2DID() const override;
+
+ static void getTransformation( const ViewContactOfUnoControl& _rVOC, ::basegfx::B2DHomMatrix& _out_Transformation );
+
+ private:
+ void impl_positionAndZoomControl( const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
+ {
+ if ( !_rViewInformation.getViewport().isEmpty() )
+ m_pVOCImpl->positionAndZoomControl( _rViewInformation.getObjectToViewTransformation() );
+ }
+
+ private:
+ ::rtl::Reference< ViewObjectContactOfUnoControl_Impl > m_pVOCImpl;
+ /** The geometry is part of the identity of a primitive, so we cannot calculate it on demand
+ (since the data the calculation is based on might have changed then), but need to calc
+ it at construction time, and remember it.
+ */
+ ::basegfx::B2DHomMatrix m_aTransformation;
+ };
+
+ }
+
+ ViewObjectContactOfUnoControl_Impl::ViewObjectContactOfUnoControl_Impl( ViewObjectContactOfUnoControl* _pAntiImpl )
+ :m_pAntiImpl( _pAntiImpl )
+ ,m_bCreatingControl( false )
+ ,m_pOutputDeviceForWindow( nullptr )
+ ,m_bControlIsVisible( false )
+ ,m_bIsDesignModeListening( false )
+ ,m_eControlDesignMode( eUnknown )
+ {
+ DBG_ASSERT( m_pAntiImpl, "ViewObjectContactOfUnoControl_Impl::ViewObjectContactOfUnoControl_Impl: invalid AntiImpl!" );
+
+ const OutputDevice& rPageViewDevice( impl_getOutputDevice_throw() );
+ m_aZoomLevelNormalization = rPageViewDevice.GetInverseViewTransformation();
+
+ #if OSL_DEBUG_LEVEL > 0
+ ::basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ m_aZoomLevelNormalization.decompose( aScale, aTranslate, fRotate, fShearX );
+ #endif
+
+ ::basegfx::B2DHomMatrix aScaleNormalization;
+ const MapMode& aCurrentDeviceMapMode( rPageViewDevice.GetMapMode() );
+ aScaleNormalization.set( 0, 0, static_cast<double>(aCurrentDeviceMapMode.GetScaleX()) );
+ aScaleNormalization.set( 1, 1, static_cast<double>(aCurrentDeviceMapMode.GetScaleY()) );
+ m_aZoomLevelNormalization *= aScaleNormalization;
+
+ #if OSL_DEBUG_LEVEL > 0
+ m_aZoomLevelNormalization.decompose( aScale, aTranslate, fRotate, fShearX );
+ #endif
+ }
+
+
+ ViewObjectContactOfUnoControl_Impl::~ViewObjectContactOfUnoControl_Impl()
+ {
+ if ( !impl_isDisposed_nofail() )
+ {
+ acquire();
+ dispose();
+ }
+
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::impl_dispose_nothrow( bool _bAlsoDisposeControl )
+ {
+ if ( impl_isDisposed_nofail() )
+ return;
+
+ if ( m_aControl.is() )
+ impl_switchControlListening_nothrow( false );
+
+ if ( m_xContainer.is() )
+ impl_switchContainerListening_nothrow( false );
+
+ // dispose the control
+ if ( _bAlsoDisposeControl )
+ UnoControlContactHelper::disposeAndClearControl_nothrow( m_aControl );
+
+ m_aControl.clear();
+ m_xContainer.clear();
+ m_pOutputDeviceForWindow = nullptr;
+ m_bControlIsVisible = false;
+
+ m_pAntiImpl = nullptr;
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::dispose()
+ {
+ SolarMutexGuard aSolarGuard;
+ impl_dispose_nothrow( true );
+ }
+
+
+ SdrUnoObj* ViewObjectContactOfUnoControl_Impl::getUnoObject() const
+ {
+ OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::getUnoObject: already disposed()" );
+ if ( impl_isDisposed_nofail() )
+ return nullptr;
+ auto pRet = dynamic_cast< SdrUnoObj* >( m_pAntiImpl->GetViewContact().TryToGetSdrObject() );
+ DBG_ASSERT( pRet || !m_pAntiImpl->GetViewContact().TryToGetSdrObject(),
+ "ViewObjectContactOfUnoControl_Impl::getUnoObject: invalid SdrObject!" );
+ return pRet;
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::positionAndZoomControl( const basegfx::B2DHomMatrix& _rViewTransformation ) const
+ {
+ OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::positionAndZoomControl: no output device or no control!" );
+ if ( !m_aControl.is() )
+ return;
+
+ try
+ {
+ SdrUnoObj* pUnoObject = getUnoObject();
+ if ( pUnoObject )
+ {
+ const tools::Rectangle aRect( pUnoObject->GetLogicRect() );
+ UnoControlContactHelper::adjustControlGeometry_throw( m_aControl, aRect, _rViewTransformation, m_aZoomLevelNormalization );
+ }
+ else
+ OSL_FAIL( "ViewObjectContactOfUnoControl_Impl::positionAndZoomControl: no SdrUnoObj!" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::ensureControl( const basegfx::B2DHomMatrix* _pInitialViewTransformationOrNULL )
+ {
+ OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::ensureControl: already disposed()" );
+ if ( impl_isDisposed_nofail() )
+ return;
+
+ ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
+ if ( pPageViewContact )
+ {
+ SdrPageViewAccess aPVAccess( pPageViewContact->GetPageWindow().GetPageView() );
+ const OutputDevice& rDevice( *m_pAntiImpl->getPageViewOutputDevice() );
+ impl_ensureControl_nothrow(
+ aPVAccess,
+ rDevice,
+ _pInitialViewTransformationOrNULL ? *_pInitialViewTransformationOrNULL : rDevice.GetViewTransformation()
+ );
+ return;
+ }
+
+ DummyPageViewAccess aNoPageView;
+ const OutputDevice& rDevice( impl_getOutputDevice_throw() );
+ impl_ensureControl_nothrow(
+ aNoPageView,
+ rDevice,
+ _pInitialViewTransformationOrNULL ? *_pInitialViewTransformationOrNULL : rDevice.GetViewTransformation()
+ );
+ }
+
+
+ const OutputDevice& ViewObjectContactOfUnoControl_Impl::impl_getOutputDevice_throw() const
+ {
+ // do not use ObjectContact::TryToGetOutputDevice, it would not care for the PageWindow's
+ // OriginalPaintWindow
+ const OutputDevice* oPageOutputDev = m_pAntiImpl->getPageViewOutputDevice();
+ if( oPageOutputDev )
+ return *oPageOutputDev;
+
+ const OutputDevice* pDevice = m_pAntiImpl->GetObjectContact().TryToGetOutputDevice();
+ ENSURE_OR_THROW( pDevice, "no output device -> no control" );
+ return *pDevice;
+ }
+
+
+ namespace
+ {
+ void lcl_resetFlag( bool& rbFlag )
+ {
+ rbFlag = false;
+ }
+ }
+
+
+ bool ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow( IPageViewAccess const & _rPageView, const OutputDevice& _rDevice,
+ const basegfx::B2DHomMatrix& _rInitialViewTransformation )
+ {
+ if ( m_bCreatingControl )
+ {
+ OSL_FAIL( "ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow: reentrance is not really good here!" );
+ // We once had a situation where this was called reentrantly, which lead to all kind of strange effects. All
+ // those affected the grid control, which is the only control so far which is visible in design mode (and
+ // not only in alive mode).
+ // Creating the control triggered a Window::Update on some of its child windows, which triggered a
+ // Paint on parent of the grid control (e.g. the SwEditWin), which triggered a reentrant call to this method,
+ // which it is not really prepared for.
+
+ // /me thinks that re-entrance should be caught on a higher level, i.e. the Drawing Layer should not allow
+ // reentrant paint requests. For the moment, until /me can discuss this with AW, catch it here. #i104544#
+ return false;
+ }
+
+ m_bCreatingControl = true;
+ ::comphelper::ScopeGuard aGuard([&] () { lcl_resetFlag(m_bCreatingControl); });
+
+ if ( m_aControl.is() )
+ {
+ if ( m_pOutputDeviceForWindow.get() == &_rDevice )
+ return true;
+
+ // Somebody requested a control for a new device, which means either of
+ // - our PageView's paint window changed since we were last here
+ // - we don't belong to a page view, and are simply painted onto different devices
+ // The first sounds strange (doesn't it?), the second means we could perhaps
+ // optimize this in the future - there is no need to re-create the control every time,
+ // is it? #i74523#
+ if ( m_xContainer.is() )
+ impl_switchContainerListening_nothrow( false );
+ impl_switchControlListening_nothrow( false );
+ UnoControlContactHelper::disposeAndClearControl_nothrow( m_aControl );
+ }
+
+ SdrUnoObj* pUnoObject = getUnoObject();
+ if ( !pUnoObject )
+ return false;
+
+ ControlHolder aControl;
+ if ( !createControlForDevice( _rPageView, _rDevice, *pUnoObject, _rInitialViewTransformation, m_aZoomLevelNormalization, aControl ) )
+ return false;
+
+ m_pOutputDeviceForWindow = const_cast< OutputDevice * >( &_rDevice );
+ m_aControl = aControl;
+ m_xContainer.set(_rPageView.getControlContainer( _rDevice ), css::uno::UNO_QUERY);
+ DBG_ASSERT( ( m_xContainer.is() // either have a XControlContainer
+ || ( ( !_rPageView.getControlContainer( _rDevice ).is() ) // or don't have any container,
+ && ( _rDevice.GetOwnerWindow() == nullptr ) // which is allowed for non-Window instances only
+ )
+ ),
+ "ViewObjectContactOfUnoControl_Impl::impl_ensureControl_nothrow: no XContainer at the ControlContainer!" );
+
+ try
+ {
+ m_eControlDesignMode = m_aControl.isDesignMode() ? eDesign : eAlive;
+ m_bControlIsVisible = m_aControl.isVisible();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ // start listening at all aspects of the control which are interesting to us ...
+ impl_switchControlListening_nothrow( true );
+
+ // start listening at the control container, in case somebody tampers with our control
+ if ( m_xContainer.is() )
+ impl_switchContainerListening_nothrow( true );
+
+ return m_aControl.is();
+ }
+
+
+ bool ViewObjectContactOfUnoControl_Impl::createControlForDevice( IPageViewAccess const & _rPageView,
+ const OutputDevice& _rDevice, const SdrUnoObj& _rUnoObject, const basegfx::B2DHomMatrix& _rInitialViewTransformation,
+ const basegfx::B2DHomMatrix& _rInitialZoomNormalization, ControlHolder& _out_rControl )
+ {
+ _out_rControl.clear();
+
+ const Reference< XControlModel >& xControlModel( _rUnoObject.GetUnoControlModel() );
+ DBG_ASSERT( xControlModel.is(), "ViewObjectContactOfUnoControl_Impl::createControlForDevice: no control model at the SdrUnoObject!?" );
+ if ( !xControlModel.is() )
+ return false;
+
+ bool bSuccess = false;
+ try
+ {
+ const OUString& sControlServiceName( _rUnoObject.GetUnoControlTypeName() );
+
+ Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ _out_rControl = Reference<XControl>( xContext->getServiceManager()->createInstanceWithContext(sControlServiceName, xContext), UNO_QUERY_THROW );
+
+ // knit the model and the control
+ _out_rControl.setModel( xControlModel );
+ const tools::Rectangle aRect( _rUnoObject.GetLogicRect() );
+
+ // proper geometry
+ UnoControlContactHelper::adjustControlGeometry_throw(
+ _out_rControl,
+ aRect,
+ _rInitialViewTransformation,
+ _rInitialZoomNormalization
+ );
+
+ // set design mode before peer is created,
+ // this is also needed for accessibility
+ _out_rControl.setDesignMode( _rPageView.isDesignMode() );
+
+ // adjust the initial visibility according to the visibility of the layer
+ impl_adjustControlVisibilityToLayerVisibility_throw( _out_rControl, _rUnoObject, _rPageView, false, true );
+
+ // add the control to the respective control container
+ // do this last
+ Reference< XControlContainer > xControlContainer( _rPageView.getControlContainer( _rDevice ) );
+ if ( xControlContainer.is() )
+ xControlContainer->addControl( sControlServiceName, _out_rControl.getControl() );
+
+ bSuccess = true;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+ if ( !bSuccess )
+ {
+ // delete the control which might have been created already
+ UnoControlContactHelper::disposeAndClearControl_nothrow( _out_rControl );
+ }
+
+ return _out_rControl.is();
+ }
+
+
+ bool ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow( SdrPageView*& _out_rpPageView )
+ {
+ OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow: already disposed!" );
+
+ _out_rpPageView = nullptr;
+ if ( impl_isDisposed_nofail() )
+ return false;
+
+ ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &m_pAntiImpl->GetObjectContact() );
+ if ( pPageViewContact )
+ _out_rpPageView = &pPageViewContact->GetPageWindow().GetPageView();
+
+ DBG_ASSERT( _out_rpPageView != nullptr, "ViewObjectContactOfUnoControl_Impl::impl_getPageView_nothrow: this method is expected to always have success!" );
+ return ( _out_rpPageView != nullptr );
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw()
+ {
+ OSL_PRECOND( m_aControl.is(),
+ "ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw: only valid if we have a control!" );
+
+ SdrPageView* pPageView( nullptr );
+ if ( !impl_getPageView_nothrow( pPageView ) )
+ return;
+
+ SdrUnoObj* pUnoObject = getUnoObject();
+ if ( !pUnoObject )
+ return;
+
+ SdrPageViewAccess aPVAccess( *pPageView );
+ impl_adjustControlVisibilityToLayerVisibility_throw( m_aControl, *pUnoObject, aPVAccess, m_bControlIsVisible, false/*_bForce*/ );
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::impl_adjustControlVisibilityToLayerVisibility_throw( const ControlHolder& _rControl,
+ const SdrUnoObj& _rUnoObject, IPageViewAccess const & _rPageView, bool _bIsCurrentlyVisible, bool _bForce )
+ {
+ // in design mode, there is no problem with the visibility: The XControl is hidden by
+ // default, and the Drawing Layer will simply not call our paint routine, if we're in
+ // a hidden layer. So, only alive mode matters.
+ if ( !_rControl.isDesignMode() )
+ {
+ // the layer of our object
+ SdrLayerID nObjectLayer = _rUnoObject.GetLayer();
+ // is the object we're residing in visible in this view?
+ bool bIsObjectVisible = _rUnoObject.IsVisible() && _rPageView.isLayerVisible( nObjectLayer );
+
+ if ( _bForce || ( bIsObjectVisible != _bIsCurrentlyVisible ) )
+ {
+ _rControl.setVisible( bIsObjectVisible );
+ }
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::impl_switchContainerListening_nothrow( bool _bStart )
+ {
+ OSL_PRECOND( m_xContainer.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchContainerListening_nothrow: no control container!" );
+ if ( !m_xContainer.is() )
+ return;
+
+ try
+ {
+ if ( _bStart )
+ m_xContainer->addContainerListener( this );
+ else
+ m_xContainer->removeContainerListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::impl_switchControlListening_nothrow( bool _bStart )
+ {
+ OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchControlListening_nothrow: invalid control!" );
+ if ( !m_aControl.is() )
+ return;
+
+ try
+ {
+ // listen for visibility changes
+ if ( _bStart )
+ m_aControl.addWindowListener( this );
+ else
+ m_aControl.removeWindowListener( this );
+
+ // in design mode, listen for some more aspects
+ impl_switchDesignModeListening_nothrow( impl_isControlDesignMode_nothrow() && _bStart );
+
+ // listen for design mode changes
+ Reference< XModeChangeBroadcaster > xDesignModeChanges( m_aControl.getControl(), UNO_QUERY_THROW );
+ if ( _bStart )
+ xDesignModeChanges->addModeChangeListener( this );
+ else
+ xDesignModeChanges->removeModeChangeListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::impl_switchDesignModeListening_nothrow( bool _bStart )
+ {
+ if ( m_bIsDesignModeListening != _bStart )
+ {
+ m_bIsDesignModeListening = _bStart;
+ impl_switchPropertyListening_nothrow( _bStart );
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::impl_switchPropertyListening_nothrow( bool _bStart )
+ {
+ OSL_PRECOND( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::impl_switchPropertyListening_nothrow: no control!" );
+ if ( !m_aControl.is() )
+ return;
+
+ try
+ {
+ Reference< XPropertySet > xModelProperties( m_aControl.getModel(), UNO_QUERY_THROW );
+ if ( _bStart )
+ xModelProperties->addPropertyChangeListener( OUString(), this );
+ else
+ xModelProperties->removePropertyChangeListener( OUString(), this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ bool ViewObjectContactOfUnoControl_Impl::isPrintableControl() const
+ {
+ SdrUnoObj* pUnoObject = getUnoObject();
+ if ( !pUnoObject )
+ return false;
+
+ bool bIsPrintable = false;
+ try
+ {
+ Reference< XPropertySet > xModelProperties( pUnoObject->GetUnoControlModel(), UNO_QUERY_THROW );
+ OSL_VERIFY( xModelProperties->getPropertyValue( "Printable" ) >>= bIsPrintable );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ return bIsPrintable;
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::disposing( const EventObject& Source )
+ {
+ SolarMutexGuard aSolarGuard;
+ // some code below - in particular our disposal - might trigger actions which require the
+ // SolarMutex. In particular, in our disposal, we remove ourself as listener from the control,
+ // which alone needs the SolarMutex. Of course this - a removeFooListener needed the SolarMutex -
+ // is the real bug. Toolkit really is infested with solar mutex usage ... :( #i82169#
+
+ if ( !m_aControl.is() )
+ return;
+
+ if ( ( m_aControl == Source.Source )
+ || ( m_aControl.getModel() == Source.Source )
+ )
+ {
+ // the model or the control is dying ... hmm, not much sense in that we ourself continue
+ // living
+ impl_dispose_nothrow( false );
+ return;
+ }
+
+ DBG_ASSERT( Source.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::disposing: Who's this?" );
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowResized( const WindowEvent& /*e*/ )
+ {
+ // not interested in
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowMoved( const WindowEvent& /*e*/ )
+ {
+ // not interested in
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowShown( const EventObject& /*e*/ )
+ {
+ SolarMutexGuard aSolarGuard;
+ m_bControlIsVisible = true;
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::windowHidden( const EventObject& /*e*/ )
+ {
+ SolarMutexGuard aSolarGuard;
+ m_bControlIsVisible = false;
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::propertyChange( const PropertyChangeEvent& /*_rEvent*/ )
+ {
+ SolarMutexGuard aSolarGuard;
+ // (re)painting might require VCL operations, which need the SolarMutex
+
+ OSL_PRECOND( !impl_isDisposed_nofail(), "ViewObjectContactOfUnoControl_Impl::propertyChange: already disposed()" );
+ if ( impl_isDisposed_nofail() )
+ return;
+
+ DBG_ASSERT( m_aControl.is(), "ViewObjectContactOfUnoControl_Impl::propertyChange: " );
+ if ( !m_aControl.is() )
+ return;
+
+ // a generic property changed. If we're in design mode, we need to repaint the control
+ if ( impl_isControlDesignMode_nothrow() )
+ {
+ m_pAntiImpl->propertyChange();
+ }
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::modeChanged( const ModeChangeEvent& _rSource )
+ {
+ SolarMutexGuard aSolarGuard;
+
+ DBG_ASSERT( _rSource.NewMode == "design" || _rSource.NewMode == "alive", "ViewObjectContactOfUnoControl_Impl::modeChanged: unexpected mode!" );
+
+ m_eControlDesignMode = _rSource.NewMode == "design" ? eDesign : eAlive;
+
+ impl_switchDesignModeListening_nothrow( impl_isControlDesignMode_nothrow() );
+
+ try
+ {
+ // if the control is part of an invisible layer, we need to explicitly hide it in alive mode
+ impl_adjustControlVisibilityToLayerVisibility_throw();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementInserted( const ContainerEvent& /*_Event*/ )
+ {
+ // not interested in
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementRemoved( const ContainerEvent& Event )
+ {
+ SolarMutexGuard aSolarGuard;
+ // some code below - in particular our disposal - might trigger actions which require the
+ // SolarMutex. In particular, in our disposal, we remove ourself as listener from the control,
+ // which alone needs the SolarMutex. Of course this - a removeFooListener needed the SolarMutex -
+ // is the real bug. Toolkit really is infested with solar mutex usage ... :( #i82169#
+ DBG_ASSERT( Event.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::elementRemoved: where did this come from?" );
+
+ if ( m_aControl == Event.Element )
+ impl_dispose_nothrow( false );
+ }
+
+
+ void SAL_CALL ViewObjectContactOfUnoControl_Impl::elementReplaced( const ContainerEvent& Event )
+ {
+ SolarMutexGuard aSolarGuard;
+ DBG_ASSERT( Event.Source == m_xContainer, "ViewObjectContactOfUnoControl_Impl::elementReplaced: where did this come from?" );
+
+ if ( ! ( m_aControl == Event.ReplacedElement ) )
+ return;
+
+ Reference< XControl > xNewControl( Event.Element, UNO_QUERY );
+ DBG_ASSERT( xNewControl.is(), "ViewObjectContactOfUnoControl_Impl::elementReplaced: invalid new control!" );
+ if ( !xNewControl.is() )
+ return;
+
+ ENSURE_OR_THROW( m_pOutputDeviceForWindow, "calling this without /me having an output device should be impossible." );
+
+ DBG_ASSERT( xNewControl->getModel() == m_aControl.getModel(), "ViewObjectContactOfUnoControl_Impl::elementReplaced: another model at the new control?" );
+ // another model should - in the drawing layer - also imply another SdrUnoObj, which
+ // should also result in new ViewContact, and thus in new ViewObjectContacts
+
+ impl_switchControlListening_nothrow( false );
+
+ ControlHolder aNewControl( xNewControl );
+ aNewControl.setZoom( m_aControl.getZoom() );
+ aNewControl.setPosSize( m_aControl.getPosSize() );
+ aNewControl.setDesignMode( impl_isControlDesignMode_nothrow() );
+
+ m_aControl = xNewControl;
+ m_bControlIsVisible = m_aControl.isVisible();
+
+ impl_switchControlListening_nothrow( true );
+
+ m_pAntiImpl->onControlChangedOrModified( ViewObjectContactOfUnoControl::ImplAccess() );
+ }
+
+
+ void ViewObjectContactOfUnoControl_Impl::setControlDesignMode( bool _bDesignMode ) const
+ {
+ if ( ( m_eControlDesignMode != eUnknown ) && ( _bDesignMode == impl_isControlDesignMode_nothrow() ) )
+ // nothing to do
+ return;
+ m_eControlDesignMode = _bDesignMode ? eDesign : eAlive;
+
+ if ( !m_aControl.is() )
+ // nothing to do, the setting will be respected as soon as the control
+ // is created
+ return;
+
+ try
+ {
+ m_aControl.setDesignMode( _bDesignMode );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ //= LazyControlCreationPrimitive2D
+
+
+ bool LazyControlCreationPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if ( !BufferedDecompositionPrimitive2D::operator==( rPrimitive ) )
+ return false;
+
+ const LazyControlCreationPrimitive2D* pRHS = dynamic_cast< const LazyControlCreationPrimitive2D* >( &rPrimitive );
+ if ( !pRHS )
+ return false;
+
+ if ( m_pVOCImpl != pRHS->m_pVOCImpl )
+ return false;
+
+ if ( m_aTransformation != pRHS->m_aTransformation )
+ return false;
+
+ return true;
+ }
+
+
+ void LazyControlCreationPrimitive2D::getTransformation( const ViewContactOfUnoControl& _rVOC, ::basegfx::B2DHomMatrix& _out_Transformation )
+ {
+ // Do use model data directly to create the correct geometry. Do NOT
+ // use getBoundRect()/getSnapRect() here; these will use the sequence of
+ // primitives themselves in the long run.
+ const tools::Rectangle aSdrGeoData( _rVOC.GetSdrUnoObj().GetGeoRect() );
+ const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aSdrGeoData);
+
+ _out_Transformation.identity();
+ _out_Transformation.set( 0, 0, aRange.getWidth() );
+ _out_Transformation.set( 1, 1, aRange.getHeight() );
+ _out_Transformation.set( 0, 2, aRange.getMinX() );
+ _out_Transformation.set( 1, 2, aRange.getMinY() );
+ }
+
+
+ ::basegfx::B2DRange LazyControlCreationPrimitive2D::getB2DRange( const ::drawinglayer::geometry::ViewInformation2D& /*rViewInformation*/ ) const
+ {
+ ::basegfx::B2DRange aRange( 0.0, 0.0, 1.0, 1.0 );
+ aRange.transform( m_aTransformation );
+ return aRange;
+ }
+
+
+ void LazyControlCreationPrimitive2D::get2DDecomposition( ::drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor, const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
+ {
+ #if OSL_DEBUG_LEVEL > 0
+ ::basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ _rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
+ #endif
+ if ( m_pVOCImpl->hasControl() )
+ impl_positionAndZoomControl( _rViewInformation );
+ BufferedDecompositionPrimitive2D::get2DDecomposition( rVisitor, _rViewInformation );
+ }
+
+
+ void LazyControlCreationPrimitive2D::create2DDecomposition( ::drawinglayer::primitive2d::Primitive2DContainer& rContainer, const ::drawinglayer::geometry::ViewInformation2D& _rViewInformation ) const
+ {
+ #if OSL_DEBUG_LEVEL > 0
+ ::basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ _rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
+ #endif
+ const bool bHadControl = m_pVOCImpl->getExistentControl().is();
+
+ // force control here to make it a VCL ChildWindow. Will be fetched
+ // and used below by getExistentControl()
+ m_pVOCImpl->ensureControl( &_rViewInformation.getObjectToViewTransformation() );
+ impl_positionAndZoomControl( _rViewInformation );
+
+ // get needed data
+ const ViewContactOfUnoControl& rViewContactOfUnoControl( m_pVOCImpl->getViewContact() );
+ Reference< XControlModel > xControlModel( rViewContactOfUnoControl.GetSdrUnoObj().GetUnoControlModel() );
+ const ControlHolder& rControl( m_pVOCImpl->getExistentControl() );
+
+ if ( !bHadControl && rControl.is() && rControl.isVisible() )
+ rControl.invalidate();
+
+ // check if we already have an XControl.
+ if ( !xControlModel.is() || !rControl.is() )
+ {
+ // use the default mechanism. This will create a ControlPrimitive2D without
+ // handing over a XControl. If not even a XControlModel exists, it will
+ // create the SdrObject fallback visualisation
+ rViewContactOfUnoControl.getViewIndependentPrimitive2DContainer(rContainer);
+ return;
+ }
+
+ // create a primitive and hand over the existing xControl. This will
+ // allow the primitive to not need to create another one on demand.
+ rContainer.push_back( new ::drawinglayer::primitive2d::ControlPrimitive2D(
+ m_aTransformation, xControlModel, rControl.getControl() ) );
+ }
+
+ sal_uInt32 LazyControlCreationPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRCONTROLPRIMITIVE2D;
+ }
+
+ ViewObjectContactOfUnoControl::ViewObjectContactOfUnoControl( ObjectContact& _rObjectContact, ViewContactOfUnoControl& _rViewContact )
+ :ViewObjectContactOfSdrObj( _rObjectContact, _rViewContact )
+ ,m_pImpl( new ViewObjectContactOfUnoControl_Impl( this ) )
+ {
+ }
+
+
+ ViewObjectContactOfUnoControl::~ViewObjectContactOfUnoControl()
+ {
+ m_pImpl->dispose();
+ m_pImpl = nullptr;
+
+ }
+
+
+ Reference< XControl > ViewObjectContactOfUnoControl::getControl()
+ {
+ SolarMutexGuard aSolarGuard;
+ m_pImpl->ensureControl( nullptr );
+ return m_pImpl->getExistentControl().getControl();
+ }
+
+
+ Reference< XControl > ViewObjectContactOfUnoControl::getTemporaryControlForWindow(
+ const vcl::Window& _rWindow, Reference< XControlContainer >& _inout_ControlContainer, const SdrUnoObj& _rUnoObject )
+ {
+ ControlHolder aControl;
+
+ InvisibleControlViewAccess aSimulatePageView( _inout_ControlContainer );
+ OSL_VERIFY( ViewObjectContactOfUnoControl_Impl::createControlForDevice( aSimulatePageView, *_rWindow.GetOutDev(), _rUnoObject,
+ _rWindow.GetOutDev()->GetViewTransformation(), _rWindow.GetOutDev()->GetInverseViewTransformation(), aControl ) );
+ return aControl.getControl();
+ }
+
+
+ void ViewObjectContactOfUnoControl::ensureControlVisibility( bool _bVisible ) const
+ {
+ SolarMutexGuard aSolarGuard;
+
+ try
+ {
+ const ControlHolder& rControl( m_pImpl->getExistentControl() );
+ if ( !rControl.is() )
+ return;
+
+ // only need to care for alive mode
+ if ( rControl.isDesignMode() )
+ return;
+
+ // is the visibility correct?
+ if ( m_pImpl->isControlVisible() == _bVisible )
+ return;
+
+ // no -> adjust it
+ rControl.setVisible( _bVisible );
+ DBG_ASSERT( m_pImpl->isControlVisible() == _bVisible, "ViewObjectContactOfUnoControl::ensureControlVisibility: this didn't work!" );
+ // now this would mean that either isControlVisible is not reliable,
+ // or that showing/hiding the window did not work as intended.
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl::setControlDesignMode( bool _bDesignMode ) const
+ {
+ SolarMutexGuard aSolarGuard;
+ m_pImpl->setControlDesignMode( _bDesignMode );
+
+ if(!_bDesignMode)
+ {
+ // when live mode is switched on, a refresh is needed. The edit mode visualisation
+ // needs to be repainted and the now used VCL-Window needs to be positioned and
+ // sized. Both is done from the repaint refresh.
+ const_cast< ViewObjectContactOfUnoControl* >(this)->ActionChanged();
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ if ( m_pImpl->isDisposed() )
+ // our control already died.
+ // TODO: Is it worth re-creating the control? Finally, this is a pathological situation, it means some instance
+ // disposed the control though it doesn't own it. So, /me thinks we should not bother here.
+ return;
+
+ if ( GetObjectContact().getViewInformation2D().getViewTransformation().isIdentity() )
+ // remove this when #i115754# is fixed
+ return;
+
+ // ignore existing controls which are in alive mode and manually switched to "invisible" #i102090#
+ const ControlHolder& rControl( m_pImpl->getExistentControl() );
+ if ( rControl.is() && !rControl.isDesignMode() && !rControl.isVisible() )
+ return;
+
+ rVisitor.visit( new LazyControlCreationPrimitive2D( m_pImpl ) );
+ }
+
+
+ bool ViewObjectContactOfUnoControl::isPrimitiveVisible( const DisplayInfo& _rDisplayInfo ) const
+ {
+ SolarMutexGuard aSolarGuard;
+
+ if ( m_pImpl->hasControl() )
+ {
+ const ::drawinglayer::geometry::ViewInformation2D& rViewInformation( GetObjectContact().getViewInformation2D() );
+ #if OSL_DEBUG_LEVEL > 0
+ ::basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rViewInformation.getObjectToViewTransformation().decompose( aScale, aTranslate, fRotate, fShearX );
+ #endif
+
+ if ( !rViewInformation.getViewport().isEmpty() )
+ {
+ // tdf#121963 check and eventually pre-multiply ViewTransformation
+ // with GridOffset transformation to avoid alternating positions of
+ // FormControls which are victims of the non-linear calc ViewTransformation
+ // aka GridOffset. For other paths (e.g. repaint) this is included already
+ // as part of the object's sequence of B2DPrimitive - representation
+ // (see ViewObjectContact::getPrimitive2DSequence and how getGridOffset is used there)
+ basegfx::B2DHomMatrix aViewTransformation(rViewInformation.getObjectToViewTransformation());
+
+ if(GetObjectContact().supportsGridOffsets())
+ {
+ const basegfx::B2DVector& rGridOffset(getGridOffset());
+
+ if(0.0 != rGridOffset.getX() || 0.0 != rGridOffset.getY())
+ {
+ // pre-multiply: GridOffset needs to be applied directly to logic model data
+ // of object coordinates, so multiply GridOffset from right to make it
+ // work as 1st change - these objects may still be part of groups/hierarchies
+ aViewTransformation = aViewTransformation * basegfx::utils::createTranslateB2DHomMatrix(rGridOffset);
+ }
+ }
+
+ m_pImpl->positionAndZoomControl(aViewTransformation);
+ }
+ }
+
+ return ViewObjectContactOfSdrObj::isPrimitiveVisible( _rDisplayInfo );
+ }
+
+
+ void ViewObjectContactOfUnoControl::propertyChange()
+ {
+ impl_onControlChangedOrModified();
+ }
+
+
+ void ViewObjectContactOfUnoControl::ActionChanged()
+ {
+ // call parent
+ ViewObjectContactOfSdrObj::ActionChanged();
+ const ControlHolder& rControl(m_pImpl->getExistentControl());
+
+ if(!rControl.is() || rControl.isDesignMode())
+ return;
+
+ // #i93180# if layer visibility has changed and control is in live mode, it is necessary
+ // to correct visibility to make those control vanish on SdrObject LayerID changes
+ const SdrPageView* pSdrPageView = GetObjectContact().TryToGetSdrPageView();
+
+ if(pSdrPageView)
+ {
+ const SdrObject& rObject = getSdrObject();
+ const bool bIsLayerVisible( rObject.IsVisible() && pSdrPageView->GetVisibleLayers().IsSet(rObject.GetLayer()));
+
+ if(rControl.isVisible() != bIsLayerVisible)
+ {
+ rControl.setVisible(bIsLayerVisible);
+ }
+ }
+ }
+
+
+ void ViewObjectContactOfUnoControl::impl_onControlChangedOrModified()
+ {
+ // graphical invalidate at all views
+ ActionChanged();
+
+ // #i93318# flush Primitive2DContainer to force recreation with updated XControlModel
+ // since e.g. background color has changed and existing decompositions are possibly no
+ // longer valid. Unfortunately this is not detected from ControlPrimitive2D::operator==
+ // since it only has a uno reference to the XControlModel
+ flushPrimitive2DSequence();
+ }
+
+ UnoControlPrintOrPreviewContact::UnoControlPrintOrPreviewContact( ObjectContactOfPageView& _rObjectContact, ViewContactOfUnoControl& _rViewContact )
+ :ViewObjectContactOfUnoControl( _rObjectContact, _rViewContact )
+ {
+ }
+
+
+ UnoControlPrintOrPreviewContact::~UnoControlPrintOrPreviewContact()
+ {
+ }
+
+
+ void UnoControlPrintOrPreviewContact::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor ) const
+ {
+ if ( !m_pImpl->isPrintableControl() )
+ return;
+ ViewObjectContactOfUnoControl::createPrimitive2DSequence( rDisplayInfo, rVisitor );
+ }
+
+
+} // namespace sdr::contact
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactredirector.cxx b/svx/source/sdr/contact/viewobjectcontactredirector.cxx
new file mode 100644
index 000000000..c49909327
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactredirector.cxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/contact/viewobjectcontactredirector.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+
+namespace sdr::contact
+{
+// basic constructor.
+ViewObjectContactRedirector::ViewObjectContactRedirector() {}
+
+// The destructor.
+ViewObjectContactRedirector::~ViewObjectContactRedirector() {}
+
+void ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
+ const sdr::contact::ViewObjectContact& rOriginal, const sdr::contact::DisplayInfo& rDisplayInfo,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor)
+{
+ return rOriginal.createPrimitive2DSequence(rDisplayInfo, rVisitor);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/misc/ImageMapInfo.cxx b/svx/source/sdr/misc/ImageMapInfo.cxx
new file mode 100644
index 000000000..c50fb2fcc
--- /dev/null
+++ b/svx/source/sdr/misc/ImageMapInfo.cxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/ImageMapInfo.hxx>
+
+#include <svx/svdobj.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <vcl/imapobj.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/outdev.hxx>
+
+SvxIMapInfo* SvxIMapInfo::GetIMapInfo(SdrObject const* pObject)
+{
+ assert(pObject);
+
+ SvxIMapInfo* pIMapInfo = nullptr;
+ sal_uInt16 nCount = pObject->GetUserDataCount();
+
+ // Can we find IMap information within the user data?
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ {
+ SdrObjUserData* pUserData = pObject->GetUserData(i);
+
+ if ((pUserData->GetInventor() == SdrInventor::StarDrawUserData)
+ && (pUserData->GetId() == SVX_IMAPINFO_ID))
+ pIMapInfo = static_cast<SvxIMapInfo*>(pUserData);
+ }
+
+ return pIMapInfo;
+}
+
+IMapObject* SvxIMapInfo::GetHitIMapObject(const SdrObject* pObj, const Point& rWinPoint,
+ const OutputDevice* pCmpWnd)
+{
+ SvxIMapInfo* pIMapInfo = GetIMapInfo(pObj);
+ IMapObject* pIMapObj = nullptr;
+
+ if (pIMapInfo)
+ {
+ const MapMode aMap100(MapUnit::Map100thMM);
+ Size aGraphSize;
+ Point aRelPoint(rWinPoint);
+ ImageMap& rImageMap = const_cast<ImageMap&>(pIMapInfo->GetImageMap());
+ tools::Rectangle& rRect = const_cast<tools::Rectangle&>(pObj->GetLogicRect());
+
+ if (pCmpWnd)
+ {
+ MapMode aWndMode = pCmpWnd->GetMapMode();
+ aRelPoint = pCmpWnd->LogicToLogic(rWinPoint, &aWndMode, &aMap100);
+ rRect = pCmpWnd->LogicToLogic(pObj->GetLogicRect(), &aWndMode, &aMap100);
+ }
+
+ bool bObjSupported = false;
+
+ // execute HitTest
+ if (auto pGrafObj = dynamic_cast<const SdrGrafObj*>(pObj)) // simple graphics object
+ {
+ const GeoStat& rGeo = pGrafObj->GetGeoStat();
+ std::unique_ptr<SdrGrafObjGeoData> pGeoData(
+ static_cast<SdrGrafObjGeoData*>(pGrafObj->GetGeoData().release()));
+
+ // Undo rotation
+ if (rGeo.nRotationAngle)
+ RotatePoint(aRelPoint, rRect.TopLeft(), -rGeo.mfSinRotationAngle,
+ rGeo.mfCosRotationAngle);
+
+ // Undo mirroring
+ if (pGeoData->bMirrored)
+ aRelPoint.setX(rRect.Right() + rRect.Left() - aRelPoint.X());
+
+ // Undo shearing
+ if (rGeo.nShearAngle)
+ ShearPoint(aRelPoint, rRect.TopLeft(), -rGeo.mfTanShearAngle);
+
+ if (pGrafObj->GetGrafPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
+ aGraphSize = Application::GetDefaultDevice()->PixelToLogic(
+ pGrafObj->GetGrafPrefSize(), aMap100);
+ else
+ aGraphSize = OutputDevice::LogicToLogic(pGrafObj->GetGrafPrefSize(),
+ pGrafObj->GetGrafPrefMapMode(), aMap100);
+
+ bObjSupported = true;
+ }
+ else if (auto pOleObj = dynamic_cast<const SdrOle2Obj*>(pObj)) // OLE object
+ {
+ aGraphSize = pOleObj->GetOrigObjSize();
+ bObjSupported = true;
+ }
+
+ // Everything worked out well, thus execute HitTest
+ if (bObjSupported)
+ {
+ // Calculate relative position of mouse cursor
+ aRelPoint -= rRect.TopLeft();
+ pIMapObj = rImageMap.GetHitIMapObject(aGraphSize, rRect.GetSize(), aRelPoint);
+
+ // We don't care about deactivated objects
+ if (pIMapObj && !pIMapObj->IsActive())
+ pIMapObj = nullptr;
+ }
+ }
+
+ return pIMapObj;
+}
diff --git a/svx/source/sdr/overlay/overlayanimatedbitmapex.cxx b/svx/source/sdr/overlay/overlayanimatedbitmapex.cxx
new file mode 100644
index 000000000..967e9665b
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayanimatedbitmapex.cxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/overlay/overlayanimatedbitmapex.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayAnimatedBitmapEx::createOverlayObjectPrimitive2DSequence()
+ {
+ if(mbOverlayState)
+ {
+ const drawinglayer::primitive2d::Primitive2DReference aPrimitive(
+ new drawinglayer::primitive2d::OverlayBitmapExPrimitive(
+ maBitmapEx1,
+ getBasePosition(),
+ mnCenterX1,
+ mnCenterY1,
+ getShearX(),
+ getRotation()));
+
+ return drawinglayer::primitive2d::Primitive2DContainer { aPrimitive };
+ }
+ else
+ {
+ const drawinglayer::primitive2d::Primitive2DReference aPrimitive(
+ new drawinglayer::primitive2d::OverlayBitmapExPrimitive(
+ maBitmapEx2,
+ getBasePosition(),
+ mnCenterX2,
+ mnCenterY2,
+ getShearX(),
+ getRotation()));
+
+ return drawinglayer::primitive2d::Primitive2DContainer { aPrimitive };
+ }
+ }
+
+ OverlayAnimatedBitmapEx::OverlayAnimatedBitmapEx(
+ const basegfx::B2DPoint& rBasePos,
+ const BitmapEx& rBitmapEx1,
+ const BitmapEx& rBitmapEx2,
+ sal_uInt64 nBlinkTime,
+ sal_uInt16 nCenX1,
+ sal_uInt16 nCenY1,
+ sal_uInt16 nCenX2,
+ sal_uInt16 nCenY2,
+ double fShearX,
+ double fRotation)
+ : OverlayObjectWithBasePosition(rBasePos, COL_WHITE),
+ maBitmapEx1(rBitmapEx1),
+ maBitmapEx2(rBitmapEx2),
+ mnCenterX1(nCenX1), mnCenterY1(nCenY1),
+ mnCenterX2(nCenX2), mnCenterY2(nCenY2),
+ mnBlinkTime(impCheckBlinkTimeValueRange(nBlinkTime)),
+ mfShearX(fShearX),
+ mfRotation(fRotation),
+ mbOverlayState(false)
+ {
+ // set AllowsAnimation flag to mark this object as animation capable
+ mbAllowsAnimation = true;
+ }
+
+ OverlayAnimatedBitmapEx::~OverlayAnimatedBitmapEx()
+ {
+ }
+
+ void OverlayAnimatedBitmapEx::Trigger(sal_uInt32 nTime)
+ {
+ if(!getOverlayManager())
+ return;
+
+ // #i53216# produce event after nTime + x
+ SetTime(nTime + mnBlinkTime);
+
+ // switch state
+ if(mbOverlayState)
+ {
+ mbOverlayState = false;
+ }
+ else
+ {
+ mbOverlayState = true;
+ }
+
+ // re-insert me as event
+ getOverlayManager()->InsertEvent(*this);
+
+ // register change (after change)
+ objectChange();
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlaybitmapex.cxx b/svx/source/sdr/overlay/overlaybitmapex.cxx
new file mode 100644
index 000000000..54ccf788b
--- /dev/null
+++ b/svx/source/sdr/overlay/overlaybitmapex.cxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <svx/sdr/overlay/overlaybitmapex.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayBitmapEx::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::OverlayBitmapExPrimitive(
+ maBitmapEx,
+ getBasePosition(),
+ mnCenterX,
+ mnCenterY,
+ mfShearX,
+ mfRotation));
+
+ if(basegfx::fTools::more(mfAlpha, 0.0))
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aNewTransPrimitiveVector { aReference };
+ aReference = drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(aNewTransPrimitiveVector), mfAlpha));
+ }
+
+ return drawinglayer::primitive2d::Primitive2DContainer { aReference };
+ }
+
+ OverlayBitmapEx::OverlayBitmapEx(
+ const basegfx::B2DPoint& rBasePos,
+ const BitmapEx& rBitmapEx,
+ sal_uInt16 nCenX,
+ sal_uInt16 nCenY,
+ double fAlpha,
+ double fShearX,
+ double fRotation)
+ : OverlayObjectWithBasePosition(rBasePos, COL_WHITE),
+ maBitmapEx(rBitmapEx),
+ mnCenterX(nCenX),
+ mnCenterY(nCenY),
+ mfAlpha(fAlpha),
+ mfShearX(fShearX),
+ mfRotation(fRotation)
+ {
+ }
+
+ OverlayBitmapEx::~OverlayBitmapEx()
+ {
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlaycrosshair.cxx b/svx/source/sdr/overlay/overlaycrosshair.cxx
new file mode 100644
index 000000000..942534d68
--- /dev/null
+++ b/svx/source/sdr/overlay/overlaycrosshair.cxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlaycrosshair.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayCrosshairStriped::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ if(getOverlayManager())
+ {
+ const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor());
+ const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor());
+ const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel());
+
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::OverlayCrosshairPrimitive(
+ getBasePosition(),
+ aRGBColorA,
+ aRGBColorB,
+ fStripeLengthPixel));
+
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aReference };
+ }
+
+ return aRetval;
+ }
+
+ void OverlayCrosshairStriped::stripeDefinitionHasChanged()
+ {
+ // react on OverlayManager's stripe definition change
+ objectChange();
+ }
+
+ OverlayCrosshairStriped::OverlayCrosshairStriped(const basegfx::B2DPoint& rBasePos)
+ : OverlayObjectWithBasePosition(rBasePos, COL_BLACK)
+ {
+ }
+
+ OverlayCrosshairStriped::~OverlayCrosshairStriped()
+ {
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayhandle.cxx b/svx/source/sdr/overlay/overlayhandle.cxx
new file mode 100644
index 000000000..c94da8e07
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayhandle.cxx
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlayhandle.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+
+namespace sdr::overlay {
+
+using namespace drawinglayer;
+using namespace basegfx;
+
+primitive2d::Primitive2DContainer OverlayHandle::createOverlayObjectPrimitive2DSequence()
+{
+ basegfx::BColor aStrokeColor = maStrokeColor.getBColor();
+ basegfx::BColor aFillColor = getBaseColor().getBColor();
+
+ const primitive2d::Primitive2DReference aReference(
+ new primitive2d::OverlayStaticRectanglePrimitive(maBasePosition, maSize, aStrokeColor, aFillColor, 0.3f, 0.0f));
+
+ return primitive2d::Primitive2DContainer { aReference };
+}
+
+OverlayHandle::OverlayHandle(const B2DPoint& rBasePos,
+ const B2DSize& rSize,
+ Color const & rStrokeColor,
+ Color const & rFillColor)
+ : OverlayObjectWithBasePosition(rBasePos, rFillColor)
+ , maSize(rSize)
+ , maStrokeColor(rStrokeColor)
+{
+}
+
+OverlayHandle::~OverlayHandle()
+{
+}
+
+} // end of namespace sdr::overlay
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayhelpline.cxx b/svx/source/sdr/overlay/overlayhelpline.cxx
new file mode 100644
index 000000000..9955122bb
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayhelpline.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlayhelpline.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayHelplineStriped::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ if(getOverlayManager())
+ {
+ const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor());
+ const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor());
+ const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel());
+ const drawinglayer::primitive2d::HelplineStyle aStyle(
+ SdrHelpLineKind::Point == getKind() ? drawinglayer::primitive2d::HELPLINESTYLE_POINT :
+ SdrHelpLineKind::Vertical == getKind() ? drawinglayer::primitive2d::HELPLINESTYLE_VERTICAL :
+ drawinglayer::primitive2d::HELPLINESTYLE_HORIZONTAL);
+
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::OverlayHelplineStripedPrimitive(
+ getBasePosition(),
+ aStyle,
+ aRGBColorA,
+ aRGBColorB,
+ fStripeLengthPixel));
+
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aReference };
+ }
+
+ return aRetval;
+ }
+
+ void OverlayHelplineStriped::stripeDefinitionHasChanged()
+ {
+ // react on OverlayManager's stripe definition change
+ objectChange();
+ }
+
+ OverlayHelplineStriped::OverlayHelplineStriped(
+ const basegfx::B2DPoint& rBasePos,
+ SdrHelpLineKind eNewKind)
+ : OverlayObjectWithBasePosition(rBasePos, COL_BLACK),
+ meKind(eNewKind)
+ {
+ }
+
+ OverlayHelplineStriped::~OverlayHelplineStriped()
+ {
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayline.cxx b/svx/source/sdr/overlay/overlayline.cxx
new file mode 100644
index 000000000..30c08f026
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayline.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlayline.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/PolygonMarkerPrimitive2D.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayLineStriped::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ if(getOverlayManager())
+ {
+ const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor());
+ const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor());
+ const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel());
+ basegfx::B2DPolygon aLine;
+
+ aLine.append(getBasePosition());
+ aLine.append(getSecondPosition());
+
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::PolygonMarkerPrimitive2D(
+ aLine,
+ aRGBColorA,
+ aRGBColorB,
+ fStripeLengthPixel));
+
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aReference };
+ }
+
+ return aRetval;
+ }
+
+ void OverlayLineStriped::stripeDefinitionHasChanged()
+ {
+ // react on OverlayManager's stripe definition change
+ objectChange();
+ }
+
+ OverlayLineStriped::OverlayLineStriped(
+ const basegfx::B2DPoint& rBasePos,
+ const basegfx::B2DPoint& rSecondPos)
+ : OverlayObjectWithBasePosition(rBasePos, COL_BLACK),
+ maSecondPosition(rSecondPos)
+ {
+ }
+
+ OverlayLineStriped::~OverlayLineStriped()
+ {
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlaymanager.cxx b/svx/source/sdr/overlay/overlaymanager.cxx
new file mode 100644
index 000000000..3cbd821fb
--- /dev/null
+++ b/svx/source/sdr/overlay/overlaymanager.cxx
@@ -0,0 +1,346 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <tools/gen.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/window.hxx>
+#include <svx/sdr/overlay/overlayobject.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <osl/diagnose.h>
+#include <memory>
+
+
+using namespace com::sun::star;
+
+
+namespace sdr::overlay
+{
+ void OverlayManager::ImpDrawMembers(const basegfx::B2DRange& rRange, OutputDevice& rDestinationDevice) const
+ {
+ const sal_uInt32 nSize(maOverlayObjects.size());
+
+ if(!nSize)
+ return;
+
+ const AntialiasingFlags nOriginalAA(rDestinationDevice.GetAntialiasing());
+ const bool bIsAntiAliasing(SvtOptionsDrawinglayer::IsAntiAliasing());
+
+ // create processor
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
+ rDestinationDevice,
+ getCurrentViewInformation2D()));
+
+ for(const auto& rpOverlayObject : maOverlayObjects)
+ {
+ OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
+ const OverlayObject& rCandidate = *rpOverlayObject;
+
+ if(rCandidate.isVisible())
+ {
+ const drawinglayer::primitive2d::Primitive2DContainer& rSequence = rCandidate.getOverlayObjectPrimitive2DSequence();
+
+ if(!rSequence.empty())
+ {
+ if(rRange.overlaps(rCandidate.getBaseRange()))
+ {
+ if(bIsAntiAliasing && rCandidate.allowsAntiAliase())
+ {
+ rDestinationDevice.SetAntialiasing(nOriginalAA | AntialiasingFlags::Enable);
+ }
+ else
+ {
+ rDestinationDevice.SetAntialiasing(nOriginalAA & ~AntialiasingFlags::Enable);
+ }
+
+ pProcessor->process(rSequence);
+ }
+ }
+ }
+ }
+
+ pProcessor.reset();
+
+ // restore AA settings
+ rDestinationDevice.SetAntialiasing(nOriginalAA);
+ }
+
+ void OverlayManager::ImpStripeDefinitionChanged()
+ {
+ const sal_uInt32 nSize(maOverlayObjects.size());
+
+ if(nSize)
+ {
+ for(const auto& rpOverlayObject : maOverlayObjects)
+ {
+ OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
+ OverlayObject& rCandidate = *rpOverlayObject;
+ rCandidate.stripeDefinitionHasChanged();
+ }
+ }
+ }
+
+ double OverlayManager::getDiscreteOne() const
+ {
+ if(basegfx::fTools::equalZero(mfDiscreteOne))
+ {
+ const basegfx::B2DVector aDiscreteInLogic(getOutputDevice().GetInverseViewTransformation() * basegfx::B2DVector(1.0, 0.0));
+ const_cast< OverlayManager* >(this)->mfDiscreteOne = aDiscreteInLogic.getLength();
+ }
+
+ return mfDiscreteOne;
+ }
+
+ OverlayManager::OverlayManager(OutputDevice& rOutputDevice)
+ : mrOutputDevice(rOutputDevice),
+ maStripeColorA(COL_BLACK),
+ maStripeColorB(COL_WHITE),
+ mnStripeLengthPixel(5),
+ mfDiscreteOne(0.0)
+ {
+ // set Property 'ReducedDisplayQuality' to true to allow simpler interaction
+ // visualisations
+ uno::Sequence< beans::PropertyValue > xProperties{
+ comphelper::makePropertyValue("ReducedDisplayQuality", true)
+ };
+ maViewInformation2D = drawinglayer::geometry::createViewInformation2D(xProperties);
+ }
+
+ rtl::Reference<OverlayManager> OverlayManager::create(OutputDevice& rOutputDevice)
+ {
+ return rtl::Reference<OverlayManager>(new OverlayManager(rOutputDevice));
+ }
+
+ drawinglayer::geometry::ViewInformation2D const & OverlayManager::getCurrentViewInformation2D() const
+ {
+ if(getOutputDevice().GetViewTransformation() != maViewTransformation)
+ {
+ basegfx::B2DRange aViewRange(maViewInformation2D.getViewport());
+
+ if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
+ {
+ const Size aOutputSizePixel(getOutputDevice().GetOutputSizePixel());
+
+ // only set when we *have* an output size, else let aViewRange
+ // stay on empty
+ if(aOutputSizePixel.Width() && aOutputSizePixel.Height())
+ {
+ aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
+ aViewRange.transform(getOutputDevice().GetInverseViewTransformation());
+ }
+ }
+
+ OverlayManager* pThis = const_cast< OverlayManager* >(this);
+
+ pThis->maViewTransformation = getOutputDevice().GetViewTransformation();
+ pThis->maViewInformation2D = drawinglayer::geometry::ViewInformation2D(
+ maViewInformation2D.getObjectTransformation(),
+ maViewTransformation,
+ aViewRange,
+ maViewInformation2D.getVisualizedPage(),
+ maViewInformation2D.getViewTime());
+ pThis->mfDiscreteOne = 0.0;
+ }
+
+ return maViewInformation2D;
+ }
+
+ void OverlayManager::impApplyRemoveActions(OverlayObject& rTarget)
+ {
+ // handle evtl. animation
+ if(rTarget.allowsAnimation())
+ {
+ // remove from event chain
+ RemoveEvent(&rTarget);
+ }
+
+ // make invisible
+ invalidateRange(rTarget.getBaseRange());
+
+ // clear manager
+ rTarget.mpOverlayManager = nullptr;
+ }
+
+ void OverlayManager::impApplyAddActions(OverlayObject& rTarget)
+ {
+ // set manager
+ rTarget.mpOverlayManager = this;
+
+ // make visible
+ invalidateRange(rTarget.getBaseRange());
+
+ // handle evtl. animation
+ if(rTarget.allowsAnimation())
+ {
+ // Trigger at current time to get alive. This will do the
+ // object-specific next time calculation and hand over adding
+ // again to the scheduler to the animated object, too. This works for
+ // a paused or non-paused animator.
+ rTarget.Trigger(GetTime());
+ }
+ }
+
+ OverlayManager::~OverlayManager()
+ {
+ // The OverlayManager is not the owner of the OverlayObjects
+ // and thus will not delete them, but remove them. Profit here
+ // from knowing that all will be removed
+ const sal_uInt32 nSize(maOverlayObjects.size());
+
+ if(nSize)
+ {
+ for(const auto& rpOverlayObject : maOverlayObjects)
+ {
+ OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
+ OverlayObject& rCandidate = *rpOverlayObject;
+ impApplyRemoveActions(rCandidate);
+ }
+
+ // erase vector
+ maOverlayObjects.clear();
+ }
+ }
+
+ void OverlayManager::completeRedraw(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice) const
+ {
+ if(rRegion.IsEmpty() || maOverlayObjects.empty())
+ return;
+
+ // check for changed MapModes. That may influence the
+ // logical size of pixel based OverlayObjects (like BitmapHandles)
+ //ImpCheckMapModeChange();
+
+ // paint members
+ const tools::Rectangle aRegionBoundRect(rRegion.GetBoundRect());
+ const basegfx::B2DRange aRegionRange = vcl::unotools::b2DRectangleFromRectangle(aRegionBoundRect);
+
+ OutputDevice& rTarget = pPreRenderDevice ? *pPreRenderDevice : getOutputDevice();
+ ImpDrawMembers(aRegionRange, rTarget);
+ }
+
+ void OverlayManager::flush()
+ {
+ // default has nothing to do
+ }
+
+ void OverlayManager::add(OverlayObject& rOverlayObject)
+ {
+ OSL_ENSURE(nullptr == rOverlayObject.mpOverlayManager, "OverlayObject is added twice to an OverlayManager (!)");
+
+ // add to the end of chain to preserve display order in paint
+ maOverlayObjects.push_back(&rOverlayObject);
+
+ // execute add actions
+ impApplyAddActions(rOverlayObject);
+ }
+
+ void OverlayManager::remove(OverlayObject& rOverlayObject)
+ {
+ OSL_ENSURE(rOverlayObject.mpOverlayManager == this, "OverlayObject is removed from wrong OverlayManager (!)");
+
+ // execute remove actions
+ impApplyRemoveActions(rOverlayObject);
+
+ // remove from vector
+ const OverlayObjectVector::iterator aFindResult = ::std::find(maOverlayObjects.begin(), maOverlayObjects.end(), &rOverlayObject);
+ const bool bFound(aFindResult != maOverlayObjects.end());
+ OSL_ENSURE(bFound, "OverlayObject NOT found at OverlayManager (!)");
+
+ if(bFound)
+ {
+ maOverlayObjects.erase(aFindResult);
+ }
+ }
+
+ tools::Rectangle OverlayManager::RangeToInvalidateRectangle(const basegfx::B2DRange& rRange) const
+ {
+ if (rRange.isEmpty()) {
+ return {};
+ }
+ if (SvtOptionsDrawinglayer::IsAntiAliasing())
+ {
+ // assume AA needs one pixel more and invalidate one pixel more
+ const double fDiscreteOne(getDiscreteOne());
+ const tools::Rectangle aInvalidateRectangle(
+ static_cast<tools::Long>(floor(rRange.getMinX() - fDiscreteOne)),
+ static_cast<tools::Long>(floor(rRange.getMinY() - fDiscreteOne)),
+ static_cast<tools::Long>(ceil(rRange.getMaxX() + fDiscreteOne)),
+ static_cast<tools::Long>(ceil(rRange.getMaxY() + fDiscreteOne)));
+ return aInvalidateRectangle;
+ }
+ else
+ {
+ // #i77674# transform to rectangle. Use floor/ceil to get all covered
+ // discrete pixels, see #i75163# and OverlayManagerBuffered::invalidateRange
+ const tools::Rectangle aInvalidateRectangle(
+ static_cast<sal_Int32>(floor(rRange.getMinX())), static_cast<sal_Int32>(floor(rRange.getMinY())),
+ static_cast<sal_Int32>(ceil(rRange.getMaxX())), static_cast<sal_Int32>(ceil(rRange.getMaxY())));
+ return aInvalidateRectangle;
+ }
+ }
+
+ void OverlayManager::invalidateRange(const basegfx::B2DRange& rRange)
+ {
+ if (OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
+ {
+ tools::Rectangle aInvalidateRectangle(RangeToInvalidateRectangle(rRange));
+ // simply invalidate
+ getOutputDevice().GetOwnerWindow()->Invalidate(aInvalidateRectangle, InvalidateFlags::NoErase);
+ }
+ }
+
+ // stripe support ColA
+ void OverlayManager::setStripeColorA(Color aNew)
+ {
+ if(aNew != maStripeColorA)
+ {
+ maStripeColorA = aNew;
+ ImpStripeDefinitionChanged();
+ }
+ }
+
+ // stripe support ColB
+ void OverlayManager::setStripeColorB(Color aNew)
+ {
+ if(aNew != maStripeColorB)
+ {
+ maStripeColorB = aNew;
+ ImpStripeDefinitionChanged();
+ }
+ }
+
+ // stripe support StripeLengthPixel
+ void OverlayManager::setStripeLengthPixel(sal_uInt32 nNew)
+ {
+ if(nNew != mnStripeLengthPixel)
+ {
+ mnStripeLengthPixel = nNew;
+ ImpStripeDefinitionChanged();
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlaymanagerbuffered.cxx b/svx/source/sdr/overlay/overlaymanagerbuffered.cxx
new file mode 100644
index 000000000..ae37c2ce4
--- /dev/null
+++ b/svx/source/sdr/overlay/overlaymanagerbuffered.cxx
@@ -0,0 +1,441 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlaymanagerbuffered.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <vcl/outdev.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <vcl/window.hxx>
+#include <tools/fract.hxx>
+#include <vcl/cursor.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+
+
+namespace sdr::overlay
+{
+ void OverlayManagerBuffered::ImpPrepareBufferDevice()
+ {
+ // compare size of mpBufferDevice with size of visible area
+ if(mpBufferDevice->GetOutputSizePixel() != getOutputDevice().GetOutputSizePixel())
+ {
+ // set new buffer size, copy as much content as possible (use bool parameter for vcl).
+ // Newly uncovered regions will be repainted.
+ mpBufferDevice->SetOutputSizePixel(getOutputDevice().GetOutputSizePixel(), false);
+ }
+
+ // compare the MapModes for zoom/scroll changes
+ if(mpBufferDevice->GetMapMode() != getOutputDevice().GetMapMode())
+ {
+ const bool bZoomed(
+ mpBufferDevice->GetMapMode().GetScaleX() != getOutputDevice().GetMapMode().GetScaleX()
+ || mpBufferDevice->GetMapMode().GetScaleY() != getOutputDevice().GetMapMode().GetScaleY());
+
+ if(!bZoomed)
+ {
+ const Point& rOriginOld = mpBufferDevice->GetMapMode().GetOrigin();
+ const Point& rOriginNew = getOutputDevice().GetMapMode().GetOrigin();
+ const bool bScrolled(rOriginOld != rOriginNew);
+
+
+ if(bScrolled)
+ {
+ // get pixel bounds (tdf#149322 do subtraction in logic units before converting result back to pixel)
+ const Point aLogicOriginDiff(rOriginNew - rOriginOld);
+ const Size aPixelOriginDiff(mpBufferDevice->LogicToPixel(Size(aLogicOriginDiff.X(), aLogicOriginDiff.Y())));
+ const Point aDestinationOffsetPixel(aPixelOriginDiff.Width(), aPixelOriginDiff.Height());
+ const Size aOutputSizePixel(mpBufferDevice->GetOutputSizePixel());
+
+ // remember and switch off MapMode
+ const bool bMapModeWasEnabled(mpBufferDevice->IsMapModeEnabled());
+ mpBufferDevice->EnableMapMode(false);
+
+ // scroll internally buffered stuff
+ mpBufferDevice->DrawOutDev(
+ aDestinationOffsetPixel, aOutputSizePixel, // destination
+ Point(), aOutputSizePixel); // source
+
+ // restore MapMode
+ mpBufferDevice->EnableMapMode(bMapModeWasEnabled);
+
+ // scroll remembered region, too.
+ if(!maBufferRememberedRangePixel.isEmpty())
+ {
+ const basegfx::B2IPoint aIPointDestinationOffsetPixel(aDestinationOffsetPixel.X(), aDestinationOffsetPixel.Y());
+ const basegfx::B2IPoint aNewMinimum(maBufferRememberedRangePixel.getMinimum() + aIPointDestinationOffsetPixel);
+ const basegfx::B2IPoint aNewMaximum(maBufferRememberedRangePixel.getMaximum() + aIPointDestinationOffsetPixel);
+ maBufferRememberedRangePixel = basegfx::B2IRange(aNewMinimum, aNewMaximum);
+ }
+ }
+ }
+
+ // copy new MapMode
+ mpBufferDevice->SetMapMode(getOutputDevice().GetMapMode());
+ }
+
+ // #i29186#
+ mpBufferDevice->SetDrawMode(getOutputDevice().GetDrawMode());
+ mpBufferDevice->SetSettings(getOutputDevice().GetSettings());
+ mpBufferDevice->SetAntialiasing(getOutputDevice().GetAntialiasing());
+ }
+
+ void OverlayManagerBuffered::ImpRestoreBackground() const
+ {
+ const tools::Rectangle aRegionRectanglePixel(
+ maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(),
+ maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY());
+ const vcl::Region aRegionPixel(aRegionRectanglePixel);
+
+ ImpRestoreBackground(aRegionPixel);
+ }
+
+ void OverlayManagerBuffered::ImpRestoreBackground(const vcl::Region& rRegionPixel) const
+ {
+ // MapModes off
+ const bool bMapModeWasEnabledDest(getOutputDevice().IsMapModeEnabled());
+ const bool bMapModeWasEnabledSource(mpBufferDevice->IsMapModeEnabled());
+ getOutputDevice().EnableMapMode(false);
+ const_cast<OverlayManagerBuffered*>(this)->mpBufferDevice->EnableMapMode(false);
+
+ // local region
+ RectangleVector aRectangles;
+ rRegionPixel.GetRegionRectangles(aRectangles);
+
+ for(const auto& rRect : aRectangles)
+ {
+ // restore the area
+ const Point aTopLeft(rRect.TopLeft());
+ const Size aSize(rRect.GetSize());
+
+ getOutputDevice().DrawOutDev(
+ aTopLeft, aSize, // destination
+ aTopLeft, aSize, // source
+ *mpBufferDevice);
+ }
+
+ // restore MapModes
+ getOutputDevice().EnableMapMode(bMapModeWasEnabledDest);
+ const_cast<OverlayManagerBuffered*>(this)->mpBufferDevice->EnableMapMode(bMapModeWasEnabledSource);
+ }
+
+ void OverlayManagerBuffered::ImpSaveBackground(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice)
+ {
+ // prepare source
+ OutputDevice& rSource = pPreRenderDevice ? *pPreRenderDevice : getOutputDevice();
+
+ // Ensure buffer is valid
+ ImpPrepareBufferDevice();
+
+ // build region which needs to be copied
+ vcl::Region aRegion(rSource.LogicToPixel(rRegion));
+
+ // limit to PaintRegion if it's a window. This will be evtl. the expanded one,
+ // but always the exact redraw area
+ if(OUTDEV_WINDOW == rSource.GetOutDevType())
+ {
+ vcl::Window& rWindow = *rSource.GetOwnerWindow();
+ vcl::Region aPaintRegionPixel = rWindow.LogicToPixel(rWindow.GetPaintRegion());
+ aRegion.Intersect(aPaintRegionPixel);
+
+ // #i72754# Make sure content is completely rendered, the window
+ // will be used as source of a DrawOutDev soon
+ rWindow.GetOutDev()->Flush();
+ }
+
+ // also limit to buffer size
+ const tools::Rectangle aBufferDeviceRectanglePixel(Point(), mpBufferDevice->GetOutputSizePixel());
+ aRegion.Intersect(aBufferDeviceRectanglePixel);
+
+ // MapModes off
+ const bool bMapModeWasEnabledDest(rSource.IsMapModeEnabled());
+ const bool bMapModeWasEnabledSource(mpBufferDevice->IsMapModeEnabled());
+ rSource.EnableMapMode(false);
+ mpBufferDevice->EnableMapMode(false);
+
+ // prepare to iterate over the rectangles from the region in pixels
+ RectangleVector aRectangles;
+ aRegion.GetRegionRectangles(aRectangles);
+
+ for(const auto& rRect : aRectangles)
+ {
+ // for each rectangle, save the area
+ const Point aTopLeft(rRect.TopLeft());
+ const Size aSize(rRect.GetSize());
+
+ mpBufferDevice->DrawOutDev(
+ aTopLeft, aSize, // destination
+ aTopLeft, aSize, // source
+ rSource);
+ }
+
+ // restore MapModes
+ rSource.EnableMapMode(bMapModeWasEnabledDest);
+ mpBufferDevice->EnableMapMode(bMapModeWasEnabledSource);
+ }
+
+ IMPL_LINK_NOARG(OverlayManagerBuffered, ImpBufferTimerHandler, Timer*, void)
+ {
+ //Resolves: fdo#46728 ensure this exists until end of scope
+ rtl::Reference<OverlayManager> xKeepAlive(this);
+
+ // stop timer
+ maBufferIdle.Stop();
+
+ if(maBufferRememberedRangePixel.isEmpty())
+ return;
+
+ // logic size for impDrawMember call
+ basegfx::B2DRange aBufferRememberedRangeLogic(
+ maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(),
+ maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY());
+ aBufferRememberedRangeLogic.transform(getOutputDevice().GetInverseViewTransformation());
+
+ // prepare cursor handling
+ const bool bTargetIsWindow(OUTDEV_WINDOW == mrOutputDevice.GetOutDevType());
+ bool bCursorWasEnabled(false);
+
+ // #i80730# switch off VCL cursor during overlay refresh
+ if(bTargetIsWindow)
+ {
+ vcl::Window& rWindow = *mrOutputDevice.GetOwnerWindow();
+ vcl::Cursor* pCursor = rWindow.GetCursor();
+
+ if(pCursor && pCursor->IsVisible())
+ {
+ pCursor->Hide();
+ bCursorWasEnabled = true;
+ }
+ }
+
+ // refresh with prerendering
+ {
+ // #i73602# ensure valid and sized mpOutputBufferDevice
+ const Size aDestinationSizePixel(mpBufferDevice->GetOutputSizePixel());
+ const Size aOutputBufferSizePixel(mpOutputBufferDevice->GetOutputSizePixel());
+
+ if(aDestinationSizePixel != aOutputBufferSizePixel)
+ {
+ mpOutputBufferDevice->SetOutputSizePixel(aDestinationSizePixel);
+ }
+
+ mpOutputBufferDevice->SetMapMode(getOutputDevice().GetMapMode());
+ mpOutputBufferDevice->EnableMapMode(false);
+ mpOutputBufferDevice->SetDrawMode(mpBufferDevice->GetDrawMode());
+ mpOutputBufferDevice->SetSettings(mpBufferDevice->GetSettings());
+ mpOutputBufferDevice->SetAntialiasing(mpBufferDevice->GetAntialiasing());
+
+ // calculate sizes
+ tools::Rectangle aRegionRectanglePixel(
+ maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(),
+ maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY());
+
+ // truncate aRegionRectanglePixel to destination pixel size, more does
+ // not need to be prepared since destination is a buffer for a window. So,
+ // maximum size indirectly shall be limited to getOutputDevice().GetOutputSizePixel()
+ if(aRegionRectanglePixel.Left() < 0)
+ {
+ aRegionRectanglePixel.SetLeft( 0 );
+ }
+
+ if(aRegionRectanglePixel.Top() < 0)
+ {
+ aRegionRectanglePixel.SetTop( 0 );
+ }
+
+ if(aRegionRectanglePixel.Right() > aDestinationSizePixel.getWidth())
+ {
+ aRegionRectanglePixel.SetRight( aDestinationSizePixel.getWidth() );
+ }
+
+ if(aRegionRectanglePixel.Bottom() > aDestinationSizePixel.getHeight())
+ {
+ aRegionRectanglePixel.SetBottom( aDestinationSizePixel.getHeight() );
+ }
+
+ // get sizes
+ const Point aTopLeft(aRegionRectanglePixel.TopLeft());
+ const Size aSize(aRegionRectanglePixel.GetSize());
+
+ {
+ const bool bMapModeWasEnabledDest(mpBufferDevice->IsMapModeEnabled());
+ mpBufferDevice->EnableMapMode(false);
+
+ mpOutputBufferDevice->DrawOutDev(
+ aTopLeft, aSize, // destination
+ aTopLeft, aSize, // source
+ *mpBufferDevice);
+
+ // restore MapModes
+ mpBufferDevice->EnableMapMode(bMapModeWasEnabledDest);
+ }
+
+ // paint overlay content for remembered region, use
+ // method from base class directly
+ mpOutputBufferDevice->EnableMapMode();
+ OverlayManager::ImpDrawMembers(aBufferRememberedRangeLogic, *mpOutputBufferDevice);
+ mpOutputBufferDevice->EnableMapMode(false);
+
+ // copy to output
+ {
+ const bool bMapModeWasEnabledDest(getOutputDevice().IsMapModeEnabled());
+ getOutputDevice().EnableMapMode(false);
+
+ getOutputDevice().DrawOutDev(
+ aTopLeft, aSize, // destination
+ aTopLeft, aSize, // source
+ *mpOutputBufferDevice);
+
+ // debug
+ /*getOutputDevice().SetLineCOL_RED);
+ getOutputDevice().SetFillColor();
+ getOutputDevice().DrawRect(Rectangle(aTopLeft, aSize));*/
+
+ // restore MapModes
+ getOutputDevice().EnableMapMode(bMapModeWasEnabledDest);
+ }
+ }
+
+ // VCL hack for transparent child windows
+ // Problem is e.g. a radiobutton form control in life mode. The used window
+ // is a transparence vcl childwindow. This flag only allows the parent window to
+ // paint into the child windows area, but there is no mechanism which takes
+ // care for a repaint of the child window. A transparent child window is NOT
+ // a window which always keeps it's content consistent over the parent, but it's
+ // more like just a paint flag for the parent.
+ // To get the update, the windows in question are updated manually here.
+ if(bTargetIsWindow)
+ {
+ vcl::Window& rWindow = *mrOutputDevice.GetOwnerWindow();
+
+ const tools::Rectangle aRegionRectanglePixel(
+ maBufferRememberedRangePixel.getMinX(),
+ maBufferRememberedRangePixel.getMinY(),
+ maBufferRememberedRangePixel.getMaxX(),
+ maBufferRememberedRangePixel.getMaxY());
+ PaintTransparentChildren(rWindow, aRegionRectanglePixel);
+ }
+
+ // #i80730# restore visibility of VCL cursor
+ if(bCursorWasEnabled)
+ {
+ vcl::Window& rWindow = *mrOutputDevice.GetOwnerWindow();
+ vcl::Cursor* pCursor = rWindow.GetCursor();
+
+ if(pCursor)
+ {
+ // check if cursor still exists. It may have been deleted from someone
+ pCursor->Show();
+ }
+ }
+
+ // forget remembered Region
+ maBufferRememberedRangePixel.reset();
+ }
+
+ OverlayManagerBuffered::OverlayManagerBuffered(
+ OutputDevice& rOutputDevice)
+ : OverlayManager(rOutputDevice),
+ mpBufferDevice(VclPtr<VirtualDevice>::Create()),
+ mpOutputBufferDevice(VclPtr<VirtualDevice>::Create()),
+ maBufferIdle( "sdr::overlay::OverlayManagerBuffered maBufferIdle" )
+ {
+ // Init timer
+ maBufferIdle.SetPriority( TaskPriority::POST_PAINT );
+ maBufferIdle.SetInvokeHandler(LINK(this, OverlayManagerBuffered, ImpBufferTimerHandler));
+ }
+
+ rtl::Reference<OverlayManager> OverlayManagerBuffered::create(
+ OutputDevice& rOutputDevice)
+ {
+ return rtl::Reference<OverlayManager>(new OverlayManagerBuffered(rOutputDevice));
+ }
+
+ OverlayManagerBuffered::~OverlayManagerBuffered()
+ {
+ // Clear timer
+ maBufferIdle.Stop();
+
+ if(!maBufferRememberedRangePixel.isEmpty())
+ {
+ // Restore all rectangles for remembered region from buffer
+ ImpRestoreBackground();
+ }
+ }
+
+ void OverlayManagerBuffered::completeRedraw(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice) const
+ {
+ if(!rRegion.IsEmpty())
+ {
+ // save new background
+ const_cast<OverlayManagerBuffered*>(this)->ImpSaveBackground(rRegion, pPreRenderDevice);
+ }
+
+ // call parent
+ OverlayManager::completeRedraw(rRegion, pPreRenderDevice);
+ }
+
+ void OverlayManagerBuffered::flush()
+ {
+ // call timer handler direct
+ ImpBufferTimerHandler(nullptr);
+ }
+
+ void OverlayManagerBuffered::invalidateRange(const basegfx::B2DRange& rRange)
+ {
+ if(rRange.isEmpty())
+ return;
+
+ // buffered output, do not invalidate but use the timer
+ // to trigger a timer event for refresh
+ maBufferIdle.Start();
+
+ // add the discrete range to the remembered region
+ // #i75163# use double precision and floor/ceil rounding to get overlapped pixel region, even
+ // when the given logic region has a width/height of 0.0. This does NOT work with LogicToPixel
+ // since it just transforms the top left and bottom right points equally without taking
+ // discrete pixel coverage into account. An empty B2DRange and thus empty logic Rectangle translated
+ // to an also empty discrete pixel rectangle - what is wrong.
+ basegfx::B2DRange aDiscreteRange(rRange);
+ aDiscreteRange.transform(getOutputDevice().GetViewTransformation());
+
+ if(SvtOptionsDrawinglayer::IsAntiAliasing())
+ {
+ // assume AA needs one pixel more and invalidate one pixel more
+ const double fDiscreteOne(getDiscreteOne());
+ const basegfx::B2IPoint aTopLeft(
+ static_cast<sal_Int32>(floor(aDiscreteRange.getMinX() - fDiscreteOne)),
+ static_cast<sal_Int32>(floor(aDiscreteRange.getMinY() - fDiscreteOne)));
+ const basegfx::B2IPoint aBottomRight(
+ static_cast<sal_Int32>(ceil(aDiscreteRange.getMaxX() + fDiscreteOne)),
+ static_cast<sal_Int32>(ceil(aDiscreteRange.getMaxY() + fDiscreteOne)));
+
+ maBufferRememberedRangePixel.expand(aTopLeft);
+ maBufferRememberedRangePixel.expand(aBottomRight);
+ }
+ else
+ {
+ const basegfx::B2IPoint aTopLeft(static_cast<sal_Int32>(floor(aDiscreteRange.getMinX())), static_cast<sal_Int32>(floor(aDiscreteRange.getMinY())));
+ const basegfx::B2IPoint aBottomRight(static_cast<sal_Int32>(ceil(aDiscreteRange.getMaxX())), static_cast<sal_Int32>(ceil(aDiscreteRange.getMaxY())));
+
+ maBufferRememberedRangePixel.expand(aTopLeft);
+ maBufferRememberedRangePixel.expand(aBottomRight);
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayobject.cxx b/svx/source/sdr/overlay/overlayobject.cxx
new file mode 100644
index 000000000..4fd227977
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayobject.cxx
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/overlay/overlayobject.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <osl/diagnose.h>
+
+namespace sdr::overlay
+{
+ void OverlayObject::objectChange()
+ {
+ const basegfx::B2DRange aPreviousRange(maBaseRange);
+ maBaseRange.reset();
+ resetPrimitive2DSequence();
+// setPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DContainer());
+
+ if(getOverlayManager() && !aPreviousRange.isEmpty())
+ {
+ getOverlayManager()->invalidateRange(aPreviousRange);
+ }
+
+ const basegfx::B2DRange& rCurrentRange = getBaseRange();
+
+ if(getOverlayManager() && rCurrentRange != aPreviousRange && !rCurrentRange.isEmpty())
+ {
+ getOverlayManager()->invalidateRange(rCurrentRange);
+ }
+ }
+
+ // OverlayObject implementations.
+ drawinglayer::primitive2d::Primitive2DContainer OverlayObject::createOverlayObjectPrimitive2DSequence()
+ {
+ // Default implementation has to assert a missing implementation. It cannot
+ // be useful to have overlay object derivations which have no visualisation
+ // at all
+ OSL_FAIL("OverlayObject derivation without visualisation definition (missing createOverlayObjectPrimitive2DSequence implementation) (!)");
+ return drawinglayer::primitive2d::Primitive2DContainer();
+ }
+
+ sal_uInt32 OverlayObject::impCheckBlinkTimeValueRange(sal_uInt64 nBlinkTime)
+ {
+ if(nBlinkTime < 25)
+ {
+ nBlinkTime = 25;
+ }
+ else if(nBlinkTime > 10000)
+ {
+ nBlinkTime = 10000;
+ }
+
+ return nBlinkTime;
+ }
+
+ void OverlayObject::allowAntiAliase(bool bNew)
+ {
+ if(bNew != mbAllowsAntiAliase)
+ {
+ // remember new value
+ mbAllowsAntiAliase = bNew;
+
+ // register change (after change)
+ objectChange();
+ }
+ }
+
+ OverlayObject::OverlayObject(Color aBaseColor)
+ : mpOverlayManager(nullptr),
+ maOffset(0.0, 0.0),
+ maBaseColor(aBaseColor),
+ mbIsVisible(true),
+ mbIsHittable(true),
+ mbAllowsAnimation(false),
+ mbAllowsAntiAliase(true)
+ {
+ }
+
+ OverlayObject::~OverlayObject()
+ {
+ OSL_ENSURE(nullptr == getOverlayManager(), "OverlayObject is destructed which is still registered at OverlayManager (!)");
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer OverlayObject::getOverlayObjectPrimitive2DSequence() const
+ {
+ if(getPrimitive2DSequence().empty())
+ {
+ // no existing sequence; create one
+ const_cast< OverlayObject* >(this)->maPrimitive2DSequence = const_cast< OverlayObject* >(this)->createOverlayObjectPrimitive2DSequence();
+
+ if(!getOffset().equalZero())
+ {
+ // embed to offset transformation
+ const basegfx::B2DHomMatrix aTranslateGridOffset(
+ basegfx::utils::createTranslateB2DHomMatrix(
+ getOffset()));
+ drawinglayer::primitive2d::Primitive2DReference aEmbed(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aTranslateGridOffset,
+ std::move(const_cast<drawinglayer::primitive2d::Primitive2DContainer&>(maPrimitive2DSequence))));
+
+ const_cast< OverlayObject* >(this)->maPrimitive2DSequence = drawinglayer::primitive2d::Primitive2DContainer { aEmbed };
+ }
+ }
+
+ return getPrimitive2DSequence();
+ }
+
+ const basegfx::B2DRange& OverlayObject::getBaseRange() const
+ {
+ if(getOverlayManager() && maBaseRange.isEmpty())
+ {
+ const drawinglayer::primitive2d::Primitive2DContainer& rSequence = getOverlayObjectPrimitive2DSequence();
+
+ if(!rSequence.empty())
+ {
+ const drawinglayer::geometry::ViewInformation2D & aViewInformation2D(getOverlayManager()->getCurrentViewInformation2D());
+
+ const_cast< sdr::overlay::OverlayObject* >(this)->maBaseRange =
+ rSequence.getB2DRange(aViewInformation2D);
+ }
+ }
+
+ return maBaseRange;
+ }
+
+ void OverlayObject::setVisible(bool bNew)
+ {
+ if(bNew != mbIsVisible)
+ {
+ // remember new value
+ mbIsVisible = bNew;
+
+ // register change (after change)
+ objectChange();
+ }
+ }
+
+ void OverlayObject::setHittable(bool bNew)
+ {
+ if(bNew != mbIsHittable)
+ {
+ // remember new value
+ mbIsHittable = bNew;
+
+ // register change (after change)
+ objectChange();
+ }
+ }
+
+ void OverlayObject::setBaseColor(Color aNew)
+ {
+ if(aNew != maBaseColor)
+ {
+ // remember new value
+ maBaseColor = aNew;
+
+ // register change (after change)
+ objectChange();
+ }
+ }
+
+ void OverlayObject::setOffset(const basegfx::B2DVector& rOffset)
+ {
+ if(rOffset != maOffset)
+ {
+ // remember new value
+ maOffset = rOffset;
+
+ // register change (after change)
+ objectChange();
+ }
+ }
+
+ void OverlayObject::Trigger(sal_uInt32 /*nTime*/)
+ {
+ // default does not register again
+ }
+
+ void OverlayObject::stripeDefinitionHasChanged()
+ {
+ // default does not need to do anything
+ }
+
+
+ OverlayObjectWithBasePosition::OverlayObjectWithBasePosition(const basegfx::B2DPoint& rBasePos, Color aBaseColor)
+ : OverlayObject(aBaseColor),
+ maBasePosition(rBasePos)
+ {
+ }
+
+ OverlayObjectWithBasePosition::~OverlayObjectWithBasePosition()
+ {
+ }
+
+ void OverlayObjectWithBasePosition::setBasePosition(const basegfx::B2DPoint& rNew)
+ {
+ if(rNew != maBasePosition)
+ {
+ // remember new value
+ maBasePosition = rNew;
+
+ // register change (after change)
+ objectChange();
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayobjectcell.cxx b/svx/source/sdr/overlay/overlayobjectcell.cxx
new file mode 100644
index 000000000..a7da6a299
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayobjectcell.cxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <basegfx/numeric/ftools.hxx>
+#include <sdr/overlay/overlayobjectcell.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+
+using namespace ::basegfx;
+
+namespace sdr::overlay
+{
+ OverlayObjectCell::OverlayObjectCell( const Color& rColor, RangeVector&& rRects )
+ : OverlayObject( rColor ),
+ maRectangles( std::move(rRects) )
+ {
+ // no AA for selection overlays
+ allowAntiAliase(false);
+ }
+
+ OverlayObjectCell::~OverlayObjectCell()
+ {
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer OverlayObjectCell::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+ const sal_uInt32 nCount(maRectangles.size());
+
+ if(nCount)
+ {
+ const basegfx::BColor aRGBColor(getBaseColor().getBColor());
+ aRetval.resize(nCount);
+
+ // create primitives for all ranges
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const basegfx::B2DRange& rRange(maRectangles[a]);
+ const basegfx::B2DPolygon aPolygon(basegfx::utils::createPolygonFromRect(rRange));
+
+ aRetval[a] = drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aPolygon),
+ aRGBColor));
+ }
+
+
+ // embed in 50% transparent paint
+ drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparence(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ std::move(aRetval),
+ 0.5));
+
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparence };
+ }
+
+ return aRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayobjectlist.cxx b/svx/source/sdr/overlay/overlayobjectlist.cxx
new file mode 100644
index 000000000..d71f6c278
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayobjectlist.cxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/overlay/overlayobjectlist.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <vcl/outdev.hxx>
+#include <tools/gen.hxx>
+
+#include <drawinglayer/processor2d/hittestprocessor2d.hxx>
+#include <comphelper/lok.hxx>
+
+#define DEFAULT_VALUE_FOR_HITTEST_PIXEL (2)
+#define DEFAULT_VALUE_FOR_HITTEST_TWIP (30)
+
+namespace sdr::overlay
+{
+ OverlayObjectList::~OverlayObjectList()
+ {
+ clear();
+ }
+
+ void OverlayObjectList::clear()
+ {
+ for(auto & pCandidate : maVector)
+ {
+ if(pCandidate->getOverlayManager())
+ pCandidate->getOverlayManager()->remove(*pCandidate);
+ }
+ maVector.clear();
+ }
+
+ void OverlayObjectList::append(std::unique_ptr<OverlayObject> pOverlayObject)
+ {
+ assert(pOverlayObject && "tried to add invalid OverlayObject to OverlayObjectList");
+ maVector.push_back(std::move(pOverlayObject));
+ }
+
+ bool OverlayObjectList::isHitLogic(const basegfx::B2DPoint& rLogicPosition, double fLogicTolerance) const
+ {
+ if(!maVector.empty())
+ {
+ OverlayObject* pFirst = maVector.front().get();
+ OverlayManager* pManager = pFirst->getOverlayManager();
+
+ if(pManager)
+ {
+ if(0.0 == fLogicTolerance)
+ {
+ Size aSizeLogic(pManager->getOutputDevice().PixelToLogic(
+ Size(DEFAULT_VALUE_FOR_HITTEST_PIXEL, DEFAULT_VALUE_FOR_HITTEST_PIXEL)));
+
+ // When tiled rendering, we always work in logic units, use the non-pixel default.
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ aSizeLogic = Size(DEFAULT_VALUE_FOR_HITTEST_TWIP, DEFAULT_VALUE_FOR_HITTEST_TWIP);
+ if (pManager->getOutputDevice().GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+ aSizeLogic = o3tl::convert(aSizeLogic, o3tl::Length::twip, o3tl::Length::mm100);
+ }
+
+ fLogicTolerance = aSizeLogic.Width();
+ }
+
+ const drawinglayer::geometry::ViewInformation2D& aViewInformation2D(pManager->getCurrentViewInformation2D());
+ drawinglayer::processor2d::HitTestProcessor2D aHitTestProcessor2D(
+ aViewInformation2D,
+ rLogicPosition,
+ fLogicTolerance,
+ false);
+
+ for(auto & pCandidate : maVector)
+ {
+ if(pCandidate->isHittable())
+ {
+ const drawinglayer::primitive2d::Primitive2DContainer& rSequence = pCandidate->getOverlayObjectPrimitive2DSequence();
+
+ if(!rSequence.empty())
+ {
+ aHitTestProcessor2D.process(rSequence);
+
+ if(aHitTestProcessor2D.getHit())
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ bool OverlayObjectList::isHitPixel(const Point& rDiscretePosition) const
+ {
+ constexpr sal_uInt32 nDiscreteTolerance = DEFAULT_VALUE_FOR_HITTEST_PIXEL;
+ if(!maVector.empty())
+ {
+ OverlayObject* pCandidate = maVector.front().get();
+ OverlayManager* pManager = pCandidate->getOverlayManager();
+
+ if(pManager)
+ {
+ const Point aPosLogic(pManager->getOutputDevice().PixelToLogic(rDiscretePosition));
+ const basegfx::B2DPoint aPosition(aPosLogic.X(), aPosLogic.Y());
+
+ const Size aSizeLogic(pManager->getOutputDevice().PixelToLogic(Size(nDiscreteTolerance, nDiscreteTolerance)));
+ return isHitLogic(aPosition, static_cast<double>(aSizeLogic.Width()));
+ }
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange OverlayObjectList::getBaseRange() const
+ {
+ basegfx::B2DRange aRetval;
+
+ for(auto & pCandidate : maVector)
+ {
+ aRetval.expand(pCandidate->getBaseRange());
+ }
+
+ return aRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlaypolypolygon.cxx b/svx/source/sdr/overlay/overlaypolypolygon.cxx
new file mode 100644
index 000000000..69dacf375
--- /dev/null
+++ b/svx/source/sdr/overlay/overlaypolypolygon.cxx
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/overlay/overlaypolypolygon.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonMarkerPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonSelectionPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+
+
+namespace sdr::overlay
+{
+ OverlayPolyPolygon::OverlayPolyPolygon(
+ const basegfx::B2DPolyPolygon& rLinePolyPolygon,
+ Color const & rLineColor,
+ double fLineWidth,
+ Color const & rFillColor)
+ : OverlayObject(rLineColor)
+ , maLinePolyPolygon(rLinePolyPolygon)
+ , mfLineWidth(fLineWidth)
+ , maFillColor(rFillColor)
+ {
+ }
+
+ OverlayPolyPolygon::~OverlayPolyPolygon() = default;
+
+ drawinglayer::primitive2d::Primitive2DContainer OverlayPolyPolygon::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aReturnContainer;
+
+ if (getOverlayManager())
+ {
+ const drawinglayer::attribute::LineAttribute aLineAttribute(getBaseColor().getBColor(), mfLineWidth);
+
+ aReturnContainer = drawinglayer::primitive2d::Primitive2DContainer {
+ new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(maLinePolyPolygon, aLineAttribute) };
+
+ if (maFillColor.GetAlpha() != 0)
+ {
+ aReturnContainer.push_back(new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(maLinePolyPolygon, maFillColor.getBColor()));
+ }
+
+ sal_uInt8 nTransparency = 255 - getBaseColor().GetAlpha();
+ if (nTransparency > 0)
+ {
+ drawinglayer::primitive2d::Primitive2DReference aTransparencePrimitive(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(aReturnContainer), nTransparency / 255.0));
+ aReturnContainer = drawinglayer::primitive2d::Primitive2DContainer{ aTransparencePrimitive };
+ }
+ }
+
+ return aReturnContainer;
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer OverlayPolyPolygonStripedAndFilled::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ if(getOverlayManager())
+ {
+ const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor());
+ const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor());
+ const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel());
+ const drawinglayer::primitive2d::Primitive2DReference aStriped(
+ new drawinglayer::primitive2d::PolyPolygonMarkerPrimitive2D(
+ getLinePolyPolygon(),
+ aRGBColorA,
+ aRGBColorB,
+ fStripeLengthPixel));
+
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aStriped };
+
+ const basegfx::BColor aHilightColor(SvtOptionsDrawinglayer::getHilightColor().getBColor());
+ const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
+
+ const drawinglayer::primitive2d::Primitive2DReference aFilled(
+ new drawinglayer::primitive2d::PolyPolygonSelectionPrimitive2D(
+ getLinePolyPolygon(),
+ aHilightColor,
+ fTransparence,
+ 3.0,
+ false));
+
+ aRetval.push_back(aFilled);
+ }
+
+ return aRetval;
+ }
+
+ void OverlayPolyPolygonStripedAndFilled::stripeDefinitionHasChanged()
+ {
+ // react on OverlayManager's stripe definition change
+ objectChange();
+ }
+
+ OverlayPolyPolygonStripedAndFilled::OverlayPolyPolygonStripedAndFilled(
+ const basegfx::B2DPolyPolygon& rLinePolyPolygon)
+ : OverlayObject(COL_BLACK),
+ maLinePolyPolygon(rLinePolyPolygon)
+ {
+ }
+
+ OverlayPolyPolygonStripedAndFilled::~OverlayPolyPolygonStripedAndFilled()
+ {
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayprimitive2dsequenceobject.cxx b/svx/source/sdr/overlay/overlayprimitive2dsequenceobject.cxx
new file mode 100644
index 000000000..eabd290f8
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayprimitive2dsequenceobject.cxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayPrimitive2DSequenceObject::createOverlayObjectPrimitive2DSequence()
+ {
+ return maSequence;
+ }
+
+ OverlayPrimitive2DSequenceObject::OverlayPrimitive2DSequenceObject(drawinglayer::primitive2d::Primitive2DContainer&& rSequence)
+ : OverlayObjectWithBasePosition(basegfx::B2DPoint(), COL_BLACK),
+ maSequence(std::move(rSequence))
+ {
+ }
+
+ OverlayPrimitive2DSequenceObject::~OverlayPrimitive2DSequenceObject()
+ {
+ }
+} // end of namespace sdr::overlay
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayrectangle.cxx b/svx/source/sdr/overlay/overlayrectangle.cxx
new file mode 100644
index 000000000..617c6d4dc
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayrectangle.cxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlayrectangle.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayRectangle::createOverlayObjectPrimitive2DSequence()
+ {
+ const basegfx::B2DRange aHatchRange(getBasePosition(), maSecondPosition);
+ basegfx::BColor aColor(getBaseColor().getBColor());
+ static const double fChange(0.1); // just small optical change, do not make it annoying
+
+ if(mbOverlayState)
+ {
+ aColor += basegfx::B3DTuple(fChange, fChange, fChange);
+ aColor.clamp();
+ }
+ else
+ {
+ aColor -= basegfx::B3DTuple(fChange, fChange, fChange);
+ aColor.clamp();
+ }
+
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::OverlayRectanglePrimitive(
+ aHatchRange,
+ aColor,
+ mfTransparence,
+ mfDiscreteGrow,
+ mfDiscreteShrink,
+ mfRotation));
+
+ return drawinglayer::primitive2d::Primitive2DContainer { aReference };
+ }
+
+ OverlayRectangle::OverlayRectangle(
+ const basegfx::B2DPoint& rBasePosition,
+ const basegfx::B2DPoint& rSecondPosition,
+ const Color& rHatchColor,
+ double fTransparence,
+ double fDiscreteGrow,
+ double fDiscreteShrink,
+ double fRotation,
+ bool bAnimate)
+ : OverlayObjectWithBasePosition(rBasePosition, rHatchColor),
+ maSecondPosition(rSecondPosition),
+ mfTransparence(fTransparence),
+ mfDiscreteGrow(fDiscreteGrow),
+ mfDiscreteShrink(fDiscreteShrink),
+ mfRotation(fRotation),
+ mnBlinkTime(impCheckBlinkTimeValueRange(500)),
+ mbOverlayState(false)
+ {
+ if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ // no animation in high contrast mode
+ bAnimate = false;
+ }
+
+ // set AllowsAnimation flag to mark this object as animation capable
+ mbAllowsAnimation = bAnimate;
+ }
+
+ void OverlayRectangle::Trigger(sal_uInt32 nTime)
+ {
+ if(!getOverlayManager())
+ return;
+
+ // #i53216# produce event after nTime + x
+ SetTime(nTime + mnBlinkTime);
+
+ // switch state
+ if(mbOverlayState)
+ {
+ mbOverlayState = false;
+ }
+ else
+ {
+ mbOverlayState = true;
+ }
+
+ // re-insert me as event
+ getOverlayManager()->InsertEvent(*this);
+
+ // register change (after change)
+ objectChange();
+ }
+} // end of namespace
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayrollingrectangle.cxx b/svx/source/sdr/overlay/overlayrollingrectangle.cxx
new file mode 100644
index 000000000..f03380edd
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayrollingrectangle.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlayrollingrectangle.hxx>
+#include <sdr/overlay/overlaytools.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonMarkerPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonSelectionPrimitive2D.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayRollingRectangleStriped::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+ if(getOverlayManager() && (mbShowBounds || mbExtendedLines))
+ {
+ const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor());
+ const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor());
+ const double fStripeLengthPixel(getOverlayManager()->getStripeLengthPixel());
+ const basegfx::B2DRange aRollingRectangle(getBasePosition(), getSecondPosition());
+
+ if(mbShowBounds)
+ {
+ // view-independent part, create directly
+ const basegfx::B2DPolygon aPolygon(basegfx::utils::createPolygonFromRect(aRollingRectangle));
+
+ aRetval.resize(2);
+ aRetval[0] = new drawinglayer::primitive2d::PolyPolygonMarkerPrimitive2D(
+ basegfx::B2DPolyPolygon(aPolygon),
+ aRGBColorA,
+ aRGBColorB,
+ fStripeLengthPixel);
+
+ const basegfx::BColor aHilightColor(SvtOptionsDrawinglayer::getHilightColor().getBColor());
+ const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
+
+ aRetval[1] = new drawinglayer::primitive2d::PolyPolygonSelectionPrimitive2D(
+ basegfx::B2DPolyPolygon(aPolygon),
+ aHilightColor,
+ fTransparence,
+ 3.0,
+ false);
+ }
+
+ if(mbExtendedLines)
+ {
+ // view-dependent part, use helper primitive
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::OverlayRollingRectanglePrimitive(
+ aRollingRectangle,
+ aRGBColorA,
+ aRGBColorB,
+ fStripeLengthPixel));
+
+ aRetval.push_back(aReference);
+ }
+ }
+
+ return aRetval;
+ }
+
+ void OverlayRollingRectangleStriped::stripeDefinitionHasChanged()
+ {
+ // react on OverlayManager's stripe definition change
+ objectChange();
+ }
+
+ OverlayRollingRectangleStriped::OverlayRollingRectangleStriped(
+ const basegfx::B2DPoint& rBasePos,
+ const basegfx::B2DPoint& rSecondPos,
+ bool bExtendedLines,
+ bool bShowBounds)
+ : OverlayObjectWithBasePosition(rBasePos, COL_BLACK),
+ maSecondPosition(rSecondPos),
+ mbExtendedLines(bExtendedLines),
+ mbShowBounds(bShowBounds)
+ {
+ }
+
+ OverlayRollingRectangleStriped::~OverlayRollingRectangleStriped()
+ {
+ }
+
+ void OverlayRollingRectangleStriped::setSecondPosition(const basegfx::B2DPoint& rNew)
+ {
+ if(rNew != maSecondPosition)
+ {
+ // remember new value
+ maSecondPosition = rNew;
+
+ // register change (after change)
+ objectChange();
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlayselection.cxx b/svx/source/sdr/overlay/overlayselection.cxx
new file mode 100644
index 000000000..0463567c5
--- /dev/null
+++ b/svx/source/sdr/overlay/overlayselection.cxx
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/overlay/overlayselection.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonHairlinePrimitive2D.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/settings.hxx>
+#include <drawinglayer/primitive2d/invertprimitive2d.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+
+
+namespace sdr::overlay
+{
+ // combine rages geometrically to a single, ORed polygon
+ static basegfx::B2DPolyPolygon impCombineRangesToPolyPolygon(const std::vector< basegfx::B2DRange >& rRanges)
+ {
+ const sal_uInt32 nCount(rRanges.size());
+ basegfx::B2DPolyPolygon aRetval;
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const basegfx::B2DPolygon aDiscretePolygon(basegfx::utils::createPolygonFromRect(rRanges[a]));
+
+ if(0 == a)
+ {
+ aRetval.append(aDiscretePolygon);
+ }
+ else
+ {
+ aRetval = basegfx::utils::solvePolygonOperationOr(aRetval, basegfx::B2DPolyPolygon(aDiscretePolygon));
+ }
+ }
+
+ return aRetval;
+ }
+
+ // check if wanted type OverlayType::Transparent or OverlayType::Solid
+ // is possible. If not, fallback to invert mode (classic mode)
+ static OverlayType impCheckPossibleOverlayType(OverlayType aOverlayType)
+ {
+ if(OverlayType::Invert != aOverlayType)
+ {
+ if(!SvtOptionsDrawinglayer::IsTransparentSelection())
+ {
+ // not possible when switched off by user
+ return OverlayType::Invert;
+ }
+ else if (const OutputDevice* pOut = Application::GetDefaultDevice())
+ {
+
+ if(pOut->GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ // not possible when in high contrast mode
+ return OverlayType::Invert;
+ }
+
+ if(!pOut->SupportsOperation(OutDevSupportType::TransparentRect))
+ {
+ // not possible when no fast transparence paint is supported on the system
+ return OverlayType::Invert;
+ }
+ }
+ }
+
+ return aOverlayType;
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer OverlaySelection::createOverlayObjectPrimitive2DSequence()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aRetval;
+ const sal_uInt32 nCount(getRanges().size());
+
+ if(nCount)
+ {
+ // create range primitives
+ const bool bInvert(OverlayType::Invert == maLastOverlayType);
+ basegfx::BColor aRGBColor(getBaseColor().getBColor());
+ aRetval.resize(nCount);
+
+ if(bInvert)
+ {
+ // force color to white for invert to get a full invert
+ aRGBColor = basegfx::BColor(1.0, 1.0, 1.0);
+ }
+
+ for(sal_uInt32 a(0);a < nCount; a++)
+ {
+ const basegfx::B2DPolygon aPolygon(basegfx::utils::createPolygonFromRect(maRanges[a]));
+ aRetval[a] = drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aPolygon),
+ aRGBColor));
+ }
+
+ if(bInvert)
+ {
+ // embed all in invert primitive
+ drawinglayer::primitive2d::Primitive2DReference aInvert(
+ new drawinglayer::primitive2d::InvertPrimitive2D(
+ std::move(aRetval)));
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aInvert };
+ }
+ else if(OverlayType::Transparent == maLastOverlayType)
+ {
+ // embed all rectangles in transparent paint
+ const double fTransparence(mnLastTransparence / 100.0);
+ const drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparence(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ std::move(aRetval),
+ fTransparence));
+
+ if(mbBorder)
+ {
+ const basegfx::B2DPolyPolygon aPolyPolygon(impCombineRangesToPolyPolygon(getRanges()));
+ const drawinglayer::primitive2d::Primitive2DReference aSelectionOutline(
+ new drawinglayer::primitive2d::PolyPolygonHairlinePrimitive2D(
+ aPolyPolygon,
+ aRGBColor));
+
+ // add both to result
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparence, aSelectionOutline };
+ }
+ else
+ {
+ // just add transparent part
+ aRetval = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparence };
+ }
+ }
+ }
+
+ return aRetval;
+ }
+
+ OverlaySelection::OverlaySelection(
+ OverlayType eType,
+ const Color& rColor,
+ std::vector< basegfx::B2DRange >&& rRanges,
+ bool bBorder)
+ : OverlayObject(rColor),
+ meOverlayType(eType),
+ maRanges(std::move(rRanges)),
+ maLastOverlayType(eType),
+ mnLastTransparence(0),
+ mbBorder(bBorder)
+ {
+ // no AA for selection overlays
+ allowAntiAliase(false);
+ }
+
+ OverlaySelection::~OverlaySelection()
+ {
+ if(getOverlayManager())
+ {
+ getOverlayManager()->remove(*this);
+ }
+ }
+
+ drawinglayer::primitive2d::Primitive2DContainer OverlaySelection::getOverlayObjectPrimitive2DSequence() const
+ {
+ // get current values
+ const OverlayType aNewOverlayType(impCheckPossibleOverlayType(meOverlayType));
+ const sal_uInt16 nNewTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent());
+
+ if(!getPrimitive2DSequence().empty())
+ {
+ if(aNewOverlayType != maLastOverlayType
+ || nNewTransparence != mnLastTransparence)
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< OverlaySelection* >(this)->resetPrimitive2DSequence();
+ }
+ }
+
+ if(getPrimitive2DSequence().empty())
+ {
+ // remember new values
+ const_cast< OverlaySelection* >(this)->maLastOverlayType = aNewOverlayType;
+ const_cast< OverlaySelection* >(this)->mnLastTransparence = nNewTransparence;
+ }
+
+ // call base implementation
+ return OverlayObject::getOverlayObjectPrimitive2DSequence();
+ }
+
+ void OverlaySelection::setRanges(std::vector< basegfx::B2DRange >&& rNew)
+ {
+ if(rNew != maRanges)
+ {
+ maRanges = std::move(rNew);
+ objectChange();
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlaytools.cxx b/svx/source/sdr/overlay/overlaytools.cxx
new file mode 100644
index 000000000..ceeb32b3f
--- /dev/null
+++ b/svx/source/sdr/overlay/overlaytools.cxx
@@ -0,0 +1,601 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sdr/overlay/overlaytools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/PolygonMarkerPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonHatchPrimitive2D.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+
+namespace drawinglayer::primitive2d
+{
+
+OverlayStaticRectanglePrimitive::OverlayStaticRectanglePrimitive(
+ const basegfx::B2DPoint& rPosition,
+ const basegfx::B2DSize& rSize,
+ const basegfx::BColor& rStrokeColor,
+ const basegfx::BColor& rFillColor,
+ double fTransparence,
+ double fRotation)
+ : maPosition(rPosition)
+ , maSize(rSize)
+ , maStrokeColor(rStrokeColor)
+ , maFillColor(rFillColor)
+ , mfTransparence(fTransparence)
+ , mfRotation(fRotation)
+{}
+
+void OverlayStaticRectanglePrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
+{
+ Primitive2DContainer aPrimitive2DSequence;
+ const double fHalfWidth = maSize.getX() * getDiscreteUnit() / 2.0;
+ const double fHalfHeight = maSize.getY() * getDiscreteUnit() / 2.0;
+
+ basegfx::B2DRange aRange(
+ maPosition.getX() - fHalfWidth, maPosition.getY() - fHalfHeight,
+ maPosition.getX() + fHalfWidth, maPosition.getY() + fHalfHeight);
+
+ if (basegfx::fTools::more(getDiscreteUnit(), 0.0) && mfTransparence <= 1.0)
+ {
+ basegfx::B2DPolygon aPolygon(
+ basegfx::utils::createPolygonFromRect(aRange));
+
+ // create filled primitive
+ basegfx::B2DPolyPolygon aPolyPolygon;
+ aPolyPolygon.append(aPolygon);
+
+ const attribute::LineAttribute aLineAttribute(maStrokeColor, 1.0);
+
+ // create data
+ const Primitive2DReference aStroke(
+ new PolyPolygonStrokePrimitive2D(aPolyPolygon, aLineAttribute));
+
+ // create fill primitive
+ const Primitive2DReference aFill(
+ new PolyPolygonColorPrimitive2D(aPolyPolygon, maFillColor));
+
+ aPrimitive2DSequence = Primitive2DContainer(2);
+ aPrimitive2DSequence[0] = aFill;
+ aPrimitive2DSequence[1] = aStroke;
+
+ // embed filled to transparency (if used)
+ if (mfTransparence > 0.0)
+ {
+ const Primitive2DReference aFillTransparent(
+ new UnifiedTransparencePrimitive2D(
+ std::move(aPrimitive2DSequence),
+ mfTransparence));
+
+ aPrimitive2DSequence = Primitive2DContainer { aFillTransparent };
+ }
+ }
+
+ rContainer.append(std::move(aPrimitive2DSequence));
+}
+
+bool OverlayStaticRectanglePrimitive::operator==(const BasePrimitive2D& rPrimitive) const
+{
+ if (DiscreteMetricDependentPrimitive2D::operator==(rPrimitive))
+ {
+ const OverlayStaticRectanglePrimitive& rCompare = static_cast<const OverlayStaticRectanglePrimitive&>(rPrimitive);
+
+ return (maPosition == rCompare.maPosition
+ && maSize == rCompare.maSize
+ && maStrokeColor == rCompare.maStrokeColor
+ && maFillColor == rCompare.maFillColor
+ && mfTransparence == rCompare.mfTransparence
+ && mfRotation == rCompare.mfRotation);
+ }
+
+ return false;
+}
+
+sal_uInt32 OverlayStaticRectanglePrimitive::getPrimitive2DID() const
+{
+ return PRIMITIVE2D_ID_OVERLAYRECTANGLEPRIMITIVE;
+}
+
+
+
+ OverlayBitmapExPrimitive::OverlayBitmapExPrimitive(
+ const BitmapEx& rBitmapEx,
+ const basegfx::B2DPoint& rBasePosition,
+ sal_uInt16 nCenterX,
+ sal_uInt16 nCenterY,
+ double fShearX,
+ double fRotation)
+ : maBitmapEx(rBitmapEx),
+ maBasePosition(rBasePosition),
+ mnCenterX(nCenterX),
+ mnCenterY(nCenterY),
+ mfShearX(fShearX),
+ mfRotation(fRotation)
+ {}
+
+ void OverlayBitmapExPrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ const Size aBitmapSize(getBitmapEx().GetSizePixel());
+
+ if(!aBitmapSize.Width() || !aBitmapSize.Height() || !basegfx::fTools::more(getDiscreteUnit(), 0.0))
+ return;
+
+ // calculate back from internal bitmap's extreme coordinates (the edges)
+ // to logical coordinates. Only use a unified scaling value (getDiscreteUnit(),
+ // the prepared one which expresses how many logic units form a discrete unit)
+ // for this step. This primitive is to be displayed always unscaled (in its pixel size)
+ // and unrotated, more like a marker
+ const double fLeft((0.0 - getCenterX()) * getDiscreteUnit());
+ const double fTop((0.0 - getCenterY()) * getDiscreteUnit());
+ const double fRight((aBitmapSize.getWidth() - getCenterX()) * getDiscreteUnit());
+ const double fBottom((aBitmapSize.getHeight() - getCenterY()) * getDiscreteUnit());
+
+ // create a BitmapPrimitive2D using those positions
+ basegfx::B2DHomMatrix aTransform;
+
+ aTransform.set(0, 0, fRight - fLeft);
+ aTransform.set(1, 1, fBottom - fTop);
+ aTransform.set(0, 2, fLeft);
+ aTransform.set(1, 2, fTop);
+
+ // if shearX is used, apply it, too
+ if(!basegfx::fTools::equalZero(getShearX()))
+ {
+ aTransform.shearX(getShearX());
+ }
+
+ // if rotation is used, apply it, too
+ if(!basegfx::fTools::equalZero(getRotation()))
+ {
+ aTransform.rotate(getRotation());
+ }
+
+ // add BasePosition
+ aTransform.translate(getBasePosition().getX(), getBasePosition().getY());
+
+ rContainer.push_back(
+ new BitmapPrimitive2D(
+ VCLUnoHelper::CreateVCLXBitmap(getBitmapEx()),
+ aTransform));
+ }
+
+ bool OverlayBitmapExPrimitive::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive))
+ {
+ const OverlayBitmapExPrimitive& rCompare = static_cast< const OverlayBitmapExPrimitive& >(rPrimitive);
+
+ return (getBitmapEx() == rCompare.getBitmapEx()
+ && getBasePosition() == rCompare.getBasePosition()
+ && getCenterX() == rCompare.getCenterX()
+ && getCenterY() == rCompare.getCenterY()
+ && getShearX() == rCompare.getShearX()
+ && getRotation() == rCompare.getRotation());
+ }
+
+ return false;
+ }
+
+ sal_uInt32 OverlayBitmapExPrimitive::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_OVERLAYBITMAPEXPRIMITIVE;
+ }
+
+
+
+ OverlayCrosshairPrimitive::OverlayCrosshairPrimitive(
+ const basegfx::B2DPoint& rBasePosition,
+ const basegfx::BColor& rRGBColorA,
+ const basegfx::BColor& rRGBColorB,
+ double fDiscreteDashLength)
+ : maBasePosition(rBasePosition),
+ maRGBColorA(rRGBColorA),
+ maRGBColorB(rRGBColorB),
+ mfDiscreteDashLength(fDiscreteDashLength)
+ {}
+
+ void OverlayCrosshairPrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // use the prepared Viewport information accessible using getViewport()
+
+ if(getViewport().isEmpty())
+ return;
+
+ basegfx::B2DPolygon aPolygon;
+
+ aPolygon.append(basegfx::B2DPoint(getViewport().getMinX(), getBasePosition().getY()));
+ aPolygon.append(basegfx::B2DPoint(getViewport().getMaxX(), getBasePosition().getY()));
+
+ rContainer.push_back(
+ new PolygonMarkerPrimitive2D(
+ aPolygon,
+ getRGBColorA(),
+ getRGBColorB(),
+ getDiscreteDashLength()));
+
+ aPolygon.clear();
+ aPolygon.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMinY()));
+ aPolygon.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMaxY()));
+
+ rContainer.push_back(
+ new PolygonMarkerPrimitive2D(
+ aPolygon,
+ getRGBColorA(),
+ getRGBColorB(),
+ getDiscreteDashLength()));
+ }
+
+ bool OverlayCrosshairPrimitive::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(ViewportDependentPrimitive2D::operator==(rPrimitive))
+ {
+ const OverlayCrosshairPrimitive& rCompare = static_cast< const OverlayCrosshairPrimitive& >(rPrimitive);
+
+ return (getBasePosition() == rCompare.getBasePosition()
+ && getRGBColorA() == rCompare.getRGBColorA()
+ && getRGBColorB() == rCompare.getRGBColorB()
+ && getDiscreteDashLength() == rCompare.getDiscreteDashLength());
+ }
+
+ return false;
+ }
+
+ sal_uInt32 OverlayCrosshairPrimitive::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_OVERLAYCROSSHAIRPRIMITIVE;
+ }
+
+
+
+ OverlayRectanglePrimitive::OverlayRectanglePrimitive(
+ const basegfx::B2DRange& rObjectRange,
+ const basegfx::BColor& rColor,
+ double fTransparence,
+ double fDiscreteGrow,
+ double fDiscreteShrink,
+ double fRotation)
+ : maObjectRange(rObjectRange),
+ maColor(rColor),
+ mfTransparence(fTransparence),
+ mfDiscreteGrow(fDiscreteGrow),
+ mfDiscreteShrink(fDiscreteShrink),
+ mfRotation(fRotation)
+ {}
+
+ void OverlayRectanglePrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ Primitive2DContainer aRetval;
+ basegfx::B2DRange aInnerRange(getObjectRange());
+
+ if(!aInnerRange.isEmpty() && basegfx::fTools::more(getDiscreteUnit(), 0.0) && getTransparence() <= 1.0)
+ {
+ basegfx::B2DRange aOuterRange(getObjectRange());
+
+ // grow/shrink inner/outer polygons
+ aOuterRange.grow(getDiscreteUnit() * getDiscreteGrow());
+ aInnerRange.grow(getDiscreteUnit() * -getDiscreteShrink());
+
+ // convert to polygons
+ const double fFullGrow(getDiscreteGrow() + getDiscreteShrink());
+ const double fRelativeRadiusX(fFullGrow / aOuterRange.getWidth());
+ const double fRelativeRadiusY(fFullGrow / aOuterRange.getHeight());
+ basegfx::B2DPolygon aOuterPolygon(
+ basegfx::utils::createPolygonFromRect(
+ aOuterRange,
+ fRelativeRadiusX,
+ fRelativeRadiusY));
+ basegfx::B2DPolygon aInnerPolygon(
+ basegfx::utils::createPolygonFromRect(
+ aInnerRange));
+
+ // apply evtl. existing rotation
+ if(!basegfx::fTools::equalZero(getRotation()))
+ {
+ const basegfx::B2DHomMatrix aTransform(basegfx::utils::createRotateAroundPoint(
+ getObjectRange().getMinX(), getObjectRange().getMinY(), getRotation()));
+
+ aOuterPolygon.transform(aTransform);
+ aInnerPolygon.transform(aTransform);
+ }
+
+ // create filled primitive
+ basegfx::B2DPolyPolygon aPolyPolygon;
+
+ aPolyPolygon.append(aOuterPolygon);
+ aPolyPolygon.append(aInnerPolygon);
+
+ if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
+ {
+ // for high contrast, use hatch
+ const basegfx::BColor aHighContrastLineColor(Application::GetSettings().GetStyleSettings().GetFontColor().getBColor());
+ const basegfx::BColor aEmptyColor(0.0, 0.0, 0.0);
+ const double fHatchRotation(basegfx::deg2rad(45));
+ const double fDiscreteHatchDistance(3.0);
+ const drawinglayer::attribute::FillHatchAttribute aFillHatchAttribute(
+ drawinglayer::attribute::HatchStyle::Single,
+ fDiscreteHatchDistance * getDiscreteUnit(),
+ fHatchRotation - getRotation(),
+ aHighContrastLineColor,
+ 3, // same default as VCL, a minimum of three discrete units (pixels) offset
+ false);
+ const Primitive2DReference aHatch(
+ new PolyPolygonHatchPrimitive2D(
+ aPolyPolygon,
+ aEmptyColor,
+ aFillHatchAttribute));
+
+ aRetval = Primitive2DContainer { aHatch };
+ }
+ else
+ {
+ // create fill primitive
+ const Primitive2DReference aFill(
+ new PolyPolygonColorPrimitive2D(
+ aPolyPolygon,
+ getColor()));
+
+ aRetval = Primitive2DContainer { aFill };
+
+ // embed filled to transparency (if used)
+ if(getTransparence() > 0.0)
+ {
+ Primitive2DReference aFillTransparent(
+ new UnifiedTransparencePrimitive2D(
+ std::move(aRetval),
+ getTransparence()));
+
+ aRetval = Primitive2DContainer { aFillTransparent };
+ }
+ }
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ bool OverlayRectanglePrimitive::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive))
+ {
+ const OverlayRectanglePrimitive& rCompare = static_cast< const OverlayRectanglePrimitive& >(rPrimitive);
+
+ return (getObjectRange() == rCompare.getObjectRange()
+ && getColor() == rCompare.getColor()
+ && getTransparence() == rCompare.getTransparence()
+ && getDiscreteGrow() == rCompare.getDiscreteGrow()
+ && getDiscreteShrink() == rCompare.getDiscreteShrink()
+ && getRotation() == rCompare.getRotation());
+ }
+
+ return false;
+ }
+
+ sal_uInt32 OverlayRectanglePrimitive::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_OVERLAYRECTANGLEPRIMITIVE;
+ }
+
+
+
+ OverlayHelplineStripedPrimitive::OverlayHelplineStripedPrimitive(
+ const basegfx::B2DPoint& rBasePosition,
+ HelplineStyle eStyle,
+ const basegfx::BColor& rRGBColorA,
+ const basegfx::BColor& rRGBColorB,
+ double fDiscreteDashLength)
+ : maBasePosition(rBasePosition),
+ meStyle(eStyle),
+ maRGBColorA(rRGBColorA),
+ maRGBColorB(rRGBColorB),
+ mfDiscreteDashLength(fDiscreteDashLength)
+ {}
+
+ void OverlayHelplineStripedPrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // use the prepared Viewport information accessible using getViewport()
+
+ if(getViewport().isEmpty())
+ return;
+
+ switch(getStyle())
+ {
+ case HELPLINESTYLE_VERTICAL :
+ {
+ basegfx::B2DPolygon aLine;
+
+ aLine.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMinY()));
+ aLine.append(basegfx::B2DPoint(getBasePosition().getX(), getViewport().getMaxY()));
+
+ rContainer.push_back(
+ new PolygonMarkerPrimitive2D(
+ aLine,
+ getRGBColorA(),
+ getRGBColorB(),
+ getDiscreteDashLength()));
+ break;
+ }
+
+ case HELPLINESTYLE_HORIZONTAL :
+ {
+ basegfx::B2DPolygon aLine;
+
+ aLine.append(basegfx::B2DPoint(getViewport().getMinX(), getBasePosition().getY()));
+ aLine.append(basegfx::B2DPoint(getViewport().getMaxX(), getBasePosition().getY()));
+
+ rContainer.push_back(
+ new PolygonMarkerPrimitive2D(
+ aLine,
+ getRGBColorA(),
+ getRGBColorB(),
+ getDiscreteDashLength()));
+ break;
+ }
+
+ default: // case HELPLINESTYLE_POINT :
+ {
+ const double fDiscreteUnit((rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength());
+ basegfx::B2DPolygon aLineA, aLineB;
+
+ aLineA.append(basegfx::B2DPoint(getBasePosition().getX(), getBasePosition().getY() - fDiscreteUnit));
+ aLineA.append(basegfx::B2DPoint(getBasePosition().getX(), getBasePosition().getY() + fDiscreteUnit));
+
+ rContainer.push_back(
+ new PolygonMarkerPrimitive2D(
+ aLineA,
+ getRGBColorA(),
+ getRGBColorB(),
+ getDiscreteDashLength()));
+
+ aLineB.append(basegfx::B2DPoint(getBasePosition().getX() - fDiscreteUnit, getBasePosition().getY()));
+ aLineB.append(basegfx::B2DPoint(getBasePosition().getX() + fDiscreteUnit, getBasePosition().getY()));
+
+ rContainer.push_back(
+ new PolygonMarkerPrimitive2D(
+ aLineB,
+ getRGBColorA(),
+ getRGBColorB(),
+ getDiscreteDashLength()));
+
+ break;
+ }
+ }
+ }
+
+ bool OverlayHelplineStripedPrimitive::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(ViewportDependentPrimitive2D::operator==(rPrimitive))
+ {
+ const OverlayHelplineStripedPrimitive& rCompare = static_cast< const OverlayHelplineStripedPrimitive& >(rPrimitive);
+
+ return (getBasePosition() == rCompare.getBasePosition()
+ && getStyle() == rCompare.getStyle()
+ && getRGBColorA() == rCompare.getRGBColorA()
+ && getRGBColorB() == rCompare.getRGBColorB()
+ && getDiscreteDashLength() == rCompare.getDiscreteDashLength());
+ }
+
+ return false;
+ }
+
+ sal_uInt32 OverlayHelplineStripedPrimitive::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_OVERLAYHELPLINESTRIPEDPRIMITIVE;
+ }
+
+
+
+ OverlayRollingRectanglePrimitive::OverlayRollingRectanglePrimitive(
+ const basegfx::B2DRange& aRollingRectangle,
+ const basegfx::BColor& rRGBColorA,
+ const basegfx::BColor& rRGBColorB,
+ double fDiscreteDashLength)
+ : maRollingRectangle(aRollingRectangle),
+ maRGBColorA(rRGBColorA),
+ maRGBColorB(rRGBColorB),
+ mfDiscreteDashLength(fDiscreteDashLength)
+ {}
+
+ void OverlayRollingRectanglePrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ // use the prepared Viewport information accessible using getViewport()
+
+ if(getViewport().isEmpty())
+ return;
+
+ basegfx::B2DPolygon aLine;
+
+ // Left lines
+ aLine.append(basegfx::B2DPoint(getViewport().getMinX(), getRollingRectangle().getMinY()));
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMinY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ aLine.clear();
+ aLine.append(basegfx::B2DPoint(getViewport().getMinX(), getRollingRectangle().getMaxY()));
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMaxY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ // Right lines
+ aLine.clear();
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMinY()));
+ aLine.append(basegfx::B2DPoint(getViewport().getMaxX(), getRollingRectangle().getMinY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ aLine.clear();
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMaxY()));
+ aLine.append(basegfx::B2DPoint(getViewport().getMaxX(), getRollingRectangle().getMaxY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ // Top lines
+ aLine.clear();
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getViewport().getMinY()));
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMinY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ aLine.clear();
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getViewport().getMinY()));
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMinY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ // Bottom lines
+ aLine.clear();
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getRollingRectangle().getMaxY()));
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMinX(), getViewport().getMaxY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ aLine.clear();
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getRollingRectangle().getMaxY()));
+ aLine.append(basegfx::B2DPoint(getRollingRectangle().getMaxX(), getViewport().getMaxY()));
+ rContainer.push_back(new PolygonMarkerPrimitive2D(aLine, getRGBColorA(), getRGBColorB(), getDiscreteDashLength()));
+
+ }
+
+ bool OverlayRollingRectanglePrimitive::operator==( const BasePrimitive2D& rPrimitive ) const
+ {
+ if(ViewportDependentPrimitive2D::operator==(rPrimitive))
+ {
+ const OverlayRollingRectanglePrimitive& rCompare = static_cast< const OverlayRollingRectanglePrimitive& >(rPrimitive);
+
+ return (getRollingRectangle() == rCompare.getRollingRectangle()
+ && getRGBColorA() == rCompare.getRGBColorA()
+ && getRGBColorB() == rCompare.getRGBColorB()
+ && getDiscreteDashLength() == rCompare.getDiscreteDashLength());
+ }
+
+ return false;
+ }
+
+ sal_uInt32 OverlayRollingRectanglePrimitive::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_OVERLAYROLLINGRECTANGLEPRIMITIVE;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/overlay/overlaytriangle.cxx b/svx/source/sdr/overlay/overlaytriangle.cxx
new file mode 100644
index 000000000..f46fcf1e2
--- /dev/null
+++ b/svx/source/sdr/overlay/overlaytriangle.cxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/overlay/overlaytriangle.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+
+
+namespace sdr::overlay
+{
+ drawinglayer::primitive2d::Primitive2DContainer OverlayTriangle::createOverlayObjectPrimitive2DSequence()
+ {
+ basegfx::B2DPolygon aPolygon;
+
+ aPolygon.append(getBasePosition());
+ aPolygon.append(maSecondPosition);
+ aPolygon.append(maThirdPosition);
+ aPolygon.setClosed(true);
+
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ basegfx::B2DPolyPolygon(aPolygon),
+ getBaseColor().getBColor()));
+
+ return drawinglayer::primitive2d::Primitive2DContainer { aReference };
+ }
+
+ OverlayTriangle::OverlayTriangle(
+ const basegfx::B2DPoint& rBasePos,
+ const basegfx::B2DPoint& rSecondPos,
+ const basegfx::B2DPoint& rThirdPos,
+ Color aTriangleColor)
+ : OverlayObjectWithBasePosition(rBasePos, aTriangleColor),
+ maSecondPosition(rSecondPos),
+ maThirdPosition(rThirdPos)
+ {
+ }
+
+ OverlayTriangle::~OverlayTriangle()
+ {
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/primitivefactory2d.cxx b/svx/source/sdr/primitive2d/primitivefactory2d.cxx
new file mode 100644
index 000000000..c6530fd13
--- /dev/null
+++ b/svx/source/sdr/primitive2d/primitivefactory2d.cxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <sdr/primitive2d/primitivefactory2d.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/unoapi.hxx>
+
+using namespace com::sun::star;
+
+css::uno::Sequence< css::uno::Reference< css::graphic::XPrimitive2D > > SAL_CALL PrimitiveFactory2D::createPrimitivesFromXShape(
+ const uno::Reference< drawing::XShape >& xShape,
+ const uno::Sequence< beans::PropertyValue >& /*aParms*/ )
+{
+ css::uno::Sequence< css::uno::Reference< css::graphic::XPrimitive2D > > aRetval;
+
+ if(xShape.is())
+ {
+ SdrObject* pSource = SdrObject::getSdrObjectFromXShape(xShape);
+
+ if(pSource)
+ {
+ const sdr::contact::ViewContact& rSource(pSource->GetViewContact());
+ drawinglayer::primitive2d::Primitive2DContainer aSourceVal;
+ rSource.getViewIndependentPrimitive2DContainer(aSourceVal);
+ aRetval = aSourceVal.toSequence();
+ }
+ }
+
+ return aRetval;
+}
+
+void PrimitiveFactory2D::createPrimitivesFromXShape(
+ const uno::Reference< drawing::XShape >& xShape,
+ const uno::Sequence< beans::PropertyValue >& /*aParms*/,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor)
+{
+ if(xShape.is())
+ {
+ SdrObject* pSource = SdrObject::getSdrObjectFromXShape(xShape);
+
+ if(pSource)
+ {
+ const sdr::contact::ViewContact& rSource(pSource->GetViewContact());
+ rSource.getViewIndependentPrimitive2DContainer(rVisitor);
+ }
+ }
+}
+
+css::uno::Sequence< css::uno::Reference< css::graphic::XPrimitive2D > > SAL_CALL PrimitiveFactory2D::createPrimitivesFromXDrawPage(
+ const uno::Reference< drawing::XDrawPage >& xDrawPage,
+ const uno::Sequence< beans::PropertyValue >& /*aParms*/ )
+{
+ css::uno::Sequence< css::uno::Reference< css::graphic::XPrimitive2D > > aRetval;
+
+ if(xDrawPage.is())
+ {
+ SdrPage* pSource = GetSdrPageFromXDrawPage(xDrawPage);
+
+ if(pSource)
+ {
+ const sdr::contact::ViewContact& rSource(pSource->GetViewContact());
+ drawinglayer::primitive2d::Primitive2DContainer aSourceRetval;
+ rSource.getViewIndependentPrimitive2DContainer(aSourceRetval);
+ aRetval = aSourceRetval.toSequence();
+ }
+ }
+
+ return aRetval;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_graphic_PrimitiveFactory2D_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new PrimitiveFactory2D);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrattributecreator.cxx b/svx/source/sdr/primitive2d/sdrattributecreator.cxx
new file mode 100644
index 000000000..bafa96f95
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrattributecreator.cxx
@@ -0,0 +1,1151 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <svl/itemset.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdooitm.hxx>
+#include <svx/sdprcitm.hxx>
+#include <svx/xdef.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflbmpit.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlinjoit.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnstcit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnedcit.hxx>
+#include <svx/xdash.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xfilluseslidebackgrounditem.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xgrscit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xflbckit.hxx>
+#include <svx/xflbmsxy.hxx>
+#include <svx/xflbtoxy.hxx>
+#include <svx/xflboxy.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/xtextit0.hxx>
+#include <drawinglayer/attribute/sdrfillgraphicattribute.hxx>
+#include <svx/svdotext.hxx>
+#include <sdr/attribute/sdrtextattribute.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svl/itempool.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/GraphicLoader.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <svx/svx3ditems.hxx>
+#include <com/sun/star/drawing/ProjectionMode.hpp>
+#include <com/sun/star/drawing/ShadeMode.hpp>
+#include <drawinglayer/attribute/sdrallattribute3d.hxx>
+#include <svx/rectenum.hxx>
+#include <svx/sdtfchim.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/xflbmsli.hxx>
+#include <editeng/editstat.hxx>
+#include <osl/diagnose.h>
+#include <drawinglayer/attribute/fillhatchattribute.hxx>
+#include <drawinglayer/attribute/fillgradientattribute.hxx>
+#include <sdr/attribute/sdreffectstextattribute.hxx>
+#include <sdr/attribute/sdrlineeffectstextattribute.hxx>
+#include <sdr/attribute/sdrformtextattribute.hxx>
+#include <sdr/attribute/sdrlinefilleffectstextattribute.hxx>
+#include <drawinglayer/attribute/sdrglowattribute.hxx>
+#include <drawinglayer/attribute/sdrsceneattribute3d.hxx>
+#include <drawinglayer/attribute/sdrlightingattribute3d.hxx>
+#include <drawinglayer/attribute/sdrlightattribute3d.hxx>
+#include <sdr/attribute/sdrfilltextattribute.hxx>
+#include <com/sun/star/drawing/LineCap.hpp>
+
+using namespace com::sun::star;
+
+namespace drawinglayer
+{
+ namespace
+ {
+ attribute::GradientStyle XGradientStyleToGradientStyle(css::awt::GradientStyle eStyle)
+ {
+ switch(eStyle)
+ {
+ case css::awt::GradientStyle_LINEAR :
+ {
+ return attribute::GradientStyle::Linear;
+ }
+ case css::awt::GradientStyle_AXIAL :
+ {
+ return attribute::GradientStyle::Axial;
+ }
+ case css::awt::GradientStyle_RADIAL :
+ {
+ return attribute::GradientStyle::Radial;
+ }
+ case css::awt::GradientStyle_ELLIPTICAL :
+ {
+ return attribute::GradientStyle::Elliptical;
+ }
+ case css::awt::GradientStyle_SQUARE :
+ {
+ return attribute::GradientStyle::Square;
+ }
+ default :
+ {
+ return attribute::GradientStyle::Rect; // css::awt::GradientStyle_RECT
+ }
+ }
+ }
+
+ attribute::HatchStyle XHatchStyleToHatchStyle(css::drawing::HatchStyle eStyle)
+ {
+ switch(eStyle)
+ {
+ case css::drawing::HatchStyle_SINGLE :
+ {
+ return attribute::HatchStyle::Single;
+ }
+ case css::drawing::HatchStyle_DOUBLE :
+ {
+ return attribute::HatchStyle::Double;
+ }
+ default :
+ {
+ return attribute::HatchStyle::Triple; // css::drawing::HatchStyle_TRIPLE
+ }
+ }
+ }
+
+ basegfx::B2DLineJoin LineJointToB2DLineJoin(css::drawing::LineJoint eLineJoint)
+ {
+ switch(eLineJoint)
+ {
+ case css::drawing::LineJoint_BEVEL :
+ {
+ return basegfx::B2DLineJoin::Bevel;
+ }
+ case css::drawing::LineJoint_MIDDLE :
+ case css::drawing::LineJoint_MITER :
+ {
+ return basegfx::B2DLineJoin::Miter;
+ }
+ case css::drawing::LineJoint_ROUND :
+ {
+ return basegfx::B2DLineJoin::Round;
+ }
+ default : // css::drawing::LineJoint_NONE
+ {
+ return basegfx::B2DLineJoin::NONE;
+ }
+ }
+ }
+
+ basegfx::B2DVector RectPointToB2DVector(RectPoint eRectPoint)
+ {
+ basegfx::B2DVector aRetval(0.0, 0.0);
+
+ // position changes X
+ switch(eRectPoint)
+ {
+ case RectPoint::LT: case RectPoint::LM: case RectPoint::LB:
+ {
+ aRetval.setX(-1.0);
+ break;
+ }
+
+ case RectPoint::RT: case RectPoint::RM: case RectPoint::RB:
+ {
+ aRetval.setX(1.0);
+ break;
+ }
+
+ default :
+ {
+ break;
+ }
+ }
+
+ // position changes Y
+ switch(eRectPoint)
+ {
+ case RectPoint::LT: case RectPoint::MT: case RectPoint::RT:
+ {
+ aRetval.setY(-1.0);
+ break;
+ }
+
+ case RectPoint::LB: case RectPoint::MB: case RectPoint::RB:
+ {
+ aRetval.setY(1.0);
+ break;
+ }
+
+ default :
+ {
+ break;
+ }
+ }
+
+ return aRetval;
+ }
+
+ attribute::SdrGlowAttribute createNewSdrGlowAttribute(const SfxItemSet& rSet)
+ {
+ sal_Int32 nRadius = rSet.Get(SDRATTR_GLOW_RADIUS).GetValue();
+ if (!nRadius)
+ return attribute::SdrGlowAttribute();
+ Color aColor(rSet.Get(SDRATTR_GLOW_COLOR).GetColorValue());
+ sal_uInt16 nTransparency(rSet.Get(SDRATTR_GLOW_TRANSPARENCY).GetValue());
+ if (nTransparency)
+ aColor.SetAlpha(255 - std::round(nTransparency / 100.0 * 255.0));
+
+ attribute::SdrGlowAttribute glowAttr{ nRadius, aColor };
+ return glowAttr;
+ }
+
+ sal_Int32 getSoftEdgeRadius(const SfxItemSet& rSet)
+ {
+ return rSet.Get(SDRATTR_SOFTEDGE_RADIUS).GetValue();
+ }
+ } // end of anonymous namespace
+} // end of namespace drawinglayer
+
+
+namespace drawinglayer::primitive2d
+{
+ attribute::SdrLineAttribute createNewSdrLineAttribute(const SfxItemSet& rSet)
+ {
+ const css::drawing::LineStyle eStyle(rSet.Get(XATTR_LINESTYLE).GetValue());
+
+ if(drawing::LineStyle_NONE != eStyle)
+ {
+ sal_uInt16 nTransparence(rSet.Get(XATTR_LINETRANSPARENCE).GetValue());
+
+ if(nTransparence > 100)
+ {
+ nTransparence = 100;
+ }
+
+ if(100 != nTransparence)
+ {
+ const sal_uInt32 nWidth(rSet.Get(XATTR_LINEWIDTH).GetValue());
+ const Color aColor(rSet.Get(XATTR_LINECOLOR).GetColorValue());
+ const css::drawing::LineJoint eJoint(rSet.Get(XATTR_LINEJOINT).GetValue());
+ const css::drawing::LineCap eCap(rSet.Get(XATTR_LINECAP).GetValue());
+ ::std::vector< double > aDotDashArray;
+ double fFullDotDashLen(0.0);
+
+ if(drawing::LineStyle_DASH == eStyle)
+ {
+ const XDash& rDash = rSet.Get(XATTR_LINEDASH).GetDashValue();
+
+ if(rDash.GetDots() || rDash.GetDashes())
+ {
+ fFullDotDashLen = rDash.CreateDotDashArray(aDotDashArray, static_cast<double>(nWidth));
+ }
+ }
+
+ return attribute::SdrLineAttribute(
+ LineJointToB2DLineJoin(eJoint),
+ static_cast<double>(nWidth),
+ static_cast<double>(nTransparence) * 0.01,
+ aColor.getBColor(),
+ eCap,
+ std::move(aDotDashArray),
+ fFullDotDashLen);
+ }
+ }
+
+ return attribute::SdrLineAttribute();
+ }
+
+ attribute::SdrLineStartEndAttribute createNewSdrLineStartEndAttribute(
+ const SfxItemSet& rSet,
+ double fWidth)
+ {
+ const sal_Int32 nTempStartWidth(rSet.Get(XATTR_LINESTARTWIDTH).GetValue());
+ const sal_Int32 nTempEndWidth(rSet.Get(XATTR_LINEENDWIDTH).GetValue());
+ basegfx::B2DPolyPolygon aStartPolyPolygon;
+ basegfx::B2DPolyPolygon aEndPolyPolygon;
+ double fStartWidth(0.0);
+ double fEndWidth(0.0);
+ bool bStartActive(false);
+ bool bEndActive(false);
+ bool bStartCentered(true);
+ bool bEndCentered(true);
+
+ if(nTempStartWidth)
+ {
+ if(nTempStartWidth < 0)
+ {
+ fStartWidth = (static_cast<double>(-nTempStartWidth) * fWidth) * 0.01;
+ }
+ else
+ {
+ fStartWidth = static_cast<double>(nTempStartWidth);
+ }
+
+ if(0.0 != fStartWidth)
+ {
+ aStartPolyPolygon = rSet.Get(XATTR_LINESTART).GetLineStartValue();
+
+ if(aStartPolyPolygon.count() && aStartPolyPolygon.getB2DPolygon(0).count())
+ {
+ bStartActive = true;
+ bStartCentered = rSet.Get(XATTR_LINESTARTCENTER).GetValue();
+ }
+ }
+ }
+
+ if(nTempEndWidth)
+ {
+ if(nTempEndWidth < 0)
+ {
+ fEndWidth = (static_cast<double>(-nTempEndWidth) * fWidth) * 0.01;
+ }
+ else
+ {
+ fEndWidth = static_cast<double>(nTempEndWidth);
+ }
+
+ if(0.0 != fEndWidth)
+ {
+ aEndPolyPolygon = rSet.Get(XATTR_LINEEND).GetLineEndValue();
+
+ if(aEndPolyPolygon.count() && aEndPolyPolygon.getB2DPolygon(0).count())
+ {
+ bEndActive = true;
+ bEndCentered = rSet.Get(XATTR_LINEENDCENTER).GetValue();
+ }
+ }
+ }
+
+ if(bStartActive || bEndActive)
+ {
+ return attribute::SdrLineStartEndAttribute(
+ aStartPolyPolygon, aEndPolyPolygon, fStartWidth, fEndWidth,
+ bStartActive, bEndActive, bStartCentered, bEndCentered);
+ }
+
+ return attribute::SdrLineStartEndAttribute();
+ }
+
+ attribute::SdrShadowAttribute createNewSdrShadowAttribute(const SfxItemSet& rSet)
+ {
+ const bool bShadow(rSet.Get(SDRATTR_SHADOW).GetValue());
+
+ if(bShadow)
+ {
+ sal_uInt16 nTransparence(rSet.Get(SDRATTR_SHADOWTRANSPARENCE).GetValue());
+
+ if(nTransparence > 100)
+ {
+ nTransparence = 100;
+ }
+
+ if(nTransparence)
+ {
+ sal_uInt16 nFillTransparence(rSet.Get(XATTR_FILLTRANSPARENCE).GetValue());
+
+ if(nFillTransparence > 100)
+ {
+ nFillTransparence = 100;
+ }
+
+ if(nTransparence == nFillTransparence)
+ {
+ // shadow does not really have an own transparence, but the application
+ // sets the shadow transparence equal to the object transparence for
+ // convenience. This is not useful for primitive creation, so take
+ // this as no shadow transparence
+ nTransparence = 0;
+ }
+ }
+
+ if(100 != nTransparence)
+ {
+ const basegfx::B2DVector aOffset(
+ static_cast<double>(rSet.Get(SDRATTR_SHADOWXDIST).GetValue()),
+ static_cast<double>(rSet.Get(SDRATTR_SHADOWYDIST).GetValue()));
+
+ const basegfx::B2DVector aSize(
+ static_cast<double>(rSet.Get(SDRATTR_SHADOWSIZEX).GetValue()),
+ static_cast<double>(rSet.Get(SDRATTR_SHADOWSIZEY).GetValue()));
+
+ const Color aColor(rSet.Get(SDRATTR_SHADOWCOLOR).GetColorValue());
+
+ sal_Int32 nBlur(rSet.Get(SDRATTR_SHADOWBLUR).GetValue());
+
+ return attribute::SdrShadowAttribute(aOffset, aSize, static_cast<double>(nTransparence) * 0.01,nBlur, aColor.getBColor());
+ }
+ }
+
+ return attribute::SdrShadowAttribute();
+ }
+
+ attribute::SdrFillAttribute createNewSdrFillAttribute(const SfxItemSet& rSet)
+ {
+ const drawing::FillStyle eStyle(rSet.Get(XATTR_FILLSTYLE).GetValue());
+
+ sal_uInt16 nTransparence(rSet.Get(XATTR_FILLTRANSPARENCE).GetValue());
+
+ if(nTransparence > 100)
+ {
+ nTransparence = 100;
+ }
+
+ if(drawing::FillStyle_NONE == eStyle)
+ {
+ XFillUseSlideBackgroundItem aBckItem(rSet.Get(XATTR_FILLUSESLIDEBACKGROUND));
+ const bool bSlideBackgroundFill(aBckItem.GetValue());
+
+ if(bSlideBackgroundFill)
+ {
+ // we have SlideBackgroundFill mode, create a
+ // SdrFillAttribute accordingly
+ return attribute::SdrFillAttribute(true);
+ }
+ }
+
+ if(drawing::FillStyle_NONE != eStyle)
+ {
+ if(100 != nTransparence)
+ {
+ // need to check XFillFloatTransparence, object fill may still be completely transparent
+ const XFillFloatTransparenceItem* pGradientItem;
+
+ if((pGradientItem = rSet.GetItemIfSet(XATTR_FILLFLOATTRANSPARENCE, true))
+ && pGradientItem->IsEnabled())
+ {
+ const XGradient& rGradient = pGradientItem->GetGradientValue();
+ const sal_uInt8 nStartLuminance(rGradient.GetStartColor().GetLuminance());
+ const sal_uInt8 nEndLuminance(rGradient.GetEndColor().GetLuminance());
+ const bool bCompletelyTransparent(0xff == nStartLuminance && 0xff == nEndLuminance);
+
+ if(bCompletelyTransparent)
+ {
+ nTransparence = 100;
+ }
+ }
+ }
+
+ if(100 != nTransparence)
+ {
+ const Color aColor(rSet.Get(XATTR_FILLCOLOR).GetColorValue());
+ attribute::FillGradientAttribute aGradient;
+ attribute::FillHatchAttribute aHatch;
+ attribute::SdrFillGraphicAttribute aFillGraphic;
+
+ switch(eStyle)
+ {
+ default:
+ {
+ // nothing to do, color is defined
+ break;
+ }
+ case drawing::FillStyle_GRADIENT :
+ {
+ XGradient aXGradient(rSet.Get(XATTR_FILLGRADIENT).GetGradientValue());
+
+ const Color aStartColor(aXGradient.GetStartColor());
+ const sal_uInt16 nStartIntens(aXGradient.GetStartIntens());
+ basegfx::BColor aStart(aStartColor.getBColor());
+
+ if(nStartIntens != 100)
+ {
+ const basegfx::BColor aBlack;
+ aStart = interpolate(aBlack, aStart, static_cast<double>(nStartIntens) * 0.01);
+ }
+
+ const Color aEndColor(aXGradient.GetEndColor());
+ const sal_uInt16 nEndIntens(aXGradient.GetEndIntens());
+ basegfx::BColor aEnd(aEndColor.getBColor());
+
+ if(nEndIntens != 100)
+ {
+ const basegfx::BColor aBlack;
+ aEnd = interpolate(aBlack, aEnd, static_cast<double>(nEndIntens) * 0.01);
+ }
+
+ aGradient = attribute::FillGradientAttribute(
+ XGradientStyleToGradientStyle(aXGradient.GetGradientStyle()),
+ static_cast<double>(aXGradient.GetBorder()) * 0.01,
+ static_cast<double>(aXGradient.GetXOffset()) * 0.01,
+ static_cast<double>(aXGradient.GetYOffset()) * 0.01,
+ toRadians(aXGradient.GetAngle()),
+ aStart,
+ aEnd,
+ rSet.Get(XATTR_GRADIENTSTEPCOUNT).GetValue());
+
+ break;
+ }
+ case drawing::FillStyle_HATCH :
+ {
+ const XHatch& rHatch(rSet.Get(XATTR_FILLHATCH).GetHatchValue());
+ const Color aColorB(rHatch.GetColor());
+
+ aHatch = attribute::FillHatchAttribute(
+ XHatchStyleToHatchStyle(rHatch.GetHatchStyle()),
+ static_cast<double>(rHatch.GetDistance()),
+ toRadians(rHatch.GetAngle()),
+ aColorB.getBColor(),
+ 3, // same default as VCL, a minimum of three discrete units (pixels) offset
+ rSet.Get(XATTR_FILLBACKGROUND).GetValue());
+
+ break;
+ }
+ case drawing::FillStyle_BITMAP :
+ {
+ aFillGraphic = createNewSdrFillGraphicAttribute(rSet);
+ break;
+ }
+ }
+
+ return attribute::SdrFillAttribute(
+ static_cast<double>(nTransparence) * 0.01,
+ aColor.getBColor(),
+ aGradient,
+ aHatch,
+ aFillGraphic);
+ }
+ }
+
+ if(nTransparence == 100)
+ {
+ attribute::FillGradientAttribute aGradient;
+ attribute::FillHatchAttribute aHatch;
+ attribute::SdrFillGraphicAttribute aFillGraphic;
+ return attribute::SdrFillAttribute(
+ 1,
+ basegfx::BColor( 0, 0, 0 ),
+ aGradient,
+ aHatch,
+ aFillGraphic);
+ }
+
+ return attribute::SdrFillAttribute();
+ }
+
+ // #i101508# Support handing over given text-to-border distances
+ attribute::SdrTextAttribute createNewSdrTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText& rText,
+ const sal_Int32* pLeft,
+ const sal_Int32* pUpper,
+ const sal_Int32* pRight,
+ const sal_Int32* pLower)
+ {
+ const SdrTextObj& rTextObj = rText.GetObject();
+
+ // Save chaining attributes
+ bool bChainable = rTextObj.IsChainable();
+
+
+ if(rText.GetOutlinerParaObject())
+ {
+ // added TextEdit text suppression
+ bool bInEditMode(false);
+
+ if(rText.GetObject().getTextCount() > 1)
+ {
+ bInEditMode = rTextObj.IsInEditMode() && rText.GetObject().getActiveText() == &rText;
+ }
+ else
+ {
+ bInEditMode = rTextObj.IsInEditMode();
+ }
+
+ OutlinerParaObject aOutlinerParaObject(*rText.GetOutlinerParaObject());
+
+ if(bInEditMode)
+ {
+ std::optional<OutlinerParaObject> pTempObj = rTextObj.CreateEditOutlinerParaObject();
+
+ if(pTempObj)
+ {
+ aOutlinerParaObject = *pTempObj;
+ }
+ else
+ {
+ // #i100537#
+ // CreateEditOutlinerParaObject() returning no object does not mean that
+ // text edit mode is not active. Do not reset the flag here
+ // bInEditMode = false;
+ }
+ }
+
+ const SdrTextAniKind eAniKind(rTextObj.GetTextAniKind());
+
+ // #i107346#
+ const SdrOutliner& rDrawTextOutliner(rText.GetObject().getSdrModelFromSdrObject().GetDrawOutliner(&rTextObj));
+ const bool bWrongSpell(rDrawTextOutliner.GetControlWord() & EEControlBits::ONLINESPELLING);
+
+ return attribute::SdrTextAttribute(
+ rText,
+ aOutlinerParaObject,
+ rSet.Get(XATTR_FORMTXTSTYLE).GetValue(),
+ pLeft ? *pLeft : rTextObj.GetTextLeftDistance(),
+ pUpper ? *pUpper : rTextObj.GetTextUpperDistance(),
+ pRight ? *pRight : rTextObj.GetTextRightDistance(),
+ pLower ? *pLower : rTextObj.GetTextLowerDistance(),
+ rTextObj.GetTextHorizontalAdjust(rSet),
+ rTextObj.GetTextVerticalAdjust(rSet),
+ rSet.Get(SDRATTR_TEXT_CONTOURFRAME).GetValue(),
+ rTextObj.IsFitToSize(),
+ rTextObj.IsAutoFit(),
+ rSet.Get(XATTR_FORMTXTHIDEFORM).GetValue(),
+ SdrTextAniKind::Blink == eAniKind,
+ SdrTextAniKind::Scroll == eAniKind || SdrTextAniKind::Alternate == eAniKind || SdrTextAniKind::Slide == eAniKind,
+ bInEditMode,
+ rSet.Get(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue(),
+ bWrongSpell,
+ bChainable);
+ }
+
+ return attribute::SdrTextAttribute();
+ }
+
+ attribute::FillGradientAttribute createNewTransparenceGradientAttribute(const SfxItemSet& rSet)
+ {
+ const XFillFloatTransparenceItem* pGradientItem;
+
+ if((pGradientItem = rSet.GetItemIfSet(XATTR_FILLFLOATTRANSPARENCE))
+ && pGradientItem->IsEnabled())
+ {
+ // test if float transparence is completely transparent
+ const XGradient& rGradient = pGradientItem->GetGradientValue();
+ const sal_uInt8 nStartLuminance(rGradient.GetStartColor().GetLuminance());
+ const sal_uInt8 nEndLuminance(rGradient.GetEndColor().GetLuminance());
+ const bool bCompletelyTransparent(0xff == nStartLuminance && 0xff == nEndLuminance);
+ const bool bNotTransparent(0x00 == nStartLuminance && 0x00 == nEndLuminance);
+
+ // create nothing when completely transparent: This case is already checked for the
+ // normal fill attributes, XFILL_NONE will be used.
+ // create nothing when not transparent: use normal fill, no need t create a FillGradientAttribute.
+ // Both cases are optimizations, always creating FillGradientAttribute will work, too
+ if(!bNotTransparent && !bCompletelyTransparent)
+ {
+ const double fStartLum(nStartLuminance / 255.0);
+ const double fEndLum(nEndLuminance / 255.0);
+
+ return attribute::FillGradientAttribute(
+ XGradientStyleToGradientStyle(rGradient.GetGradientStyle()),
+ static_cast<double>(rGradient.GetBorder()) * 0.01,
+ static_cast<double>(rGradient.GetXOffset()) * 0.01,
+ static_cast<double>(rGradient.GetYOffset()) * 0.01,
+ toRadians(rGradient.GetAngle()),
+ basegfx::BColor(fStartLum, fStartLum, fStartLum),
+ basegfx::BColor(fEndLum, fEndLum, fEndLum));
+ }
+ }
+
+ return attribute::FillGradientAttribute();
+ }
+
+ attribute::SdrFillGraphicAttribute createNewSdrFillGraphicAttribute(const SfxItemSet& rSet)
+ {
+ Graphic aGraphic(rSet.Get(XATTR_FILLBITMAP).GetGraphicObject().GetGraphic());
+
+ OUString aOriginURL = aGraphic.getOriginURL();
+ if (aGraphic.GetType() == GraphicType::Default && !aOriginURL.isEmpty())
+ {
+ aGraphic = vcl::graphic::loadFromURL(aGraphic.getOriginURL());
+ aGraphic.setOriginURL(aOriginURL);
+ }
+
+ if(GraphicType::Bitmap != aGraphic.GetType() && GraphicType::GdiMetafile != aGraphic.GetType())
+ {
+ // no content if not bitmap or metafile
+ OSL_ENSURE(false, "No fill graphic in SfxItemSet (!)");
+ return attribute::SdrFillGraphicAttribute();
+ }
+
+ Size aPrefSize(aGraphic.GetPrefSize());
+
+ if(!aPrefSize.Width() || !aPrefSize.Height())
+ {
+ // if there is no logical size, create a size from pixel size and set MapMode accordingly
+ if(GraphicType::Bitmap == aGraphic.GetType())
+ {
+ aGraphic.SetPrefSize(aGraphic.GetBitmapEx().GetSizePixel());
+ aGraphic.SetPrefMapMode(MapMode(MapUnit::MapPixel));
+ aPrefSize = aGraphic.GetPrefSize();
+ }
+ }
+
+ if(!aPrefSize.Width() || !aPrefSize.Height())
+ {
+ // no content if no size
+ OSL_ENSURE(false, "Graphic has no size in SfxItemSet (!)");
+ return attribute::SdrFillGraphicAttribute();
+ }
+
+ // convert size and MapMode to destination logical size and MapMode
+ const MapUnit aDestinationMapUnit(rSet.GetPool()->GetMetric(0));
+ basegfx::B2DVector aGraphicLogicSize(aGraphic.GetPrefSize().Width(), aGraphic.GetPrefSize().Height());
+
+ if (aGraphic.GetPrefMapMode().GetMapUnit() != aDestinationMapUnit)
+ {
+ // #i100360# for MapUnit::MapPixel, LogicToLogic will not work properly,
+ // so fallback to Application::GetDefaultDevice()
+ Size aNewSize(0, 0);
+
+ if(MapUnit::MapPixel == aGraphic.GetPrefMapMode().GetMapUnit())
+ {
+ aNewSize = Application::GetDefaultDevice()->PixelToLogic(
+ aGraphic.GetPrefSize(),
+ MapMode(aDestinationMapUnit));
+ }
+ else
+ {
+ aNewSize = OutputDevice::LogicToLogic(
+ aGraphic.GetPrefSize(),
+ aGraphic.GetPrefMapMode(),
+ MapMode(aDestinationMapUnit));
+ }
+
+ // #i124002# do not set new size using SetPrefSize at the graphic, this will lead to problems.
+ // Instead, adapt the GraphicLogicSize which will be used for further decompositions
+ aGraphicLogicSize = basegfx::B2DVector(aNewSize.Width(), aNewSize.Height());
+ }
+
+ // get size
+ const basegfx::B2DVector aSize(
+ static_cast<double>(rSet.Get(XATTR_FILLBMP_SIZEX).GetValue()),
+ static_cast<double>(rSet.Get(XATTR_FILLBMP_SIZEY).GetValue()));
+ const basegfx::B2DVector aOffset(
+ static_cast<double>(rSet.Get(XATTR_FILLBMP_TILEOFFSETX).GetValue()),
+ static_cast<double>(rSet.Get(XATTR_FILLBMP_TILEOFFSETY).GetValue()));
+ const basegfx::B2DVector aOffsetPosition(
+ static_cast<double>(rSet.Get(XATTR_FILLBMP_POSOFFSETX).GetValue()),
+ static_cast<double>(rSet.Get(XATTR_FILLBMP_POSOFFSETY).GetValue()));
+
+ return attribute::SdrFillGraphicAttribute(
+ aGraphic,
+ aGraphicLogicSize,
+ aSize,
+ aOffset,
+ aOffsetPosition,
+ RectPointToB2DVector(rSet.GetItem<XFillBmpPosItem>(XATTR_FILLBMP_POS)->GetValue()),
+ rSet.Get(XATTR_FILLBMP_TILE).GetValue(),
+ rSet.Get(XATTR_FILLBMP_STRETCH).GetValue(),
+ rSet.Get(XATTR_FILLBMP_SIZELOG).GetValue());
+ }
+
+ attribute::SdrEffectsTextAttribute createNewSdrEffectsTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText* pText,
+ bool bSuppressText)
+ {
+ attribute::SdrTextAttribute aText;
+
+ // #i98072# added option to suppress text
+ // look for text first
+ if(!bSuppressText && pText)
+ {
+ aText = createNewSdrTextAttribute(rSet, *pText);
+ }
+
+ // try shadow
+ const attribute::SdrShadowAttribute aShadow(createNewSdrShadowAttribute(rSet));
+ const attribute::SdrGlowAttribute aGlow(createNewSdrGlowAttribute(rSet));
+ const sal_Int32 nSoftEdgeRadius(getSoftEdgeRadius(rSet));
+
+ return attribute::SdrEffectsTextAttribute(aShadow, aText, aGlow, nSoftEdgeRadius);
+ }
+
+ attribute::SdrLineEffectsTextAttribute createNewSdrLineEffectsTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText* pText)
+ {
+ attribute::SdrLineAttribute aLine;
+ attribute::SdrLineStartEndAttribute aLineStartEnd;
+ attribute::SdrTextAttribute aText;
+ bool bFontworkHideContour(false);
+
+ // look for text first
+ if(pText)
+ {
+ aText = createNewSdrTextAttribute(rSet, *pText);
+
+ // when object has text and text is fontwork and hide contour is set for fontwork, force
+ // line and fill style to empty
+ if(!aText.isDefault()
+ && !aText.getSdrFormTextAttribute().isDefault()
+ && aText.isHideContour())
+ {
+ bFontworkHideContour = true;
+ }
+ }
+
+ // try line style
+ if(!bFontworkHideContour)
+ {
+ aLine = createNewSdrLineAttribute(rSet);
+
+ if(!aLine.isDefault())
+ {
+ // try LineStartEnd
+ aLineStartEnd = createNewSdrLineStartEndAttribute(rSet, aLine.getWidth());
+ }
+ }
+
+ if(!aLine.isDefault() || !aText.isDefault())
+ {
+ // try shadow
+ const attribute::SdrShadowAttribute aShadow(createNewSdrShadowAttribute(rSet));
+ const attribute::SdrGlowAttribute aGlow = createNewSdrGlowAttribute(rSet);
+ const sal_Int32 nSoftEdgeRadius(getSoftEdgeRadius(rSet));
+
+ return attribute::SdrLineEffectsTextAttribute(aLine, aLineStartEnd, aShadow, aText,
+ aGlow, nSoftEdgeRadius);
+ }
+
+ return attribute::SdrLineEffectsTextAttribute();
+ }
+
+ attribute::SdrLineFillEffectsTextAttribute createNewSdrLineFillEffectsTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText* pText,
+ bool bHasContent)
+ {
+ attribute::SdrLineAttribute aLine;
+ attribute::SdrFillAttribute aFill;
+ attribute::SdrLineStartEndAttribute aLineStartEnd;
+ attribute::FillGradientAttribute aFillFloatTransGradient;
+ attribute::SdrTextAttribute aText;
+ bool bFontworkHideContour(false);
+
+ // look for text first
+ if(pText)
+ {
+ aText = createNewSdrTextAttribute(rSet, *pText);
+
+ // when object has text and text is fontwork and hide contour is set for fontwork, force
+ // line and fill style to empty
+ if(!aText.getSdrFormTextAttribute().isDefault() && aText.isHideContour())
+ {
+ bFontworkHideContour = true;
+ }
+ }
+
+ if(!bFontworkHideContour)
+ {
+ // try line style
+ aLine = createNewSdrLineAttribute(rSet);
+
+ if(!aLine.isDefault())
+ {
+ // try LineStartEnd
+ aLineStartEnd = createNewSdrLineStartEndAttribute(rSet, aLine.getWidth());
+ }
+
+ // try fill style
+ aFill = createNewSdrFillAttribute(rSet);
+
+ if(!aFill.isDefault())
+ {
+ // try fillfloattransparence
+ aFillFloatTransGradient = createNewTransparenceGradientAttribute(rSet);
+ }
+ }
+
+ // bHasContent is used from OLE and graphic objects. Normally a possible shadow
+ // depends on line, fill or text to be set, but for these objects it is possible
+ // to have none of these, but still content which needs to have a shadow (if set),
+ // so shadow needs to be tried
+ if(bHasContent || !aLine.isDefault() || !aFill.isDefault() || !aText.isDefault())
+ {
+ // try shadow
+ const attribute::SdrShadowAttribute aShadow = createNewSdrShadowAttribute(rSet);
+
+ // glow
+ const attribute::SdrGlowAttribute aGlow = createNewSdrGlowAttribute(rSet);
+
+ const sal_Int32 nSoftEdgeRadius(getSoftEdgeRadius(rSet));
+
+ return attribute::SdrLineFillEffectsTextAttribute(aLine, aFill, aLineStartEnd,
+ aShadow, aFillFloatTransGradient,
+ aText, aGlow, nSoftEdgeRadius);
+ }
+
+ return attribute::SdrLineFillEffectsTextAttribute();
+ }
+
+ attribute::SdrLineFillShadowAttribute3D createNewSdrLineFillShadowAttribute(const SfxItemSet& rSet, bool bSuppressFill)
+ {
+ attribute::SdrFillAttribute aFill;
+ attribute::SdrLineStartEndAttribute aLineStartEnd;
+ attribute::SdrShadowAttribute aShadow;
+ attribute::FillGradientAttribute aFillFloatTransGradient;
+
+ // try line style
+ const attribute::SdrLineAttribute aLine(createNewSdrLineAttribute(rSet));
+
+ if(!aLine.isDefault())
+ {
+ // try LineStartEnd
+ aLineStartEnd = createNewSdrLineStartEndAttribute(rSet, aLine.getWidth());
+ }
+
+ // try fill style
+ if(!bSuppressFill)
+ {
+ aFill = createNewSdrFillAttribute(rSet);
+
+ if(!aFill.isDefault())
+ {
+ // try fillfloattransparence
+ aFillFloatTransGradient = createNewTransparenceGradientAttribute(rSet);
+ }
+ }
+
+ if(!aLine.isDefault() || !aFill.isDefault())
+ {
+ // try shadow
+ aShadow = createNewSdrShadowAttribute(rSet);
+
+ return attribute::SdrLineFillShadowAttribute3D(
+ aLine, aFill, aLineStartEnd, aShadow, aFillFloatTransGradient);
+ }
+
+ return attribute::SdrLineFillShadowAttribute3D();
+ }
+
+ attribute::SdrSceneAttribute createNewSdrSceneAttribute(const SfxItemSet& rSet)
+ {
+ // get perspective
+ css::drawing::ProjectionMode aProjectionMode(css::drawing::ProjectionMode_PARALLEL);
+ const sal_uInt16 nProjectionValue(rSet.Get(SDRATTR_3DSCENE_PERSPECTIVE).GetValue());
+
+ if(1 == nProjectionValue)
+ {
+ aProjectionMode = css::drawing::ProjectionMode_PERSPECTIVE;
+ }
+
+ // get distance
+ const double fDistance(rSet.Get(SDRATTR_3DSCENE_DISTANCE).GetValue());
+
+ // get shadow slant
+ const double fShadowSlant(
+ basegfx::deg2rad(rSet.Get(SDRATTR_3DSCENE_SHADOW_SLANT).GetValue()));
+
+ // get shade mode
+ css::drawing::ShadeMode aShadeMode(css::drawing::ShadeMode_FLAT);
+ const sal_uInt16 nShadeValue(rSet.Get(SDRATTR_3DSCENE_SHADE_MODE).GetValue());
+
+ if(1 == nShadeValue)
+ {
+ aShadeMode = css::drawing::ShadeMode_PHONG;
+ }
+ else if(2 == nShadeValue)
+ {
+ aShadeMode = css::drawing::ShadeMode_SMOOTH;
+ }
+ else if(3 == nShadeValue)
+ {
+ aShadeMode = css::drawing::ShadeMode_DRAFT;
+ }
+
+ // get two sided lighting
+ const bool bTwoSidedLighting(rSet.Get(SDRATTR_3DSCENE_TWO_SIDED_LIGHTING).GetValue());
+
+ return attribute::SdrSceneAttribute(fDistance, fShadowSlant, aProjectionMode, aShadeMode, bTwoSidedLighting);
+ }
+
+ attribute::SdrLightingAttribute createNewSdrLightingAttribute(const SfxItemSet& rSet)
+ {
+ // extract lights from given SfxItemSet (from scene)
+ ::std::vector< attribute::Sdr3DLightAttribute > aLightVector;
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_1).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_1).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_1).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, true);
+ }
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_2).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_2).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_2).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, false);
+ }
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_3).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_3).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_3).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, false);
+ }
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_4).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_4).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_4).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, false);
+ }
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_5).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_5).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_5).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, false);
+ }
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_6).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_6).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_6).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, false);
+ }
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_7).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_7).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_7).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, false);
+ }
+
+ if(rSet.Get(SDRATTR_3DSCENE_LIGHTON_8).GetValue())
+ {
+ const basegfx::BColor aColor(rSet.Get(SDRATTR_3DSCENE_LIGHTCOLOR_8).GetValue().getBColor());
+ const basegfx::B3DVector aDirection(rSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_8).GetValue());
+ aLightVector.emplace_back(aColor, aDirection, false);
+ }
+
+ // get ambient color
+ const Color aAmbientValue(rSet.Get(SDRATTR_3DSCENE_AMBIENTCOLOR).GetValue());
+ const basegfx::BColor aAmbientLight(aAmbientValue.getBColor());
+
+ return attribute::SdrLightingAttribute(aAmbientLight, std::move(aLightVector));
+ }
+
+ void calculateRelativeCornerRadius(sal_Int32 nRadius, const basegfx::B2DRange& rObjectRange, double& rfCornerRadiusX, double& rfCornerRadiusY)
+ {
+ rfCornerRadiusX = rfCornerRadiusY = static_cast<double>(nRadius);
+
+ if(0.0 != rfCornerRadiusX)
+ {
+ const double fHalfObjectWidth(rObjectRange.getWidth() * 0.5);
+
+ if(0.0 != fHalfObjectWidth)
+ {
+ if(rfCornerRadiusX < 0.0)
+ {
+ rfCornerRadiusX = 0.0;
+ }
+
+ if(rfCornerRadiusX > fHalfObjectWidth)
+ {
+ rfCornerRadiusX = fHalfObjectWidth;
+ }
+
+ rfCornerRadiusX /= fHalfObjectWidth;
+ }
+ else
+ {
+ rfCornerRadiusX = 0.0;
+ }
+ }
+
+ if(0.0 == rfCornerRadiusY)
+ return;
+
+ const double fHalfObjectHeight(rObjectRange.getHeight() * 0.5);
+
+ if(0.0 != fHalfObjectHeight)
+ {
+ if(rfCornerRadiusY < 0.0)
+ {
+ rfCornerRadiusY = 0.0;
+ }
+
+ if(rfCornerRadiusY > fHalfObjectHeight)
+ {
+ rfCornerRadiusY = fHalfObjectHeight;
+ }
+
+ rfCornerRadiusY /= fHalfObjectHeight;
+ }
+ else
+ {
+ rfCornerRadiusY = 0.0;
+ }
+ }
+
+ // #i101508# Support handing over given text-to-border distances
+ attribute::SdrFillTextAttribute createNewSdrFillTextAttribute(
+ const SfxItemSet& rSet,
+ const SdrText* pText,
+ const sal_Int32* pLeft,
+ const sal_Int32* pUpper,
+ const sal_Int32* pRight,
+ const sal_Int32* pLower)
+ {
+ attribute::SdrFillAttribute aFill;
+ attribute::FillGradientAttribute aFillFloatTransGradient;
+ attribute::SdrTextAttribute aText;
+ bool bFontworkHideContour(false);
+
+ // look for text first
+ if(pText)
+ {
+ aText = createNewSdrTextAttribute(rSet, *pText, pLeft, pUpper, pRight, pLower);
+
+ // when object has text and text is fontwork and hide contour is set for fontwork, force
+ // fill style to empty
+ if(!aText.getSdrFormTextAttribute().isDefault() && aText.isHideContour())
+ {
+ bFontworkHideContour = true;
+ }
+ }
+
+ if(!bFontworkHideContour)
+ {
+ // try fill style
+ aFill = createNewSdrFillAttribute(rSet);
+
+ if(!aFill.isDefault())
+ {
+ // try fillfloattransparence
+ aFillFloatTransGradient = createNewTransparenceGradientAttribute(rSet);
+ }
+ }
+
+ if(!aFill.isDefault() || !aText.isDefault())
+ {
+ return attribute::SdrFillTextAttribute(aFill, aFillFloatTransGradient, aText);
+ }
+
+ return attribute::SdrFillTextAttribute();
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrcaptionprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrcaptionprimitive2d.cxx
new file mode 100644
index 000000000..50787ed39
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrcaptionprimitive2d.cxx
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrcaptionprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ void SdrCaptionPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ Primitive2DContainer aRetval;
+
+ // create unit outline polygon
+ const basegfx::B2DPolygon aUnitOutline(basegfx::utils::createPolygonFromRect(
+ basegfx::B2DRange(0.0, 0.0, 1.0, 1.0),
+ getCornerRadiusX(),
+ getCornerRadiusY()));
+
+ // add fill
+ if(getSdrLFSTAttribute().getFill().isDefault())
+ {
+ // create invisible fill for HitTest
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ true,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform()));
+ }
+ else
+ {
+ basegfx::B2DPolyPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+
+ // add line
+ if(getSdrLFSTAttribute().getLine().isDefault())
+ {
+ // create invisible line for HitTest/BoundRect
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ false,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform()));
+
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ false,
+ basegfx::B2DPolyPolygon(getTail()),
+ {}));
+ }
+ else
+ {
+ basegfx::B2DPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getLine(),
+ attribute::SdrLineStartEndAttribute()));
+
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ getTail(),
+ getSdrLFSTAttribute().getLine(),
+ getSdrLFSTAttribute().getLineStartEnd()));
+ }
+
+ // add text
+ if(!getSdrLFSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(
+ createTextPrimitive(
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform(),
+ getSdrLFSTAttribute().getText(),
+ getSdrLFSTAttribute().getLine(),
+ false,
+ false));
+ }
+
+ // add shadow
+ if(!getSdrLFSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(std::move(aRetval), getSdrLFSTAttribute().getShadow());
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrCaptionPrimitive2D::SdrCaptionPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ const basegfx::B2DPolygon& rTail,
+ double fCornerRadiusX,
+ double fCornerRadiusY)
+ : maTransform(rTransform),
+ maSdrLFSTAttribute(rSdrLFSTAttribute),
+ maTail(rTail),
+ mfCornerRadiusX(fCornerRadiusX),
+ mfCornerRadiusY(fCornerRadiusY)
+ {
+ }
+
+ bool SdrCaptionPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrCaptionPrimitive2D& rCompare = static_cast<const SdrCaptionPrimitive2D&>(rPrimitive);
+
+ return (getCornerRadiusX() == rCompare.getCornerRadiusX()
+ && getCornerRadiusY() == rCompare.getCornerRadiusY()
+ && getTail() == rCompare.getTail()
+ && getTransform() == rCompare.getTransform()
+ && getSdrLFSTAttribute() == rCompare.getSdrLFSTAttribute());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrCaptionPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRCAPTIONPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrconnectorprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrconnectorprimitive2d.cxx
new file mode 100644
index 000000000..aa663fb7a
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrconnectorprimitive2d.cxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrconnectorprimitive2d.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ void SdrConnectorPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ Primitive2DContainer aRetval;
+
+ // add line
+ if(getSdrLSTAttribute().getLine().isDefault())
+ {
+ // create invisible line for HitTest/BoundRect
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ basegfx::B2DPolyPolygon(getUnitPolygon())));
+ }
+ else
+ {
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ getUnitPolygon(),
+ getSdrLSTAttribute().getLine(),
+ getSdrLSTAttribute().getLineStartEnd()));
+ }
+
+ // add text
+ if(!getSdrLSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(
+ createTextPrimitive(
+ basegfx::B2DPolyPolygon(getUnitPolygon()),
+ basegfx::B2DHomMatrix(),
+ getSdrLSTAttribute().getText(),
+ getSdrLSTAttribute().getLine(),
+ false,
+ false));
+ }
+
+ // add shadow
+ if(!getSdrLSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(
+ std::move(aRetval),
+ getSdrLSTAttribute().getShadow());
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrConnectorPrimitive2D::SdrConnectorPrimitive2D(
+ const attribute::SdrLineEffectsTextAttribute& rSdrLSTAttribute,
+ const ::basegfx::B2DPolygon& rUnitPolygon)
+ : maSdrLSTAttribute(rSdrLSTAttribute),
+ maUnitPolygon(rUnitPolygon)
+ {
+ }
+
+ bool SdrConnectorPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrConnectorPrimitive2D& rCompare = static_cast<const SdrConnectorPrimitive2D&>(rPrimitive);
+
+ return (getUnitPolygon() == rCompare.getUnitPolygon()
+ && getSdrLSTAttribute() == rCompare.getSdrLSTAttribute());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrConnectorPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRCONNECTORPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d.cxx
new file mode 100644
index 000000000..dddb8aa30
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrcustomshapeprimitive2d.cxx
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrcustomshapeprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/attribute/sdrlineattribute.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ void SdrCustomShapePrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ Primitive2DContainer aRetval(getSubPrimitives());
+
+ // Soft edges should be before text, since text is not affected by soft edges
+ if (!aRetval.empty() && getSdrSTAttribute().getSoftEdgeRadius())
+ {
+ aRetval = createEmbeddedSoftEdgePrimitive(std::move(aRetval),
+ getSdrSTAttribute().getSoftEdgeRadius());
+ }
+
+ // add text
+ if(!getSdrSTAttribute().getText().isDefault())
+ {
+ const basegfx::B2DPolygon& aUnitOutline(basegfx::utils::createUnitPolygon());
+
+ aRetval.push_back(
+ createTextPrimitive(
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTextBox(),
+ getSdrSTAttribute().getText(),
+ attribute::SdrLineAttribute(),
+ false,
+ getWordWrap()));
+ }
+
+ // tdf#132199: put glow before shadow, to have shadow of the glow, not the opposite
+ if (!aRetval.empty() && !getSdrSTAttribute().getGlow().isDefault())
+ {
+ // glow
+ aRetval = createEmbeddedGlowPrimitive(std::move(aRetval), getSdrSTAttribute().getGlow());
+ }
+
+ // add shadow
+ if(!aRetval.empty() && !getSdrSTAttribute().getShadow().isDefault())
+ {
+ // #i105323# add generic shadow only for 2D shapes. For
+ // 3D shapes shadow will be set at the individual created
+ // visualisation objects and be visualized by the 3d renderer
+ // as a single shadow.
+
+ // The shadow for AutoShapes could be handled uniformly by not setting any
+ // shadow items at the helper model objects and only adding shadow here for
+ // 2D and 3D (and it works, too), but this would lead to two 3D scenes for
+ // the 3D object; one for the shadow and one for the content. The one for the
+ // shadow will be correct (using ColorModifierStack), but expensive.
+ if(!get3DShape())
+ {
+ aRetval = createEmbeddedShadowPrimitive(std::move(aRetval), getSdrSTAttribute().getShadow(),
+ maTransform);
+ }
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrCustomShapePrimitive2D::SdrCustomShapePrimitive2D(
+ const attribute::SdrEffectsTextAttribute& rSdrSTAttribute,
+ Primitive2DContainer&& rSubPrimitives,
+ const basegfx::B2DHomMatrix& rTextBox,
+ bool bWordWrap,
+ bool b3DShape,
+ const basegfx::B2DHomMatrix& rTransform)
+ : maSdrSTAttribute(rSdrSTAttribute),
+ maSubPrimitives(std::move(rSubPrimitives)),
+ maTextBox(rTextBox),
+ mbWordWrap(bWordWrap),
+ mb3DShape(b3DShape),
+ maTransform(rTransform)
+ {
+ }
+
+ bool SdrCustomShapePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrCustomShapePrimitive2D& rCompare = static_cast<const SdrCustomShapePrimitive2D&>(rPrimitive);
+
+ return (getSdrSTAttribute() == rCompare.getSdrSTAttribute()
+ && getSubPrimitives() == rCompare.getSubPrimitives()
+ && getTextBox() == rCompare.getTextBox()
+ && getWordWrap() == rCompare.getWordWrap()
+ && get3DShape() == rCompare.get3DShape());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrCustomShapePrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRCUSTOMSHAPEPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
new file mode 100644
index 000000000..a1838b03f
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
@@ -0,0 +1,884 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <drawinglayer/primitive2d/baseprimitive2d.hxx>
+#include <drawinglayer/primitive2d/PolygonStrokeArrowPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonGradientPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonHatchPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonGraphicPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/softedgeprimitive2d.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
+#include <drawinglayer/attribute/strokeattribute.hxx>
+#include <drawinglayer/attribute/linestartendattribute.hxx>
+#include <drawinglayer/attribute/sdrfillgraphicattribute.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
+#include <sdr/attribute/sdrtextattribute.hxx>
+#include <drawinglayer/primitive2d/glowprimitive2d.hxx>
+#include <sdr/primitive2d/sdrtextprimitive2d.hxx>
+#include <svx/svdotext.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
+#include <drawinglayer/animation/animationtiming.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
+#include <drawinglayer/attribute/sdrfillattribute.hxx>
+#include <drawinglayer/attribute/sdrlineattribute.hxx>
+#include <drawinglayer/attribute/sdrlinestartendattribute.hxx>
+#include <drawinglayer/attribute/sdrshadowattribute.hxx>
+#include <drawinglayer/attribute/sdrglowattribute.hxx>
+#include <osl/diagnose.h>
+
+// for SlideBackgroundFillPrimitive2D
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/svdpage.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <sdr/contact/viewcontactofmasterpagedescriptor.hxx>
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+namespace
+{
+// See also: SdrTextObj::AdjustRectToTextDistance
+basegfx::B2DRange getTextAnchorRange(const attribute::SdrTextAttribute& rText,
+ const basegfx::B2DRange& rSnapRange)
+{
+ // Take vertical text orientation into account when deciding
+ // which dimension is its width, and which is its height
+ const OutlinerParaObject& rOutlinerParaObj = rText.getOutlinerParaObject();
+ const bool bVerticalWriting(rOutlinerParaObj.IsEffectivelyVertical());
+ const double fWidthForText = bVerticalWriting ? rSnapRange.getHeight() : rSnapRange.getWidth();
+ // create a range describing the wanted text position and size (aTextAnchorRange). This
+ // means to use the text distance values here
+ // If the margin is larger than the entire width of the text area, then limit the
+ // margin.
+ const double fTextLeftDistance
+ = std::min(static_cast<double>(rText.getTextLeftDistance()), fWidthForText);
+ const double nTextRightDistance
+ = std::min(static_cast<double>(rText.getTextRightDistance()), fWidthForText);
+ double fDistanceForTextL, fDistanceForTextT, fDistanceForTextR, fDistanceForTextB;
+ if (!bVerticalWriting)
+ {
+ fDistanceForTextL = fTextLeftDistance;
+ fDistanceForTextT = rText.getTextUpperDistance();
+ fDistanceForTextR = nTextRightDistance;
+ fDistanceForTextB = rText.getTextLowerDistance();
+ }
+ else if (rOutlinerParaObj.IsTopToBottom())
+ {
+ fDistanceForTextL = rText.getTextLowerDistance();
+ fDistanceForTextT = fTextLeftDistance;
+ fDistanceForTextR = rText.getTextUpperDistance();
+ fDistanceForTextB = nTextRightDistance;
+ }
+ else
+ {
+ fDistanceForTextL = rText.getTextUpperDistance();
+ fDistanceForTextT = nTextRightDistance;
+ fDistanceForTextR = rText.getTextLowerDistance();
+ fDistanceForTextB = fTextLeftDistance;
+ }
+ const basegfx::B2DPoint aTopLeft(rSnapRange.getMinX() + fDistanceForTextL,
+ rSnapRange.getMinY() + fDistanceForTextT);
+ const basegfx::B2DPoint aBottomRight(rSnapRange.getMaxX() - fDistanceForTextR,
+ rSnapRange.getMaxY() - fDistanceForTextB);
+ basegfx::B2DRange aAnchorRange;
+ aAnchorRange.expand(aTopLeft);
+ aAnchorRange.expand(aBottomRight);
+
+ // If the shape has no width, then don't attempt to break the text into multiple
+ // lines, not a single character would satisfy a zero width requirement.
+ // SdrTextObj::impDecomposeBlockTextPrimitive() uses the same constant to
+ // effectively set no limits.
+ if (!bVerticalWriting && aAnchorRange.getWidth() == 0)
+ {
+ aAnchorRange.expand(basegfx::B2DPoint(aTopLeft.getX() - 1000000, aTopLeft.getY()));
+ aAnchorRange.expand(basegfx::B2DPoint(aBottomRight.getX() + 1000000, aBottomRight.getY()));
+ }
+ else if (bVerticalWriting && aAnchorRange.getHeight() == 0)
+ {
+ aAnchorRange.expand(basegfx::B2DPoint(aTopLeft.getX(), aTopLeft.getY() - 1000000));
+ aAnchorRange.expand(basegfx::B2DPoint(aBottomRight.getX(), aBottomRight.getY() + 1000000));
+ }
+ return aAnchorRange;
+}
+
+drawinglayer::attribute::SdrFillAttribute getMasterPageFillAttribute(
+ const geometry::ViewInformation2D& rViewInformation,
+ basegfx::B2DVector& rPageSize)
+{
+ drawinglayer::attribute::SdrFillAttribute aRetval;
+
+ // get SdrPage
+ const SdrPage* pVisualizedPage(GetSdrPageFromXDrawPage(rViewInformation.getVisualizedPage()));
+
+ if(nullptr != pVisualizedPage)
+ {
+ // copy needed values for further processing
+ rPageSize.setX(pVisualizedPage->GetWidth());
+ rPageSize.setY(pVisualizedPage->GetHeight());
+
+ if(pVisualizedPage->IsMasterPage())
+ {
+ // the page is a MasterPage, so we are in MasterPage view
+ // still need #i110846#, see ViewContactOfMasterPage
+ if(pVisualizedPage->getSdrPageProperties().GetStyleSheet())
+ {
+ // create page fill attributes with correct properties
+ aRetval = drawinglayer::primitive2d::createNewSdrFillAttribute(
+ pVisualizedPage->getSdrPageProperties().GetItemSet());
+ }
+ }
+ else
+ {
+ // the page is *no* MasterPage, we are in normal Page view, get the MasterPage
+ if(pVisualizedPage->TRG_HasMasterPage())
+ {
+ sdr::contact::ViewContact& rVC(pVisualizedPage->TRG_GetMasterPageDescriptorViewContact());
+ sdr::contact::ViewContactOfMasterPageDescriptor* pVCOMPD(
+ dynamic_cast<sdr::contact::ViewContactOfMasterPageDescriptor*>(&rVC));
+
+ if(nullptr != pVCOMPD)
+ {
+ // in this case the still needed #i110846# is part of
+ // getCorrectSdrPageProperties, that's the main reason to re-use
+ // that call/functionality here
+ const SdrPageProperties* pCorrectProperties(
+ pVCOMPD->GetMasterPageDescriptor().getCorrectSdrPageProperties());
+
+ if(pCorrectProperties)
+ {
+ // create page fill attributes when correct properties were identified
+ aRetval = drawinglayer::primitive2d::createNewSdrFillAttribute(
+ pCorrectProperties->GetItemSet());
+ }
+ }
+ }
+ }
+ }
+
+ return aRetval;
+}
+
+// provide a Primitive2D for the SlideBackgroundFill-mode. It is capable
+// of expressing that state of fill and it's decomposition implements all
+// needed preparation of the geometry in an isolated and controllable
+// space and way.
+// It is currently simple buffered (due to being derived from
+// BufferedDecompositionPrimitive2D) and detects if FillStyle changes
+class SlideBackgroundFillPrimitive2D final : public BufferedDecompositionPrimitive2D
+{
+private:
+ /// the basegfx::B2DPolyPolygon geometry
+ basegfx::B2DPolyPolygon maPolyPolygon;
+
+ /// the last SdrFillAttribute the geometry was created for
+ drawinglayer::attribute::SdrFillAttribute maLastFill;
+
+protected:
+ // create decomposition data
+ virtual void create2DDecomposition(
+ Primitive2DContainer& rContainer,
+ const geometry::ViewInformation2D& rViewInformation) const override;
+
+public:
+ /// constructor
+ SlideBackgroundFillPrimitive2D(
+ const basegfx::B2DPolyPolygon& rPolyPolygon);
+
+ /// check existing decomposition data, call parent
+ virtual void get2DDecomposition(
+ Primitive2DDecompositionVisitor& rVisitor,
+ const geometry::ViewInformation2D& rViewInformation) const override;
+
+ /// data read access
+ const basegfx::B2DPolyPolygon& getB2DPolyPolygon() const { return maPolyPolygon; }
+
+ /// compare operator
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ /// get range
+ virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override;
+
+ /// provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+};
+
+SlideBackgroundFillPrimitive2D::SlideBackgroundFillPrimitive2D(
+ const basegfx::B2DPolyPolygon& rPolyPolygon)
+: BufferedDecompositionPrimitive2D()
+, maPolyPolygon(rPolyPolygon)
+, maLastFill()
+{
+}
+
+void SlideBackgroundFillPrimitive2D::create2DDecomposition(
+ Primitive2DContainer& rContainer,
+ const geometry::ViewInformation2D& rViewInformation) const
+{
+ basegfx::B2DVector aPageSize;
+
+ // get fill from target Page, this will check for all needed things
+ // like MasterPage/relationships, etc. (see getMasterPageFillAttribute impl above)
+ drawinglayer::attribute::SdrFillAttribute aFill(
+ getMasterPageFillAttribute(rViewInformation, aPageSize));
+
+ // if fill is on default (empty), nothing will be shown, we are done
+ if(aFill.isDefault())
+ return;
+
+ // Get PolygonRange of own local geometry
+ const basegfx::B2DRange aPolygonRange(getB2DPolyPolygon().getB2DRange());
+
+ // if local geometry is empty, nothing will be shown, we are done
+ if(aPolygonRange.isEmpty())
+ return;
+
+ // Get PageRange
+ const basegfx::B2DRange aPageRange(0.0, 0.0, aPageSize.getX(), aPageSize.getY());
+
+ // if local geometry does not overlap with PageRange, nothing will be shown, we are done
+ if(!aPageRange.overlaps(aPolygonRange))
+ return;
+
+ // create FillPrimitive2D with the geometry (the PolyPolygon) and
+ // the page's definitonRange to:
+ // - on one hand limit to geometry
+ // - on the other hand allow continutation of fill outside of
+ // MasterPage's range
+ const attribute::FillGradientAttribute aEmptyFillTransparenceGradient;
+ const Primitive2DReference aCreatedFill(
+ createPolyPolygonFillPrimitive(
+ getB2DPolyPolygon(), // geometry
+ aPageRange, // definition range
+ aFill,
+ aEmptyFillTransparenceGradient));
+
+ rContainer = Primitive2DContainer { aCreatedFill };
+}
+
+void SlideBackgroundFillPrimitive2D::get2DDecomposition(
+ Primitive2DDecompositionVisitor& rVisitor,
+ const geometry::ViewInformation2D& rViewInformation) const
+{
+ basegfx::B2DVector aPageSize;
+ drawinglayer::attribute::SdrFillAttribute aFill;
+
+ if(!getBuffered2DDecomposition().empty())
+ {
+ aFill = getMasterPageFillAttribute(rViewInformation, aPageSize);
+
+ if(!(aFill == maLastFill))
+ {
+ // conditions of last local decomposition have changed, delete
+ const_cast< SlideBackgroundFillPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DContainer());
+ }
+ }
+
+ if(getBuffered2DDecomposition().empty())
+ {
+ // remember last Fill
+ const_cast< SlideBackgroundFillPrimitive2D* >(this)->maLastFill = aFill;
+ }
+
+ // use parent implementation
+ BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
+}
+
+bool SlideBackgroundFillPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+{
+ if (BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SlideBackgroundFillPrimitive2D& rCompare
+ = static_cast<const SlideBackgroundFillPrimitive2D&>(rPrimitive);
+
+ return getB2DPolyPolygon() == rCompare.getB2DPolyPolygon();
+ }
+
+ return false;
+}
+
+basegfx::B2DRange SlideBackgroundFillPrimitive2D::getB2DRange(
+ const geometry::ViewInformation2D& /*rViewInformation*/) const
+{
+ // return range
+ return basegfx::utils::getRange(getB2DPolyPolygon());
+}
+
+// provide unique ID
+sal_uInt32 SlideBackgroundFillPrimitive2D::getPrimitive2DID() const
+{
+ return PRIMITIVE2D_ID_SLIDEBACKGROUNDFILLPRIMITIVE2D;
+}
+
+}; // end of anonymous namespace
+
+ class TransparencePrimitive2D;
+
+ Primitive2DReference createPolyPolygonFillPrimitive(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const attribute::SdrFillAttribute& rFill,
+ const attribute::FillGradientAttribute& rFillGradient)
+ {
+ // when we have no given definition range, use the range of the given geometry
+ // also for definition (simplest case)
+ const basegfx::B2DRange aRange(basegfx::utils::getRange(rPolyPolygon));
+
+ return createPolyPolygonFillPrimitive(
+ rPolyPolygon,
+ aRange,
+ rFill,
+ rFillGradient);
+ }
+
+ Primitive2DReference createPolyPolygonFillPrimitive(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ const basegfx::B2DRange& rDefinitionRange,
+ const attribute::SdrFillAttribute& rFill,
+ const attribute::FillGradientAttribute& rFillGradient)
+ {
+ if(basegfx::fTools::moreOrEqual(rFill.getTransparence(), 1.0))
+ {
+ return Primitive2DReference();
+ }
+
+ // prepare fully scaled polygon
+ rtl::Reference<BasePrimitive2D> pNewFillPrimitive;
+
+ if(!rFill.getGradient().isDefault())
+ {
+ pNewFillPrimitive = new PolyPolygonGradientPrimitive2D(
+ rPolyPolygon,
+ rDefinitionRange,
+ rFill.getGradient());
+ }
+ else if(!rFill.getHatch().isDefault())
+ {
+ pNewFillPrimitive = new PolyPolygonHatchPrimitive2D(
+ rPolyPolygon,
+ rDefinitionRange,
+ rFill.getColor(),
+ rFill.getHatch());
+ }
+ else if(!rFill.getFillGraphic().isDefault())
+ {
+ pNewFillPrimitive = new PolyPolygonGraphicPrimitive2D(
+ rPolyPolygon,
+ rDefinitionRange,
+ rFill.getFillGraphic().createFillGraphicAttribute(rDefinitionRange));
+ }
+ else if(rFill.isSlideBackgroundFill())
+ {
+ // create needed Primitive2D representation for
+ // SlideBackgroundFill-mode
+ pNewFillPrimitive = new SlideBackgroundFillPrimitive2D(
+ rPolyPolygon);
+ }
+ else
+ {
+ pNewFillPrimitive = new PolyPolygonColorPrimitive2D(
+ rPolyPolygon,
+ rFill.getColor());
+ }
+
+ if(0.0 != rFill.getTransparence())
+ {
+ // create simpleTransparencePrimitive, add created fill primitive
+ Primitive2DContainer aContent { pNewFillPrimitive };
+ return Primitive2DReference(new UnifiedTransparencePrimitive2D(std::move(aContent), rFill.getTransparence()));
+ }
+ else if(!rFillGradient.isDefault())
+ {
+ // create sequence with created fill primitive
+ Primitive2DContainer aContent { pNewFillPrimitive };
+
+ // create FillGradientPrimitive2D for transparence and add to new sequence
+ // fillGradientPrimitive is enough here (compared to PolyPolygonGradientPrimitive2D) since float transparence will be masked anyways
+ const basegfx::B2DRange aRange(basegfx::utils::getRange(rPolyPolygon));
+ Primitive2DReference xRefB(
+ new FillGradientPrimitive2D(
+ aRange,
+ rDefinitionRange,
+ rFillGradient));
+ Primitive2DContainer aAlpha { xRefB };
+
+ // create TransparencePrimitive2D using alpha and content
+ return Primitive2DReference(new TransparencePrimitive2D(std::move(aContent), std::move(aAlpha)));
+ }
+ else
+ {
+ // add to decomposition
+ return pNewFillPrimitive;
+ }
+ }
+
+ Primitive2DReference createPolygonLinePrimitive(
+ const basegfx::B2DPolygon& rPolygon,
+ const attribute::SdrLineAttribute& rLine,
+ const attribute::SdrLineStartEndAttribute& rStroke)
+ {
+ // create line and stroke attribute
+ const attribute::LineAttribute aLineAttribute(rLine.getColor(), rLine.getWidth(), rLine.getJoin(), rLine.getCap());
+ const attribute::StrokeAttribute aStrokeAttribute(std::vector(rLine.getDotDashArray()), rLine.getFullDotDashLen());
+ rtl::Reference<BasePrimitive2D> pNewLinePrimitive;
+
+ if(!rPolygon.isClosed() && !rStroke.isDefault())
+ {
+ attribute::LineStartEndAttribute aStart(rStroke.getStartWidth(), rStroke.getStartPolyPolygon(), rStroke.isStartCentered());
+ attribute::LineStartEndAttribute aEnd(rStroke.getEndWidth(), rStroke.getEndPolyPolygon(), rStroke.isEndCentered());
+
+ // create data
+ pNewLinePrimitive = new PolygonStrokeArrowPrimitive2D(rPolygon, aLineAttribute, aStrokeAttribute, aStart, aEnd);
+ }
+ else
+ {
+ // create data
+ pNewLinePrimitive = new PolygonStrokePrimitive2D(rPolygon, aLineAttribute, aStrokeAttribute);
+ }
+
+ if(0.0 != rLine.getTransparence())
+ {
+ // create simpleTransparencePrimitive, add created fill primitive
+ Primitive2DContainer aContent { pNewLinePrimitive };
+ return Primitive2DReference(new UnifiedTransparencePrimitive2D(std::move(aContent), rLine.getTransparence()));
+ }
+ else
+ {
+ // add to decomposition
+ return pNewLinePrimitive;
+ }
+ }
+
+ Primitive2DReference createTextPrimitive(
+ const basegfx::B2DPolyPolygon& rUnitPolyPolygon,
+ const basegfx::B2DHomMatrix& rObjectTransform,
+ const attribute::SdrTextAttribute& rText,
+ const attribute::SdrLineAttribute& rStroke,
+ bool bCellText,
+ bool bWordWrap)
+ {
+ basegfx::B2DHomMatrix aAnchorTransform(rObjectTransform);
+ rtl::Reference<SdrTextPrimitive2D> pNew;
+
+ if(rText.isContour())
+ {
+ // contour text
+ if(!rStroke.isDefault() && 0.0 != rStroke.getWidth())
+ {
+ // take line width into account and shrink contour polygon accordingly
+ // decompose to get scale
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // scale outline to object's size to allow growing with value relative to that size
+ // and also to keep aspect ratio
+ basegfx::B2DPolyPolygon aScaledUnitPolyPolygon(rUnitPolyPolygon);
+ aScaledUnitPolyPolygon.transform(basegfx::utils::createScaleB2DHomMatrix(
+ fabs(aScale.getX()), fabs(aScale.getY())));
+
+ // grow the polygon. To shrink, use negative value (half width)
+ aScaledUnitPolyPolygon = basegfx::utils::growInNormalDirection(aScaledUnitPolyPolygon, -(rStroke.getWidth() * 0.5));
+
+ // scale back to unit polygon
+ aScaledUnitPolyPolygon.transform(basegfx::utils::createScaleB2DHomMatrix(
+ 0.0 != aScale.getX() ? 1.0 / aScale.getX() : 1.0,
+ 0.0 != aScale.getY() ? 1.0 / aScale.getY() : 1.0));
+
+ // create with unit polygon
+ pNew = new SdrContourTextPrimitive2D(
+ &rText.getSdrText(),
+ rText.getOutlinerParaObject(),
+ aScaledUnitPolyPolygon,
+ rObjectTransform);
+ }
+ else
+ {
+ // create with unit polygon
+ pNew = new SdrContourTextPrimitive2D(
+ &rText.getSdrText(),
+ rText.getOutlinerParaObject(),
+ rUnitPolyPolygon,
+ rObjectTransform);
+ }
+ }
+ else if(!rText.getSdrFormTextAttribute().isDefault())
+ {
+ // text on path, use scaled polygon
+ basegfx::B2DPolyPolygon aScaledPolyPolygon(rUnitPolyPolygon);
+ aScaledPolyPolygon.transform(rObjectTransform);
+ pNew = new SdrPathTextPrimitive2D(
+ &rText.getSdrText(),
+ rText.getOutlinerParaObject(),
+ aScaledPolyPolygon,
+ rText.getSdrFormTextAttribute());
+ }
+ else
+ {
+ // rObjectTransform is the whole SdrObject transformation from unit rectangle
+ // to its size and position. Decompose to allow working with single values.
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // extract mirroring
+ const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
+ const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
+ aScale = basegfx::absolute(aScale);
+
+ // Get the real size, since polygon outline and scale
+ // from the object transformation may vary (e.g. ellipse segments)
+ basegfx::B2DHomMatrix aJustScaleTransform;
+ aJustScaleTransform.set(0, 0, aScale.getX());
+ aJustScaleTransform.set(1, 1, aScale.getY());
+ basegfx::B2DPolyPolygon aScaledUnitPolyPolygon(rUnitPolyPolygon);
+ aScaledUnitPolyPolygon.transform(aJustScaleTransform);
+ const basegfx::B2DRange aTextAnchorRange
+ = getTextAnchorRange(rText, basegfx::utils::getRange(aScaledUnitPolyPolygon));
+
+ // now create a transformation from this basic range (aTextAnchorRange)
+ // #i121494# if we have no scale use at least 1.0 to have a carrier e.g. for
+ // mirror values, else these will get lost
+ aAnchorTransform = basegfx::utils::createScaleTranslateB2DHomMatrix(
+ basegfx::fTools::equalZero(aTextAnchorRange.getWidth()) ? 1.0 : aTextAnchorRange.getWidth(),
+ basegfx::fTools::equalZero(aTextAnchorRange.getHeight()) ? 1.0 : aTextAnchorRange.getHeight(),
+ aTextAnchorRange.getMinX(), aTextAnchorRange.getMinY());
+
+ // apply mirroring
+ aAnchorTransform.scale(bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0);
+
+ // apply object's other transforms
+ aAnchorTransform = basegfx::utils::createShearXRotateTranslateB2DHomMatrix(fShearX, fRotate, aTranslate)
+ * aAnchorTransform;
+
+ if(rText.isFitToSize())
+ {
+ // stretched text in range
+ pNew = new SdrStretchTextPrimitive2D(
+ &rText.getSdrText(),
+ rText.getOutlinerParaObject(),
+ aAnchorTransform,
+ rText.isFixedCellHeight());
+ }
+ else if(rText.isAutoFit())
+ {
+ // isotropically scaled text in range
+ pNew = new SdrAutoFitTextPrimitive2D(
+ &rText.getSdrText(),
+ rText.getOutlinerParaObject(),
+ aAnchorTransform,
+ bWordWrap);
+ }
+ else if( rText.isChainable() && !rText.isInEditMode() )
+ {
+ pNew = new SdrChainedTextPrimitive2D(
+ &rText.getSdrText(),
+ rText.getOutlinerParaObject(),
+ aAnchorTransform );
+ }
+ else // text in range
+ {
+ // build new primitive
+ pNew = new SdrBlockTextPrimitive2D(
+ &rText.getSdrText(),
+ rText.getOutlinerParaObject(),
+ aAnchorTransform,
+ rText.getSdrTextHorzAdjust(),
+ rText.getSdrTextVertAdjust(),
+ rText.isFixedCellHeight(),
+ rText.isScroll(),
+ bCellText,
+ bWordWrap);
+ }
+ }
+
+ OSL_ENSURE(pNew != nullptr, "createTextPrimitive: no text primitive created (!)");
+
+ if(rText.isBlink())
+ {
+ // prepare animation and primitive list
+ drawinglayer::animation::AnimationEntryList aAnimationList;
+ rText.getBlinkTextTiming(aAnimationList);
+
+ if(0.0 != aAnimationList.getDuration())
+ {
+ // create content sequence
+ Primitive2DReference xRefA(pNew);
+ Primitive2DContainer aContent { xRefA };
+
+ // create and add animated switch primitive
+ return Primitive2DReference(new AnimatedBlinkPrimitive2D(aAnimationList, std::move(aContent)));
+ }
+ else
+ {
+ // add to decomposition
+ return Primitive2DReference(pNew);
+ }
+ }
+
+ if(rText.isScroll())
+ {
+ // suppress scroll when FontWork
+ if(rText.getSdrFormTextAttribute().isDefault())
+ {
+ // get scroll direction
+ const SdrTextAniDirection eDirection(rText.getSdrText().GetObject().GetTextAniDirection());
+ const bool bHorizontal(SdrTextAniDirection::Left == eDirection || SdrTextAniDirection::Right == eDirection);
+
+ // decompose to get separated values for the scroll box
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ aAnchorTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // build transform from scaled only to full AnchorTransform and inverse
+ const basegfx::B2DHomMatrix aSRT(basegfx::utils::createShearXRotateTranslateB2DHomMatrix(
+ fShearX, fRotate, aTranslate));
+ basegfx::B2DHomMatrix aISRT(aSRT);
+ aISRT.invert();
+
+ // bring the primitive back to scaled only and get scaled range, create new clone for this
+ rtl::Reference<SdrTextPrimitive2D> pNew2 = pNew->createTransformedClone(aISRT);
+ OSL_ENSURE(pNew2, "createTextPrimitive: Could not create transformed clone of text primitive (!)");
+ pNew = pNew2.get();
+
+ // create neutral geometry::ViewInformation2D for local range and decompose calls. This is okay
+ // since the decompose is view-independent
+ geometry::ViewInformation2D aViewInformation2D;
+
+ // get range
+ const basegfx::B2DRange aScaledRange(pNew->getB2DRange(aViewInformation2D));
+
+ // create left outside and right outside transformations. Also take care
+ // of the clip rectangle
+ basegfx::B2DHomMatrix aLeft, aRight;
+ basegfx::B2DPoint aClipTopLeft(0.0, 0.0);
+ basegfx::B2DPoint aClipBottomRight(aScale.getX(), aScale.getY());
+
+ if(bHorizontal)
+ {
+ aClipTopLeft.setY(aScaledRange.getMinY());
+ aClipBottomRight.setY(aScaledRange.getMaxY());
+ aLeft.translate(-aScaledRange.getMaxX(), 0.0);
+ aRight.translate(aScale.getX() - aScaledRange.getMinX(), 0.0);
+ }
+ else
+ {
+ aClipTopLeft.setX(aScaledRange.getMinX());
+ aClipBottomRight.setX(aScaledRange.getMaxX());
+ aLeft.translate(0.0, -aScaledRange.getMaxY());
+ aRight.translate(0.0, aScale.getY() - aScaledRange.getMinY());
+ }
+
+ aLeft *= aSRT;
+ aRight *= aSRT;
+
+ // prepare animation list
+ drawinglayer::animation::AnimationEntryList aAnimationList;
+
+ if(bHorizontal)
+ {
+ rText.getScrollTextTiming(aAnimationList, aScale.getX(), aScaledRange.getWidth());
+ }
+ else
+ {
+ rText.getScrollTextTiming(aAnimationList, aScale.getY(), aScaledRange.getHeight());
+ }
+
+ if(0.0 != aAnimationList.getDuration())
+ {
+ // create a new Primitive2DContainer containing the animated text in its scaled only state.
+ // use the decomposition to force to simple text primitives, those will no longer
+ // need the outliner for formatting (alternatively it is also possible to just add
+ // pNew to aNewPrimitiveSequence)
+ Primitive2DContainer aAnimSequence;
+ pNew->get2DDecomposition(aAnimSequence, aViewInformation2D);
+ pNew.clear();
+
+ // create a new animatedInterpolatePrimitive and add it
+ Primitive2DReference xRefA(new AnimatedInterpolatePrimitive2D({ aLeft, aRight }, aAnimationList, std::move(aAnimSequence)));
+ Primitive2DContainer aContent { xRefA };
+
+ // scrolling needs an encapsulating clipping primitive
+ const basegfx::B2DRange aClipRange(aClipTopLeft, aClipBottomRight);
+ basegfx::B2DPolygon aClipPolygon(basegfx::utils::createPolygonFromRect(aClipRange));
+ aClipPolygon.transform(aSRT);
+ return Primitive2DReference(new MaskPrimitive2D(basegfx::B2DPolyPolygon(aClipPolygon), std::move(aContent)));
+ }
+ else
+ {
+ // add to decomposition
+ return Primitive2DReference(pNew);
+ }
+ }
+ }
+
+ if(rText.isInEditMode())
+ {
+ // #i97628#
+ // encapsulate with TextHierarchyEditPrimitive2D to allow renderers
+ // to suppress actively edited content if needed
+ Primitive2DReference xRefA(pNew);
+ Primitive2DContainer aContent { xRefA };
+
+ // create and add TextHierarchyEditPrimitive2D primitive
+ return Primitive2DReference(new TextHierarchyEditPrimitive2D(std::move(aContent)));
+ }
+ else
+ {
+ // add to decomposition
+ return pNew;
+ }
+ }
+
+ Primitive2DContainer createEmbeddedShadowPrimitive(
+ Primitive2DContainer&& rContent,
+ const attribute::SdrShadowAttribute& rShadow,
+ const basegfx::B2DHomMatrix& rObjectMatrix,
+ const Primitive2DContainer* pContentForShadow)
+ {
+ if(rContent.empty())
+ return std::move(rContent);
+
+ basegfx::B2DHomMatrix aShadowOffset;
+
+ if(rShadow.getSize().getX() != 100000)
+ {
+ basegfx::B2DTuple aScale;
+ basegfx::B2DTuple aTranslate;
+ double fRotate = 0;
+ double fShearX = 0;
+ rObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+ // Scale the shadow
+ double nTranslateX = aTranslate.getX();
+ double nTranslateY = aTranslate.getY();
+
+ // The origin for scaling is the top left corner by default. A negative
+ // shadow offset changes the origin.
+ if (rShadow.getOffset().getX() < 0)
+ nTranslateX += aScale.getX();
+ if (rShadow.getOffset().getY() < 0)
+ nTranslateY += aScale.getY();
+
+ aShadowOffset.translate(-nTranslateX, -nTranslateY);
+ aShadowOffset.scale(rShadow.getSize().getX() * 0.00001, rShadow.getSize().getY() * 0.00001);
+ aShadowOffset.translate(nTranslateX, nTranslateY);
+ }
+
+ aShadowOffset.translate(rShadow.getOffset().getX(), rShadow.getOffset().getY());
+
+ // create shadow primitive and add content
+ const Primitive2DContainer& rContentForShadow
+ = pContentForShadow ? *pContentForShadow : rContent;
+ int nContentWithTransparence = std::count_if(
+ rContentForShadow.begin(), rContentForShadow.end(),
+ [](const Primitive2DReference& xChild) {
+ auto pChild = dynamic_cast<BufferedDecompositionPrimitive2D*>(xChild.get());
+ return pChild && pChild->getTransparenceForShadow() != 0;
+ });
+ if (nContentWithTransparence == 0)
+ {
+ Primitive2DContainer aRetval(2);
+ aRetval[0] = Primitive2DReference(
+ new ShadowPrimitive2D(
+ aShadowOffset,
+ rShadow.getColor(),
+ rShadow.getBlur(),
+ Primitive2DContainer(pContentForShadow ? *pContentForShadow : rContent)));
+
+ if (0.0 != rShadow.getTransparence())
+ {
+ // create SimpleTransparencePrimitive2D
+ Primitive2DContainer aTempContent{ aRetval[0] };
+
+ aRetval[0] = Primitive2DReference(
+ new UnifiedTransparencePrimitive2D(
+ std::move(aTempContent),
+ rShadow.getTransparence()));
+ }
+
+ aRetval[1] = Primitive2DReference(new GroupPrimitive2D(std::move(rContent)));
+ return aRetval;
+ }
+
+ Primitive2DContainer aRetval;
+ for (const auto& xChild : rContentForShadow)
+ {
+ double fChildTransparence = 0.0;
+ auto pChild = dynamic_cast<BufferedDecompositionPrimitive2D*>(xChild.get());
+ if (pChild)
+ {
+ fChildTransparence = pChild->getTransparenceForShadow();
+ fChildTransparence /= 100;
+ }
+ aRetval.push_back(Primitive2DReference(
+ new ShadowPrimitive2D(aShadowOffset, rShadow.getColor(), rShadow.getBlur(),
+ Primitive2DContainer({ xChild }))));
+ if (rShadow.getTransparence() != 0.0 || fChildTransparence != 0.0)
+ {
+ Primitive2DContainer aTempContent{ aRetval.back() };
+
+ double fChildAlpha = 1.0 - fChildTransparence;
+ double fShadowAlpha = 1.0 - rShadow.getTransparence();
+ double fTransparence = 1.0 - fChildAlpha * fShadowAlpha;
+ aRetval.back() = Primitive2DReference(new UnifiedTransparencePrimitive2D(
+ std::move(aTempContent), fTransparence));
+ }
+ }
+
+ aRetval.push_back(
+ Primitive2DReference(new GroupPrimitive2D(std::move(rContent))));
+ return aRetval;
+ }
+
+ Primitive2DContainer createEmbeddedGlowPrimitive(
+ Primitive2DContainer&& rContent,
+ const attribute::SdrGlowAttribute& rGlow)
+ {
+ if(rContent.empty())
+ return std::move(rContent);
+ Primitive2DContainer aRetval(2);
+ aRetval[0] = Primitive2DReference(
+ new GlowPrimitive2D(rGlow.getColor(), rGlow.getRadius(), Primitive2DContainer(rContent)));
+ aRetval[1] = Primitive2DReference(new GroupPrimitive2D(Primitive2DContainer(rContent)));
+ return aRetval;
+ }
+
+ Primitive2DContainer createEmbeddedSoftEdgePrimitive(Primitive2DContainer&& aContent,
+ sal_Int32 nRadius)
+ {
+ if (aContent.empty() || !nRadius)
+ return std::move(aContent);
+ Primitive2DContainer aRetval(1);
+ aRetval[0] = Primitive2DReference(new SoftEdgePrimitive2D(nRadius, std::move(aContent)));
+ return aRetval;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrellipseprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrellipseprimitive2d.cxx
new file mode 100644
index 000000000..89c348beb
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrellipseprimitive2d.cxx
@@ -0,0 +1,266 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrellipseprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ void SdrEllipsePrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ Primitive2DContainer aRetval;
+
+ // create unit outline polygon
+ // Do use createPolygonFromUnitCircle, but let create from first quadrant to mimic old geometry creation.
+ // This is needed to have the same look when stroke is used since the polygon start point defines the
+ // stroke start, too.
+ basegfx::B2DPolygon aUnitOutline(basegfx::utils::createPolygonFromUnitCircle(1));
+
+ // scale and move UnitEllipse to UnitObject (-1,-1 1,1) -> (0,0 1,1)
+ const basegfx::B2DHomMatrix aUnitCorrectionMatrix(
+ basegfx::utils::createScaleTranslateB2DHomMatrix(0.5, 0.5, 0.5, 0.5));
+
+ // apply to the geometry
+ aUnitOutline.transform(aUnitCorrectionMatrix);
+
+ // add fill
+ if(!getSdrLFSTAttribute().getFill().isDefault())
+ {
+ basegfx::B2DPolyPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+
+ // add line
+ if(getSdrLFSTAttribute().getLine().isDefault())
+ {
+ // create invisible line for HitTest/BoundRect
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ false,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform()));
+ }
+ else
+ {
+ basegfx::B2DPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getLine(),
+ attribute::SdrLineStartEndAttribute()));
+ }
+
+ // add text
+ if(!getSdrLFSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(
+ createTextPrimitive(
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform(),
+ getSdrLFSTAttribute().getText(),
+ getSdrLFSTAttribute().getLine(),
+ false,
+ false));
+ }
+
+ // add shadow
+ if(!getSdrLFSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(
+ std::move(aRetval),
+ getSdrLFSTAttribute().getShadow());
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrEllipsePrimitive2D::SdrEllipsePrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute)
+ : maTransform(rTransform),
+ maSdrLFSTAttribute(rSdrLFSTAttribute)
+ {
+ }
+
+ bool SdrEllipsePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrEllipsePrimitive2D& rCompare = static_cast<const SdrEllipsePrimitive2D&>(rPrimitive);
+
+ return (getTransform() == rCompare.getTransform()
+ && getSdrLFSTAttribute() == rCompare.getSdrLFSTAttribute());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrEllipsePrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRELLIPSEPRIMITIVE2D;
+ }
+
+
+
+ void SdrEllipseSegmentPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ Primitive2DContainer aRetval;
+
+ // create unit outline polygon
+ basegfx::B2DPolygon aUnitOutline(basegfx::utils::createPolygonFromUnitEllipseSegment(mfStartAngle, mfEndAngle));
+
+ if(mbCloseSegment)
+ {
+ if(mbCloseUsingCenter)
+ {
+ // for compatibility, insert the center point at polygon start to get the same
+ // line stroking pattern as the old painting mechanisms.
+ aUnitOutline.insert(0, basegfx::B2DPoint(0.0, 0.0));
+ }
+
+ aUnitOutline.setClosed(true);
+ }
+
+ // move and scale UnitEllipse to UnitObject (-1,-1 1,1) -> (0,0 1,1)
+ const basegfx::B2DHomMatrix aUnitCorrectionMatrix(
+ basegfx::utils::createScaleTranslateB2DHomMatrix(0.5, 0.5, 0.5, 0.5));
+
+ // apply to the geometry
+ aUnitOutline.transform(aUnitCorrectionMatrix);
+
+ // add fill
+ if(!getSdrLFSTAttribute().getFill().isDefault() && aUnitOutline.isClosed())
+ {
+ basegfx::B2DPolyPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+
+ // add line
+ if(getSdrLFSTAttribute().getLine().isDefault())
+ {
+ // create invisible line for HitTest/BoundRect
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ false,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform()));
+ }
+ else
+ {
+ basegfx::B2DPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getLine(),
+ getSdrLFSTAttribute().getLineStartEnd()));
+ }
+
+ // add text
+ if(!getSdrLFSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(
+ createTextPrimitive(
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform(),
+ getSdrLFSTAttribute().getText(),
+ getSdrLFSTAttribute().getLine(),
+ false,
+ false));
+ }
+
+ // add shadow
+ if(!getSdrLFSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(
+ std::move(aRetval),
+ getSdrLFSTAttribute().getShadow());
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrEllipseSegmentPrimitive2D::SdrEllipseSegmentPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ double fStartAngle,
+ double fEndAngle,
+ bool bCloseSegment,
+ bool bCloseUsingCenter)
+ : SdrEllipsePrimitive2D(rTransform, rSdrLFSTAttribute),
+ mfStartAngle(fStartAngle),
+ mfEndAngle(fEndAngle),
+ mbCloseSegment(bCloseSegment),
+ mbCloseUsingCenter(bCloseUsingCenter)
+ {
+ }
+
+ bool SdrEllipseSegmentPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(SdrEllipsePrimitive2D::operator==(rPrimitive))
+ {
+ const SdrEllipseSegmentPrimitive2D& rCompare = static_cast<const SdrEllipseSegmentPrimitive2D&>(rPrimitive);
+
+ if( mfStartAngle == rCompare.mfStartAngle
+ && mfEndAngle == rCompare.mfEndAngle
+ && mbCloseSegment == rCompare.mbCloseSegment
+ && mbCloseUsingCenter == rCompare.mbCloseUsingCenter)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrEllipseSegmentPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRELLIPSESEGMENTPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx
new file mode 100644
index 000000000..0610f43b0
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrframeborderprimitive2d.cxx
@@ -0,0 +1,928 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx>
+#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <svtools/borderhelper.hxx>
+
+namespace
+{
+ double snapToDiscreteUnit(
+ double fValue,
+ double fMinimalDiscreteUnit)
+ {
+ if(0.0 != fValue)
+ {
+ fValue = std::max(fValue, fMinimalDiscreteUnit);
+ }
+
+ return fValue;
+ }
+
+ class StyleVectorCombination
+ {
+ private:
+ struct OffsetAndHalfWidthAndColor
+ {
+ double mfOffset;
+ double mfHalfWidth;
+ Color maColor;
+
+ OffsetAndHalfWidthAndColor(double offset, double halfWidth, Color color) :
+ mfOffset(offset),
+ mfHalfWidth(halfWidth),
+ maColor(color)
+ {}
+ };
+
+ double mfRefModeOffset;
+ basegfx::B2DVector maB2DVector;
+ double mfAngle;
+ std::vector< OffsetAndHalfWidthAndColor > maOffsets;
+
+ public:
+ StyleVectorCombination(
+ const svx::frame::Style& rStyle,
+ const basegfx::B2DVector& rB2DVector,
+ double fAngle,
+ bool bMirrored,
+ const Color* pForceColor,
+ double fMinimalDiscreteUnit)
+ : mfRefModeOffset(0.0),
+ maB2DVector(rB2DVector),
+ mfAngle(fAngle)
+ {
+ if (!rStyle.IsUsed())
+ return;
+
+ svx::frame::RefMode aRefMode(rStyle.GetRefMode());
+ Color aPrim(rStyle.GetColorPrim());
+ Color aSecn(rStyle.GetColorSecn());
+ const bool bSecnUsed(0.0 != rStyle.Secn());
+
+ // Get the single segment line widths. This is the point where the
+ // minimal discrete unit will be used if given (fMinimalDiscreteUnit). If
+ // not given it's 0.0 and thus will have no influence.
+ double fPrim(snapToDiscreteUnit(rStyle.Prim(), fMinimalDiscreteUnit));
+ const double fDist(snapToDiscreteUnit(rStyle.Dist(), fMinimalDiscreteUnit));
+ double fSecn(snapToDiscreteUnit(rStyle.Secn(), fMinimalDiscreteUnit));
+
+ // Of course also do not use svx::frame::Style::GetWidth() for obvious
+ // reasons.
+ const double fStyleWidth(fPrim + fDist + fSecn);
+
+ if(bMirrored)
+ {
+ switch(aRefMode)
+ {
+ case svx::frame::RefMode::Begin: aRefMode = svx::frame::RefMode::End; break;
+ case svx::frame::RefMode::End: aRefMode = svx::frame::RefMode::Begin; break;
+ default: break;
+ }
+
+ if(bSecnUsed)
+ {
+ std::swap(aPrim, aSecn);
+ std::swap(fPrim, fSecn);
+ }
+ }
+
+ if (svx::frame::RefMode::Centered != aRefMode)
+ {
+ const double fHalfWidth(fStyleWidth * 0.5);
+
+ if (svx::frame::RefMode::Begin == aRefMode)
+ {
+ // move aligned below vector
+ mfRefModeOffset = fHalfWidth;
+ }
+ else if (svx::frame::RefMode::End == aRefMode)
+ {
+ // move aligned above vector
+ mfRefModeOffset = -fHalfWidth;
+ }
+ }
+
+ if (bSecnUsed)
+ {
+ // both or all three lines used
+ const bool bPrimTransparent(rStyle.GetColorPrim().IsFullyTransparent());
+ const bool bDistTransparent(!rStyle.UseGapColor() || rStyle.GetColorGap().IsFullyTransparent());
+ const bool bSecnTransparent(aSecn.IsFullyTransparent());
+
+ if(!bPrimTransparent || !bDistTransparent || !bSecnTransparent)
+ {
+ const double a(mfRefModeOffset - (fStyleWidth * 0.5));
+ const double b(a + fPrim);
+ const double c(b + fDist);
+ const double d(c + fSecn);
+
+ maOffsets.push_back(
+ OffsetAndHalfWidthAndColor(
+ (a + b) * 0.5,
+ fPrim * 0.5,
+ nullptr != pForceColor ? *pForceColor : aPrim));
+
+ maOffsets.push_back(
+ OffsetAndHalfWidthAndColor(
+ (b + c) * 0.5,
+ fDist * 0.5,
+ rStyle.UseGapColor()
+ ? (nullptr != pForceColor ? *pForceColor : rStyle.GetColorGap())
+ : COL_TRANSPARENT));
+
+ maOffsets.push_back(
+ OffsetAndHalfWidthAndColor(
+ (c + d) * 0.5,
+ fSecn * 0.5,
+ nullptr != pForceColor ? *pForceColor : aSecn));
+ }
+ }
+ else
+ {
+ // one line used, push two values, from outer to inner
+ if(!rStyle.GetColorPrim().IsFullyTransparent())
+ {
+ maOffsets.push_back(
+ OffsetAndHalfWidthAndColor(
+ mfRefModeOffset,
+ fPrim * 0.5,
+ nullptr != pForceColor ? *pForceColor : aPrim));
+ }
+ }
+ }
+
+ double getRefModeOffset() const { return mfRefModeOffset; }
+ const basegfx::B2DVector& getB2DVector() const { return maB2DVector; }
+ double getAngle() const { return mfAngle; }
+ bool empty() const { return maOffsets.empty(); }
+ size_t size() const { return maOffsets.size(); }
+
+ void getColorAndOffsetAndHalfWidth(size_t nIndex, Color& rColor, double& rfOffset, double& rfHalfWidth) const
+ {
+ if(nIndex >= maOffsets.size())
+ return;
+ const OffsetAndHalfWidthAndColor& rCandidate(maOffsets[nIndex]);
+ rfOffset = rCandidate.mfOffset;
+ rfHalfWidth = rCandidate.mfHalfWidth;
+ rColor = rCandidate.maColor;
+ }
+ };
+
+ class StyleVectorTable
+ {
+ private:
+ std::vector< StyleVectorCombination > maEntries;
+
+ public:
+ StyleVectorTable()
+ {
+ }
+
+ void add(
+ const svx::frame::Style& rStyle,
+ const basegfx::B2DVector& rMyVector,
+ const basegfx::B2DVector& rOtherVector,
+ bool bMirrored,
+ double fMinimalDiscreteUnit)
+ {
+ if(!rStyle.IsUsed() || basegfx::areParallel(rMyVector, rOtherVector))
+ return;
+
+ // create angle between both. angle() needs vectors pointing away from the same point,
+ // so take the mirrored one. Add M_PI to get from -pi..+pi to [0..M_PI_2] for sorting
+ const double fAngle(basegfx::B2DVector(-rMyVector.getX(), -rMyVector.getY()).angle(rOtherVector) + M_PI);
+ maEntries.emplace_back(
+ rStyle,
+ rOtherVector,
+ fAngle,
+ bMirrored,
+ nullptr,
+ fMinimalDiscreteUnit);
+ }
+
+ void sort()
+ {
+ // sort inverse from highest to lowest
+ std::sort(
+ maEntries.begin(),
+ maEntries.end(),
+ [](const StyleVectorCombination& a, const StyleVectorCombination& b)
+ { return a.getAngle() > b.getAngle(); });
+ }
+
+ bool empty() const { return maEntries.empty(); }
+ const std::vector< StyleVectorCombination >& getEntries() const{ return maEntries; }
+ };
+
+ struct CutSet
+ {
+ double mfOLML;
+ double mfORML;
+ double mfOLMR;
+ double mfORMR;
+
+ CutSet() : mfOLML(0.0), mfORML(0.0), mfOLMR(0.0), mfORMR(0.0)
+ {
+ }
+
+ bool operator<( const CutSet& rOther) const
+ {
+ const double fA(mfOLML + mfORML + mfOLMR + mfORMR);
+ const double fB(rOther.mfOLML + rOther.mfORML + rOther.mfOLMR + rOther.mfORMR);
+
+ return fA < fB;
+ }
+
+ double getSum() const { return mfOLML + mfORML + mfOLMR + mfORMR; }
+ };
+
+ void getCutSet(
+ CutSet& rCutSet,
+ const basegfx::B2DPoint& rLeft,
+ const basegfx::B2DPoint& rRight,
+ const basegfx::B2DVector& rX,
+ const basegfx::B2DPoint& rOtherLeft,
+ const basegfx::B2DPoint& rOtherRight,
+ const basegfx::B2DVector& rOtherX)
+ {
+ basegfx::utils::findCut(
+ rLeft,
+ rX,
+ rOtherLeft,
+ rOtherX,
+ CutFlagValue::LINE,
+ &rCutSet.mfOLML);
+
+ basegfx::utils::findCut(
+ rRight,
+ rX,
+ rOtherLeft,
+ rOtherX,
+ CutFlagValue::LINE,
+ &rCutSet.mfOLMR);
+
+ basegfx::utils::findCut(
+ rLeft,
+ rX,
+ rOtherRight,
+ rOtherX,
+ CutFlagValue::LINE,
+ &rCutSet.mfORML);
+
+ basegfx::utils::findCut(
+ rRight,
+ rX,
+ rOtherRight,
+ rOtherX,
+ CutFlagValue::LINE,
+ &rCutSet.mfORMR);
+ }
+
+ struct ExtendSet
+ {
+ double mfExtLeft;
+ double mfExtRight;
+
+ ExtendSet() : mfExtLeft(0.0), mfExtRight(0.0) {}
+ };
+
+ void getExtends(
+ std::vector<ExtendSet>& rExtendSet, // target Left/Right values to fill
+ const basegfx::B2DPoint& rOrigin, // own vector start
+ const StyleVectorCombination& rCombination, // own vector and offsets for lines
+ const basegfx::B2DVector& rPerpendX, // normalized perpendicular to own vector
+ const std::vector< StyleVectorCombination >& rStyleVector) // other vectors emerging in this point
+ {
+ if(!(!rCombination.empty() && !rStyleVector.empty() && rCombination.size() == rExtendSet.size()))
+ return;
+
+ const size_t nOffsetA(rCombination.size());
+
+ if(1 == nOffsetA)
+ {
+ Color aMyColor; double fMyOffset(0.0); double fMyHalfWidth(0.0);
+ rCombination.getColorAndOffsetAndHalfWidth(0, aMyColor, fMyOffset, fMyHalfWidth);
+
+ if(!aMyColor.IsFullyTransparent())
+ {
+ const basegfx::B2DPoint aLeft(rOrigin + (rPerpendX * (fMyOffset - fMyHalfWidth)));
+ const basegfx::B2DPoint aRight(rOrigin + (rPerpendX * (fMyOffset + fMyHalfWidth)));
+ std::vector< CutSet > aCutSets;
+
+ for(const auto& rStyleCandidate : rStyleVector)
+ {
+ const basegfx::B2DVector aOtherPerpend(basegfx::getNormalizedPerpendicular(rStyleCandidate.getB2DVector()));
+ const size_t nOffsetB(rStyleCandidate.size());
+
+ for(size_t other(0); other < nOffsetB; other++)
+ {
+ Color aOtherColor; double fOtherOffset(0.0); double fOtherHalfWidth(0.0);
+ rStyleCandidate.getColorAndOffsetAndHalfWidth(other, aOtherColor, fOtherOffset, fOtherHalfWidth);
+
+ if(!aOtherColor.IsFullyTransparent())
+ {
+ const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (fOtherOffset - fOtherHalfWidth)));
+ const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (fOtherOffset + fOtherHalfWidth)));
+
+ CutSet aNewCutSet;
+ getCutSet(aNewCutSet, aLeft, aRight, rCombination.getB2DVector(), aOtherLeft, aOtherRight, rStyleCandidate.getB2DVector());
+ aCutSets.push_back(aNewCutSet);
+ }
+ }
+ }
+
+ if(!aCutSets.empty())
+ {
+ CutSet aCutSet(aCutSets[0]);
+ const size_t nNumCutSets(aCutSets.size());
+
+ if(1 != nNumCutSets)
+ {
+ double fCutSet(aCutSet.getSum());
+
+ for(size_t a(1); a < nNumCutSets; a++)
+ {
+ const CutSet& rCandidate(aCutSets[a]);
+ const double fCandidate(rCandidate.getSum());
+
+ if(basegfx::fTools::equalZero(fCandidate - fCutSet))
+ {
+ // both have equal center point, use medium cut
+ const double fNewOLML(std::max(std::min(rCandidate.mfOLML, rCandidate.mfORML), std::min(aCutSet.mfOLML, aCutSet.mfORML)));
+ const double fNewORML(std::min(std::max(rCandidate.mfOLML, rCandidate.mfORML), std::max(aCutSet.mfOLML, aCutSet.mfORML)));
+ const double fNewOLMR(std::max(std::min(rCandidate.mfOLMR, rCandidate.mfORMR), std::min(aCutSet.mfOLMR, aCutSet.mfORMR)));
+ const double fNewORMR(std::min(std::max(rCandidate.mfOLMR, rCandidate.mfORMR), std::max(aCutSet.mfOLMR, aCutSet.mfORMR)));
+ aCutSet.mfOLML = fNewOLML;
+ aCutSet.mfORML = fNewORML;
+ aCutSet.mfOLMR = fNewOLMR;
+ aCutSet.mfORMR = fNewORMR;
+ fCutSet = aCutSet.getSum();
+ }
+ else if(fCandidate < fCutSet)
+ {
+ // get minimum
+ fCutSet = fCandidate;
+ aCutSet = rCandidate;
+ }
+ }
+ }
+
+ ExtendSet& rExt(rExtendSet[0]);
+
+ rExt.mfExtLeft = std::min(aCutSet.mfOLML, aCutSet.mfORML);
+ rExt.mfExtRight = std::min(aCutSet.mfOLMR, aCutSet.mfORMR);
+ }
+ }
+ }
+ else
+ {
+ size_t nVisEdgeUp(0);
+ size_t nVisEdgeDn(0);
+
+ for(size_t my(0); my < nOffsetA; my++)
+ {
+ Color aMyColor; double fMyOffset(0.0); double fMyHalfWidth(0.0);
+ rCombination.getColorAndOffsetAndHalfWidth(my, aMyColor, fMyOffset, fMyHalfWidth);
+
+ if(!aMyColor.IsFullyTransparent())
+ {
+ const basegfx::B2DPoint aLeft(rOrigin + (rPerpendX * (fMyOffset - fMyHalfWidth)));
+ const basegfx::B2DPoint aRight(rOrigin + (rPerpendX * (fMyOffset + fMyHalfWidth)));
+ const bool bUpper(my <= (nOffsetA >> 1));
+ const StyleVectorCombination& rStyleCandidate(bUpper ? rStyleVector.front() : rStyleVector.back());
+ const basegfx::B2DVector aOtherPerpend(basegfx::getNormalizedPerpendicular(rStyleCandidate.getB2DVector()));
+ const size_t nOffsetB(rStyleCandidate.size());
+ std::vector< CutSet > aCutSets;
+
+ for(size_t other(0); other < nOffsetB; other++)
+ {
+ Color aOtherColor; double fOtherOffset(0.0); double fOtherHalfWidth(0.0);
+ rStyleCandidate.getColorAndOffsetAndHalfWidth(other, aOtherColor, fOtherOffset, fOtherHalfWidth);
+
+ if(!aOtherColor.IsFullyTransparent())
+ {
+ const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (fOtherOffset - fOtherHalfWidth)));
+ const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (fOtherOffset + fOtherHalfWidth)));
+ CutSet aCutSet;
+ getCutSet(aCutSet, aLeft, aRight, rCombination.getB2DVector(), aOtherLeft, aOtherRight, rStyleCandidate.getB2DVector());
+ aCutSets.push_back(aCutSet);
+ }
+ }
+
+ if(!aCutSets.empty())
+ {
+ // sort: min to start, max to end
+ std::sort(aCutSets.begin(), aCutSets.end());
+ const bool bOtherUpper(rStyleCandidate.getAngle() > M_PI);
+
+ // check if we need min or max
+ // bUpper bOtherUpper MinMax
+ // t t max
+ // t f min
+ // f f max
+ // f t min
+ const bool bMax(bUpper == bOtherUpper);
+ size_t nBaseIndex(0);
+ const size_t nNumCutSets(aCutSets.size());
+
+ if(bMax)
+ {
+ // access at end
+ nBaseIndex = nNumCutSets - 1 - (bUpper ? nVisEdgeUp : nVisEdgeDn);
+ }
+ else
+ {
+ // access at start
+ nBaseIndex = bUpper ? nVisEdgeUp : nVisEdgeDn;
+ }
+
+ const size_t nSecuredIndex(std::clamp(nBaseIndex, size_t(0), size_t(nNumCutSets - 1)));
+ const CutSet& rCutSet(aCutSets[nSecuredIndex]);
+ ExtendSet& rExt(rExtendSet[my]);
+
+ rExt.mfExtLeft = std::min(rCutSet.mfOLML, rCutSet.mfORML);
+ rExt.mfExtRight = std::min(rCutSet.mfOLMR, rCutSet.mfORMR);
+ }
+
+ if(bUpper)
+ {
+ nVisEdgeUp++;
+ }
+ else
+ {
+ nVisEdgeDn++;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper method to create the correct drawinglayer::primitive2d::BorderLinePrimitive2D
+ * for the given data, especially the correct drawinglayer::primitive2d::BorderLine entries
+ * including the correctly solved/created LineStartEnd extends
+ *
+ * rTarget : Here the evtl. created BorderLinePrimitive2D will be appended
+ * rOrigin : StartPoint of the Borderline
+ * rX : Vector of the Borderline
+ * rBorder : svx::frame::Style of the of the Borderline
+ * rStartStyleVectorTable : All other Borderlines which have to be taken into account because
+ * they have the same StartPoint as the current Borderline. These will be used to calculate
+ * the correct LineStartEnd extends tor the BorderLinePrimitive2D. The definition should be
+ * built up using svx::frame::StyleVectorTable and StyleVectorTable::add and includes:
+ * rStyle : the svx::frame::Style of one other BorderLine
+ * rMyVector : the Vector of the *new* to-be-defined BorderLine, identical to rX
+ * rOtherVector: the Vector of one other BorderLine (may be, but does not need to be normalized),
+ * always *pointing away* from the common StartPoint rOrigin
+ * bMirrored : define if rStyle of one other BorderLine shall be mirrored (e.g. bottom-right edges)
+ * With multiple BorderLines the definitions have to be CounterClockWise. This will be
+ * ensured by StyleVectorTable sorting the entries, but knowing this may allow more efficient
+ * data creation.
+ * rEndStyleVectorTable: All other BorderLines that have the same EndPoint. There are differences to
+ * the Start definitions:
+ * - do not forget to consequently use -rX for rMyVector
+ * - definitions have to be ClockWise for the EndBorderLines, will be ensured by sorting
+ *
+ * If you take all this into account, you will get correctly extended BorderLinePrimitive2D
+ * representations for the new to be defined BorderLine. That extensions will overlap nicely
+ * with the corresponding BorderLines and take all multiple line definitions in the ::Style into
+ * account.
+ * The internal solver is *not limited* to ::Style(s) with three parts (Left/Gap/Right), this is
+ * just due to svx::frame::Style's definitions. A new solver based on this one can be created
+ * anytime using more mulötiple borders based on the more flexible
+ * std::vector< drawinglayer::primitive2d::BorderLine > if needed.
+ */
+ void CreateBorderPrimitives(
+ drawinglayer::primitive2d::Primitive2DContainer& rTarget, /// target for created primitives
+ const basegfx::B2DPoint& rOrigin, /// start point of borderline
+ const basegfx::B2DVector& rX, /// X-Axis of borderline with length
+ const svx::frame::Style& rBorder, /// Style of borderline
+ const StyleVectorTable& rStartStyleVectorTable, /// Styles and vectors (pointing away) at borderline start, ccw
+ const StyleVectorTable& rEndStyleVectorTable, /// Styles and vectors (pointing away) at borderline end, cw
+ const Color* pForceColor, /// If specified, overrides frame border color.
+ double fMinimalDiscreteUnit) /// minimal discrete unit to use for svx::frame::Style width values
+ {
+ // get offset color pairs for style, one per visible line
+ const StyleVectorCombination aCombination(
+ rBorder,
+ rX,
+ 0.0,
+ false,
+ pForceColor,
+ fMinimalDiscreteUnit);
+
+ if(aCombination.empty())
+ return;
+
+ const basegfx::B2DVector aPerpendX(basegfx::getNormalizedPerpendicular(rX));
+ const bool bHasStartStyles(!rStartStyleVectorTable.empty());
+ const bool bHasEndStyles(!rEndStyleVectorTable.empty());
+ const size_t nOffsets(aCombination.size());
+ std::vector<ExtendSet> aExtendSetStart(nOffsets);
+ std::vector<ExtendSet> aExtendSetEnd(nOffsets);
+
+ if(bHasStartStyles)
+ {
+ // create extends for line starts, use given point/vector and offsets
+ getExtends(aExtendSetStart, rOrigin, aCombination, aPerpendX, rStartStyleVectorTable.getEntries());
+ }
+
+ if(bHasEndStyles)
+ {
+ // Create extends for line ends, create inverse point/vector and inverse offsets.
+ const StyleVectorCombination aMirroredCombination(
+ rBorder,
+ -rX,
+ 0.0,
+ true,
+ pForceColor,
+ fMinimalDiscreteUnit);
+
+ getExtends(aExtendSetEnd, rOrigin + rX, aMirroredCombination, -aPerpendX, rEndStyleVectorTable.getEntries());
+
+ // also need to inverse the result to apply to the correct lines
+ std::reverse(aExtendSetEnd.begin(), aExtendSetEnd.end());
+ }
+
+ std::vector< drawinglayer::primitive2d::BorderLine > aBorderlines;
+ const double fNegLength(-rX.getLength());
+
+ for(size_t a(0); a < nOffsets; a++)
+ {
+ Color aMyColor;
+ double fMyOffset(0.0);
+ double fMyHalfWidth(0.0);
+ aCombination.getColorAndOffsetAndHalfWidth(a, aMyColor, fMyOffset, fMyHalfWidth);
+ const ExtendSet& rExtStart(aExtendSetStart[a]);
+ const ExtendSet& rExtEnd(aExtendSetEnd[a]);
+
+ if(aMyColor.IsFullyTransparent())
+ {
+ aBorderlines.push_back(
+ drawinglayer::primitive2d::BorderLine(
+ fMyHalfWidth * 2.0));
+ }
+ else
+ {
+ aBorderlines.push_back(
+ drawinglayer::primitive2d::BorderLine(
+ drawinglayer::attribute::LineAttribute(
+ aMyColor.getBColor(),
+ fMyHalfWidth * 2.0),
+ fNegLength * rExtStart.mfExtLeft,
+ fNegLength * rExtStart.mfExtRight,
+ fNegLength * rExtEnd.mfExtRight,
+ fNegLength * rExtEnd.mfExtLeft));
+ }
+ }
+
+ static const double fPatScFact(10.0); // 10.0 multiply, see old code
+ std::vector<double> aDashing(svtools::GetLineDashing(rBorder.Type(), rBorder.PatternScale() * fPatScFact));
+ const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(std::move(aDashing));
+ const basegfx::B2DPoint aStart(rOrigin + (aPerpendX * aCombination.getRefModeOffset()));
+
+ rTarget.append(
+ drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::BorderLinePrimitive2D(
+ aStart,
+ aStart + rX,
+ std::move(aBorderlines),
+ aStrokeAttribute)));
+ }
+
+ double getMinimalNonZeroValue(double fCurrent, double fNew)
+ {
+ if(0.0 != fNew)
+ {
+ if(0.0 != fCurrent)
+ {
+ fCurrent = std::min(fNew, fCurrent);
+ }
+ else
+ {
+ fCurrent = fNew;
+ }
+ }
+
+ return fCurrent;
+ }
+
+ double getMinimalNonZeroBorderWidthFromStyle(double fCurrent, const svx::frame::Style& rStyle)
+ {
+ if(rStyle.IsUsed())
+ {
+ fCurrent = getMinimalNonZeroValue(fCurrent, rStyle.Prim());
+ fCurrent = getMinimalNonZeroValue(fCurrent, rStyle.Dist());
+ fCurrent = getMinimalNonZeroValue(fCurrent, rStyle.Secn());
+ }
+
+ return fCurrent;
+ }
+}
+
+namespace drawinglayer::primitive2d
+{
+ SdrFrameBorderData::SdrConnectStyleData::SdrConnectStyleData(
+ const svx::frame::Style& rStyle,
+ const basegfx::B2DVector& rNormalizedPerpendicular,
+ bool bStyleMirrored)
+ : maStyle(rStyle),
+ maNormalizedPerpendicular(rNormalizedPerpendicular),
+ mbStyleMirrored(bStyleMirrored)
+ {
+ }
+
+ bool SdrFrameBorderData::SdrConnectStyleData::operator==(const SdrFrameBorderData::SdrConnectStyleData& rCompare) const
+ {
+ return mbStyleMirrored == rCompare.mbStyleMirrored
+ && maStyle == rCompare.maStyle
+ && maNormalizedPerpendicular == rCompare.maNormalizedPerpendicular;
+ }
+
+ SdrFrameBorderData::SdrFrameBorderData(
+ const basegfx::B2DPoint& rOrigin,
+ const basegfx::B2DVector& rX,
+ const svx::frame::Style& rStyle,
+ const Color* pForceColor)
+ : maOrigin(rOrigin),
+ maX(rX),
+ maStyle(rStyle),
+ maColor(nullptr != pForceColor ? *pForceColor : Color()),
+ mbForceColor(nullptr != pForceColor)
+ {
+ }
+
+ void SdrFrameBorderData::addSdrConnectStyleData(
+ bool bStart,
+ const svx::frame::Style& rStyle,
+ const basegfx::B2DVector& rNormalizedPerpendicular,
+ bool bStyleMirrored)
+ {
+ if(rStyle.IsUsed())
+ {
+ if(bStart)
+ {
+ maStart.emplace_back(rStyle, rNormalizedPerpendicular, bStyleMirrored);
+ }
+ else
+ {
+ maEnd.emplace_back(rStyle, rNormalizedPerpendicular, bStyleMirrored);
+ }
+ }
+ }
+
+ void SdrFrameBorderData::create2DDecomposition(
+ Primitive2DContainer& rContainer,
+ double fMinimalDiscreteUnit) const
+ {
+ StyleVectorTable aStartVector;
+ StyleVectorTable aEndVector;
+ const basegfx::B2DVector aAxis(-maX);
+
+ for(const auto& rStart : maStart)
+ {
+ aStartVector.add(
+ rStart.getStyle(),
+ maX,
+ rStart.getNormalizedPerpendicular(),
+ rStart.getStyleMirrored(),
+ fMinimalDiscreteUnit);
+ }
+
+ for(const auto& rEnd : maEnd)
+ {
+ aEndVector.add(
+ rEnd.getStyle(),
+ aAxis,
+ rEnd.getNormalizedPerpendicular(),
+ rEnd.getStyleMirrored(),
+ fMinimalDiscreteUnit);
+ }
+
+ aStartVector.sort();
+ aEndVector.sort();
+
+ CreateBorderPrimitives(
+ rContainer,
+ maOrigin,
+ maX,
+ maStyle,
+ aStartVector,
+ aEndVector,
+ mbForceColor ? &maColor : nullptr,
+ fMinimalDiscreteUnit);
+ }
+
+ double SdrFrameBorderData::getMinimalNonZeroBorderWidth() const
+ {
+ double fRetval(getMinimalNonZeroBorderWidthFromStyle(0.0, maStyle));
+
+ for(const auto& rStart : maStart)
+ {
+ fRetval = getMinimalNonZeroBorderWidthFromStyle(fRetval, rStart.getStyle());
+ }
+
+ for(const auto& rEnd : maEnd)
+ {
+ fRetval = getMinimalNonZeroBorderWidthFromStyle(fRetval, rEnd.getStyle());
+ }
+
+ return fRetval;
+ }
+
+
+ bool SdrFrameBorderData::operator==(const SdrFrameBorderData& rCompare) const
+ {
+ return maOrigin == rCompare.maOrigin
+ && maX == rCompare.maX
+ && maStyle == rCompare.maStyle
+ && maColor == rCompare.maColor
+ && mbForceColor == rCompare.mbForceColor
+ && maStart == rCompare.maStart
+ && maEnd == rCompare.maEnd;
+ }
+
+
+ void SdrFrameBorderPrimitive2D::create2DDecomposition(
+ Primitive2DContainer& rContainer,
+ const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ if(!getFrameBorders())
+ {
+ return;
+ }
+
+ Primitive2DContainer aRetval;
+
+ // Check and use the minimal non-zero BorderWidth for decompose
+ // if that is set and wanted
+ const double fMinimalDiscreteUnit(doForceToSingleDiscreteUnit()
+ ? mfMinimalNonZeroBorderWidthUsedForDecompose
+ : 0.0);
+
+ {
+ // decompose all buffered SdrFrameBorderData entries and try to merge them
+ // to reduce existing number of BorderLinePrimitive2D(s)
+ for(const auto& rCandidate : *getFrameBorders())
+ {
+ // get decomposition on one SdrFrameBorderData entry
+ Primitive2DContainer aPartial;
+ rCandidate.create2DDecomposition(
+ aPartial,
+ fMinimalDiscreteUnit);
+
+ for(const auto& aCandidatePartial : aPartial)
+ {
+ if(aRetval.empty())
+ {
+ // no local data yet, just add as 1st entry, done
+ aRetval.append(aCandidatePartial);
+ }
+ else
+ {
+ bool bDidMerge(false);
+
+ for(auto& aCandidateRetval : aRetval)
+ {
+ // try to merge by appending new data to existing data
+ const drawinglayer::primitive2d::Primitive2DReference aMergeRetvalPartial(
+ drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(
+ static_cast<BorderLinePrimitive2D*>(aCandidateRetval.get()),
+ static_cast<BorderLinePrimitive2D*>(aCandidatePartial.get())));
+
+ if(aMergeRetvalPartial.is())
+ {
+ // could append, replace existing data with merged data, done
+ aCandidateRetval = aMergeRetvalPartial;
+ bDidMerge = true;
+ break;
+ }
+
+ // try to merge by appending existing data to new data
+ const drawinglayer::primitive2d::Primitive2DReference aMergePartialRetval(
+ drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(
+ static_cast<BorderLinePrimitive2D*>(aCandidatePartial.get()),
+ static_cast<BorderLinePrimitive2D*>(aCandidateRetval.get())));
+
+ if(aMergePartialRetval.is())
+ {
+ // could append, replace existing data with merged data, done
+ aCandidateRetval = aMergePartialRetval;
+ bDidMerge = true;
+ break;
+ }
+ }
+
+ if(!bDidMerge)
+ {
+ // no merge after checking all existing data, append as new segment
+ aRetval.append(aCandidatePartial);
+ }
+ }
+ }
+ }
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrFrameBorderPrimitive2D::SdrFrameBorderPrimitive2D(
+ std::shared_ptr<SdrFrameBorderDataVector>& rFrameBorders,
+ bool bForceToSingleDiscreteUnit)
+ : maFrameBorders(std::move(rFrameBorders)),
+ mfMinimalNonZeroBorderWidth(0.0),
+ mfMinimalNonZeroBorderWidthUsedForDecompose(0.0),
+ mbForceToSingleDiscreteUnit(bForceToSingleDiscreteUnit)
+ {
+ if(getFrameBorders() && doForceToSingleDiscreteUnit())
+ {
+ // detect used minimal non-zero partial border width
+ for(const auto& rCandidate : *getFrameBorders())
+ {
+ mfMinimalNonZeroBorderWidth = getMinimalNonZeroValue(
+ mfMinimalNonZeroBorderWidth,
+ rCandidate.getMinimalNonZeroBorderWidth());
+ }
+ }
+ }
+
+ bool SdrFrameBorderPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrFrameBorderPrimitive2D& rCompare = static_cast<const SdrFrameBorderPrimitive2D&>(rPrimitive);
+
+ return (getFrameBorders() == rCompare.getFrameBorders()
+ || (getFrameBorders() && rCompare.getFrameBorders()
+ && *getFrameBorders() == *rCompare.getFrameBorders()))
+ && doForceToSingleDiscreteUnit() == rCompare.doForceToSingleDiscreteUnit();
+ }
+
+ return false;
+ }
+
+ void SdrFrameBorderPrimitive2D::get2DDecomposition(
+ Primitive2DDecompositionVisitor& rVisitor,
+ const geometry::ViewInformation2D& rViewInformation) const
+ {
+ if(doForceToSingleDiscreteUnit())
+ {
+ // Get the current DiscreteUnit, look at X and Y and use the maximum
+ const basegfx::B2DVector aDiscreteVector(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
+ double fDiscreteUnit(std::min(fabs(aDiscreteVector.getX()), fabs(aDiscreteVector.getY())));
+
+ if(fDiscreteUnit <= mfMinimalNonZeroBorderWidth)
+ {
+ // no need to use it, reset
+ fDiscreteUnit = 0.0;
+ }
+
+ if(fDiscreteUnit != mfMinimalNonZeroBorderWidthUsedForDecompose)
+ {
+ // conditions of last local decomposition have changed, delete
+ // possible content
+ if(!getBuffered2DDecomposition().empty())
+ {
+ const_cast< SdrFrameBorderPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DContainer());
+ }
+
+ // remember new conditions
+ const_cast< SdrFrameBorderPrimitive2D* >(this)->mfMinimalNonZeroBorderWidthUsedForDecompose = fDiscreteUnit;
+ }
+ }
+
+ // call parent. This will call back ::create2DDecomposition above
+ // where mfMinimalNonZeroBorderWidthUsedForDecompose will be used
+ // when doForceToSingleDiscreteUnit() is true
+ BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrFrameBorderPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRFRAMEBORDERTPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrgrafprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrgrafprimitive2d.cxx
new file mode 100644
index 000000000..f5ac21cfc
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrgrafprimitive2d.cxx
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrgrafprimitive2d.hxx>
+#include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+namespace drawinglayer::primitive2d
+{
+void SdrGrafPrimitive2D::create2DDecomposition(
+ Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+{
+ Primitive2DContainer aRetval;
+
+ // create unit outline polygon
+ const basegfx::B2DPolygon& aUnitOutline(basegfx::utils::createUnitPolygon());
+
+ // add fill, but only when graphic is transparent
+ if (!getSdrLFSTAttribute().getFill().isDefault() && isTransparent())
+ {
+ basegfx::B2DPolyPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(aTransformed, getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+
+ // add graphic content
+ if (0 != getGraphicAttr().GetAlpha())
+ {
+ // standard graphic fill
+ const Primitive2DReference xGraphicContentPrimitive(
+ new GraphicPrimitive2D(getTransform(), getGraphicObject(), getGraphicAttr()));
+ aRetval.push_back(xGraphicContentPrimitive);
+ }
+
+ // add line
+ if (!getSdrLFSTAttribute().getLine().isDefault())
+ {
+ // if line width is given, polygon needs to be grown by half of it to make the
+ // outline to be outside of the bitmap
+ if (0.0 != getSdrLFSTAttribute().getLine().getWidth())
+ {
+ // decompose to get scale
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // create expanded range (add relative half line width to unit rectangle)
+ double fHalfLineWidth(getSdrLFSTAttribute().getLine().getWidth() * 0.5);
+ double fScaleX(0.0 != aScale.getX() ? fHalfLineWidth / fabs(aScale.getX()) : 1.0);
+ double fScaleY(0.0 != aScale.getY() ? fHalfLineWidth / fabs(aScale.getY()) : 1.0);
+ const basegfx::B2DRange aExpandedRange(-fScaleX, -fScaleY, 1.0 + fScaleX,
+ 1.0 + fScaleY);
+ basegfx::B2DPolygon aExpandedUnitOutline(
+ basegfx::utils::createPolygonFromRect(aExpandedRange));
+
+ aExpandedUnitOutline.transform(getTransform());
+ aRetval.push_back(createPolygonLinePrimitive(aExpandedUnitOutline,
+ getSdrLFSTAttribute().getLine(),
+ attribute::SdrLineStartEndAttribute()));
+ }
+ else
+ {
+ basegfx::B2DPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(createPolygonLinePrimitive(aTransformed,
+ getSdrLFSTAttribute().getLine(),
+ attribute::SdrLineStartEndAttribute()));
+ }
+ }
+
+ // Soft edges should be before text, since text is not affected by soft edges
+ if (!aRetval.empty() && getSdrLFSTAttribute().getSoftEdgeRadius())
+ {
+ aRetval = createEmbeddedSoftEdgePrimitive(std::move(aRetval),
+ getSdrLFSTAttribute().getSoftEdgeRadius());
+ }
+
+ // add text
+ if (!getSdrLFSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(createTextPrimitive(basegfx::B2DPolyPolygon(aUnitOutline), getTransform(),
+ getSdrLFSTAttribute().getText(),
+ getSdrLFSTAttribute().getLine(), false, false));
+ }
+
+ // tdf#132199: put glow before shadow, to have shadow of the glow, not the opposite
+ if (!aRetval.empty() && !getSdrLFSTAttribute().getGlow().isDefault())
+ {
+ // glow
+ aRetval = createEmbeddedGlowPrimitive(std::move(aRetval), getSdrLFSTAttribute().getGlow());
+ }
+
+ // add shadow
+ if (!getSdrLFSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(std::move(aRetval),
+ getSdrLFSTAttribute().getShadow(), getTransform());
+ }
+
+ rContainer.append(std::move(aRetval));
+}
+
+SdrGrafPrimitive2D::SdrGrafPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ const GraphicObject& rGraphicObject, const GraphicAttr& rGraphicAttr)
+ : maTransform(rTransform)
+ , maSdrLFSTAttribute(rSdrLFSTAttribute)
+ , maGraphicObject(rGraphicObject)
+ , maGraphicAttr(rGraphicAttr)
+{
+ // reset some values from GraphicAttr which are part of transformation already
+ maGraphicAttr.SetRotation(0_deg10);
+}
+
+bool SdrGrafPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+{
+ if (BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrGrafPrimitive2D& rCompare = static_cast<const SdrGrafPrimitive2D&>(rPrimitive);
+
+ return (getTransform() == rCompare.getTransform()
+ && getSdrLFSTAttribute() == rCompare.getSdrLFSTAttribute()
+ && getGraphicObject() == rCompare.getGraphicObject()
+ && getGraphicAttr() == rCompare.getGraphicAttr());
+ }
+
+ return false;
+}
+
+bool SdrGrafPrimitive2D::isTransparent() const
+{
+ return ((255 != getGraphicAttr().GetAlpha()) || (getGraphicObject().IsTransparent()));
+}
+
+// provide unique ID
+sal_uInt32 SdrGrafPrimitive2D::getPrimitive2DID() const
+{
+ return PRIMITIVE2D_ID_SDRGRAFPRIMITIVE2D;
+}
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrmeasureprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrmeasureprimitive2d.cxx
new file mode 100644
index 000000000..aada2aee0
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrmeasureprimitive2d.cxx
@@ -0,0 +1,498 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrmeasureprimitive2d.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <sdr/primitive2d/sdrtextprimitive2d.hxx>
+#include <sdr/attribute/sdrtextattribute.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <rtl/ref.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
+#include <osl/diagnose.h>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ Primitive2DReference SdrMeasurePrimitive2D::impCreatePart(
+ const attribute::SdrLineAttribute& rLineAttribute,
+ const basegfx::B2DHomMatrix& rObjectMatrix,
+ const basegfx::B2DPoint& rStart,
+ const basegfx::B2DPoint& rEnd,
+ bool bLeftActive,
+ bool bRightActive) const
+ {
+ const attribute::SdrLineStartEndAttribute& rLineStartEnd = getSdrLSTAttribute().getLineStartEnd();
+ basegfx::B2DPolygon aPolygon;
+
+ aPolygon.append(rStart);
+ aPolygon.append(rEnd);
+ aPolygon.transform(rObjectMatrix);
+
+ if(rLineStartEnd.isDefault() || (!bLeftActive && !bRightActive))
+ {
+ return createPolygonLinePrimitive(
+ aPolygon,
+ rLineAttribute,
+ attribute::SdrLineStartEndAttribute());
+ }
+
+ if(bLeftActive && bRightActive)
+ {
+ return createPolygonLinePrimitive(
+ aPolygon,
+ rLineAttribute,
+ rLineStartEnd);
+ }
+
+ const basegfx::B2DPolyPolygon aEmpty;
+ const attribute::SdrLineStartEndAttribute aLineStartEnd(
+ bLeftActive ? rLineStartEnd.getStartPolyPolygon() : aEmpty, bRightActive ? rLineStartEnd.getEndPolyPolygon() : aEmpty,
+ bLeftActive ? rLineStartEnd.getStartWidth() : 0.0, bRightActive ? rLineStartEnd.getEndWidth() : 0.0,
+ bLeftActive && rLineStartEnd.isStartActive(), bRightActive && rLineStartEnd.isEndActive(),
+ bLeftActive && rLineStartEnd.isStartCentered(), bRightActive && rLineStartEnd.isEndCentered());
+
+ return createPolygonLinePrimitive(
+ aPolygon,
+ rLineAttribute,
+ aLineStartEnd);
+ }
+
+ void SdrMeasurePrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const
+ {
+ Primitive2DContainer aRetval;
+ rtl::Reference<SdrBlockTextPrimitive2D> xBlockText;
+ basegfx::B2DRange aTextRange;
+ const basegfx::B2DVector aLine(getEnd() - getStart());
+ const double fDistance(aLine.getLength());
+ const double fAngle(atan2(aLine.getY(), aLine.getX()));
+ bool bAutoUpsideDown(false);
+ const attribute::SdrTextAttribute rTextAttribute = getSdrLSTAttribute().getText();
+ const basegfx::B2DHomMatrix aObjectMatrix(
+ basegfx::utils::createShearXRotateTranslateB2DHomMatrix(0.0, fAngle, getStart()));
+
+ // prepare text, but do not add yet; it needs to be aligned to
+ // the line geometry
+ if(!rTextAttribute.isDefault())
+ {
+ basegfx::B2DHomMatrix aTextMatrix;
+ double fTestAngle(fAngle);
+
+ if(getTextRotation())
+ {
+ aTextMatrix.rotate(-M_PI_2);
+ fTestAngle -= (M_PI_2);
+
+ if(getTextAutoAngle() && fTestAngle < -M_PI)
+ {
+ fTestAngle += 2 * M_PI;
+ }
+ }
+
+ if(getTextAutoAngle())
+ {
+ if(fTestAngle > (M_PI / 4.0) || fTestAngle < (-M_PI * (3.0 / 4.0)))
+ {
+ bAutoUpsideDown = true;
+ }
+ }
+
+ // create primitive and get text range
+ xBlockText = new SdrBlockTextPrimitive2D(
+ &rTextAttribute.getSdrText(),
+ rTextAttribute.getOutlinerParaObject(),
+ aTextMatrix,
+ SDRTEXTHORZADJUST_CENTER,
+ SDRTEXTVERTADJUST_CENTER,
+ rTextAttribute.isScroll(),
+ false,
+ false,
+ false);
+
+ aTextRange = xBlockText->getB2DRange(aViewInformation);
+ }
+
+ // prepare line attribute and result
+ double fTextX;
+ double fTextY;
+ {
+ const attribute::SdrLineAttribute rLineAttribute(getSdrLSTAttribute().getLine());
+ bool bArrowsOutside(false);
+ bool bMainLineSplitted(false);
+ const attribute::SdrLineStartEndAttribute& rLineStartEnd = getSdrLSTAttribute().getLineStartEnd();
+ double fStartArrowW(0.0);
+ double fStartArrowH(0.0);
+ double fEndArrowW(0.0);
+ double fEndArrowH(0.0);
+
+ if(!rLineStartEnd.isDefault())
+ {
+ if(rLineStartEnd.isStartActive())
+ {
+ const basegfx::B2DRange aArrowRange(basegfx::utils::getRange(rLineStartEnd.getStartPolyPolygon()));
+ fStartArrowW = rLineStartEnd.getStartWidth();
+ fStartArrowH = aArrowRange.getHeight() * fStartArrowW / aArrowRange.getWidth();
+
+ if(rLineStartEnd.isStartCentered())
+ {
+ fStartArrowH *= 0.5;
+ }
+ }
+
+ if(rLineStartEnd.isEndActive())
+ {
+ const basegfx::B2DRange aArrowRange(basegfx::utils::getRange(rLineStartEnd.getEndPolyPolygon()));
+ fEndArrowW = rLineStartEnd.getEndWidth();
+ fEndArrowH = aArrowRange.getHeight() * fEndArrowW / aArrowRange.getWidth();
+
+ if(rLineStartEnd.isEndCentered())
+ {
+ fEndArrowH *= 0.5;
+ }
+ }
+ }
+
+ const double fSpaceNeededByArrows(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.5));
+ const double fArrowsOutsideLen((fStartArrowH + fEndArrowH + fStartArrowW + fEndArrowW) * 0.5);
+ const double fHalfLineWidth(rLineAttribute.getWidth() * 0.5);
+
+ if(fSpaceNeededByArrows > fDistance)
+ {
+ bArrowsOutside = true;
+ }
+
+ MeasureTextPosition eHorizontal(getHorizontal());
+ MeasureTextPosition eVertical(getVertical());
+
+ if(MEASURETEXTPOSITION_AUTOMATIC == eVertical)
+ {
+ eVertical = MEASURETEXTPOSITION_NEGATIVE;
+ }
+
+ if(MEASURETEXTPOSITION_CENTERED == eVertical)
+ {
+ bMainLineSplitted = true;
+ }
+
+ if(MEASURETEXTPOSITION_AUTOMATIC == eHorizontal)
+ {
+ if(aTextRange.getWidth() > fDistance)
+ {
+ eHorizontal = MEASURETEXTPOSITION_NEGATIVE;
+ }
+ else
+ {
+ eHorizontal = MEASURETEXTPOSITION_CENTERED;
+ }
+
+ if(bMainLineSplitted)
+ {
+ if(aTextRange.getWidth() + fSpaceNeededByArrows > fDistance)
+ {
+ bArrowsOutside = true;
+ }
+ }
+ else
+ {
+ const double fSmallArrowNeed(fStartArrowH + fEndArrowH + ((fStartArrowW + fEndArrowW) * 0.125));
+
+ if(aTextRange.getWidth() + fSmallArrowNeed > fDistance)
+ {
+ bArrowsOutside = true;
+ }
+ }
+ }
+
+ if(MEASURETEXTPOSITION_CENTERED != eHorizontal)
+ {
+ bArrowsOutside = true;
+ }
+
+ // switch text above/below?
+ if(getBelow() || (bAutoUpsideDown && !getTextRotation()))
+ {
+ if(MEASURETEXTPOSITION_NEGATIVE == eVertical)
+ {
+ eVertical = MEASURETEXTPOSITION_POSITIVE;
+ }
+ else if(MEASURETEXTPOSITION_POSITIVE == eVertical)
+ {
+ eVertical = MEASURETEXTPOSITION_NEGATIVE;
+ }
+ }
+
+ const double fMainLineOffset(getBelow() ? getDistance() : -getDistance());
+ const basegfx::B2DPoint aMainLeft(0.0, fMainLineOffset);
+ const basegfx::B2DPoint aMainRight(fDistance, fMainLineOffset);
+
+ // main line
+ if(bArrowsOutside)
+ {
+ double fLenLeft(fArrowsOutsideLen);
+ double fLenRight(fArrowsOutsideLen);
+
+ if(!bMainLineSplitted)
+ {
+ if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal)
+ {
+ fLenLeft = fStartArrowH + aTextRange.getWidth();
+ }
+ else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal)
+ {
+ fLenRight = fEndArrowH + aTextRange.getWidth();
+ }
+ }
+
+ const basegfx::B2DPoint aMainLeftLeft(aMainLeft.getX() - fLenLeft, aMainLeft.getY());
+ const basegfx::B2DPoint aMainRightRight(aMainRight.getX() + fLenRight, aMainRight.getY());
+
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeftLeft, aMainLeft, false, true));
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainRight, aMainRightRight, true, false));
+
+ if(!bMainLineSplitted || MEASURETEXTPOSITION_CENTERED != eHorizontal)
+ {
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, false, false));
+ }
+ }
+ else
+ {
+ if(bMainLineSplitted)
+ {
+ const double fHalfLength((fDistance - (aTextRange.getWidth() + (fStartArrowH + fEndArrowH) * 0.25)) * 0.5);
+ const basegfx::B2DPoint aMainInnerLeft(aMainLeft.getX() + fHalfLength, aMainLeft.getY());
+ const basegfx::B2DPoint aMainInnerRight(aMainRight.getX() - fHalfLength, aMainRight.getY());
+
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainInnerLeft, true, false));
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainInnerRight, aMainRight, false, true));
+ }
+ else
+ {
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aMainLeft, aMainRight, true, true));
+ }
+ }
+
+ // left/right help line value preparation
+ const double fTopEdge(getBelow() ? getUpper() + getDistance() : -getUpper() - getDistance());
+ const double fBottomLeft(getBelow() ? getLower() - getLeftDelta() : getLeftDelta() - getLower());
+ const double fBottomRight(getBelow() ? getLower() - getRightDelta() : getRightDelta() - getLower());
+
+ // left help line
+ const basegfx::B2DPoint aLeftUp(0.0, fTopEdge);
+ const basegfx::B2DPoint aLeftDown(0.0, fBottomLeft);
+
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aLeftDown, aLeftUp, false, false));
+
+ // right help line
+ const basegfx::B2DPoint aRightUp(fDistance, fTopEdge);
+ const basegfx::B2DPoint aRightDown(fDistance, fBottomRight);
+
+ aRetval.push_back(impCreatePart(rLineAttribute, aObjectMatrix, aRightDown, aRightUp, false, false));
+
+ // text horizontal position
+ if(MEASURETEXTPOSITION_NEGATIVE == eHorizontal)
+ {
+ // left
+ const double fSmall(fArrowsOutsideLen * 0.18);
+ fTextX = aMainLeft.getX() - (fStartArrowH + aTextRange.getWidth() + fSmall + fHalfLineWidth);
+
+ if(bMainLineSplitted)
+ {
+ fTextX -= (fArrowsOutsideLen - fStartArrowH);
+ }
+
+ if(!rTextAttribute.isDefault())
+ {
+ fTextX -= rTextAttribute.getTextRightDistance();
+ }
+ }
+ else if(MEASURETEXTPOSITION_POSITIVE == eHorizontal)
+ {
+ // right
+ const double fSmall(fArrowsOutsideLen * 0.18);
+ fTextX = aMainRight.getX() + (fEndArrowH + fSmall + fHalfLineWidth);
+
+ if(bMainLineSplitted)
+ {
+ fTextX += (fArrowsOutsideLen - fEndArrowH);
+ }
+
+ if(!rTextAttribute.isDefault())
+ {
+ fTextX += rTextAttribute.getTextLeftDistance();
+ }
+ }
+ else // MEASURETEXTPOSITION_CENTERED
+ {
+ // centered
+ fTextX = aMainLeft.getX() + ((fDistance - aTextRange.getWidth()) * 0.5);
+
+ if(!rTextAttribute.isDefault())
+ {
+ fTextX += (rTextAttribute.getTextLeftDistance() - rTextAttribute.getTextRightDistance()) / 2L;
+ }
+ }
+
+ // text vertical position
+ if(MEASURETEXTPOSITION_NEGATIVE == eVertical)
+ {
+ // top
+ const double fSmall(fArrowsOutsideLen * 0.10);
+ fTextY = aMainLeft.getY() - (aTextRange.getHeight() + fSmall + fHalfLineWidth);
+
+ if(!rTextAttribute.isDefault())
+ {
+ fTextY -= rTextAttribute.getTextLowerDistance();
+ }
+ }
+ else if(MEASURETEXTPOSITION_POSITIVE == eVertical)
+ {
+ // bottom
+ const double fSmall(fArrowsOutsideLen * 0.10);
+ fTextY = aMainLeft.getY() + (fSmall + fHalfLineWidth);
+
+ if(!rTextAttribute.isDefault())
+ {
+ fTextY += rTextAttribute.getTextUpperDistance();
+ }
+ }
+ else // MEASURETEXTPOSITION_CENTERED
+ {
+ // centered
+ fTextY = aMainLeft.getY() - (aTextRange.getHeight() * 0.5);
+
+ if(!rTextAttribute.isDefault())
+ {
+ fTextY += (rTextAttribute.getTextUpperDistance() - rTextAttribute.getTextLowerDistance()) / 2L;
+ }
+ }
+ }
+
+ if(getSdrLSTAttribute().getLine().isDefault())
+ {
+ // embed line geometry to invisible (100% transparent) line group for HitTest
+ Primitive2DReference xHiddenLines(new HiddenGeometryPrimitive2D(std::move(aRetval)));
+
+ aRetval = Primitive2DContainer { xHiddenLines };
+ }
+
+ if(xBlockText.is())
+ {
+ // create transformation to text primitive end position
+ basegfx::B2DHomMatrix aChange;
+
+ // handle auto text rotation
+ if(bAutoUpsideDown)
+ {
+ aChange.rotate(M_PI);
+ }
+
+ // move from aTextRange.TopLeft to fTextX, fTextY
+ aChange.translate(fTextX - aTextRange.getMinX(), fTextY - aTextRange.getMinY());
+
+ // apply object matrix
+ aChange *= aObjectMatrix;
+
+ // apply to existing text primitive
+ rtl::Reference<SdrTextPrimitive2D> pNewBlockText = xBlockText->createTransformedClone(aChange);
+ OSL_ENSURE(pNewBlockText, "SdrMeasurePrimitive2D::create2DDecomposition: Could not create transformed clone of text primitive (!)");
+ xBlockText.clear();
+
+ // add to local primitives
+ aRetval.push_back(pNewBlockText);
+ }
+
+ // add shadow
+ if(!getSdrLSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(
+ std::move(aRetval),
+ getSdrLSTAttribute().getShadow());
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrMeasurePrimitive2D::SdrMeasurePrimitive2D(
+ const attribute::SdrLineEffectsTextAttribute& rSdrLSTAttribute,
+ const basegfx::B2DPoint& rStart,
+ const basegfx::B2DPoint& rEnd,
+ MeasureTextPosition eHorizontal,
+ MeasureTextPosition eVertical,
+ double fDistance,
+ double fUpper,
+ double fLower,
+ double fLeftDelta,
+ double fRightDelta,
+ bool bBelow,
+ bool bTextRotation,
+ bool bTextAutoAngle)
+ : maSdrLSTAttribute(rSdrLSTAttribute),
+ maStart(rStart),
+ maEnd(rEnd),
+ meHorizontal(eHorizontal),
+ meVertical(eVertical),
+ mfDistance(fDistance),
+ mfUpper(fUpper),
+ mfLower(fLower),
+ mfLeftDelta(fLeftDelta),
+ mfRightDelta(fRightDelta),
+ mbBelow(bBelow),
+ mbTextRotation(bTextRotation),
+ mbTextAutoAngle(bTextAutoAngle)
+ {
+ }
+
+ bool SdrMeasurePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrMeasurePrimitive2D& rCompare = static_cast<const SdrMeasurePrimitive2D&>(rPrimitive);
+
+ return (getStart() == rCompare.getStart()
+ && getEnd() == rCompare.getEnd()
+ && getHorizontal() == rCompare.getHorizontal()
+ && getVertical() == rCompare.getVertical()
+ && getDistance() == rCompare.getDistance()
+ && getUpper() == rCompare.getUpper()
+ && getLower() == rCompare.getLower()
+ && getLeftDelta() == rCompare.getLeftDelta()
+ && getRightDelta() == rCompare.getRightDelta()
+ && getBelow() == rCompare.getBelow()
+ && getTextRotation() == rCompare.getTextRotation()
+ && getTextAutoAngle() == rCompare.getTextAutoAngle()
+ && getSdrLSTAttribute() == rCompare.getSdrLSTAttribute());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrMeasurePrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrole2primitive2d.cxx b/svx/source/sdr/primitive2d/sdrole2primitive2d.cxx
new file mode 100644
index 000000000..e7576b498
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrole2primitive2d.cxx
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrole2primitive2d.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ SdrOle2Primitive2D::SdrOle2Primitive2D(
+ Primitive2DContainer&& rOLEContent,
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute)
+ : maOLEContent(std::move(rOLEContent)),
+ maTransform(rTransform),
+ maSdrLFSTAttribute(rSdrLFSTAttribute)
+ {
+ }
+
+ bool SdrOle2Primitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BasePrimitive2D::operator==(rPrimitive))
+ {
+ const SdrOle2Primitive2D& rCompare = static_cast<const SdrOle2Primitive2D&>(rPrimitive);
+
+ // #i108636# The standard operator== on two UNO sequences did not work as i
+ // would have expected; it just checks the .is() states and the data type
+ // of the sequence. What i need here is detection of equality of the whole
+ // sequence content, thus i need to use the arePrimitive2DSequencesEqual helper
+ // here instead of the operator== which lead to always returning false and thus
+ // always re-decompositions of the subcontent.
+ if(getOLEContent() == rCompare.getOLEContent()
+ && getTransform() == rCompare.getTransform()
+ && getSdrLFSTAttribute() == rCompare.getSdrLFSTAttribute())
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void SdrOle2Primitive2D::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ // to take care of getSdrLFSTAttribute() later, the same as in SdrGrafPrimitive2D::create2DDecomposition
+ // should happen. For the moment we only need the OLE itself
+ // Added complete primitive preparation using getSdrLFSTAttribute() now.
+ Primitive2DContainer aRetval;
+
+ // create unit outline polygon
+ const basegfx::B2DPolygon& aUnitOutline(basegfx::utils::createUnitPolygon());
+
+ // add fill
+ if(!getSdrLFSTAttribute().getFill().isDefault())
+ {
+ basegfx::B2DPolyPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+
+ // add line
+ // #i97981# condition was inverse to purpose. When being compatible to paint version,
+ // border needs to be suppressed
+ if(!getSdrLFSTAttribute().getLine().isDefault())
+ {
+ // if line width is given, polygon needs to be grown by half of it to make the
+ // outline to be outside of the bitmap
+ if(0.0 != getSdrLFSTAttribute().getLine().getWidth())
+ {
+ // decompose to get scale
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // create expanded range (add relative half line width to unit rectangle)
+ double fHalfLineWidth(getSdrLFSTAttribute().getLine().getWidth() * 0.5);
+ double fScaleX(0.0 != aScale.getX() ? fHalfLineWidth / fabs(aScale.getX()) : 1.0);
+ double fScaleY(0.0 != aScale.getY() ? fHalfLineWidth / fabs(aScale.getY()) : 1.0);
+ const basegfx::B2DRange aExpandedRange(-fScaleX, -fScaleY, 1.0 + fScaleX, 1.0 + fScaleY);
+ basegfx::B2DPolygon aExpandedUnitOutline(basegfx::utils::createPolygonFromRect(aExpandedRange));
+
+ aExpandedUnitOutline.transform(getTransform());
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ aExpandedUnitOutline,
+ getSdrLFSTAttribute().getLine(),
+ attribute::SdrLineStartEndAttribute()));
+ }
+ else
+ {
+ basegfx::B2DPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getLine(),
+ attribute::SdrLineStartEndAttribute()));
+ }
+ }
+ else
+ {
+ // if initially no line is defined, create one for HitTest and BoundRect
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ false,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform()));
+ }
+
+ // add graphic content
+ aRetval.append(getOLEContent());
+
+ // add text, no need to suppress to stay compatible since text was
+ // always supported by the old paints, too
+ if(!getSdrLFSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(
+ createTextPrimitive(
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform(),
+ getSdrLFSTAttribute().getText(),
+ getSdrLFSTAttribute().getLine(),
+ false,
+ false));
+ }
+
+ // add shadow
+ if(!getSdrLFSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(
+ std::move(aRetval),
+ getSdrLFSTAttribute().getShadow());
+ }
+
+ rVisitor.visit(std::move(aRetval));
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrOle2Primitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDROLE2PRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrolecontentprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrolecontentprimitive2d.cxx
new file mode 100644
index 000000000..7edd0e601
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrolecontentprimitive2d.cxx
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrolecontentprimitive2d.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <svx/svdoole2.hxx>
+#include <vcl/svapp.hxx>
+#include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <svtools/colorcfg.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+
+namespace drawinglayer::primitive2d
+{
+ void SdrOleContentPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ const SdrOle2Obj* pSource = mpSdrOle2Obj.get();
+ bool bScaleContent(false);
+ Graphic aGraphic;
+
+ if(pSource)
+ {
+ const Graphic* pOLEGraphic = pSource->GetGraphic();
+
+ if(pOLEGraphic)
+ {
+ aGraphic = *pOLEGraphic;
+ bScaleContent = pSource->IsEmptyPresObj();
+ }
+ }
+#ifdef _WIN32 // Little point in displaying the "broken OLE" graphic on OSes that don't have real OLE, maybe?
+ if(GraphicType::NONE == aGraphic.GetType())
+ {
+ // no source, use fallback resource empty OLE graphic
+ aGraphic = SdrOle2Obj::GetEmptyOLEReplacementGraphic();
+ bScaleContent = true;
+ }
+#endif
+ if(GraphicType::NONE == aGraphic.GetType())
+ return;
+
+ const GraphicObject aGraphicObject(aGraphic);
+ const GraphicAttr aGraphicAttr;
+
+ if(bScaleContent)
+ {
+ // get transformation atoms
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ getObjectTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // get PrefSize from the graphic in 100th mm
+ Size aPrefSize(aGraphic.GetPrefSize());
+
+ if(MapUnit::MapPixel == aGraphic.GetPrefMapMode().GetMapUnit())
+ {
+ aPrefSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM));
+ }
+ else
+ {
+ aPrefSize = OutputDevice::LogicToLogic(aPrefSize, aGraphic.GetPrefMapMode(), MapMode(MapUnit::Map100thMM));
+ }
+
+ const double fOffsetX((aScale.getX() - aPrefSize.getWidth()) / 2.0);
+ const double fOffsetY((aScale.getY() - aPrefSize.getHeight()) / 2.0);
+
+ if(basegfx::fTools::moreOrEqual(fOffsetX, 0.0) && basegfx::fTools::moreOrEqual(fOffsetY, 0.0))
+ {
+ // if content fits into frame, create it
+ basegfx::B2DHomMatrix aInnerObjectMatrix(basegfx::utils::createScaleTranslateB2DHomMatrix(
+ aPrefSize.getWidth(), aPrefSize.getHeight(), fOffsetX, fOffsetY));
+ aInnerObjectMatrix = basegfx::utils::createShearXRotateTranslateB2DHomMatrix(fShearX, fRotate, aTranslate)
+ * aInnerObjectMatrix;
+
+ const drawinglayer::primitive2d::Primitive2DReference aGraphicPrimitive(
+ new drawinglayer::primitive2d::GraphicPrimitive2D(
+ aInnerObjectMatrix,
+ aGraphicObject,
+ aGraphicAttr));
+ rContainer.push_back(aGraphicPrimitive);
+ }
+ }
+ else
+ {
+ // create graphic primitive for content
+ const drawinglayer::primitive2d::Primitive2DReference aGraphicPrimitive(
+ new drawinglayer::primitive2d::GraphicPrimitive2D(
+ getObjectTransform(),
+ aGraphicObject,
+ aGraphicAttr));
+ rContainer.push_back(aGraphicPrimitive);
+ }
+
+ // a standard gray outline is created for scaled content
+ if(!bScaleContent)
+ return;
+
+ const svtools::ColorConfig aColorConfig;
+ const svtools::ColorConfigValue aColor(aColorConfig.GetColorValue(svtools::OBJECTBOUNDARIES));
+
+ if(aColor.bIsVisible)
+ {
+ basegfx::B2DPolygon aOutline(basegfx::utils::createUnitPolygon());
+ const Color aVclColor(aColor.nColor);
+ aOutline.transform(getObjectTransform());
+ const drawinglayer::primitive2d::Primitive2DReference xOutline(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aVclColor.getBColor()));
+ rContainer.push_back(xOutline);
+ }
+ }
+
+ SdrOleContentPrimitive2D::SdrOleContentPrimitive2D(
+ const SdrOle2Obj& rSdrOle2Obj,
+ const basegfx::B2DHomMatrix& rObjectTransform,
+ sal_uInt32 nGraphicVersion
+ )
+ : mpSdrOle2Obj(const_cast< SdrOle2Obj* >(&rSdrOle2Obj)),
+ maObjectTransform(rObjectTransform),
+ mnGraphicVersion(nGraphicVersion)
+ {
+ }
+
+ bool SdrOleContentPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if( BufferedDecompositionPrimitive2D::operator==(rPrimitive) )
+ {
+ const SdrOleContentPrimitive2D& rCompare = static_cast<const SdrOleContentPrimitive2D&>(rPrimitive);
+ const bool bBothNot(!mpSdrOle2Obj.is() && !rCompare.mpSdrOle2Obj.is());
+ const bool bBothAndEqual(mpSdrOle2Obj.is() && rCompare.mpSdrOle2Obj.is()
+ && mpSdrOle2Obj.get() == rCompare.mpSdrOle2Obj.get());
+
+ return ((bBothNot || bBothAndEqual)
+ && getObjectTransform() == rCompare.getObjectTransform()
+
+ // #i104867# to find out if the Graphic content of the
+ // OLE has changed, use GraphicVersion number
+ && mnGraphicVersion == rCompare.mnGraphicVersion
+ );
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange SdrOleContentPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ basegfx::B2DRange aRange(0.0, 0.0, 1.0, 1.0);
+ aRange.transform(getObjectTransform());
+
+ return aRange;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrOleContentPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDROLECONTENTPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrpathprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrpathprimitive2d.cxx
new file mode 100644
index 000000000..829525e2b
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrpathprimitive2d.cxx
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrpathprimitive2d.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ void SdrPathPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ Primitive2DContainer aRetval;
+
+ // add fill
+ if(!getSdrLFSTAttribute().getFill().isDefault()
+ && getUnitPolyPolygon().isClosed())
+ {
+ // #i108255# no need to use correctOrientations here; target is
+ // straight visualisation
+ basegfx::B2DPolyPolygon aTransformed(getUnitPolyPolygon());
+ aTransformed.transform(getTransform());
+
+ // OperationSmiley: Check if a UnitDefinitionPolyPolygon is set
+ if(getUnitDefinitionPolyPolygon().count()
+ && getUnitDefinitionPolyPolygon() != getUnitPolyPolygon())
+ {
+ // if yes, use the B2DRange of it's transformed form
+ basegfx::B2DPolyPolygon aTransformedDefinition(getUnitDefinitionPolyPolygon());
+ aTransformedDefinition.transform(getTransform());
+
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ aTransformedDefinition.getB2DRange(),
+ getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+ else
+ {
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+ }
+
+ // add line
+ if(getSdrLFSTAttribute().getLine().isDefault())
+ {
+ // if initially no line is defined, create one for HitTest and BoundRect
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ false,
+ getUnitPolyPolygon(),
+ getTransform()));
+ }
+ else
+ {
+ Primitive2DContainer aTemp(getUnitPolyPolygon().count());
+
+ for(sal_uInt32 a(0); a < getUnitPolyPolygon().count(); a++)
+ {
+ basegfx::B2DPolygon aTransformed(getUnitPolyPolygon().getB2DPolygon(a));
+
+ aTransformed.transform(getTransform());
+ aTemp[a] = createPolygonLinePrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getLine(),
+ getSdrLFSTAttribute().getLineStartEnd());
+ }
+
+ aRetval.append(aTemp);
+ }
+
+ // add text
+ if(!getSdrLFSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(
+ createTextPrimitive(
+ getUnitPolyPolygon(),
+ getTransform(),
+ getSdrLFSTAttribute().getText(),
+ getSdrLFSTAttribute().getLine(),
+ false,
+ false));
+ }
+
+ // add shadow
+ if(!getSdrLFSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(
+ std::move(aRetval),
+ getSdrLFSTAttribute().getShadow());
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrPathPrimitive2D::SdrPathPrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ const basegfx::B2DPolyPolygon& rUnitPolyPolygon,
+ const basegfx::B2DPolyPolygon& rUnitDefinitionPolyPolygon)
+ : maTransform(rTransform),
+ maSdrLFSTAttribute(rSdrLFSTAttribute),
+ maUnitPolyPolygon(rUnitPolyPolygon),
+ maUnitDefinitionPolyPolygon(rUnitDefinitionPolyPolygon)
+ {
+ }
+
+ bool SdrPathPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrPathPrimitive2D& rCompare = static_cast<const SdrPathPrimitive2D&>(rPrimitive);
+
+ return (getUnitPolyPolygon() == rCompare.getUnitPolyPolygon()
+ && getUnitDefinitionPolyPolygon() == rCompare.getUnitDefinitionPolyPolygon()
+ && getTransform() == rCompare.getTransform()
+ && getSdrLFSTAttribute() == rCompare.getSdrLFSTAttribute());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrPathPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRPATHPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrprimitivetools.cxx b/svx/source/sdr/primitive2d/sdrprimitivetools.cxx
new file mode 100644
index 000000000..6376fa796
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrprimitivetools.cxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrprimitivetools.hxx>
+#include <vcl/lazydelete.hxx>
+#include <vcl/BitmapTools.hxx>
+#include <mutex>
+
+
+// helper methods
+
+namespace drawinglayer::primitive2d
+{
+ BitmapEx createDefaultCross_3x3(const basegfx::BColor& rBColor)
+ {
+ static vcl::DeleteOnDeinit< BitmapEx > aRetVal(vcl::DeleteOnDeinitFlag::Empty);
+ static basegfx::BColor aBColor;
+ static std::mutex aMutex;
+
+ std::scoped_lock aGuard(aMutex);
+
+ if(!aRetVal.get() || rBColor != aBColor)
+ {
+ // copy values
+ aBColor = rBColor;
+
+ // create bitmap
+ Color c(aBColor);
+ sal_uInt8 r = c.GetRed();
+ sal_uInt8 g = c.GetGreen();
+ sal_uInt8 b = c.GetBlue();
+ sal_uInt8 a = 255;
+ const sal_uInt8 cross[] = {
+ 0, 0, 0, a, r, g, b, 0, 0, 0, 0, a,
+ r, g, b, 0, r, g, b, 0, r, g, b, 0,
+ 0, 0, 0, a, r, g, b, 0, 0, 0, 0, a
+ };
+ BitmapEx aBitmap = vcl::bitmap::CreateFromData(cross, 3, 3, 12, vcl::PixelFormat::N32_BPP);
+
+ // create and exchange at aRetVal
+ aRetVal.set(aBitmap);
+ }
+
+ return aRetVal.get() ? *aRetVal.get() : BitmapEx();
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrrectangleprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrrectangleprimitive2d.cxx
new file mode 100644
index 000000000..f289ea6bc
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrrectangleprimitive2d.cxx
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrrectangleprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <sdr/primitive2d/sdrdecompositiontools.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+
+using namespace com::sun::star;
+
+
+namespace drawinglayer::primitive2d
+{
+ void SdrRectanglePrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
+ {
+ Primitive2DContainer aRetval;
+
+ // create unit outline polygon
+ const basegfx::B2DPolygon aUnitOutline(basegfx::utils::createPolygonFromRect(
+ basegfx::B2DRange(0.0, 0.0, 1.0, 1.0),
+ getCornerRadiusX(),
+ getCornerRadiusY()));
+
+ // add fill
+ if(!getSdrLFSTAttribute().getFill().isDefault())
+ {
+ basegfx::B2DPolyPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolyPolygonFillPrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getFill(),
+ getSdrLFSTAttribute().getFillFloatTransGradient()));
+ }
+ else if(getForceFillForHitTest())
+ {
+ // if no fill and it's a text frame, create a fill for HitTest and
+ // BoundRect fallback
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ true,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform()));
+ }
+
+ // add line
+ if(!getSdrLFSTAttribute().getLine().isDefault())
+ {
+ basegfx::B2DPolygon aTransformed(aUnitOutline);
+
+ aTransformed.transform(getTransform());
+ aRetval.push_back(
+ createPolygonLinePrimitive(
+ aTransformed,
+ getSdrLFSTAttribute().getLine(),
+ attribute::SdrLineStartEndAttribute()));
+ }
+ else if(!getForceFillForHitTest())
+ {
+ // if initially no line is defined and it's not a text frame, create
+ // a line for HitTest and BoundRect
+ aRetval.push_back(
+ createHiddenGeometryPrimitives2D(
+ false,
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform()));
+ }
+
+ // add text
+ if(!getSdrLFSTAttribute().getText().isDefault())
+ {
+ aRetval.push_back(
+ createTextPrimitive(
+ basegfx::B2DPolyPolygon(aUnitOutline),
+ getTransform(),
+ getSdrLFSTAttribute().getText(),
+ getSdrLFSTAttribute().getLine(),
+ false,
+ false));
+ }
+
+ // add shadow
+ if(!getSdrLFSTAttribute().getShadow().isDefault())
+ {
+ aRetval = createEmbeddedShadowPrimitive(
+ std::move(aRetval),
+ getSdrLFSTAttribute().getShadow());
+ }
+
+ rContainer.append(std::move(aRetval));
+ }
+
+ SdrRectanglePrimitive2D::SdrRectanglePrimitive2D(
+ const basegfx::B2DHomMatrix& rTransform,
+ const attribute::SdrLineFillEffectsTextAttribute& rSdrLFSTAttribute,
+ double fCornerRadiusX,
+ double fCornerRadiusY,
+ bool bForceFillForHitTest)
+ : maTransform(rTransform),
+ maSdrLFSTAttribute(rSdrLFSTAttribute),
+ mfCornerRadiusX(fCornerRadiusX),
+ mfCornerRadiusY(fCornerRadiusY),
+ mbForceFillForHitTest(bForceFillForHitTest)
+ {
+ }
+
+ bool SdrRectanglePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrRectanglePrimitive2D& rCompare = static_cast<const SdrRectanglePrimitive2D&>(rPrimitive);
+
+ return (getCornerRadiusX() == rCompare.getCornerRadiusX()
+ && getCornerRadiusY() == rCompare.getCornerRadiusY()
+ && getTransform() == rCompare.getTransform()
+ && getSdrLFSTAttribute() == rCompare.getSdrLFSTAttribute()
+ && getForceFillForHitTest() == rCompare.getForceFillForHitTest());
+ }
+
+ return false;
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrRectanglePrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRRECTANGLEPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive2d/sdrtextprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrtextprimitive2d.cxx
new file mode 100644
index 000000000..6311c123d
--- /dev/null
+++ b/svx/source/sdr/primitive2d/sdrtextprimitive2d.cxx
@@ -0,0 +1,545 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive2d/sdrtextprimitive2d.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/flditem.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdoutl.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <osl/diagnose.h>
+
+
+using namespace com::sun::star;
+
+
+namespace
+{
+ sal_Int16 getPageNumber(const uno::Reference< drawing::XDrawPage >& rxDrawPage)
+ {
+ sal_Int16 nRetval(0);
+ uno::Reference< beans::XPropertySet > xSet(rxDrawPage, uno::UNO_QUERY);
+
+ if (xSet.is())
+ {
+ try
+ {
+ const uno::Any aNumber(xSet->getPropertyValue("Number"));
+ aNumber >>= nRetval;
+ }
+ catch(const uno::Exception&)
+ {
+ OSL_ASSERT(false);
+ }
+ }
+
+ return nRetval;
+ }
+
+ sal_Int16 getPageCount(const uno::Reference< drawing::XDrawPage >& rxDrawPage)
+ {
+ sal_Int16 nRetval(0);
+ SdrPage* pPage = GetSdrPageFromXDrawPage(rxDrawPage);
+
+ if(pPage)
+ {
+ if( (pPage->GetPageNum() == 0) && !pPage->IsMasterPage() )
+ {
+ // handout page!
+ return pPage->getSdrModelFromSdrPage().getHandoutPageCount();
+ }
+ else
+ {
+ const sal_uInt16 nPageCount(pPage->getSdrModelFromSdrPage().GetPageCount());
+ nRetval = (static_cast<sal_Int16>(nPageCount) - 1) / 2;
+ }
+ }
+
+ return nRetval;
+ }
+} // end of anonymous namespace
+
+
+namespace drawinglayer::primitive2d
+{
+ // support for XTEXT_PAINTSHAPE_BEGIN/XTEXT_PAINTSHAPE_END Metafile comments
+ // for slideshow. This uses TextHierarchyBlockPrimitive2D to mark a text block.
+ // ATM there is only one text block per SdrObject, this may get more in the future
+ void SdrTextPrimitive2D::encapsulateWithTextHierarchyBlockPrimitive2D(Primitive2DContainer& rContainer, Primitive2DContainer&& aCandidate)
+ {
+ rContainer.push_back(new TextHierarchyBlockPrimitive2D(drawinglayer::primitive2d::Primitive2DContainer(aCandidate)));
+ }
+
+ SdrTextPrimitive2D::SdrTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObject)
+ : mrSdrText(const_cast< SdrText* >(pSdrText)),
+ maOutlinerParaObject(rOutlinerParaObject),
+ mnLastPageNumber(0),
+ mnLastPageCount(0),
+ mbContainsPageField(false),
+ mbContainsPageCountField(false),
+ mbContainsOtherFields(false)
+ {
+ const EditTextObject& rETO = maOutlinerParaObject.GetTextObject();
+
+ mbContainsPageField = rETO.HasField(SvxPageField::CLASS_ID);
+ mbContainsPageCountField = rETO.HasField(SvxPagesField::CLASS_ID);
+ mbContainsOtherFields = rETO.HasField(SvxHeaderField::CLASS_ID)
+ || rETO.HasField(SvxFooterField::CLASS_ID)
+ || rETO.HasField(SvxDateTimeField::CLASS_ID)
+ || rETO.HasField(SvxAuthorField::CLASS_ID);
+ }
+
+ const SdrText* SdrTextPrimitive2D::getSdrText() const { return mrSdrText.get(); }
+
+ bool SdrTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrTextPrimitive2D& rCompare = static_cast<const SdrTextPrimitive2D&>(rPrimitive);
+
+ return (
+
+ // compare OPO and content, but not WrongList
+ getOutlinerParaObject() == rCompare.getOutlinerParaObject()
+
+ // also compare WrongList (not-persistent data, but visualized)
+ && getOutlinerParaObject().isWrongListEqual(rCompare.getOutlinerParaObject()));
+ }
+
+ return false;
+ }
+
+ void SdrTextPrimitive2D::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const
+ {
+ uno::Reference< drawing::XDrawPage > xCurrentlyVisualizingPage;
+ bool bCurrentlyVisualizingPageIsSet(false);
+ Color aNewTextBackgroundColor;
+ bool bNewTextBackgroundColorIsSet(false);
+ sal_Int16 nCurrentlyValidPageNumber(0);
+ sal_Int16 nCurrentlyValidPageCount(0);
+
+ if(!getBuffered2DDecomposition().empty())
+ {
+ bool bDoDelete(false);
+
+ // check visualized page
+ if(mbContainsPageField || mbContainsPageCountField || mbContainsOtherFields)
+ {
+ // get visualized page and remember
+ xCurrentlyVisualizingPage = rViewInformation.getVisualizedPage();
+ bCurrentlyVisualizingPageIsSet = true;
+
+ if(xCurrentlyVisualizingPage != mxLastVisualizingPage)
+ {
+ bDoDelete = true;
+ }
+
+ // #i98870# check visualized PageNumber
+ if(!bDoDelete && mbContainsPageField)
+ {
+ nCurrentlyValidPageNumber = getPageNumber(xCurrentlyVisualizingPage);
+
+ if(nCurrentlyValidPageNumber != mnLastPageNumber)
+ {
+ bDoDelete = true;
+ }
+ }
+
+ // #i98870# check visualized PageCount, too
+ if(!bDoDelete && mbContainsPageCountField)
+ {
+ nCurrentlyValidPageCount = getPageCount(xCurrentlyVisualizingPage);
+
+ if(nCurrentlyValidPageCount != mnLastPageCount)
+ {
+ bDoDelete = true;
+ }
+ }
+ }
+
+ // #i101443# check change of TextBackgroundolor
+ if(!bDoDelete && getSdrText())
+ {
+ SdrOutliner& rDrawOutliner = getSdrText()->GetObject().getSdrModelFromSdrObject().GetDrawOutliner();
+ aNewTextBackgroundColor = rDrawOutliner.GetBackgroundColor();
+ bNewTextBackgroundColorIsSet = true;
+
+ if(aNewTextBackgroundColor != maLastTextBackgroundColor)
+ {
+ bDoDelete = true;
+ }
+ }
+
+ if(bDoDelete)
+ {
+ const_cast< SdrTextPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DContainer());
+ }
+ }
+
+ if(getBuffered2DDecomposition().empty())
+ {
+ if(!bCurrentlyVisualizingPageIsSet && mbContainsPageField)
+ {
+ xCurrentlyVisualizingPage = rViewInformation.getVisualizedPage();
+ }
+
+ if(!nCurrentlyValidPageNumber && mbContainsPageField)
+ {
+ nCurrentlyValidPageNumber = getPageNumber(xCurrentlyVisualizingPage);
+ }
+
+ if(!nCurrentlyValidPageCount && mbContainsPageCountField)
+ {
+ nCurrentlyValidPageCount = getPageCount(xCurrentlyVisualizingPage);
+ }
+
+ if(!bNewTextBackgroundColorIsSet && getSdrText())
+ {
+ SdrOutliner& rDrawOutliner = getSdrText()->GetObject().getSdrModelFromSdrObject().GetDrawOutliner();
+ aNewTextBackgroundColor = rDrawOutliner.GetBackgroundColor();
+ }
+
+ const_cast< SdrTextPrimitive2D* >(this)->mxLastVisualizingPage = xCurrentlyVisualizingPage;
+ const_cast< SdrTextPrimitive2D* >(this)->mnLastPageNumber = nCurrentlyValidPageNumber;
+ const_cast< SdrTextPrimitive2D* >(this)->mnLastPageCount = nCurrentlyValidPageCount;
+ const_cast< SdrTextPrimitive2D* >(this)->maLastTextBackgroundColor = aNewTextBackgroundColor;
+ }
+
+ // call parent
+ BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
+ }
+
+
+
+
+ void SdrContourTextPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const
+ {
+ Primitive2DContainer aRetval;
+ getSdrText()->GetObject().impDecomposeContourTextPrimitive(aRetval, *this, aViewInformation);
+
+ encapsulateWithTextHierarchyBlockPrimitive2D(rContainer, std::move(aRetval));
+ }
+
+ SdrContourTextPrimitive2D::SdrContourTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ const basegfx::B2DPolyPolygon& rUnitPolyPolygon,
+ const basegfx::B2DHomMatrix& rObjectTransform)
+ : SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
+ maUnitPolyPolygon(rUnitPolyPolygon),
+ maObjectTransform(rObjectTransform)
+ {
+ }
+
+ bool SdrContourTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(SdrTextPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrContourTextPrimitive2D& rCompare = static_cast<const SdrContourTextPrimitive2D&>(rPrimitive);
+
+ return (getUnitPolyPolygon() == rCompare.getUnitPolyPolygon()
+ && getObjectTransform() == rCompare.getObjectTransform());
+ }
+
+ return false;
+ }
+
+ rtl::Reference<SdrTextPrimitive2D> SdrContourTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
+ {
+ return new SdrContourTextPrimitive2D(
+ getSdrText(),
+ getOutlinerParaObject(),
+ getUnitPolyPolygon(),
+ rTransform * getObjectTransform());
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrContourTextPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRCONTOURTEXTPRIMITIVE2D;
+ }
+
+
+
+ void SdrPathTextPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const
+ {
+ Primitive2DContainer aRetval;
+ getSdrText()->GetObject().impDecomposePathTextPrimitive(aRetval, *this, aViewInformation);
+
+ encapsulateWithTextHierarchyBlockPrimitive2D(rContainer, std::move(aRetval));
+ }
+
+ SdrPathTextPrimitive2D::SdrPathTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ const basegfx::B2DPolyPolygon& rPathPolyPolygon,
+ const attribute::SdrFormTextAttribute& rSdrFormTextAttribute)
+ : SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
+ maPathPolyPolygon(rPathPolyPolygon),
+ maSdrFormTextAttribute(rSdrFormTextAttribute)
+ {
+ }
+
+ bool SdrPathTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(SdrTextPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrPathTextPrimitive2D& rCompare = static_cast<const SdrPathTextPrimitive2D&>(rPrimitive);
+
+ return (getPathPolyPolygon() == rCompare.getPathPolyPolygon()
+ && getSdrFormTextAttribute() == rCompare.getSdrFormTextAttribute());
+ }
+
+ return false;
+ }
+
+ rtl::Reference<SdrTextPrimitive2D> SdrPathTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
+ {
+ basegfx::B2DPolyPolygon aNewPolyPolygon(getPathPolyPolygon());
+ aNewPolyPolygon.transform(rTransform);
+
+ return new SdrPathTextPrimitive2D(
+ getSdrText(),
+ getOutlinerParaObject(),
+ aNewPolyPolygon,
+ getSdrFormTextAttribute());
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrPathTextPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRPATHTEXTPRIMITIVE2D;
+ }
+
+
+
+ void SdrBlockTextPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const
+ {
+ Primitive2DContainer aRetval;
+ getSdrText()->GetObject().impDecomposeBlockTextPrimitive(aRetval, *this, aViewInformation);
+
+ encapsulateWithTextHierarchyBlockPrimitive2D(rContainer, std::move(aRetval));
+ }
+
+ SdrBlockTextPrimitive2D::SdrBlockTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ const basegfx::B2DHomMatrix& rTextRangeTransform,
+ SdrTextHorzAdjust aSdrTextHorzAdjust,
+ SdrTextVertAdjust aSdrTextVertAdjust,
+ bool bFixedCellHeight,
+ bool bUnlimitedPage,
+ bool bCellText,
+ bool bWordWrap)
+ : SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
+ maTextRangeTransform(rTextRangeTransform),
+ maSdrTextHorzAdjust(aSdrTextHorzAdjust),
+ maSdrTextVertAdjust(aSdrTextVertAdjust),
+ mbFixedCellHeight(bFixedCellHeight),
+ mbUnlimitedPage(bUnlimitedPage),
+ mbCellText(bCellText),
+ mbWordWrap(bWordWrap)
+ {
+ }
+
+ bool SdrBlockTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(SdrTextPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrBlockTextPrimitive2D& rCompare = static_cast<const SdrBlockTextPrimitive2D&>(rPrimitive);
+
+ return (getTextRangeTransform() == rCompare.getTextRangeTransform()
+ && getSdrTextHorzAdjust() == rCompare.getSdrTextHorzAdjust()
+ && getSdrTextVertAdjust() == rCompare.getSdrTextVertAdjust()
+ && isFixedCellHeight() == rCompare.isFixedCellHeight()
+ && getUnlimitedPage() == rCompare.getUnlimitedPage()
+ && getCellText() == rCompare.getCellText()
+ && getWordWrap() == rCompare.getWordWrap());
+ }
+
+ return false;
+ }
+
+ rtl::Reference<SdrTextPrimitive2D> SdrBlockTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
+ {
+ return new SdrBlockTextPrimitive2D(
+ getSdrText(),
+ getOutlinerParaObject(),
+ rTransform * getTextRangeTransform(),
+ getSdrTextHorzAdjust(),
+ getSdrTextVertAdjust(),
+ isFixedCellHeight(),
+ getUnlimitedPage(),
+ getCellText(),
+ getWordWrap());
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrBlockTextPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRBLOCKTEXTPRIMITIVE2D;
+ }
+
+
+
+ void SdrAutoFitTextPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const
+ {
+ Primitive2DContainer aRetval;
+ getSdrText()->GetObject().impDecomposeAutoFitTextPrimitive(aRetval, *this, aViewInformation);
+
+ encapsulateWithTextHierarchyBlockPrimitive2D(rContainer, std::move(aRetval));
+ }
+
+ SdrAutoFitTextPrimitive2D::SdrAutoFitTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rParaObj,
+ const ::basegfx::B2DHomMatrix& rTextRangeTransform,
+ bool bWordWrap)
+ : SdrTextPrimitive2D(pSdrText, rParaObj),
+ maTextRangeTransform(rTextRangeTransform),
+ mbWordWrap(bWordWrap)
+ {
+ }
+
+ bool SdrAutoFitTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(SdrTextPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrBlockTextPrimitive2D& rCompare = static_cast<const SdrBlockTextPrimitive2D&>(rPrimitive);
+
+ return (getTextRangeTransform() == rCompare.getTextRangeTransform()
+ && getWordWrap() == rCompare.getWordWrap());
+ }
+
+ return false;
+ }
+
+ rtl::Reference<SdrTextPrimitive2D> SdrAutoFitTextPrimitive2D::createTransformedClone(const ::basegfx::B2DHomMatrix& rTransform) const
+ {
+ return new SdrAutoFitTextPrimitive2D(getSdrText(), getOutlinerParaObject(), rTransform * getTextRangeTransform(), getWordWrap());
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrAutoFitTextPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRAUTOFITTEXTPRIMITIVE2D;
+ }
+
+
+
+
+ SdrChainedTextPrimitive2D::SdrChainedTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ const basegfx::B2DHomMatrix& rTextRangeTransform)
+ : SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
+ maTextRangeTransform(rTextRangeTransform)
+ { }
+
+ void SdrChainedTextPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const
+ {
+ Primitive2DContainer aRetval;
+ getSdrText()->GetObject().impDecomposeChainedTextPrimitive(aRetval, *this, aViewInformation);
+
+ encapsulateWithTextHierarchyBlockPrimitive2D(rContainer, std::move(aRetval));
+ }
+
+ bool SdrChainedTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(SdrTextPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrBlockTextPrimitive2D& rCompare = static_cast<const SdrBlockTextPrimitive2D&>(rPrimitive);
+
+ return (getTextRangeTransform() == rCompare.getTextRangeTransform());
+ }
+
+ return false;
+ }
+
+ rtl::Reference<SdrTextPrimitive2D> SdrChainedTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
+ {
+ return new SdrChainedTextPrimitive2D(getSdrText(), getOutlinerParaObject(), rTransform * getTextRangeTransform());
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrChainedTextPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRCHAINEDTEXTPRIMITIVE2D;
+ }
+
+
+ void SdrStretchTextPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const
+ {
+ Primitive2DContainer aRetval;
+ getSdrText()->GetObject().impDecomposeStretchTextPrimitive(aRetval, *this, aViewInformation);
+
+ encapsulateWithTextHierarchyBlockPrimitive2D(rContainer, std::move(aRetval));
+ }
+
+ SdrStretchTextPrimitive2D::SdrStretchTextPrimitive2D(
+ const SdrText* pSdrText,
+ const OutlinerParaObject& rOutlinerParaObject,
+ const basegfx::B2DHomMatrix& rTextRangeTransform,
+ bool bFixedCellHeight)
+ : SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
+ maTextRangeTransform(rTextRangeTransform),
+ mbFixedCellHeight(bFixedCellHeight)
+ {
+ }
+
+ bool SdrStretchTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(SdrTextPrimitive2D::operator==(rPrimitive))
+ {
+ const SdrStretchTextPrimitive2D& rCompare = static_cast<const SdrStretchTextPrimitive2D&>(rPrimitive);
+
+ return (getTextRangeTransform() == rCompare.getTextRangeTransform()
+ && isFixedCellHeight() == rCompare.isFixedCellHeight());
+ }
+
+ return false;
+ }
+
+ rtl::Reference<SdrTextPrimitive2D> SdrStretchTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
+ {
+ return new SdrStretchTextPrimitive2D(
+ getSdrText(),
+ getOutlinerParaObject(),
+ rTransform * getTextRangeTransform(),
+ isFixedCellHeight());
+ }
+
+ // provide unique ID
+ sal_uInt32 SdrStretchTextPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SDRSTRETCHTEXTPRIMITIVE2D;
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/primitive3d/sdrattributecreator3d.cxx b/svx/source/sdr/primitive3d/sdrattributecreator3d.cxx
new file mode 100644
index 000000000..6bf8f8c6e
--- /dev/null
+++ b/svx/source/sdr/primitive3d/sdrattributecreator3d.cxx
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/primitive3d/sdrattributecreator3d.hxx>
+#include <svx/svx3ditems.hxx>
+#include <svl/itemset.hxx>
+#include <com/sun/star/drawing/NormalsKind.hpp>
+#include <com/sun/star/drawing/TextureProjectionMode.hpp>
+#include <com/sun/star/drawing/TextureKind2.hpp>
+#include <com/sun/star/drawing/TextureMode.hpp>
+#include <svx/xflclit.hxx>
+#include <drawinglayer/attribute/materialattribute3d.hxx>
+#include <drawinglayer/attribute/sdrobjectattribute3d.hxx>
+
+
+namespace drawinglayer::primitive2d
+{
+ attribute::Sdr3DObjectAttribute createNewSdr3DObjectAttribute(const SfxItemSet& rSet)
+ {
+ // get NormalsKind
+ css::drawing::NormalsKind aNormalsKind(css::drawing::NormalsKind_SPECIFIC);
+ const sal_uInt16 nNormalsValue(rSet.Get(SDRATTR_3DOBJ_NORMALS_KIND).GetValue());
+
+ if(1 == nNormalsValue)
+ {
+ aNormalsKind = css::drawing::NormalsKind_FLAT;
+ }
+ else if(2 == nNormalsValue)
+ {
+ aNormalsKind = css::drawing::NormalsKind_SPHERE;
+ }
+
+ // get NormalsInvert flag
+ const bool bInvertNormals(rSet.Get(SDRATTR_3DOBJ_NORMALS_INVERT).GetValue());
+
+ // get TextureProjectionX
+ css::drawing::TextureProjectionMode aTextureProjectionX(css::drawing::TextureProjectionMode_OBJECTSPECIFIC);
+ const sal_uInt16 nTextureValueX(rSet.Get(SDRATTR_3DOBJ_TEXTURE_PROJ_X).GetValue());
+
+ if(1 == nTextureValueX)
+ {
+ aTextureProjectionX = css::drawing::TextureProjectionMode_PARALLEL;
+ }
+ else if(2 == nTextureValueX)
+ {
+ aTextureProjectionX = css::drawing::TextureProjectionMode_SPHERE;
+ }
+
+ // get TextureProjectionY
+ css::drawing::TextureProjectionMode aTextureProjectionY(css::drawing::TextureProjectionMode_OBJECTSPECIFIC);
+ const sal_uInt16 nTextureValueY(rSet.Get(SDRATTR_3DOBJ_TEXTURE_PROJ_Y).GetValue());
+
+ if(1 == nTextureValueY)
+ {
+ aTextureProjectionY = css::drawing::TextureProjectionMode_PARALLEL;
+ }
+ else if(2 == nTextureValueY)
+ {
+ aTextureProjectionY = css::drawing::TextureProjectionMode_SPHERE;
+ }
+
+ // get DoubleSided flag
+ const bool bDoubleSided(rSet.Get(SDRATTR_3DOBJ_DOUBLE_SIDED).GetValue());
+
+ // get Shadow3D flag
+ const bool bShadow3D(rSet.Get(SDRATTR_3DOBJ_SHADOW_3D).GetValue());
+
+ // get TextureFilter flag
+ const bool bTextureFilter(rSet.Get(SDRATTR_3DOBJ_TEXTURE_FILTER).GetValue());
+
+ // get texture kind
+ // TextureKind: 1 == Base3DTextureLuminance, 2 == Base3DTextureIntensity, 3 == Base3DTextureColor
+ css::drawing::TextureKind2 aTextureKind(css::drawing::TextureKind2_LUMINANCE);
+ const sal_uInt16 nTextureKind(rSet.Get(SDRATTR_3DOBJ_TEXTURE_KIND).GetValue());
+
+ if(2 == nTextureKind)
+ {
+ aTextureKind = css::drawing::TextureKind2_INTENSITY;
+ }
+ else if(3 == nTextureKind)
+ {
+ aTextureKind = css::drawing::TextureKind2_COLOR;
+ }
+
+ // get texture mode
+ // TextureMode: 1 == Base3DTextureReplace, 2 == Base3DTextureModulate, 3 == Base3DTextureBlend
+ css::drawing::TextureMode aTextureMode(css::drawing::TextureMode_REPLACE);
+ const sal_uInt16 nTextureMode(rSet.Get(SDRATTR_3DOBJ_TEXTURE_MODE).GetValue());
+
+ if(2 == nTextureMode)
+ {
+ aTextureMode = css::drawing::TextureMode_MODULATE;
+ }
+ else if(3 == nTextureMode)
+ {
+ aTextureMode = css::drawing::TextureMode_BLEND;
+ }
+
+ // get object color
+ const ::basegfx::BColor aObjectColor(rSet.Get(XATTR_FILLCOLOR).GetColorValue().getBColor());
+
+ // get specular color
+ const ::basegfx::BColor aSpecular(rSet.Get(SDRATTR_3DOBJ_MAT_SPECULAR).GetValue().getBColor());
+
+ // get emissive color
+ const ::basegfx::BColor aEmission(rSet.Get(SDRATTR_3DOBJ_MAT_EMISSION).GetValue().getBColor());
+
+ // get specular intensity
+ sal_uInt16 nSpecularIntensity(rSet.Get(SDRATTR_3DOBJ_MAT_SPECULAR_INTENSITY).GetValue());
+
+ if(nSpecularIntensity > 128)
+ {
+ nSpecularIntensity = 128;
+ }
+
+ // get reduced line geometry
+ const bool bReducedLineGeometry(rSet.Get(SDRATTR_3DOBJ_REDUCED_LINE_GEOMETRY).GetValue());
+
+ // prepare material
+ attribute::MaterialAttribute3D aMaterial(aObjectColor, aSpecular, aEmission, nSpecularIntensity);
+
+ return attribute::Sdr3DObjectAttribute(
+ aNormalsKind, aTextureProjectionX, aTextureProjectionY,
+ aTextureKind, aTextureMode, aMaterial,
+ bInvertNormals, bDoubleSided, bShadow3D, bTextureFilter, bReducedLineGeometry);
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/attributeproperties.cxx b/svx/source/sdr/properties/attributeproperties.cxx
new file mode 100644
index 000000000..7f141b8f6
--- /dev/null
+++ b/svx/source/sdr/properties/attributeproperties.cxx
@@ -0,0 +1,541 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/attributeproperties.hxx>
+#include <tools/debug.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svl/whiter.hxx>
+#include <svl/poolitem.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svddef.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <osl/diagnose.h>
+
+namespace sdr::properties
+{
+ void AttributeProperties::ImpSetParentAtSfxItemSet(bool bDontRemoveHardAttr)
+ {
+ if(HasSfxItemSet() && mpStyleSheet)
+ {
+ // Delete hard attributes where items are set in the style sheet
+ if(!bDontRemoveHardAttr)
+ {
+ const SfxItemSet& rStyle = mpStyleSheet->GetItemSet();
+ SfxWhichIter aIter(rStyle);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ while(nWhich)
+ {
+ if(SfxItemState::SET == aIter.GetItemState())
+ {
+ mxItemSet->ClearItem(nWhich);
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+ }
+
+ // set new stylesheet as parent
+ mxItemSet->SetParent(&mpStyleSheet->GetItemSet());
+ }
+ else
+ {
+ OSL_ENSURE(false, "ImpSetParentAtSfxItemSet called without SfxItemSet/SfxStyleSheet (!)");
+ }
+ }
+
+ void AttributeProperties::ImpAddStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
+ {
+ // test if old StyleSheet is cleared, else it would be lost
+ // after this method -> memory leak (!)
+ DBG_ASSERT(!mpStyleSheet, "Old style sheet not deleted before setting new one (!)");
+
+ if(!pNewStyleSheet)
+ return;
+
+ // local remember
+ mpStyleSheet = pNewStyleSheet;
+
+ if(HasSfxItemSet())
+ {
+ // register as listener
+ StartListening(*pNewStyleSheet->GetPool());
+ StartListening(*pNewStyleSheet);
+
+ // only apply the following when we have an SfxItemSet already, else
+ if(GetStyleSheet())
+ {
+ ImpSetParentAtSfxItemSet(bDontRemoveHardAttr);
+ }
+ }
+ }
+
+ void AttributeProperties::ImpRemoveStyleSheet()
+ {
+ // Check type since it is destroyed when the type is deleted
+ if(GetStyleSheet() && mpStyleSheet)
+ {
+ EndListening(*mpStyleSheet);
+ if (auto const pool = mpStyleSheet->GetPool()) { // TTTT
+ EndListening(*pool);
+ }
+
+ // reset parent of ItemSet
+ if(HasSfxItemSet())
+ {
+ mxItemSet->SetParent(nullptr);
+ }
+
+ SdrObject& rObj = GetSdrObject();
+ rObj.SetBoundRectDirty();
+ rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
+ }
+
+ mpStyleSheet = nullptr;
+ }
+
+ // create a new itemset
+ SfxItemSet AttributeProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(rPool,
+
+ // ranges from SdrAttrObj
+ svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST>);
+ }
+
+ AttributeProperties::AttributeProperties(SdrObject& rObj)
+ : DefaultProperties(rObj),
+ mpStyleSheet(nullptr)
+ {
+ // Do nothing else, esp. do *not* try to get and set
+ // a default SfxStyle sheet. Nothing is allowed to be done
+ // that may lead to calls to virtual functions like
+ // CreateObjectSpecificItemSet - these would go *wrong*.
+ // Thus the rest is lazy-init from here.
+ }
+
+ AttributeProperties::AttributeProperties(const AttributeProperties& rProps, SdrObject& rObj)
+ : DefaultProperties(rProps, rObj),
+ mpStyleSheet(nullptr)
+ {
+ SfxStyleSheet* pTargetStyleSheet(rProps.GetStyleSheet());
+
+ if(pTargetStyleSheet)
+ {
+ const bool bModelChange(&rObj.getSdrModelFromSdrObject() != &rProps.GetSdrObject().getSdrModelFromSdrObject());
+
+ if(bModelChange)
+ {
+ // tdf#117506
+ // The error shows that it is definitely necessary to solve this problem.
+ // Interestingly I already had a note here for 'work needed'.
+ // Checked in libreoffice-6-0 what happened there. In principle, the whole
+ // ::Clone of SdrPage and SdrObject happened in the same SdrModel, only
+ // afterwards a ::SetModel was used at the cloned SdrPage which went through
+ // all layers. The StyleSheet-problem was solved in
+ // AttributeProperties::MoveToItemPool at the end. There, a StyleSheet with the
+ // same name was searched for in the target-SdrModel.
+ // Start by resetting the current TargetStyleSheet so that nothing goes wrong
+ // when we do not find a fitting TargetStyleSheet.
+ // Note: The test for SdrModelChange above was wrong (compared the already set
+ // new SdrObject), so this never triggered and pTargetStyleSheet was never set to
+ // nullptr before. This means that a StyleSheet from another SdrModel was used
+ // what of course is very dangerous. Interestingly did not crash since when that
+ // other SdrModel was destroyed the ::Notify mechanism still worked reliably
+ // and de-connected this Properties successfully from the alien-StyleSheet.
+ pTargetStyleSheet = nullptr;
+
+ // Check if we have a TargetStyleSheetPool at the target-SdrModel. This *should*
+ // be the case already (SdrModel::Merge and SdDrawDocument::InsertBookmarkAsPage
+ // have already cloned the StyleSheets to the target-SdrModel when used in Draw/impress).
+ // If none is found, ImpGetDefaultStyleSheet will be used to set a 'default'
+ // StyleSheet as StyleSheet implicitly later (that's what happened in the task,
+ // thus the FillStyle changed to the 'default' Blue).
+ // Note: It *may* be necessary to do more for StyleSheets, e.g. clone/copy the
+ // StyleSheet Hierarchy from the source SdrModel and/or add the Items from there
+ // as hard attributes. If needed, have a look at the older AttributeProperties::SetModel
+ // implementation from e.g. libreoffice-6-0.
+ SfxStyleSheetBasePool* pTargetStyleSheetPool(rObj.getSdrModelFromSdrObject().GetStyleSheetPool());
+
+ if(nullptr != pTargetStyleSheetPool)
+ {
+ // If we have a TargetStyleSheetPool, search for the used StyleSheet
+ // in the target SdrModel using the Name from the original StyleSheet
+ // in the source-SdrModel.
+ pTargetStyleSheet = dynamic_cast< SfxStyleSheet* >(
+ pTargetStyleSheetPool->Find(
+ rProps.GetStyleSheet()->GetName(),
+ SfxStyleFamily::All));
+ }
+ }
+ }
+
+ if(!pTargetStyleSheet)
+ return;
+
+ if(HasSfxItemSet())
+ {
+ // The SfxItemSet has been cloned and exists,
+ // we can directly set the SfxStyleSheet at it
+ ImpAddStyleSheet(pTargetStyleSheet, true);
+ }
+ else
+ {
+ // No SfxItemSet exists yet (there is none in
+ // the source, so none was cloned). Remember the
+ // SfxStyleSheet to set it when the SfxItemSet
+ // got constructed on-demand
+ mpStyleSheet = pTargetStyleSheet;
+ }
+ }
+
+ AttributeProperties::~AttributeProperties()
+ {
+ ImpRemoveStyleSheet();
+ }
+
+ std::unique_ptr<BaseProperties> AttributeProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new AttributeProperties(*this, rObj));
+ }
+
+ const SfxItemSet& AttributeProperties::GetObjectItemSet() const
+ {
+ // remember if we had a SfxItemSet already
+ const bool bHadSfxItemSet(HasSfxItemSet());
+
+ // call parent - this will guarantee SfxItemSet existence
+ DefaultProperties::GetObjectItemSet();
+
+ if(!bHadSfxItemSet)
+ {
+ // need to take care for SfxStyleSheet for newly
+ // created SfxItemSet
+ if(nullptr == mpStyleSheet)
+ {
+ // Set missing defaults without removal of hard attributes.
+ // This is more complicated historically than I first thought:
+ // Originally for GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj
+ // SetStyleSheet(..., false) was used, while for GetDefaultStyleSheet
+ // SetStyleSheet(..., true) was used. Thus, for SdrGrafObj and SdrOle2Obj
+ // bDontRemoveHardAttr == false -> *do* delete hard attributes was used.
+ // This was probably not done by purpose, adding the method
+ // GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj additionally to
+ // GetDefaultStyleSheet was an enhancement to allow for SdrGrafObj/SdrOle2Obj
+ // with full AttributeSet (adding e.g. FillAttributes). To stay as compatible
+ // as possible these SdrObjects got a new default-StyleSheet.
+ // There is no reason to delete the HardAttributes and it anyways has only
+ // AFAIK effects on a single Item - the SdrTextHorzAdjustItem. To get things
+ // unified I will stay with not deleting the HardAttributes and adapt the
+ // UnitTests in CppunitTest_sd_import_tests accordingly.
+ const_cast< AttributeProperties* >(this)->applyDefaultStyleSheetFromSdrModel();
+ }
+ else
+ {
+ // Late-Init of setting parent to SfxStyleSheet after
+ // it's creation. Can only happen from copy-constructor
+ // (where creation of SfxItemSet is avoided due to the
+ // problem with constructors and virtual functions in C++),
+ // thus DontRemoveHardAttr is not needed.
+ const_cast< AttributeProperties* >(this)->SetStyleSheet(
+ mpStyleSheet, true, true);
+ }
+ }
+
+ return *mxItemSet;
+ }
+
+ void AttributeProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > /*aChangedItems*/, sal_uInt16 /*nDeletedWhich*/)
+ {
+ // own modifications
+ SdrObject& rObj = GetSdrObject();
+
+ rObj.SetBoundRectDirty();
+ rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
+ rObj.SetChanged();
+ }
+
+ void AttributeProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
+ {
+ if(pNewItem)
+ {
+ std::unique_ptr<SfxPoolItem> pResultItem;
+ SdrModel& rModel(GetSdrObject().getSdrModelFromSdrObject());
+
+ switch( nWhich )
+ {
+ case XATTR_FILLBITMAP:
+ {
+ // TTTT checkForUniqueItem should use SdrModel&
+ pResultItem = static_cast<const XFillBitmapItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_LINEDASH:
+ {
+ pResultItem = static_cast<const XLineDashItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_LINESTART:
+ {
+ pResultItem = static_cast<const XLineStartItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_LINEEND:
+ {
+ pResultItem = static_cast<const XLineEndItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_FILLGRADIENT:
+ {
+ pResultItem = static_cast<const XFillGradientItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_FILLFLOATTRANSPARENCE:
+ {
+ // #85953# allow all kinds of XFillFloatTransparenceItem to be set
+ pResultItem = static_cast<const XFillFloatTransparenceItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_FILLHATCH:
+ {
+ pResultItem = static_cast<const XFillHatchItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ }
+
+ // guarantee SfxItemSet existence
+ GetObjectItemSet();
+
+ if(pResultItem)
+ {
+ // force ItemSet
+ mxItemSet->Put(std::move(pResultItem));
+ }
+ else
+ {
+ mxItemSet->Put(*pNewItem);
+ }
+ }
+ else
+ {
+ // clear item if ItemSet exists
+ if(HasSfxItemSet())
+ {
+ mxItemSet->ClearItem(nWhich);
+ }
+ }
+ }
+
+ void AttributeProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool /*bBroadcast*/)
+ {
+ // guarantee SfxItemSet existence
+ GetObjectItemSet();
+
+ ImpRemoveStyleSheet();
+ ImpAddStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
+
+ SdrObject& rObj = GetSdrObject();
+ rObj.SetBoundRectDirty();
+ rObj.SetBoundAndSnapRectsDirty(true);
+ }
+
+ SfxStyleSheet* AttributeProperties::GetStyleSheet() const
+ {
+ return mpStyleSheet;
+ }
+
+ void AttributeProperties::ForceStyleToHardAttributes()
+ {
+ if(!GetStyleSheet() || mpStyleSheet == nullptr)
+ return;
+
+ // guarantee SfxItemSet existence
+ GetObjectItemSet();
+
+ // prepare copied, new itemset, but WITHOUT parent
+ SfxItemSet aDestItemSet(*mxItemSet);
+ aDestItemSet.SetParent(nullptr);
+
+ // prepare forgetting the current stylesheet like in RemoveStyleSheet()
+ EndListening(*mpStyleSheet);
+ EndListening(*mpStyleSheet->GetPool());
+
+ // prepare the iter; use the mpObjectItemSet which may have less
+ // WhichIDs than the style.
+ SfxWhichIter aIter(aDestItemSet);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+ const SfxPoolItem *pItem = nullptr;
+
+ // now set all hard attributes of the current at the new itemset
+ while(nWhich)
+ {
+ // #i61284# use mpItemSet with parents, makes things easier and reduces to
+ // one loop
+ if(SfxItemState::SET == mxItemSet->GetItemState(nWhich, true, &pItem))
+ {
+ aDestItemSet.Put(*pItem);
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+
+ // replace itemsets
+ mxItemSet.emplace(std::move(aDestItemSet));
+
+ // set necessary changes like in RemoveStyleSheet()
+ GetSdrObject().SetBoundRectDirty();
+ GetSdrObject().SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
+
+ mpStyleSheet = nullptr;
+ }
+
+ void AttributeProperties::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+ {
+ bool bHintUsed(false);
+
+ const SfxStyleSheetHint* pStyleHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint);
+
+ if(pStyleHint && pStyleHint->GetStyleSheet() == GetStyleSheet())
+ {
+ SdrObject& rObj = GetSdrObject();
+ //SdrPage* pPage = rObj.GetPage();
+
+ switch(pStyleHint->GetId())
+ {
+ case SfxHintId::StyleSheetCreated :
+ {
+ // cannot happen, nothing to do
+ break;
+ }
+ case SfxHintId::StyleSheetModified :
+ case SfxHintId::StyleSheetChanged :
+ {
+ // notify change
+ break;
+ }
+ case SfxHintId::StyleSheetErased :
+ case SfxHintId::StyleSheetInDestruction :
+ {
+ // Style needs to be exchanged
+ SfxStyleSheet* pNewStSh = nullptr;
+ SdrModel& rModel(rObj.getSdrModelFromSdrObject());
+
+ // Do nothing if object is in destruction, else a StyleSheet may be found from
+ // a StyleSheetPool which is just being deleted itself. and thus it would be fatal
+ // to register as listener to that new StyleSheet.
+ if(!rObj.IsInDestruction())
+ {
+ if(SfxStyleSheet* pStyleSheet = GetStyleSheet())
+ {
+ pNewStSh = static_cast<SfxStyleSheet*>(rModel.GetStyleSheetPool()->Find(
+ pStyleSheet->GetParent(), pStyleSheet->GetFamily()));
+ }
+
+ if(!pNewStSh)
+ {
+ pNewStSh = rModel.GetDefaultStyleSheet();
+ }
+ }
+
+ // remove used style, it's erased or in destruction
+ ImpRemoveStyleSheet();
+
+ if(pNewStSh)
+ {
+ ImpAddStyleSheet(pNewStSh, true);
+ }
+
+ break;
+ }
+ default: break;
+ }
+
+ // Get old BoundRect. Do this after the style change is handled
+ // in the ItemSet parts because GetBoundRect() may calculate a new
+ tools::Rectangle aBoundRect = rObj.GetLastBoundRect();
+
+ rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
+
+ // tell the object about the change
+ rObj.SetChanged();
+ rObj.BroadcastObjectChange();
+
+ //if(pPage && pPage->IsInserted())
+ //{
+ // rObj.BroadcastObjectChange();
+ //}
+
+ rObj.SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect);
+
+ bHintUsed = true;
+ }
+
+ if(!bHintUsed)
+ {
+ // forward to SdrObject ATM. Not sure if this will be necessary
+ // in the future.
+ GetSdrObject().Notify(rBC, rHint);
+ }
+ }
+
+ bool AttributeProperties::isUsedByModel() const
+ {
+ const SdrObject& rObj(GetSdrObject());
+ if (rObj.IsInserted())
+ {
+ const SdrPage* const pPage(rObj.getSdrPageFromSdrObject());
+ if (pPage && pPage->IsInserted())
+ return true;
+ }
+ return false;
+ }
+
+ void AttributeProperties::applyDefaultStyleSheetFromSdrModel()
+ {
+ SfxStyleSheet* pDefaultStyleSheet(GetSdrObject().getSdrModelFromSdrObject().GetDefaultStyleSheet());
+
+ // tdf#118139 Only do this when StyleSheet really differs. It may e.g.
+ // be the case that nullptr == pDefaultStyleSheet and there is none set yet,
+ // so indeed no need to set it (needed for some strange old MSWord2003
+ // documents with CustomShape-'Group' and added Text-Frames, see task description)
+ if(pDefaultStyleSheet != GetStyleSheet())
+ {
+ // do not delete hard attributes when setting dsefault Style
+ SetStyleSheet(pDefaultStyleSheet, true, true);
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/captionproperties.cxx b/svx/source/sdr/properties/captionproperties.cxx
new file mode 100644
index 000000000..2f7a2c8a7
--- /dev/null
+++ b/svx/source/sdr/properties/captionproperties.cxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/captionproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svx/svddef.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdocapt.hxx>
+
+
+namespace sdr::properties
+{
+ // create a new itemset
+ SfxItemSet CaptionProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(
+ rPool,
+ svl::Items<
+ // Ranges from SdrAttrObj, SdrCaptionObj:
+ SDRATTR_START, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+ // Range from SdrTextObj:
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ CaptionProperties::CaptionProperties(SdrObject& rObj)
+ : RectangleProperties(rObj)
+ {
+ }
+
+ CaptionProperties::CaptionProperties(const CaptionProperties& rProps, SdrObject& rObj)
+ : RectangleProperties(rProps, rObj)
+ {
+ }
+
+ CaptionProperties::~CaptionProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> CaptionProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new CaptionProperties(*this, rObj));
+ }
+
+ void CaptionProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrCaptionObj& rObj = static_cast<SdrCaptionObj&>(GetSdrObject());
+
+ // local changes
+ rObj.ImpRecalcTail();
+
+ // call parent
+ RectangleProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+ }
+
+ void CaptionProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ RectangleProperties::SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+
+ // local changes
+ SdrCaptionObj& rObj = static_cast<SdrCaptionObj&>(GetSdrObject());
+ rObj.ImpRecalcTail();
+ }
+
+ void CaptionProperties::ForceDefaultAttributes()
+ {
+ // call parent
+ RectangleProperties::ForceDefaultAttributes();
+
+ // force ItemSet
+ GetObjectItemSet();
+
+ // this was set by TextProperties::ForceDefaultAttributes(),
+ // reset to default
+ mxItemSet->ClearItem(XATTR_LINESTYLE);
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/circleproperties.cxx b/svx/source/sdr/properties/circleproperties.cxx
new file mode 100644
index 000000000..0c2a5bdc1
--- /dev/null
+++ b/svx/source/sdr/properties/circleproperties.cxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/circleproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svx/svddef.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdocirc.hxx>
+#include <sxcikitm.hxx>
+#include <svx/sxciaitm.hxx>
+
+
+namespace sdr::properties
+{
+ // create a new itemset
+ SfxItemSet CircleProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(
+ rPool,
+ svl::Items<
+ // Ranges from SdrAttrObj, SdrCircObj
+ SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_CIRC_FIRST, SDRATTR_CIRC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+ // Range from SdrTextObj:
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ CircleProperties::CircleProperties(SdrObject& rObj)
+ : RectangleProperties(rObj)
+ {
+ }
+
+ CircleProperties::CircleProperties(const CircleProperties& rProps, SdrObject& rObj)
+ : RectangleProperties(rProps, rObj)
+ {
+ }
+
+ CircleProperties::~CircleProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> CircleProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new CircleProperties(*this, rObj));
+ }
+
+ void CircleProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrCircObj& rObj = static_cast<SdrCircObj&>(GetSdrObject());
+
+ // call parent
+ RectangleProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+
+ // local changes
+ rObj.ImpSetAttrToCircInfo();
+ }
+
+ void CircleProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ RectangleProperties::SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+
+ // local changes
+ SdrCircObj& rObj = static_cast<SdrCircObj&>(GetSdrObject());
+ rObj.SetXPolyDirty();
+
+ // local changes
+ rObj.ImpSetAttrToCircInfo();
+ }
+
+ void CircleProperties::ForceDefaultAttributes()
+ {
+ SdrCircObj& rObj = static_cast<SdrCircObj&>(GetSdrObject());
+ SdrCircKind eKind = rObj.GetCircleKind();
+
+ if(eKind != SdrCircKind::Full)
+ {
+ // force ItemSet
+ GetObjectItemSet();
+
+ mxItemSet->Put(SdrCircKindItem(eKind));
+
+ if(rObj.GetStartAngle())
+ {
+ mxItemSet->Put(makeSdrCircStartAngleItem(rObj.GetStartAngle()));
+ }
+
+ if(rObj.GetEndAngle() != 36000_deg100)
+ {
+ mxItemSet->Put(makeSdrCircEndAngleItem(rObj.GetEndAngle()));
+ }
+ }
+
+ // call parent after SetObjectItem(SdrCircKindItem())
+ // because ForceDefaultAttr() will call
+ // ImpSetAttrToCircInfo() which needs a correct
+ // SdrCircKindItem
+ RectangleProperties::ForceDefaultAttributes();
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/connectorproperties.cxx b/svx/source/sdr/properties/connectorproperties.cxx
new file mode 100644
index 000000000..375a98190
--- /dev/null
+++ b/svx/source/sdr/properties/connectorproperties.cxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/connectorproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svx/svddef.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdoedge.hxx>
+
+
+namespace sdr::properties
+{
+ // create a new itemset
+ SfxItemSet ConnectorProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(
+ rPool,
+ svl::Items<
+ // Ranges from SdrAttrObj, SdrEdgeObj:
+ SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_EDGE_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+ // Range from SdrTextObj:
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ ConnectorProperties::ConnectorProperties(SdrObject& rObj)
+ : TextProperties(rObj)
+ {
+ }
+
+ ConnectorProperties::ConnectorProperties(const ConnectorProperties& rProps, SdrObject& rObj)
+ : TextProperties(rProps, rObj)
+ {
+ }
+
+ ConnectorProperties::~ConnectorProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> ConnectorProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new ConnectorProperties(*this, rObj));
+ }
+
+ void ConnectorProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrEdgeObj& rObj = static_cast<SdrEdgeObj&>(GetSdrObject());
+
+ // call parent
+ TextProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+
+ // local changes
+ rObj.ImpSetAttrToEdgeInfo();
+ }
+
+ void ConnectorProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ TextProperties::SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+
+ // local changes
+ SdrEdgeObj& rObj = static_cast<SdrEdgeObj&>(GetSdrObject());
+ rObj.ImpSetAttrToEdgeInfo();
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/customshapeproperties.cxx b/svx/source/sdr/properties/customshapeproperties.cxx
new file mode 100644
index 000000000..59135cde1
--- /dev/null
+++ b/svx/source/sdr/properties/customshapeproperties.cxx
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/customshapeproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/sdooitm.hxx>
+#include <editeng/eeitem.hxx>
+#include <svl/whiter.hxx>
+#include <svl/hint.hxx>
+
+
+namespace sdr::properties
+{
+ void CustomShapeProperties::UpdateTextFrameStatus(bool bInvalidateRenderGeometry)
+ {
+ SdrObjCustomShape& rObj = static_cast< SdrObjCustomShape& >(GetSdrObject());
+ const bool bOld(rObj.mbTextFrame);
+
+ // change TextFrame flag when bResizeShapeToFitText changes (which is mapped
+ // on the item SDRATTR_TEXT_AUTOGROWHEIGHT for custom shapes, argh)
+ rObj.mbTextFrame = GetObjectItemSet().Get(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
+
+ // check if it did change
+ if(rObj.mbTextFrame != bOld)
+ {
+ // on change also invalidate render geometry
+ bInvalidateRenderGeometry = true;
+
+ // #115391# Potential recursion, since it calls SetObjectItemSet again, but rObj.bTextFrame
+ // will not change again. Thus it will be only one level and terminate safely
+ rObj.AdaptTextMinSize();
+ }
+
+ if(bInvalidateRenderGeometry)
+ {
+ // if asked for or bResizeShapeToFitText changed, make sure that
+ // the render geometry is reconstructed using changed parameters
+ rObj.InvalidateRenderGeometry();
+ }
+ }
+
+ SfxItemSet CustomShapeProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(
+ rPool,
+ svl::Items<
+ // Ranges from SdrAttrObj:
+ SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ // Graphic attributes, 3D properties, CustomShape
+ // properties:
+ SDRATTR_GRAF_FIRST, SDRATTR_CUSTOMSHAPE_LAST,
+ SDRATTR_GLOW_FIRST, SDRATTR_SOFTEDGE_LAST,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+ // Range from SdrTextObj:
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ bool CustomShapeProperties::AllowItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem ) const
+ {
+ bool bAllowItemChange = true;
+ if ( !pNewItem )
+ {
+ if ( ( nWhich >= SDRATTR_CUSTOMSHAPE_FIRST ) && ( nWhich <= SDRATTR_CUSTOMSHAPE_LAST ) )
+ bAllowItemChange = false;
+ }
+ if ( bAllowItemChange )
+ bAllowItemChange = TextProperties::AllowItemChange( nWhich, pNewItem );
+ return bAllowItemChange;
+ }
+
+ void CustomShapeProperties::ClearObjectItem(const sal_uInt16 nWhich)
+ {
+ if ( !nWhich )
+ {
+ SfxWhichIter aIter( *mxItemSet );
+ sal_uInt16 nWhich2 = aIter.FirstWhich();
+ while( nWhich2 )
+ {
+ TextProperties::ClearObjectItemDirect( nWhich2 );
+ nWhich2 = aIter.NextWhich();
+ }
+ ItemSetChanged({}, 0);
+ }
+ else
+ TextProperties::ClearObjectItem( nWhich );
+ }
+
+ void CustomShapeProperties::ClearObjectItemDirect(const sal_uInt16 nWhich)
+ {
+ if ( !nWhich )
+ {
+ SfxWhichIter aIter( *mxItemSet );
+ sal_uInt16 nWhich2 = aIter.FirstWhich();
+ while( nWhich2 )
+ {
+ TextProperties::ClearObjectItemDirect( nWhich2 );
+ nWhich2 = aIter.NextWhich();
+ }
+ }
+ else
+ TextProperties::ClearObjectItemDirect( nWhich );
+ }
+
+ void CustomShapeProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ // call parent
+ TextProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+
+ // update bTextFrame and RenderGeometry
+ UpdateTextFrameStatus(true);
+ }
+
+ void CustomShapeProperties::PostItemChange(const sal_uInt16 nWhich)
+ {
+ switch(nWhich)
+ {
+ case SDRATTR_TEXT_AUTOGROWHEIGHT:
+ {
+ // #115391# update bTextFrame and RenderGeometry using AdaptTextMinSize()
+ UpdateTextFrameStatus(false);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ // call parent
+ TextProperties::PostItemChange(nWhich);
+ }
+
+ void CustomShapeProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
+ {
+ // call parent
+ TextProperties::ItemChange( nWhich, pNewItem );
+
+ // update bTextFrame and RenderGeometry
+ UpdateTextFrameStatus(true);
+ }
+
+ void CustomShapeProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ TextProperties::SetStyleSheet( pNewStyleSheet, bDontRemoveHardAttr, bBroadcast );
+
+ // update bTextFrame and RenderGeometry
+ UpdateTextFrameStatus(true);
+ }
+
+ void CustomShapeProperties::ForceDefaultAttributes()
+ {
+ // update bTextFrame and RenderGeometry
+ UpdateTextFrameStatus(true);
+
+ // SJ: Following is no good if creating customshapes, leading to objects that are white after loading via xml
+ // This means: Do *not* call parent here is by purpose...
+ }
+
+ CustomShapeProperties::CustomShapeProperties(SdrObject& rObj)
+ : TextProperties(rObj)
+ {
+ }
+
+ CustomShapeProperties::CustomShapeProperties(const CustomShapeProperties& rProps, SdrObject& rObj)
+ : TextProperties(rProps, rObj)
+ {
+ }
+
+ CustomShapeProperties::~CustomShapeProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> CustomShapeProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new CustomShapeProperties(*this, rObj));
+ }
+
+ void CustomShapeProperties::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+ {
+ TextProperties::Notify( rBC, rHint );
+
+ bool bRemoveRenderGeometry = false;
+ const SfxStyleSheetHint* pStyleHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint);
+
+ if ( pStyleHint && pStyleHint->GetStyleSheet() == GetStyleSheet() )
+ {
+ switch( pStyleHint->GetId() )
+ {
+ case SfxHintId::StyleSheetModified :
+ case SfxHintId::StyleSheetChanged :
+ bRemoveRenderGeometry = true;
+ break;
+ default: break;
+ }
+ }
+ else if ( rHint.GetId() == SfxHintId::DataChanged )
+ {
+ bRemoveRenderGeometry = true;
+ }
+
+ // update bTextFrame and RenderGeometry
+ UpdateTextFrameStatus(bRemoveRenderGeometry);
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/defaultproperties.cxx b/svx/source/sdr/properties/defaultproperties.cxx
new file mode 100644
index 000000000..fa5292458
--- /dev/null
+++ b/svx/source/sdr/properties/defaultproperties.cxx
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <svx/sdr/properties/defaultproperties.hxx>
+#include <sdr/properties/itemsettools.hxx>
+#include <svl/itemset.hxx>
+#include <svl/whiter.hxx>
+#include <vector>
+#include <svx/svdobj.hxx>
+#include <svx/svddef.hxx>
+#include <editeng/eeitem.hxx>
+#include <libxml/xmlwriter.h>
+#include <svx/svdmodel.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/xbtmpit.hxx>
+
+namespace sdr::properties
+{
+ SfxItemSet DefaultProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ // Basic implementation; Basic object has NO attributes
+ return SfxItemSet(rPool);
+ }
+
+ DefaultProperties::DefaultProperties(SdrObject& rObj)
+ : BaseProperties(rObj)
+ {
+ }
+
+ DefaultProperties::DefaultProperties(const DefaultProperties& rProps, SdrObject& rObj)
+ : BaseProperties(rObj)
+ {
+ if(!rProps.mxItemSet)
+ return;
+
+ // Clone may be to another model and thus another ItemPool.
+ // SfxItemSet supports that thus we are able to Clone all
+ // SfxItemState::SET items to the target pool.
+ mxItemSet.emplace(rProps.mxItemSet->CloneAsValue(
+ true,
+ &rObj.getSdrModelFromSdrObject().GetItemPool()));
+
+ // React on ModelChange: If metric has changed, scale items.
+ // As seen above, clone is supported, but scale is not included,
+ // thus: TTTT maybe add scale to SfxItemSet::Clone() (?)
+ // tdf#117707 correct ModelChange detection
+ const bool bModelChange(&rObj.getSdrModelFromSdrObject() != &rProps.GetSdrObject().getSdrModelFromSdrObject());
+
+ if(bModelChange)
+ {
+ const MapUnit aOldUnit(rProps.GetSdrObject().getSdrModelFromSdrObject().GetScaleUnit());
+ const MapUnit aNewUnit(rObj.getSdrModelFromSdrObject().GetScaleUnit());
+ const bool bScaleUnitChanged(aNewUnit != aOldUnit);
+
+ if(bScaleUnitChanged)
+ {
+ const Fraction aMetricFactor(GetMapFactor(aOldUnit, aNewUnit).X());
+
+ ScaleItemSet(*mxItemSet, aMetricFactor);
+ }
+ }
+
+ // do not keep parent info, this may be changed by later constructors.
+ // This class just copies the ItemSet, ignore parent.
+ if(mxItemSet && mxItemSet->GetParent())
+ {
+ mxItemSet->SetParent(nullptr);
+ }
+ }
+
+ std::unique_ptr<BaseProperties> DefaultProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new DefaultProperties(*this, rObj));
+ }
+
+ DefaultProperties::~DefaultProperties() {}
+
+ const SfxItemSet& DefaultProperties::GetObjectItemSet() const
+ {
+ if(!mxItemSet)
+ {
+ mxItemSet.emplace(const_cast<DefaultProperties*>(this)->CreateObjectSpecificItemSet(GetSdrObject().GetObjectItemPool()));
+ const_cast<DefaultProperties*>(this)->ForceDefaultAttributes();
+ }
+
+ assert(mxItemSet && "Could not create an SfxItemSet(!)");
+
+ return *mxItemSet;
+ }
+
+ void DefaultProperties::SetObjectItem(const SfxPoolItem& rItem)
+ {
+ const sal_uInt16 nWhichID(rItem.Which());
+
+ if(!AllowItemChange(nWhichID, &rItem))
+ return;
+
+ ItemChange(nWhichID, &rItem);
+ PostItemChange(nWhichID);
+
+ const SfxPoolItem* pItem = &rItem;
+ ItemSetChanged( {&pItem, 1}, 0);
+ }
+
+ void DefaultProperties::SetObjectItemDirect(const SfxPoolItem& rItem)
+ {
+ const sal_uInt16 nWhichID(rItem.Which());
+
+ if(AllowItemChange(nWhichID, &rItem))
+ {
+ ItemChange(nWhichID, &rItem);
+ }
+ }
+
+ void DefaultProperties::ClearObjectItem(const sal_uInt16 nWhich)
+ {
+ if(!AllowItemChange(nWhich))
+ return;
+
+ ItemChange(nWhich);
+ PostItemChange(nWhich);
+
+ if(nWhich)
+ {
+ ItemSetChanged({}, nWhich);
+ }
+ }
+
+ void DefaultProperties::ClearObjectItemDirect(const sal_uInt16 nWhich)
+ {
+ if(AllowItemChange(nWhich))
+ {
+ ItemChange(nWhich);
+ }
+ }
+
+ void DefaultProperties::SetObjectItemSet(const SfxItemSet& rSet)
+ {
+ if (rSet.HasItem(XATTR_FILLBITMAP))
+ {
+ const XFillBitmapItem* pItem = rSet.GetItem(XATTR_FILLBITMAP);
+ const std::shared_ptr<VectorGraphicData>& pVectorData
+ = pItem->GetGraphicObject().GetGraphic().getVectorGraphicData();
+ if (pVectorData)
+ {
+ // Shape is filled by a vector graphic: tell it our size as a hint.
+ basegfx::B2DTuple aSizeHint;
+ aSizeHint.setX(GetSdrObject().GetSnapRect().getWidth());
+ aSizeHint.setY(GetSdrObject().GetSnapRect().getHeight());
+ pVectorData->setSizeHint(aSizeHint);
+ }
+ }
+
+ SfxWhichIter aWhichIter(rSet);
+ sal_uInt16 nWhich(aWhichIter.FirstWhich());
+ std::vector< const SfxPoolItem * > aPostItemChangeList;
+ // give a hint to STL_Vector
+ aPostItemChangeList.reserve(rSet.Count());
+
+ while(nWhich)
+ {
+ const SfxPoolItem* pPoolItem;
+ if(SfxItemState::SET == aWhichIter.GetItemState(false, &pPoolItem))
+ {
+ if(AllowItemChange(nWhich, pPoolItem))
+ {
+ ItemChange(nWhich, pPoolItem);
+ aPostItemChangeList.emplace_back( pPoolItem );
+ }
+ }
+
+ nWhich = aWhichIter.NextWhich();
+ }
+
+ if(!aPostItemChangeList.empty())
+ {
+ for (const auto& rItem : aPostItemChangeList)
+ {
+ PostItemChange(rItem->Which());
+ }
+
+ ItemSetChanged(aPostItemChangeList, 0);
+ }
+ }
+
+ void DefaultProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > /*aChangedItems*/, sal_uInt16 /*nDeletedWhich*/)
+ {
+ }
+
+ bool DefaultProperties::AllowItemChange(const sal_uInt16 /*nWhich*/, const SfxPoolItem* /*pNewItem*/) const
+ {
+ return true;
+ }
+
+ void DefaultProperties::ItemChange(const sal_uInt16 /*nWhich*/, const SfxPoolItem* /*pNewItem*/)
+ {
+ }
+
+ void DefaultProperties::PostItemChange(const sal_uInt16 nWhich )
+ {
+ if( (nWhich == XATTR_FILLSTYLE) && mxItemSet )
+ CleanupFillProperties(*mxItemSet);
+ }
+
+ void DefaultProperties::SetStyleSheet(SfxStyleSheet* /*pNewStyleSheet*/, bool /*bDontRemoveHardAttr*/,
+ bool /*bBroadcast*/)
+ {
+ // no StyleSheet in DefaultProperties
+ }
+
+ SfxStyleSheet* DefaultProperties::GetStyleSheet() const
+ {
+ // no StyleSheet in DefaultProperties
+ return nullptr;
+ }
+
+ void DefaultProperties::ForceDefaultAttributes()
+ {
+ }
+
+ void DefaultProperties::dumpAsXml(xmlTextWriterPtr pWriter) const
+ {
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("DefaultProperties"));
+ BaseProperties::dumpAsXml(pWriter);
+ if (mxItemSet)
+ {
+ mxItemSet->dumpAsXml(pWriter);
+ }
+ (void)xmlTextWriterEndElement(pWriter);
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/e3dcompoundproperties.cxx b/svx/source/sdr/properties/e3dcompoundproperties.cxx
new file mode 100644
index 000000000..c31d85fdc
--- /dev/null
+++ b/svx/source/sdr/properties/e3dcompoundproperties.cxx
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/e3dcompoundproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/scene3d.hxx>
+
+
+namespace sdr::properties
+{
+ E3dCompoundProperties::E3dCompoundProperties(SdrObject& rObj)
+ : E3dProperties(rObj)
+ {
+ }
+
+ E3dCompoundProperties::E3dCompoundProperties(const E3dCompoundProperties& rProps, SdrObject& rObj)
+ : E3dProperties(rProps, rObj)
+ {
+ }
+
+ E3dCompoundProperties::~E3dCompoundProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> E3dCompoundProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new E3dCompoundProperties(*this, rObj));
+ }
+
+ const SfxItemSet& E3dCompoundProperties::GetMergedItemSet() const
+ {
+ // include Items of scene this object belongs to
+ const E3dCompoundObject& rObj = static_cast<const E3dCompoundObject&>(GetSdrObject());
+ E3dScene* pScene(rObj.getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ // force ItemSet
+ GetObjectItemSet();
+
+ // add filtered scene properties (SDRATTR_3DSCENE_) to local itemset
+ SfxItemSetFixed<SDRATTR_3DSCENE_FIRST, SDRATTR_3DSCENE_LAST> aSet(*mxItemSet->GetPool() );
+ aSet.Put(pScene->GetProperties().GetObjectItemSet());
+ mxItemSet->Put(aSet);
+ }
+
+ // call parent
+ return E3dProperties::GetMergedItemSet();
+ }
+
+ void E3dCompoundProperties::SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems)
+ {
+ // Set scene specific items at scene
+ E3dCompoundObject& rObj = static_cast<E3dCompoundObject&>(GetSdrObject());
+ E3dScene* pScene(rObj.getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ // force ItemSet
+ GetObjectItemSet();
+
+ // Generate filtered scene properties (SDRATTR_3DSCENE_) itemset
+ SfxItemSetFixed<SDRATTR_3DSCENE_FIRST, SDRATTR_3DSCENE_LAST> aSet(*mxItemSet->GetPool());
+ aSet.Put(rSet);
+
+ if(bClearAllItems)
+ {
+ pScene->GetProperties().ClearObjectItem();
+ }
+
+ if(aSet.Count())
+ {
+ pScene->GetProperties().SetObjectItemSet(aSet);
+ }
+ }
+
+ // call parent. This will set items on local object, too.
+ E3dProperties::SetMergedItemSet(rSet, bClearAllItems);
+ }
+
+ void E3dCompoundProperties::PostItemChange(const sal_uInt16 nWhich)
+ {
+ // call parent
+ E3dProperties::PostItemChange(nWhich);
+
+ // handle value change
+ E3dCompoundObject& rObj = static_cast<E3dCompoundObject&>(GetSdrObject());
+
+ switch(nWhich)
+ {
+ // #i28528#
+ // Added extra Item (Bool) for chart2 to be able to show reduced line geometry
+ case SDRATTR_3DOBJ_REDUCED_LINE_GEOMETRY:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_DOUBLE_SIDED:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_NORMALS_KIND:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_NORMALS_INVERT:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_TEXTURE_PROJ_X:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_TEXTURE_PROJ_Y:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/e3dextrudeproperties.cxx b/svx/source/sdr/properties/e3dextrudeproperties.cxx
new file mode 100644
index 000000000..9b9ffd8be
--- /dev/null
+++ b/svx/source/sdr/properties/e3dextrudeproperties.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/e3dextrudeproperties.hxx>
+#include <extrud3d.hxx>
+
+
+namespace sdr::properties
+{
+ E3dExtrudeProperties::E3dExtrudeProperties(SdrObject& rObj)
+ : E3dCompoundProperties(rObj)
+ {
+ }
+
+ E3dExtrudeProperties::E3dExtrudeProperties(const E3dExtrudeProperties& rProps, SdrObject& rObj)
+ : E3dCompoundProperties(rProps, rObj)
+ {
+ }
+
+ E3dExtrudeProperties::~E3dExtrudeProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> E3dExtrudeProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new E3dExtrudeProperties(*this, rObj));
+ }
+
+ void E3dExtrudeProperties::PostItemChange(const sal_uInt16 nWhich)
+ {
+ // call parent
+ E3dCompoundProperties::PostItemChange(nWhich);
+
+ // handle value change
+ E3dExtrudeObj& rObj = static_cast<E3dExtrudeObj&>(GetSdrObject());
+
+ switch(nWhich)
+ {
+ case SDRATTR_3DOBJ_PERCENT_DIAGONAL:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_BACKSCALE:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_DEPTH:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/e3dlatheproperties.cxx b/svx/source/sdr/properties/e3dlatheproperties.cxx
new file mode 100644
index 000000000..feb546534
--- /dev/null
+++ b/svx/source/sdr/properties/e3dlatheproperties.cxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/e3dlatheproperties.hxx>
+#include <svx/lathe3d.hxx>
+
+
+namespace sdr::properties
+{
+ E3dLatheProperties::E3dLatheProperties(SdrObject& rObj)
+ : E3dCompoundProperties(rObj)
+ {
+ }
+
+ E3dLatheProperties::E3dLatheProperties(const E3dLatheProperties& rProps, SdrObject& rObj)
+ : E3dCompoundProperties(rProps, rObj)
+ {
+ }
+
+ E3dLatheProperties::~E3dLatheProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> E3dLatheProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new E3dLatheProperties(*this, rObj));
+ }
+
+ void E3dLatheProperties::PostItemChange(const sal_uInt16 nWhich)
+ {
+ // call parent
+ E3dCompoundProperties::PostItemChange(nWhich);
+
+ // handle value change
+ E3dLatheObj& rObj = static_cast<E3dLatheObj&>(GetSdrObject());
+
+ switch(nWhich)
+ {
+ case SDRATTR_3DOBJ_HORZ_SEGS:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_VERT_SEGS:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_PERCENT_DIAGONAL:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_BACKSCALE:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_END_ANGLE:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/e3dproperties.cxx b/svx/source/sdr/properties/e3dproperties.cxx
new file mode 100644
index 000000000..946f879de
--- /dev/null
+++ b/svx/source/sdr/properties/e3dproperties.cxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/e3dproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svx/svddef.hxx>
+#include <svx/obj3d.hxx>
+
+
+namespace sdr::properties
+{
+ // create a new itemset
+ SfxItemSet E3dProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(rPool,
+
+ // ranges from SdrAttrObj
+ svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+
+ // ranges from E3dObject, contains object and scene because of GetMergedItemSet()
+ SDRATTR_3D_FIRST, SDRATTR_3D_LAST>);
+ }
+
+ E3dProperties::E3dProperties(SdrObject& rObj)
+ : AttributeProperties(rObj)
+ {
+ }
+
+ E3dProperties::E3dProperties(const E3dProperties& rProps, SdrObject& rObj)
+ : AttributeProperties(rProps, rObj)
+ {
+ }
+
+ E3dProperties::~E3dProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> E3dProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new E3dProperties(*this, rObj));
+ }
+
+ void E3dProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ E3dObject& rObj = static_cast<E3dObject&>(GetSdrObject());
+
+ // call parent
+ AttributeProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+
+ // local changes
+ rObj.StructureChanged();
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/e3dsceneproperties.cxx b/svx/source/sdr/properties/e3dsceneproperties.cxx
new file mode 100644
index 000000000..c156db33e
--- /dev/null
+++ b/svx/source/sdr/properties/e3dsceneproperties.cxx
@@ -0,0 +1,296 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/e3dsceneproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/whiter.hxx>
+#include <svx/svddef.hxx>
+#include <svx/scene3d.hxx>
+#include <osl/diagnose.h>
+#include <memory>
+
+
+namespace sdr::properties
+{
+ E3dSceneProperties::E3dSceneProperties(SdrObject& rObj)
+ : E3dProperties(rObj)
+ {
+ }
+
+ E3dSceneProperties::E3dSceneProperties(const E3dSceneProperties& rProps, SdrObject& rObj)
+ : E3dProperties(rProps, rObj)
+ {
+ }
+
+ E3dSceneProperties::~E3dSceneProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> E3dSceneProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new E3dSceneProperties(*this, rObj));
+ }
+
+ const SfxItemSet& E3dSceneProperties::GetMergedItemSet() const
+ {
+ // prepare ItemSet
+ if(mxItemSet)
+ {
+ // filter for SDRATTR_3DSCENE_ items, only keep those items
+ SfxItemSetFixed<SDRATTR_3DSCENE_FIRST, SDRATTR_3DSCENE_LAST> aNew(*mxItemSet->GetPool());
+ aNew.Put(*mxItemSet);
+ mxItemSet->ClearItem();
+ mxItemSet->Put(aNew);
+ }
+ else
+ {
+ // No ItemSet yet, force local ItemSet
+ GetObjectItemSet();
+ }
+
+ // collect all ItemSets of contained 3d objects
+ const SdrObjList* pSub(static_cast<const E3dScene&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ SdrObject* pObj = pSub->GetObj(a);
+
+ if(dynamic_cast<const E3dCompoundObject* >(pObj))
+ {
+ const SfxItemSet& rSet = pObj->GetMergedItemSet();
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+
+ while(nWhich)
+ {
+ // Leave out the SDRATTR_3DSCENE_ range, this would only be double
+ // and always equal.
+ if(nWhich <= SDRATTR_3DSCENE_FIRST || nWhich >= SDRATTR_3DSCENE_LAST)
+ {
+ if(SfxItemState::DONTCARE == aIter.GetItemState(false))
+ {
+ mxItemSet->InvalidateItem(nWhich);
+ }
+ else
+ {
+ mxItemSet->MergeValue(rSet.Get(nWhich), true);
+ }
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+ }
+ }
+
+ // call parent
+ return E3dProperties::GetMergedItemSet();
+ }
+
+ void E3dSceneProperties::SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems)
+ {
+ // Set SDRATTR_3DOBJ_ range at contained objects.
+ const SdrObjList* pSub(static_cast<const E3dScene&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ if(nCount)
+ {
+ // Generate filtered ItemSet which contains all but the SDRATTR_3DSCENE items.
+ // #i50808# Leak fix, Clone produces a new instance and we get ownership here
+ SfxItemSet aNewSet(rSet.CloneAsValue());
+
+ for(sal_uInt16 b(SDRATTR_3DSCENE_FIRST); b <= SDRATTR_3DSCENE_LAST; b++)
+ {
+ aNewSet.ClearItem(b);
+ }
+
+ if(aNewSet.Count())
+ {
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ SdrObject* pObj = pSub->GetObj(a);
+
+ if(dynamic_cast<const E3dCompoundObject* >(pObj))
+ {
+ // set merged ItemSet at contained 3d object.
+ pObj->SetMergedItemSet(aNewSet, bClearAllItems);
+ }
+ }
+ }
+ }
+
+ // call parent. This will set items on local object, too.
+ E3dProperties::SetMergedItemSet(rSet, bClearAllItems);
+ }
+
+ void E3dSceneProperties::SetMergedItem(const SfxPoolItem& rItem)
+ {
+ const SdrObjList* pSub(static_cast<const E3dScene&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ pSub->GetObj(a)->SetMergedItem(rItem);
+ }
+
+ // #i43809# call parent. This will set items on local object, too.
+ E3dProperties::SetMergedItem(rItem);
+ }
+
+ void E3dSceneProperties::ClearMergedItem(const sal_uInt16 nWhich)
+ {
+ const SdrObjList* pSub(static_cast<const E3dScene&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ pSub->GetObj(a)->ClearMergedItem(nWhich);
+ }
+
+ // #i43809# call parent. This will clear items on local object, too.
+ E3dProperties::ClearMergedItem(nWhich);
+ }
+
+ void E3dSceneProperties::PostItemChange(const sal_uInt16 nWhich)
+ {
+ // call parent
+ E3dProperties::PostItemChange(nWhich);
+
+ // local changes
+ E3dScene& rObj = static_cast<E3dScene&>(GetSdrObject());
+ rObj.StructureChanged();
+
+ switch(nWhich)
+ {
+ case SDRATTR_3DSCENE_PERSPECTIVE :
+ case SDRATTR_3DSCENE_DISTANCE :
+ case SDRATTR_3DSCENE_FOCAL_LENGTH :
+ {
+ // #83387#, #83391#
+ // one common function for the camera attributes
+ // since SetCamera() sets all three back to the ItemSet
+ Camera3D aSceneCam(rObj.GetCamera());
+ bool bChange(false);
+
+ // for SDRATTR_3DSCENE_PERSPECTIVE:
+ if(aSceneCam.GetProjection() != rObj.GetPerspective())
+ {
+ aSceneCam.SetProjection(rObj.GetPerspective());
+ bChange = true;
+ }
+
+ // for SDRATTR_3DSCENE_DISTANCE:
+ basegfx::B3DPoint aActualPosition(aSceneCam.GetPosition());
+ double fNew = rObj.GetDistance();
+
+ if(fNew != aActualPosition.getZ())
+ {
+ aSceneCam.SetPosition(basegfx::B3DPoint(aActualPosition.getX(), aActualPosition.getY(), fNew));
+ bChange = true;
+ }
+
+ // for SDRATTR_3DSCENE_FOCAL_LENGTH:
+ fNew = rObj.GetFocalLength() / 100.0;
+
+ if(aSceneCam.GetFocalLength() != fNew)
+ {
+ aSceneCam.SetFocalLength(fNew);
+ bChange = true;
+ }
+
+ // for all
+ if(bChange)
+ {
+ rObj.SetCamera(aSceneCam);
+ }
+
+ break;
+ }
+ }
+ }
+
+ void E3dSceneProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ const SdrObjList* pSub(static_cast<const E3dScene&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ if(bBroadcast)
+ pSub->GetObj(a)->SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
+ else
+ pSub->GetObj(a)->NbcSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
+ }
+ }
+
+ SfxStyleSheet* E3dSceneProperties::GetStyleSheet() const
+ {
+ SfxStyleSheet* pRetval = nullptr;
+
+ const SdrObjList* pSub(static_cast<const E3dScene&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ SfxStyleSheet* pCandidate = pSub->GetObj(a)->GetStyleSheet();
+
+ if(pRetval)
+ {
+ if(pCandidate != pRetval)
+ {
+ // different StyleSheelts, return none
+ return nullptr;
+ }
+ }
+ else
+ {
+ pRetval = pCandidate;
+ }
+ }
+
+ return pRetval;
+ }
+
+ void E3dSceneProperties::SetSceneItemsFromCamera()
+ {
+ // force ItemSet
+ GetObjectItemSet();
+
+ E3dScene& rObj = static_cast<E3dScene&>(GetSdrObject());
+ const Camera3D& aSceneCam(rObj.GetCamera());
+
+ // ProjectionType
+ mxItemSet->Put(Svx3DPerspectiveItem(aSceneCam.GetProjection()));
+
+ // CamPos
+ mxItemSet->Put(makeSvx3DDistanceItem(static_cast<sal_uInt32>(aSceneCam.GetPosition().getZ() + 0.5)));
+
+ // FocalLength
+ mxItemSet->Put(makeSvx3DFocalLengthItem(static_cast<sal_uInt32>((aSceneCam.GetFocalLength() * 100.0) + 0.5)));
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/e3dsphereproperties.cxx b/svx/source/sdr/properties/e3dsphereproperties.cxx
new file mode 100644
index 000000000..66f01748f
--- /dev/null
+++ b/svx/source/sdr/properties/e3dsphereproperties.cxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/e3dsphereproperties.hxx>
+#include <svx/sphere3d.hxx>
+
+
+namespace sdr::properties
+{
+ E3dSphereProperties::E3dSphereProperties(SdrObject& rObj)
+ : E3dCompoundProperties(rObj)
+ {
+ }
+
+ E3dSphereProperties::E3dSphereProperties(const E3dSphereProperties& rProps, SdrObject& rObj)
+ : E3dCompoundProperties(rProps, rObj)
+ {
+ }
+
+ E3dSphereProperties::~E3dSphereProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> E3dSphereProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new E3dSphereProperties(*this, rObj));
+ }
+
+ void E3dSphereProperties::PostItemChange(const sal_uInt16 nWhich)
+ {
+ // call parent
+ E3dCompoundProperties::PostItemChange(nWhich);
+
+ // handle value change
+ E3dSphereObj& rObj = static_cast<E3dSphereObj&>(GetSdrObject());
+
+ switch(nWhich)
+ {
+ case SDRATTR_3DOBJ_HORZ_SEGS:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ case SDRATTR_3DOBJ_VERT_SEGS:
+ {
+ rObj.ActionChanged();
+ break;
+ }
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/emptyproperties.cxx b/svx/source/sdr/properties/emptyproperties.cxx
new file mode 100644
index 000000000..1cad150b2
--- /dev/null
+++ b/svx/source/sdr/properties/emptyproperties.cxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/emptyproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svx/svdobj.hxx>
+
+
+namespace sdr::properties
+{
+ EmptyProperties::EmptyProperties(SdrObject& rObj)
+ : BaseProperties(rObj)
+ {
+ }
+
+ std::unique_ptr<BaseProperties> EmptyProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new EmptyProperties(rObj));
+ }
+
+ const SfxItemSet& EmptyProperties::GetObjectItemSet() const
+ {
+ assert(!"EmptyProperties::GetObjectItemSet() should never be called");
+ abort();
+ }
+
+ SfxItemSet EmptyProperties::CreateObjectSpecificItemSet(SfxItemPool&)
+ {
+ assert(!"EmptyProperties::CreateObjectSpecificItemSet() should never be called");
+ abort();
+ }
+
+ void EmptyProperties::SetObjectItem(const SfxPoolItem& /*rItem*/)
+ {
+ assert(!"EmptyProperties::SetObjectItem() should never be called");
+ }
+
+ void EmptyProperties::SetObjectItemDirect(const SfxPoolItem& /*rItem*/)
+ {
+ assert(!"EmptyProperties::SetObjectItemDirect() should never be called");
+ }
+
+ void EmptyProperties::ClearObjectItem(const sal_uInt16 /*nWhich*/)
+ {
+ assert(!"EmptyProperties::ClearObjectItem() should never be called");
+ }
+
+ void EmptyProperties::ClearObjectItemDirect(const sal_uInt16 /*nWhich*/)
+ {
+ assert(!"EmptyProperties::ClearObjectItemDirect() should never be called");
+ }
+
+ void EmptyProperties::SetObjectItemSet(const SfxItemSet& /*rSet*/)
+ {
+ assert(!"EmptyProperties::SetObjectItemSet() should never be called");
+ }
+
+ void EmptyProperties::SetStyleSheet(SfxStyleSheet* /*pNewStyleSheet*/, bool /*bDontRemoveHardAttr*/,
+ bool /*bBroadcast*/)
+ {
+ assert(!"EmptyProperties::SetStyleSheet() should never be called");
+ }
+
+ SfxStyleSheet* EmptyProperties::GetStyleSheet() const
+ {
+ assert(!"EmptyProperties::GetStyleSheet() should never be called");
+ return nullptr;
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/graphicproperties.cxx b/svx/source/sdr/properties/graphicproperties.cxx
new file mode 100644
index 000000000..be9b87800
--- /dev/null
+++ b/svx/source/sdr/properties/graphicproperties.cxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/graphicproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svx/svddef.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/sdgcpitm.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/sdgluitm.hxx>
+#include <sdgcoitm.hxx>
+#include <svx/sdggaitm.hxx>
+#include <sdgtritm.hxx>
+#include <sdginitm.hxx>
+#include <svx/sdgmoitm.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+
+namespace sdr::properties
+{
+ void GraphicProperties::applyDefaultStyleSheetFromSdrModel()
+ {
+ SfxStyleSheet* pStyleSheet(GetSdrObject().getSdrModelFromSdrObject().GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj());
+
+ if(pStyleSheet)
+ {
+ // do not delete hard attributes when setting dsefault Style
+ SetStyleSheet(pStyleSheet, true, true);
+ }
+ else
+ {
+ SetMergedItem(XFillStyleItem(com::sun::star::drawing::FillStyle_NONE));
+ SetMergedItem(XLineStyleItem(com::sun::star::drawing::LineStyle_NONE));
+ }
+ }
+
+ // create a new itemset
+ SfxItemSet GraphicProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(rPool,
+
+ // range from SdrAttrObj
+ svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+
+ // range from SdrGrafObj
+ SDRATTR_GRAF_FIRST, SDRATTR_GRAF_LAST,
+
+ SDRATTR_GLOW_FIRST, SDRATTR_SOFTEDGE_LAST,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+
+ // range from SdrTextObj
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ GraphicProperties::GraphicProperties(SdrObject& rObj)
+ : RectangleProperties(rObj)
+ {
+ }
+
+ GraphicProperties::GraphicProperties(const GraphicProperties& rProps, SdrObject& rObj)
+ : RectangleProperties(rProps, rObj)
+ {
+ }
+
+ GraphicProperties::~GraphicProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> GraphicProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new GraphicProperties(*this, rObj));
+ }
+
+ void GraphicProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrGrafObj& rObj = static_cast<SdrGrafObj&>(GetSdrObject());
+
+ // local changes
+ rObj.SetXPolyDirty();
+
+ // #i29367# Update GraphicAttr, too. This was formerly
+ // triggered by SdrGrafObj::Notify, which is no longer
+ // called nowadays. BTW: strictly speaking, the whole
+ // ImpSetAttrToGrafInfostuff could
+ // be dumped, when SdrGrafObj::aGrafInfo is removed and
+ // always created on the fly for repaint.
+ rObj.ImpSetAttrToGrafInfo();
+
+ // call parent
+ RectangleProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+ }
+
+ void GraphicProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ RectangleProperties::SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+
+ // local changes
+ SdrGrafObj& rObj = static_cast<SdrGrafObj&>(GetSdrObject());
+ rObj.SetXPolyDirty();
+
+ // local changes
+ rObj.ImpSetAttrToGrafInfo();
+ }
+
+ void GraphicProperties::ForceDefaultAttributes()
+ {
+ // call parent
+ RectangleProperties::ForceDefaultAttributes();
+
+ // force ItemSet
+ GetObjectItemSet();
+
+ mxItemSet->Put( SdrGrafLuminanceItem( 0 ) );
+ mxItemSet->Put( SdrGrafContrastItem( 0 ) );
+ mxItemSet->Put( SdrGrafRedItem( 0 ) );
+ mxItemSet->Put( SdrGrafGreenItem( 0 ) );
+ mxItemSet->Put( SdrGrafBlueItem( 0 ) );
+ mxItemSet->Put( SdrGrafGamma100Item( 100 ) );
+ mxItemSet->Put( SdrGrafTransparenceItem( 0 ) );
+ mxItemSet->Put( SdrGrafInvertItem( false ) );
+ mxItemSet->Put( SdrGrafModeItem( GraphicDrawMode::Standard ) );
+ mxItemSet->Put( SdrGrafCropItem( 0, 0, 0, 0 ) );
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/groupproperties.cxx b/svx/source/sdr/properties/groupproperties.cxx
new file mode 100644
index 000000000..6ec522aa3
--- /dev/null
+++ b/svx/source/sdr/properties/groupproperties.cxx
@@ -0,0 +1,240 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/groupproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/whiter.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdpage.hxx>
+#include <osl/diagnose.h>
+
+
+namespace sdr::properties
+{
+ GroupProperties::GroupProperties(SdrObject& rObj)
+ : BaseProperties(rObj)
+ {
+ }
+
+ GroupProperties::~GroupProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> GroupProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new GroupProperties(rObj));
+ }
+
+ SfxItemSet GroupProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(rPool);
+ }
+
+ const SfxItemSet& GroupProperties::GetObjectItemSet() const
+ {
+ assert(!"GroupProperties::GetObjectItemSet() should never be called");
+ abort();
+ }
+
+ const SfxItemSet& GroupProperties::GetMergedItemSet() const
+ {
+ // prepare ItemSet
+ if(mxItemSet)
+ // clear local itemset for merge
+ mxItemSet->ClearItem();
+ else if(!mxItemSet)
+ // force local itemset
+ mxItemSet.emplace(GetSdrObject().GetObjectItemPool());
+
+ // collect all ItemSets in mpItemSet
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ const SfxItemSet& rSet = pSub->GetObj(a)->GetMergedItemSet();
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+
+ while(nWhich)
+ {
+ if(SfxItemState::DONTCARE == aIter.GetItemState(false))
+ {
+ mxItemSet->InvalidateItem(nWhich);
+ }
+ else
+ {
+ mxItemSet->MergeValue(rSet.Get(nWhich), true);
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+ }
+
+ // For group properties, do not call parent since groups do
+ // not have local ItemSets.
+ return *mxItemSet;
+ }
+
+ void GroupProperties::SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems)
+ {
+ // iterate over contained SdrObjects
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ SdrObject* pObj = pSub->GetObj(a);
+
+ if(pObj)
+ {
+ // Set merged ItemSet at contained object
+ pObj->SetMergedItemSet(rSet, bClearAllItems);
+ }
+ }
+
+ // Do not call parent here. Group objects do not have local ItemSets
+ // where items need to be set.
+ }
+
+ void GroupProperties::SetObjectItem(const SfxPoolItem& /*rItem*/)
+ {
+ assert(!"GroupProperties::SetObjectItem() should never be called");
+ }
+
+ void GroupProperties::SetObjectItemDirect(const SfxPoolItem& /*rItem*/)
+ {
+ assert(!"GroupProperties::SetObjectItemDirect() should never be called");
+ }
+
+ void GroupProperties::ClearObjectItem(const sal_uInt16 nWhich)
+ {
+ // iterate over contained SdrObjects
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ SdrObject* pObj = pSub->GetObj(a);
+
+ if(pObj)
+ {
+ pObj->GetProperties().ClearObjectItem(nWhich);
+ }
+ }
+ }
+
+ void GroupProperties::ClearObjectItemDirect(const sal_uInt16 /*nWhich*/)
+ {
+ assert(!"GroupProperties::ClearObjectItemDirect() should never be called");
+ }
+
+ void GroupProperties::SetMergedItem(const SfxPoolItem& rItem)
+ {
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ pSub->GetObj(a)->GetProperties().SetMergedItem(rItem);
+ }
+ }
+
+ void GroupProperties::ClearMergedItem(const sal_uInt16 nWhich)
+ {
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ pSub->GetObj(a)->GetProperties().ClearMergedItem(nWhich);
+ }
+ }
+
+ void GroupProperties::SetObjectItemSet(const SfxItemSet& /*rSet*/)
+ {
+ assert(!"GroupProperties::SetObjectItemSet() should never be called");
+ }
+
+ SfxStyleSheet* GroupProperties::GetStyleSheet() const
+ {
+ SfxStyleSheet* pRetval = nullptr;
+
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ SfxStyleSheet* pCandidate = pSub->GetObj(a)->GetStyleSheet();
+
+ if(pRetval)
+ {
+ if(pCandidate != pRetval)
+ {
+ // different StyleSheelts, return none
+ return nullptr;
+ }
+ }
+ else
+ {
+ pRetval = pCandidate;
+ }
+ }
+
+ return pRetval;
+ }
+
+ void GroupProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ if(bBroadcast)
+ pSub->GetObj(a)->SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
+ else
+ pSub->GetObj(a)->NbcSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
+ }
+ }
+
+ void GroupProperties::ForceStyleToHardAttributes()
+ {
+ const SdrObjList* pSub(static_cast<const SdrObjGroup&>(GetSdrObject()).GetSubList());
+ OSL_ENSURE(nullptr != pSub, "Children of SdrObject expected (!)");
+ const size_t nCount(nullptr == pSub ? 0 : pSub->GetObjCount());
+
+ for(size_t a = 0; a < nCount; ++a)
+ {
+ pSub->GetObj(a)->GetProperties().ForceStyleToHardAttributes();
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/itemsettools.cxx b/svx/source/sdr/properties/itemsettools.cxx
new file mode 100644
index 000000000..11431d367
--- /dev/null
+++ b/svx/source/sdr/properties/itemsettools.cxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/itemsettools.hxx>
+#include <tools/fract.hxx>
+#include <svl/itemset.hxx>
+#include <svl/whiter.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svditer.hxx>
+#include <memory>
+
+// class to remember broadcast start positions
+
+namespace sdr::properties
+{
+ ItemChangeBroadcaster::ItemChangeBroadcaster(const SdrObject& rObj)
+ {
+ if (rObj.GetObjIdentifier() == SdrObjKind::Group)
+ {
+ const SdrObjGroup* pGroupObj = static_cast<const SdrObjGroup*>(&rObj);
+ SdrObjListIter aIter(pGroupObj->GetSubList(), SdrIterMode::DeepNoGroups);
+ maRectangles.reserve(aIter.Count());
+
+ while(aIter.IsMore())
+ {
+ SdrObject* pObj = aIter.Next();
+
+ if(pObj)
+ {
+ maRectangles.push_back(pObj->GetLastBoundRect());
+ }
+ }
+ }
+ else
+ {
+ maRectangles.push_back(rObj.GetLastBoundRect());
+ }
+ }
+
+
+ void ScaleItemSet(SfxItemSet& rSet, const Fraction& rScale)
+ {
+ sal_Int32 nMul(rScale.GetNumerator());
+ sal_Int32 nDiv(rScale.GetDenominator());
+
+ if(!rScale.IsValid() || !nDiv)
+ {
+ return;
+ }
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+ const SfxPoolItem *pItem = nullptr;
+
+ while(nWhich)
+ {
+ if(SfxItemState::SET == aIter.GetItemState(false, &pItem))
+ {
+ if(pItem->HasMetrics())
+ {
+ std::unique_ptr<SfxPoolItem> pNewItem(pItem->Clone());
+ pNewItem->ScaleMetrics(nMul, nDiv);
+ rSet.Put(std::move(pNewItem));
+ }
+ }
+ nWhich = aIter.NextWhich();
+ }
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/measureproperties.cxx b/svx/source/sdr/properties/measureproperties.cxx
new file mode 100644
index 000000000..07441c385
--- /dev/null
+++ b/svx/source/sdr/properties/measureproperties.cxx
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/measureproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svx/svddef.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdomeas.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/sdynitm.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+
+namespace sdr::properties
+{
+ // create a new itemset
+ SfxItemSet MeasureProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(
+ rPool,
+ svl::Items<
+ // Ranges from SdrAttrObj, SdrMeasureObj:
+ SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_MEASURE_FIRST, SDRATTR_MEASURE_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+ // Range from SdrTextObj:
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ MeasureProperties::MeasureProperties(SdrObject& rObj)
+ : TextProperties(rObj)
+ {
+ }
+
+ MeasureProperties::MeasureProperties(const MeasureProperties& rProps, SdrObject& rObj)
+ : TextProperties(rProps, rObj)
+ {
+ }
+
+ MeasureProperties::~MeasureProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> MeasureProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new MeasureProperties(*this, rObj));
+ }
+
+ void MeasureProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrMeasureObj& rObj = static_cast<SdrMeasureObj&>(GetSdrObject());
+
+ // call parent
+ TextProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+
+ // local changes
+ rObj.SetTextDirty();
+ }
+
+ void MeasureProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ TextProperties::SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+
+ // local changes
+ // get access to dimension line object
+ SdrMeasureObj& rObj = static_cast<SdrMeasureObj&>(GetSdrObject());
+
+ // mark dimension line text as changed (dirty) in the dimension line object
+ rObj.SetTextDirty();
+
+ // tdf#98525 ask the dimension line object to redraw the changed text
+ rObj.UndirtyText();
+ }
+
+ void MeasureProperties::ForceDefaultAttributes()
+ {
+ // call parent
+ TextProperties::ForceDefaultAttributes();
+
+ // force ItemSet
+ GetObjectItemSet();
+
+ //#71958# by default, the show units Bool-Item is set as hard
+ // attribute to sal_True to avoid confusion when copying SdrMeasureObj's
+ // from one application to another
+ mxItemSet->Put(SdrYesNoItem(SDRATTR_MEASURESHOWUNIT, true));
+
+ basegfx::B2DPolygon aNewPolygon;
+ aNewPolygon.append(basegfx::B2DPoint(100.0, 0.0));
+ aNewPolygon.append(basegfx::B2DPoint(200.0, 400.0));
+ aNewPolygon.append(basegfx::B2DPoint(0.0, 400.0));
+ aNewPolygon.setClosed(true);
+
+ mxItemSet->Put(XLineStartItem(OUString(), basegfx::B2DPolyPolygon(aNewPolygon)));
+ mxItemSet->Put(XLineStartWidthItem(200));
+ mxItemSet->Put(XLineEndItem(OUString(), basegfx::B2DPolyPolygon(aNewPolygon)));
+ mxItemSet->Put(XLineEndWidthItem(200));
+ mxItemSet->Put(XLineStyleItem(css::drawing::LineStyle_SOLID));
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/oleproperties.cxx b/svx/source/sdr/properties/oleproperties.cxx
new file mode 100644
index 000000000..587ff1d3f
--- /dev/null
+++ b/svx/source/sdr/properties/oleproperties.cxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/oleproperties.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdmodel.hxx>
+
+namespace sdr::properties
+{
+ void OleProperties::applyDefaultStyleSheetFromSdrModel()
+ {
+ SfxStyleSheet* pStyleSheet(GetSdrObject().getSdrModelFromSdrObject().GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj());
+
+ if(pStyleSheet)
+ {
+ // do not delete hard attributes when setting dsefault Style
+ SetStyleSheet(pStyleSheet, true, true);
+ }
+ else
+ {
+ SetMergedItem(XFillStyleItem(com::sun::star::drawing::FillStyle_NONE));
+ SetMergedItem(XLineStyleItem(com::sun::star::drawing::LineStyle_NONE));
+ }
+ }
+
+ OleProperties::OleProperties(SdrObject& rObj)
+ : RectangleProperties(rObj)
+ {
+ }
+
+ OleProperties::OleProperties(const OleProperties& rProps, SdrObject& rObj)
+ : RectangleProperties(rProps, rObj)
+ {
+ }
+
+ OleProperties::~OleProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> OleProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new OleProperties(*this, rObj));
+ }
+
+ void OleProperties::ForceDefaultAttributes()
+ {
+ // call parent
+ RectangleProperties::ForceDefaultAttributes();
+
+ // force ItemSet
+ GetObjectItemSet();
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/pageproperties.cxx b/svx/source/sdr/properties/pageproperties.cxx
new file mode 100644
index 000000000..011ab2192
--- /dev/null
+++ b/svx/source/sdr/properties/pageproperties.cxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/pageproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svx/svdobj.hxx>
+#include <tools/debug.hxx>
+
+
+namespace sdr::properties
+{
+ PageProperties::PageProperties(SdrObject& rObj)
+ : BaseProperties(rObj)
+ {
+ }
+
+ PageProperties::PageProperties(const PageProperties& /*rProps*/, SdrObject& rObj)
+ : BaseProperties(rObj)
+ {
+ }
+
+ PageProperties::~PageProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> PageProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new PageProperties(*this, rObj));
+ }
+
+ SfxItemSet PageProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(rPool);
+ }
+
+ // get itemset. Override here to allow creating the empty itemset
+ // without asserting
+ const SfxItemSet& PageProperties::GetObjectItemSet() const
+ {
+ if(!mxEmptyItemSet)
+ {
+ mxEmptyItemSet.emplace(GetSdrObject().GetObjectItemPool());
+ }
+
+ DBG_ASSERT(mxEmptyItemSet, "Could not create an SfxItemSet(!)");
+
+ return *mxEmptyItemSet;
+ }
+
+ SfxStyleSheet* PageProperties::GetStyleSheet() const
+ {
+ // override to legally return a 0L pointer here
+ return nullptr;
+ }
+
+ void PageProperties::SetStyleSheet(SfxStyleSheet* /*pStyleSheet*/, bool /*bDontRemoveHardAttr*/,
+ bool /*bBroadcast*/)
+ {
+ // override to legally ignore the StyleSheet here
+ }
+
+ void PageProperties::ClearObjectItem(const sal_uInt16 /*nWhich*/)
+ {
+ // simply ignore item clearing on page objects
+ }
+
+ void PageProperties::SetObjectItem(const SfxPoolItem& /*rItem*/)
+ {
+ assert(!"PageProperties::SetObjectItem() should never be called");
+ }
+
+ void PageProperties::SetObjectItemDirect(const SfxPoolItem& /*rItem*/)
+ {
+ assert(!"PageProperties::SetObjectItemDirect() should never be called");
+ }
+
+ void PageProperties::ClearObjectItemDirect(const sal_uInt16 /*nWhich*/)
+ {
+ assert(!"PageProperties::ClearObjectItemDirect() should never be called");
+ }
+
+ void PageProperties::SetObjectItemSet(const SfxItemSet& /*rSet*/)
+ {
+ assert(!"PageProperties::SetObjectItemSet() should never be called");
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/properties.cxx b/svx/source/sdr/properties/properties.cxx
new file mode 100644
index 000000000..97a264712
--- /dev/null
+++ b/svx/source/sdr/properties/properties.cxx
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <libxml/xmlwriter.h>
+
+#include <svx/sdr/properties/properties.hxx>
+#include <sdr/properties/itemsettools.hxx>
+#include <svl/itemset.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svditer.hxx>
+#include <svx/xdef.hxx>
+#include <svx/xfillit0.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr::properties
+{
+ BaseProperties::BaseProperties(SdrObject& rObj)
+ : mrObject(rObj)
+ {
+ }
+
+ BaseProperties::~BaseProperties()
+ {
+ }
+
+ const SdrObject& BaseProperties::GetSdrObject() const
+ {
+ return mrObject;
+ }
+
+ SdrObject& BaseProperties::GetSdrObject()
+ {
+ return mrObject;
+ }
+
+ const SfxItemSet& BaseProperties::GetMergedItemSet() const
+ {
+ // default implementation falls back to GetObjectItemSet()
+ return GetObjectItemSet();
+ }
+
+ void BaseProperties::SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems)
+ {
+ // clear items if requested
+ if(bClearAllItems)
+ {
+ ClearObjectItem();
+ }
+
+ // default implementation falls back to SetObjectItemSet()
+ SetObjectItemSet(rSet);
+ }
+
+ void BaseProperties::SetMergedItem(const SfxPoolItem& rItem)
+ {
+ // default implementation falls back to SetObjectItem()
+ SetObjectItem(rItem);
+ }
+
+ void BaseProperties::ClearMergedItem(const sal_uInt16 nWhich)
+ {
+ // default implementation falls back to ClearObjectItem()
+ ClearObjectItem(nWhich);
+ }
+
+ void BaseProperties::ForceStyleToHardAttributes()
+ {
+ // force all attributes which come from styles to hard attributes
+ // to be able to live without the style. Default implementation does nothing.
+ // Override where an ItemSet is implemented.
+ }
+
+ void BaseProperties::SetMergedItemSetAndBroadcast(const SfxItemSet& rSet, bool bClearAllItems)
+ {
+ ItemChangeBroadcaster aC(GetSdrObject());
+
+ if(bClearAllItems)
+ {
+ ClearObjectItem();
+ }
+
+ SetMergedItemSet(rSet);
+ BroadcastItemChange(aC);
+ }
+
+ const SfxPoolItem& BaseProperties::GetItem(const sal_uInt16 nWhich) const
+ {
+ return GetObjectItemSet().Get(nWhich);
+ }
+
+ void BaseProperties::BroadcastItemChange(const ItemChangeBroadcaster& rChange)
+ {
+ const sal_uInt32 nCount(rChange.GetRectangleCount());
+
+ // invalidate all new rectangles
+ SdrObject* pObj = &GetSdrObject();
+ if (pObj->GetObjIdentifier() == SdrObjKind::Group)
+ {
+ SdrObjGroup* pObjGroup = static_cast<SdrObjGroup*>(pObj);
+ SdrObjListIter aIter(pObjGroup, SdrIterMode::DeepNoGroups);
+
+ while(aIter.IsMore())
+ {
+ SdrObject* pChildObj = aIter.Next();
+ pChildObj->BroadcastObjectChange();
+ }
+ }
+ else
+ {
+ pObj->BroadcastObjectChange();
+ }
+
+ // also send the user calls
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ pObj->SendUserCall(SdrUserCallType::ChangeAttr, rChange.GetRectangle(a));
+ }
+ }
+
+ sal_uInt32 BaseProperties::getVersion() const
+ {
+ return 0;
+ }
+
+ void BaseProperties::dumpAsXml(xmlTextWriterPtr pWriter) const
+ {
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("BaseProperties"));
+ (void)xmlTextWriterEndElement(pWriter);
+ }
+
+ void CleanupFillProperties( SfxItemSet& rItemSet )
+ {
+ const bool bFillBitmap = rItemSet.GetItemState(XATTR_FILLBITMAP, false) == SfxItemState::SET;
+ const bool bFillGradient = rItemSet.GetItemState(XATTR_FILLGRADIENT, false) == SfxItemState::SET;
+ const bool bFillHatch = rItemSet.GetItemState(XATTR_FILLHATCH, false) == SfxItemState::SET;
+ if( !(bFillBitmap || bFillGradient || bFillHatch) )
+ return;
+
+ const XFillStyleItem* pFillStyleItem = rItemSet.GetItem(XATTR_FILLSTYLE);
+ if( !pFillStyleItem )
+ return;
+
+ if( bFillBitmap && (pFillStyleItem->GetValue() != drawing::FillStyle_BITMAP) )
+ {
+ rItemSet.ClearItem( XATTR_FILLBITMAP );
+ }
+
+ if( bFillGradient && (pFillStyleItem->GetValue() != drawing::FillStyle_GRADIENT) )
+ {
+ rItemSet.ClearItem( XATTR_FILLGRADIENT );
+ }
+
+ if( bFillHatch && (pFillStyleItem->GetValue() != drawing::FillStyle_HATCH) )
+ {
+ rItemSet.ClearItem( XATTR_FILLHATCH );
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/rectangleproperties.cxx b/svx/source/sdr/properties/rectangleproperties.cxx
new file mode 100644
index 000000000..4c3a72a2f
--- /dev/null
+++ b/svx/source/sdr/properties/rectangleproperties.cxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sdr/properties/rectangleproperties.hxx>
+#include <svx/svdorect.hxx>
+
+
+namespace sdr::properties
+{
+ RectangleProperties::RectangleProperties(SdrObject& rObj)
+ : TextProperties(rObj)
+ {
+ }
+
+ RectangleProperties::RectangleProperties(const RectangleProperties& rProps, SdrObject& rObj)
+ : TextProperties(rProps, rObj)
+ {
+ }
+
+ RectangleProperties::~RectangleProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> RectangleProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new RectangleProperties(*this, rObj));
+ }
+
+ void RectangleProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrRectObj& rObj = static_cast<SdrRectObj&>(GetSdrObject());
+
+ // call parent
+ TextProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+
+ // local changes
+ rObj.SetXPolyDirty();
+ }
+
+ // set a new StyleSheet and broadcast
+ void RectangleProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ TextProperties::SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+
+ // local changes
+ SdrRectObj& rObj = static_cast<SdrRectObj&>(GetSdrObject());
+ rObj.SetXPolyDirty();
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/properties/textproperties.cxx b/svx/source/sdr/properties/textproperties.cxx
new file mode 100644
index 000000000..d8cdf80df
--- /dev/null
+++ b/svx/source/sdr/properties/textproperties.cxx
@@ -0,0 +1,631 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/textproperties.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svl/itemiter.hxx>
+#include <svl/hint.hxx>
+#include <svx/svddef.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdtditm.hxx>
+#include <editeng/writingmodeitem.hxx>
+#include <svx/svdmodel.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <editeng/adjustitem.hxx>
+#include <svx/svdetc.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/flditem.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnwtit.hxx>
+
+using namespace com::sun::star;
+
+namespace sdr::properties
+{
+ SfxItemSet TextProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(rPool,
+
+ // range from SdrAttrObj
+ svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+
+ // range from SdrTextObj
+ EE_ITEMS_START, EE_ITEMS_END>);
+ }
+
+ TextProperties::TextProperties(SdrObject& rObj)
+ : AttributeProperties(rObj),
+ maVersion(0)
+ {
+ }
+
+ TextProperties::TextProperties(const TextProperties& rProps, SdrObject& rObj)
+ : AttributeProperties(rProps, rObj),
+ maVersion(rProps.getVersion())
+ {
+ }
+
+ TextProperties::~TextProperties()
+ {
+ }
+
+ std::unique_ptr<BaseProperties> TextProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new TextProperties(*this, rObj));
+ }
+
+ void TextProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > aChangedItems, sal_uInt16 nDeletedWhich)
+ {
+ SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+
+ // #i101556# ItemSet has changed -> new version
+ maVersion++;
+
+ if (auto pOutliner = rObj.GetTextEditOutliner())
+ {
+ pOutliner->SetTextColumns(rObj.GetTextColumnsNumber(),
+ rObj.GetTextColumnsSpacing());
+ }
+
+ const svx::ITextProvider& rTextProvider(getTextProvider());
+ sal_Int32 nText = rTextProvider.getTextCount();
+ while (nText--)
+ {
+ SdrText* pText = rTextProvider.getText( nText );
+
+ OutlinerParaObject* pParaObj = pText ? pText->GetOutlinerParaObject() : nullptr;
+
+ if(pParaObj)
+ {
+ const bool bTextEdit = rObj.IsTextEditActive() && (rObj.getActiveText() == pText);
+
+ // handle outliner attributes
+ GetObjectItemSet();
+ Outliner* pOutliner = rObj.GetTextEditOutliner();
+
+ if(!bTextEdit)
+ {
+ pOutliner = &rObj.ImpGetDrawOutliner();
+ pOutliner->SetText(*pParaObj);
+ }
+
+ sal_Int32 nParaCount(pOutliner->GetParagraphCount());
+
+ for(sal_Int32 nPara = 0; nPara < nParaCount; nPara++)
+ {
+ SfxItemSet aSet(pOutliner->GetParaAttribs(nPara));
+ for (const SfxPoolItem* pItem : aChangedItems)
+ aSet.Put(*pItem);
+ if (nDeletedWhich)
+ aSet.ClearItem(nDeletedWhich);
+ pOutliner->SetParaAttribs(nPara, aSet);
+ }
+
+ if(!bTextEdit)
+ {
+ if(nParaCount)
+ {
+ // force ItemSet
+ GetObjectItemSet();
+
+ SfxItemSet aNewSet(pOutliner->GetParaAttribs(0));
+ mxItemSet->Put(aNewSet);
+ }
+
+ std::optional<OutlinerParaObject> pTemp = pOutliner->CreateParaObject(0, nParaCount);
+ pOutliner->Clear();
+
+ rObj.NbcSetOutlinerParaObjectForText(std::move(pTemp),pText);
+ }
+ }
+ }
+
+ // Extra-Repaint for radical layout changes (#43139#)
+ for (const SfxPoolItem* pItem : aChangedItems)
+ if (pItem->Which() == SDRATTR_TEXT_CONTOURFRAME)
+ {
+ // Here only repaint wanted
+ rObj.ActionChanged();
+ //rObj.BroadcastObjectChange();
+ break;
+ }
+
+ // call parent
+ AttributeProperties::ItemSetChanged(aChangedItems, nDeletedWhich);
+ }
+
+ void TextProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
+ {
+ SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+
+ // #i25616#
+ sal_Int32 nOldLineWidth(0);
+
+ if(XATTR_LINEWIDTH == nWhich && rObj.DoesSupportTextIndentingOnLineWidthChange())
+ {
+ nOldLineWidth = GetItem(XATTR_LINEWIDTH).GetValue();
+ }
+
+ if(pNewItem && (SDRATTR_TEXTDIRECTION == nWhich))
+ {
+ bool bVertical(css::text::WritingMode_TB_RL == static_cast<const SvxWritingModeItem*>(pNewItem)->GetValue());
+ rObj.SetVerticalWriting(bVertical);
+ }
+
+ // #95501# reset to default
+ if(!pNewItem && !nWhich && rObj.HasText() )
+ {
+ SdrOutliner& rOutliner = rObj.ImpGetDrawOutliner();
+
+ const svx::ITextProvider& rTextProvider(getTextProvider());
+ sal_Int32 nCount = rTextProvider.getTextCount();
+ while (nCount--)
+ {
+ SdrText* pText = rTextProvider.getText( nCount );
+ OutlinerParaObject* pParaObj = pText->GetOutlinerParaObject();
+ if( pParaObj )
+ {
+ rOutliner.SetText(*pParaObj);
+ sal_Int32 nParaCount(rOutliner.GetParagraphCount());
+
+ if(nParaCount)
+ {
+ ESelection aSelection( 0, 0, EE_PARA_ALL, EE_TEXTPOS_ALL);
+ rOutliner.RemoveAttribs(aSelection, true, 0);
+
+ std::optional<OutlinerParaObject> pTemp = rOutliner.CreateParaObject(0, nParaCount);
+ rOutliner.Clear();
+
+ rObj.NbcSetOutlinerParaObjectForText( std::move(pTemp), pText );
+ }
+ }
+ }
+ }
+
+ // call parent
+ AttributeProperties::ItemChange( nWhich, pNewItem );
+
+ // #i25616#
+ if(!(XATTR_LINEWIDTH == nWhich && rObj.DoesSupportTextIndentingOnLineWidthChange()))
+ return;
+
+ const sal_Int32 nNewLineWidth(GetItem(XATTR_LINEWIDTH).GetValue());
+ const sal_Int32 nDifference((nNewLineWidth - nOldLineWidth) / 2);
+
+ if(!nDifference)
+ return;
+
+ const bool bLineVisible(drawing::LineStyle_NONE != GetItem(XATTR_LINESTYLE).GetValue());
+
+ if(bLineVisible)
+ {
+ const sal_Int32 nLeftDist(GetItem(SDRATTR_TEXT_LEFTDIST).GetValue());
+ const sal_Int32 nRightDist(GetItem(SDRATTR_TEXT_RIGHTDIST).GetValue());
+ const sal_Int32 nUpperDist(GetItem(SDRATTR_TEXT_UPPERDIST).GetValue());
+ const sal_Int32 nLowerDist(GetItem(SDRATTR_TEXT_LOWERDIST).GetValue());
+
+ SetObjectItemDirect(makeSdrTextLeftDistItem(nLeftDist + nDifference));
+ SetObjectItemDirect(makeSdrTextRightDistItem(nRightDist + nDifference));
+ SetObjectItemDirect(makeSdrTextUpperDistItem(nUpperDist + nDifference));
+ SetObjectItemDirect(makeSdrTextLowerDistItem(nLowerDist + nDifference));
+ }
+ }
+
+ const svx::ITextProvider& TextProperties::getTextProvider() const
+ {
+ return static_cast<const SdrTextObj&>(GetSdrObject());
+ }
+
+ void TextProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool bBroadcast)
+ {
+ // call parent (always first thing to do, may create the SfxItemSet)
+ AttributeProperties::SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr, bBroadcast);
+
+ // #i101556# StyleSheet has changed -> new version
+ SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+ maVersion++;
+
+ if(!rObj.IsLinkedText() )
+ {
+ SdrOutliner& rOutliner = rObj.ImpGetDrawOutliner();
+
+ const svx::ITextProvider& rTextProvider(getTextProvider());
+ sal_Int32 nText = rTextProvider.getTextCount();
+ while (nText--)
+ {
+ SdrText* pText = rTextProvider.getText( nText );
+
+ OutlinerParaObject* pParaObj = pText ? pText->GetOutlinerParaObject() : nullptr;
+ if( !pParaObj )
+ continue;
+
+ // apply StyleSheet to all paragraphs
+ rOutliner.SetText(*pParaObj);
+ sal_Int32 nParaCount(rOutliner.GetParagraphCount());
+
+ if(nParaCount)
+ {
+ for(sal_Int32 nPara = 0; nPara < nParaCount; nPara++)
+ {
+ std::optional<SfxItemSet> pTempSet;
+
+ // since setting the stylesheet removes all para attributes
+ if(bDontRemoveHardAttr)
+ {
+ // we need to remember them if we want to keep them
+ pTempSet.emplace(rOutliner.GetParaAttribs(nPara));
+ }
+
+ if(GetStyleSheet())
+ {
+ if((SdrObjKind::OutlineText == rObj.GetTextKind()) && (SdrInventor::Default == rObj.GetObjInventor()))
+ {
+ OUString aNewStyleSheetName(GetStyleSheet()->GetName());
+ aNewStyleSheetName = aNewStyleSheetName.copy(0, aNewStyleSheetName.getLength() - 1);
+ sal_Int16 nDepth = rOutliner.GetDepth(nPara);
+ aNewStyleSheetName += OUString::number( nDepth <= 0 ? 1 : nDepth + 1);
+ SfxStyleSheetBasePool* pStylePool(rObj.getSdrModelFromSdrObject().GetStyleSheetPool());
+ SfxStyleSheet* pNewStyle = nullptr;
+ if(pStylePool)
+ pNewStyle = static_cast<SfxStyleSheet*>(pStylePool->Find(aNewStyleSheetName, GetStyleSheet()->GetFamily()));
+ DBG_ASSERT( pNewStyle, "AutoStyleSheetName - Style not found!" );
+
+ if(pNewStyle)
+ {
+ rOutliner.SetStyleSheet(nPara, pNewStyle);
+ }
+ }
+ else
+ {
+ rOutliner.SetStyleSheet(nPara, GetStyleSheet());
+ }
+ }
+ else
+ {
+ // remove StyleSheet
+ rOutliner.SetStyleSheet(nPara, nullptr);
+ }
+
+ if(bDontRemoveHardAttr)
+ {
+ if(pTempSet)
+ {
+ // restore para attributes
+ rOutliner.SetParaAttribs(nPara, *pTempSet);
+ }
+ }
+ else
+ {
+ if(pNewStyleSheet)
+ {
+ // remove all hard paragraph attributes
+ // which occur in StyleSheet, take care of
+ // parents (!)
+ SfxItemIter aIter(pNewStyleSheet->GetItemSet());
+
+ for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem;
+ pItem = aIter.NextItem())
+ {
+ if(!IsInvalidItem(pItem))
+ {
+ sal_uInt16 nW(pItem->Which());
+
+ if(nW >= EE_ITEMS_START && nW <= EE_ITEMS_END)
+ {
+ rOutliner.RemoveCharAttribs(nPara, nW);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ std::optional<OutlinerParaObject> pTemp = rOutliner.CreateParaObject(0, nParaCount);
+ rOutliner.Clear();
+ rObj.NbcSetOutlinerParaObjectForText(std::move(pTemp), pText);
+ }
+ }
+ }
+
+ if(rObj.IsTextFrame())
+ {
+ rObj.NbcAdjustTextFrameWidthAndHeight();
+ }
+ }
+
+ void TextProperties::ForceDefaultAttributes()
+ {
+ SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+
+ if( rObj.GetObjInventor() == SdrInventor::Default )
+ {
+ const SdrObjKind nSdrObjKind = rObj.GetObjIdentifier();
+
+ if( nSdrObjKind == SdrObjKind::TitleText || nSdrObjKind == SdrObjKind::OutlineText )
+ return; // no defaults for presentation objects
+ }
+
+ bool bTextFrame(rObj.IsTextFrame());
+
+ // force ItemSet
+ GetObjectItemSet();
+
+ if(bTextFrame)
+ {
+ mxItemSet->Put(XLineStyleItem(drawing::LineStyle_NONE));
+ mxItemSet->Put(XFillColorItem(OUString(), COL_WHITE));
+ mxItemSet->Put(XFillStyleItem(drawing::FillStyle_NONE));
+ }
+ else
+ {
+ mxItemSet->Put(SvxAdjustItem(SvxAdjust::Center, EE_PARA_JUST));
+ mxItemSet->Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_CENTER));
+ mxItemSet->Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER));
+ }
+ }
+
+ void TextProperties::ForceStyleToHardAttributes()
+ {
+ // #i61284# call parent first to get the hard ObjectItemSet
+ AttributeProperties::ForceStyleToHardAttributes();
+
+ // #i61284# push hard ObjectItemSet to OutlinerParaObject attributes
+ // using existing functionality
+ GetObjectItemSet(); // force ItemSet
+ std::vector<const SfxPoolItem*> aChangedItems;
+ SfxItemIter aIter(*mxItemSet);
+ for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
+ {
+ if(!IsInvalidItem(pItem))
+ aChangedItems.push_back(pItem);
+ }
+ ItemSetChanged(aChangedItems, 0);
+
+ // now the standard TextProperties stuff
+ SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+
+ if(rObj.IsTextEditActive() || rObj.IsLinkedText())
+ return;
+
+ std::unique_ptr<Outliner> pOutliner = SdrMakeOutliner(OutlinerMode::OutlineObject, rObj.getSdrModelFromSdrObject());
+ const svx::ITextProvider& rTextProvider(getTextProvider());
+ sal_Int32 nText = rTextProvider.getTextCount();
+ while (nText--)
+ {
+ SdrText* pText = rTextProvider.getText( nText );
+
+ OutlinerParaObject* pParaObj = pText ? pText->GetOutlinerParaObject() : nullptr;
+ if( !pParaObj )
+ continue;
+
+ pOutliner->SetText(*pParaObj);
+
+ sal_Int32 nParaCount(pOutliner->GetParagraphCount());
+
+ if(nParaCount)
+ {
+ bool bBurnIn(false);
+
+ for(sal_Int32 nPara = 0; nPara < nParaCount; nPara++)
+ {
+ SfxStyleSheet* pSheet = pOutliner->GetStyleSheet(nPara);
+
+ if(pSheet)
+ {
+ SfxItemSet aParaSet(pOutliner->GetParaAttribs(nPara));
+ SfxItemSet aSet(*aParaSet.GetPool());
+ aSet.Put(pSheet->GetItemSet());
+
+ /** the next code handles a special case for paragraphs that contain a
+ url field. The color for URL fields is either the system color for
+ urls or the char color attribute that formats the portion in which the
+ url field is contained.
+ When we set a char color attribute to the paragraphs item set from the
+ styles item set, we would have this char color attribute as an attribute
+ that is spanned over the complete paragraph after xml import due to some
+ problems in the xml import (using a XCursor on import so it does not know
+ the paragraphs and can't set char attributes to paragraphs ).
+
+ To avoid this, as soon as we try to set a char color attribute from the style
+ we
+ 1. check if we have at least one url field in this paragraph
+ 2. if we found at least one url field, we span the char color attribute over
+ all portions that are not url fields and remove the char color attribute
+ from the paragraphs item set
+ */
+
+ bool bHasURL(false);
+
+ if(aSet.GetItemState(EE_CHAR_COLOR) == SfxItemState::SET)
+ {
+ EditEngine* pEditEngine = const_cast<EditEngine*>(&(pOutliner->GetEditEngine()));
+ std::vector<EECharAttrib> aAttribs;
+ pEditEngine->GetCharAttribs(nPara, aAttribs);
+
+ for(const auto& rAttrib : aAttribs)
+ {
+ if(rAttrib.pAttr && EE_FEATURE_FIELD == rAttrib.pAttr->Which())
+ {
+ const SvxFieldItem* pFieldItem = static_cast<const SvxFieldItem*>(rAttrib.pAttr);
+
+ if(pFieldItem)
+ {
+ const SvxFieldData* pData = pFieldItem->GetField();
+
+ if(dynamic_cast<const SvxURLField*>( pData))
+ {
+ bHasURL = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if(bHasURL)
+ {
+ SfxItemSetFixed<EE_CHAR_COLOR, EE_CHAR_COLOR> aColorSet(*aSet.GetPool());
+ aColorSet.Put(aSet, false);
+
+ ESelection aSel(nPara, 0);
+
+ for(const auto& rAttrib : aAttribs)
+ {
+ if(EE_FEATURE_FIELD == rAttrib.pAttr->Which())
+ {
+ aSel.nEndPos = rAttrib.nStart;
+
+ if(aSel.nStartPos != aSel.nEndPos)
+ pEditEngine->QuickSetAttribs(aColorSet, aSel);
+
+ aSel.nStartPos = rAttrib.nEnd;
+ }
+ }
+
+ aSel.nEndPos = pEditEngine->GetTextLen(nPara);
+
+ if(aSel.nStartPos != aSel.nEndPos)
+ {
+ pEditEngine->QuickSetAttribs( aColorSet, aSel );
+ }
+ }
+
+ }
+
+ aSet.Put(aParaSet, false);
+
+ if(bHasURL)
+ {
+ aSet.ClearItem(EE_CHAR_COLOR);
+ }
+
+ pOutliner->SetParaAttribs(nPara, aSet);
+ bBurnIn = true; // #i51163# Flag was set wrong
+ }
+ }
+
+ if(bBurnIn)
+ {
+ std::optional<OutlinerParaObject> pTemp = pOutliner->CreateParaObject(0, nParaCount);
+ rObj.NbcSetOutlinerParaObjectForText(std::move(pTemp),pText);
+ }
+ }
+
+ pOutliner->Clear();
+ }
+ }
+
+ void TextProperties::SetObjectItemNoBroadcast(const SfxPoolItem& rItem)
+ {
+ GetObjectItemSet();
+ mxItemSet->Put(rItem);
+ }
+
+
+ void TextProperties::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+ {
+ // call parent
+ AttributeProperties::Notify(rBC, rHint);
+
+ SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+ if(!rObj.HasText())
+ return;
+
+ const svx::ITextProvider& rTextProvider(getTextProvider());
+ if(dynamic_cast<const SfxStyleSheet *>(&rBC) != nullptr)
+ {
+ SfxHintId nId(rHint.GetId());
+
+ if(SfxHintId::DataChanged == nId)
+ {
+ sal_Int32 nText = rTextProvider.getTextCount();
+ while (nText--)
+ {
+ OutlinerParaObject* pParaObj = rTextProvider.getText( nText )->GetOutlinerParaObject();
+ if( pParaObj )
+ pParaObj->ClearPortionInfo();
+ }
+ rObj.SetTextSizeDirty();
+
+ if(rObj.IsTextFrame() && rObj.NbcAdjustTextFrameWidthAndHeight())
+ {
+ // here only repaint wanted
+ rObj.ActionChanged();
+ //rObj.BroadcastObjectChange();
+ }
+
+ // #i101556# content of StyleSheet has changed -> new version
+ maVersion++;
+ }
+
+ if(SfxHintId::Dying == nId)
+ {
+ sal_Int32 nText = rTextProvider.getTextCount();
+ while (nText--)
+ {
+ OutlinerParaObject* pParaObj = rTextProvider.getText( nText )->GetOutlinerParaObject();
+ if( pParaObj )
+ pParaObj->ClearPortionInfo();
+ }
+ }
+ }
+ else if(dynamic_cast<const SfxStyleSheetBasePool *>(&rBC) != nullptr)
+ {
+ const SfxStyleSheetModifiedHint* pExtendedHint = dynamic_cast<const SfxStyleSheetModifiedHint*>(&rHint);
+
+ if(pExtendedHint
+ && SfxHintId::StyleSheetModified == pExtendedHint->GetId())
+ {
+ const OUString& aOldName(pExtendedHint->GetOldName());
+ OUString aNewName(pExtendedHint->GetStyleSheet()->GetName());
+ SfxStyleFamily eFamily = pExtendedHint->GetStyleSheet()->GetFamily();
+
+ if(aOldName != aNewName)
+ {
+ sal_Int32 nText = rTextProvider.getTextCount();
+ while (nText--)
+ {
+ OutlinerParaObject* pParaObj = rTextProvider.getText( nText )->GetOutlinerParaObject();
+ if( pParaObj )
+ pParaObj->ChangeStyleSheetName(eFamily, aOldName, aNewName);
+ }
+ }
+ }
+ }
+ }
+
+ // #i101556# Handout version information
+ sal_uInt32 TextProperties::getVersion() const
+ {
+ return maVersion;
+ }
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */