summaryrefslogtreecommitdiffstats
path: root/svx/source/sdr/contact
diff options
context:
space:
mode:
Diffstat (limited to 'svx/source/sdr/contact')
-rw-r--r--svx/source/sdr/contact/displayinfo.cxx78
-rw-r--r--svx/source/sdr/contact/objectcontact.cxx234
-rw-r--r--svx/source/sdr/contact/objectcontactofobjlistpainter.cxx207
-rw-r--r--svx/source/sdr/contact/objectcontactofpageview.cxx490
-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.cxx304
-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.cxx447
-rw-r--r--svx/source/sdr/contact/viewcontactofe3dsphere.cxx80
-rw-r--r--svx/source/sdr/contact/viewcontactofgraphic.cxx387
-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.cxx192
-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.cxx623
-rw-r--r--svx/source/sdr/contact/viewcontactofsdrpathobj.cxx168
-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.cxx143
-rw-r--r--svx/source/sdr/contact/viewcontactofvirtobj.cxx100
-rw-r--r--svx/source/sdr/contact/viewobjectcontact.cxx630
-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.cxx93
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.cxx133
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofpageobj.cxx324
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofsdrmediaobj.cxx175
-rw-r--r--svx/source/sdr/contact/viewobjectcontactofsdrobj.cxx198
-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.cxx1798
-rw-r--r--svx/source/sdr/contact/viewobjectcontactredirector.cxx39
45 files changed, 10101 insertions, 0 deletions
diff --git a/svx/source/sdr/contact/displayinfo.cxx b/svx/source/sdr/contact/displayinfo.cxx
new file mode 100644
index 0000000000..1c76b70afc
--- /dev/null
+++ b/svx/source/sdr/contact/displayinfo.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 <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),
+ 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::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 0000000000..f36c5412b1
--- /dev/null
+++ b/svx/source/sdr/contact/objectcontact.cxx
@@ -0,0 +1,234 @@
+/* -*- 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::calculateGridOffsetForViewObjectContact(
+ 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;
+}
+
+// display page decoration? Default is true
+bool ObjectContact::isPageDecorationActive() const
+{
+ return true;
+}
+
+// display mster page content (ViewContactOfMasterPage)? Default is true
+bool ObjectContact::isMasterPageActive() const
+{
+ return true;
+}
+
+// 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;
+}
+
+::vcl::PDFExtOutDevData const* ObjectContact::GetPDFExtOutDevData() const
+{
+ return nullptr;
+}
+
+// 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 0000000000..d20b1426e6
--- /dev/null
+++ b/svx/source/sdr/contact/objectcontactofobjlistpainter.cxx
@@ -0,0 +1,207 @@
+/* -*- 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
+ drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
+ aNewViewInformation2D.setViewTransformation(pTargetDevice->GetViewTransformation());
+ aNewViewInformation2D.setViewport(aViewRange);
+ aNewViewInformation2D.setVisualizedPage(GetXDrawPageForSdrPage(const_cast< SdrPage* >(mpProcessedPage)));
+ 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;
+}
+
+::vcl::PDFExtOutDevData const* ObjectContactOfObjListPainter::GetPDFExtOutDevData() const
+{
+ if (!isOutputToPDFFile())
+ {
+ return nullptr;
+ }
+ vcl::PDFExtOutDevData *const pPDFExtOutDevData(
+ dynamic_cast<vcl::PDFExtOutDevData*>(mrTargetOutputDevice.GetExtOutDevData()));
+ return pPDFExtOutDevData;
+}
+
+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 0000000000..c777d069ea
--- /dev/null
+++ b/svx/source/sdr/contact/objectcontactofpageview.cxx
@@ -0,0 +1,490 @@
+/* -*- 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());
+
+ // tdf#153102 using the given RedrawArea is needed e.g. for Writer's
+ // visual clipping against PageBounds (also for android viewer)
+ if(!rRedrawArea.IsEmpty())
+ {
+ 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
+ drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
+ aNewViewInformation2D.setViewTransformation(rTargetOutDev.GetViewTransformation());
+ aNewViewInformation2D.setViewport(aViewRange);
+ aNewViewInformation2D.setVisualizedPage(GetXDrawPageForSdrPage(GetSdrPage()));
+ aNewViewInformation2D.setViewTime(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.
+ for (const rtl::Reference<SdrObject>& pObject : *GetSdrPage())
+ {
+ 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)
+ {
+ // tdf#122735
+ // Here it is necessary to check for SdrObject 1st, that may
+ // return nullptr if it is not a SdrObject/SdrObjGroup.
+ // Checking for SrPage OTOH will *always* try to return
+ // something useful due to SdrObjGroup::getSdrPageFromSdrObjList
+ // using getSdrPageFromSdrObject which will recursively go up the
+ // hierarchy to get the SdrPage the SdrObject belongs to, so
+ // this will *not* be nullptr for e.g. a SdrObjGroup if the
+ // SdrObjGroup is inserted to a SdrPage.
+ // NOTE: It is also possible to use dynamic_cast<SdrObjGroup*>
+ // here, but getSdrObjectFromSdrObjList and
+ // getSdrPageFromSdrObjListexist to not need to do that
+ SdrObject* pSdrObject(pActiveGroupList->getSdrObjectFromSdrObjList());
+
+ if(nullptr != pSdrObject)
+ {
+ // It is a group object
+ return &(pSdrObject->GetViewContact());
+ }
+ else
+ {
+ SdrPage* pSdrPage(pActiveGroupList->getSdrPageFromSdrObjList());
+
+ if(nullptr != pSdrPage)
+ {
+ // It's a Page itself
+ return &(pSdrPage->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;
+ return SvtAccessibilityOptions::GetIsAllowAnimatedText();
+ }
+
+ // check if graphic animation is allowed.
+ bool ObjectContactOfPageView::IsGraphicAnimationAllowed() const
+ {
+ if (utl::ConfigManager::IsFuzzing())
+ return true;
+
+ // Related tdf#156630 respect system animation setting
+ return SvtAccessibilityOptions::GetIsAllowAnimatedGraphics() && !MiscSettings::GetUseReducedAnimation();
+ }
+
+ // print?
+ bool ObjectContactOfPageView::isOutputToPrinter() const
+ {
+ return (OUTDEV_PRINTER == mrPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType());
+ }
+
+ // display page decoration? Default is true
+ bool ObjectContactOfPageView::isPageDecorationActive() const
+ {
+ return GetPageWindow().GetPageView().GetView().IsPageDecorationAllowed();
+ }
+
+ // display mster page content (ViewContactOfMasterPage)? Default is true
+ bool ObjectContactOfPageView::isMasterPageActive() const
+ {
+ return GetPageWindow().GetPageView().GetView().IsMasterPageVisualizationAllowed();
+ }
+
+ // 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;
+ }
+
+ ::vcl::PDFExtOutDevData const* ObjectContactOfPageView::GetPDFExtOutDevData() const
+ {
+ if (!isOutputToPDFFile())
+ {
+ return nullptr;
+ }
+ vcl::PDFExtOutDevData* pPDFExtOutDevData(dynamic_cast<vcl::PDFExtOutDevData*>(
+ mrPageWindow.GetPaintWindow().GetOutputDevice().GetExtOutDevData()));
+ return pPDFExtOutDevData;
+ }
+
+ // 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 0000000000..086e12cee0
--- /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 0000000000..fb3cda6fcb
--- /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 0000000000..99106d0d6e
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontact.cxx
@@ -0,0 +1,304 @@
+/* -*- 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 (!)");
+
+ mxViewIndependentPrimitive2DSequence = drawinglayer::primitive2d::Primitive2DContainer();
+}
+
+// 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 (!)");
+ 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(std::move(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();
+}
+
+void ViewContact::getPrimitive2DSequenceHierarchyOfIndex(
+ sal_uInt32 a, DisplayInfo& rDisplayInfo, ObjectContact& rObjectContact,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor)
+{
+ const ViewObjectContact& rCandidate(GetViewContact(a).GetViewObjectContact(rObjectContact));
+ rCandidate.getPrimitive2DSequenceHierarchy(rDisplayInfo, rVisitor);
+}
+}
+/* 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 0000000000..8766192157
--- /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(),
+ std::move(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 0000000000..2687aab32f
--- /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 0000000000..146a06305d
--- /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
+ 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,
+ std::move(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 0000000000..a7e73acc58
--- /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
+ 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,
+ std::move(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 0000000000..f0e2e02d54
--- /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(
+ std::move(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 0000000000..63b031fdeb
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofe3dscene.cxx
@@ -0,0 +1,447 @@
+/* -*- 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>
+#include <osl/diagnose.h>
+
+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.getOpenWidth());
+ maObjectTransformation.set(1, 1, aRectangle.getOpenHeight());
+ 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 0000000000..7a99719b81
--- /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 0000000000..53fc46fff6
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofgraphic.cxx
@@ -0,0 +1,387 @@
+/* -*- 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(
+ std::move(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(
+ 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
+ rtl::Reference<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);
+ }
+ }
+
+ 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.m_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 0000000000..18e5e07aa2
--- /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 0000000000..20463d0fc2
--- /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 0000000000..3736faefa2
--- /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);
+ 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(std::move(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 0000000000..d6d6446e58
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrcaptionobj.cxx
@@ -0,0 +1,192 @@
+/* -*- 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/sdooitm.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, rCaptionObj.GetSpecialTextBoxShadow()));
+
+ // 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.m_nRotationAngle ? toRadians(36000_deg100 - rGeoStat.m_nRotationAngle) : 0.0,
+ aObjectRange.getMinX(), aObjectRange.getMinY()));
+
+ // calculate corner radius
+ double fCornerRadiusX;
+ double fCornerRadiusY;
+ drawinglayer::primitive2d::calculateRelativeCornerRadius(
+ rCaptionObj.GetEckenradius(), aObjectRange, fCornerRadiusX, fCornerRadiusY);
+ 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,
+ std::move(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 bool bShadow(rItemSet.Get(SDRATTR_SHADOW).GetValue());
+ const sal_uInt32 nXDist(rItemSet.Get(SDRATTR_SHADOWXDIST).GetValue());
+ const sal_uInt32 nYDist(rItemSet.Get(SDRATTR_SHADOWYDIST).GetValue());
+
+ if (bShadow && (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 0000000000..25cd0048ba
--- /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.m_nRotationAngle ? toRadians(36000_deg100 - rGeoStat.m_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 0000000000..a0e26c5bf2
--- /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
+ {
+ 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,
+ std::move(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 0000000000..eb04efd715
--- /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 0000000000..7c713bc4b7
--- /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 0000000000..5f13af5cbe
--- /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 = DynCastSdrTextObj(&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 0000000000..9b6e287d80
--- /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.m_nShearAngle || rGeoStat.m_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.m_nShearAngle)
+ {
+ aRotMatrix.shearX(-rGeoStat.mfTanShearAngle);
+ }
+
+ if(rGeoStat.m_nRotationAngle)
+ {
+ aRotMatrix.rotate(toRadians(36000_deg100 - rGeoStat.m_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 != DynCastE3dObject(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.m_nShearAngle || rGeoStat.m_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.m_nShearAngle)
+ {
+ aTextBoxMatrix.shearX(-rGeoStat.mfTanShearAngle);
+ }
+
+ if(rGeoStat.m_nRotationAngle)
+ {
+ aTextBoxMatrix.rotate(toRadians(36000_deg100 - rGeoStat.m_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 0000000000..7871675400
--- /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.m_nRotationAngle ? toRadians(36000_deg100 - rGeoStat.m_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 0000000000..43ca1fd5c0
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrpage.cxx
@@ -0,0 +1,623 @@
+/* -*- 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/displayinfo.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 <svx/sdr/contact/viewobjectcontactofsdrobj.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(std::move(aLeft), aRGBBorderColor)));
+ rVisitor.visit(drawinglayer::primitive2d::Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(std::move(aRight), aRGBBorderColor)));
+ }
+ else
+ {
+ basegfx::B2DPolygon aPageBorderPolygon(basegfx::utils::createPolygonFromRect(aPageBorderRange));
+ rVisitor.visit(drawinglayer::primitive2d::Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(std::move(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()));
+ 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(std::move(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();
+}
+
+SdrObject& ViewContactOfPageHierarchy::GetSdrObject(sal_uInt32 nIndex) const
+{
+ SdrObject* pObj = getPage().GetObj(nIndex);
+ assert(pObj && "ViewContactOfPageHierarchy::GetViewContact: Corrupt SdrObjList (!)");
+ return *pObj;
+}
+
+ViewContact& ViewContactOfPageHierarchy::GetViewContact(sal_uInt32 nIndex) const
+{
+ return GetSdrObject(nIndex).GetViewContact();
+}
+
+void ViewContactOfPageHierarchy::getPrimitive2DSequenceHierarchyOfIndex(
+ sal_uInt32 nIndex, DisplayInfo& rDisplayInfo, ObjectContact& rObjectContact,
+ drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor)
+{
+ SdrObject& rSdrObject(GetSdrObject(nIndex));
+
+ // optimization over parent impl to skip SdrObject::GetViewContent(), etc if the SdrObject isn't
+ // shown on the target layer. ViewObjectContactOfSdrobject::getPrimitive2DSequenceHierarchy does
+ // the same check, but after a set of allocations which is expensive in the case of SdrCaptions
+ // in a calc internal layer where there can be thousands of such objects.
+ if (!ViewObjectContactOfSdrObj::isObjectVisibleOnAnyLayer(rSdrObject, rDisplayInfo.GetProcessLayers()))
+ return;
+
+ ViewContact& rViewContact = rSdrObject.GetViewContact();
+ const ViewObjectContact& rCandidate(rViewContact.GetViewObjectContact(rObjectContact));
+ rCandidate.getPrimitive2DSequenceHierarchy(rDisplayInfo, rVisitor);
+}
+
+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 10;
+}
+
+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: 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 0000000000..d95d5fbeb7
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofsdrpathobj.cxx
@@ -0,0 +1,168 @@
+/* -*- 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 <svx/svdopath.hxx>
+#include <sdr/primitive2d/sdrattributecreator.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.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();
+ // return early if we definitely have geometry
+ if (nPointCount > 1)
+ return nPolyCount == 1;
+ }
+
+ 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;
+ const bool bIsLine(
+ !aUnitPolyPolygon.areControlPointsUsed()
+ && bPolyCountIsOne
+ && 2 == aUnitPolyPolygon.getB2DPolygon(0).count());
+
+ if(bIsLine)
+ {
+ // special handling for single line mode (2 points)
+ const basegfx::B2DPolygon & rSubPolygon(aUnitPolyPolygon.getB2DPolygon(0));
+ const basegfx::B2DPoint aStart(rSubPolygon.getB2DPoint(0));
+ const basegfx::B2DPoint aEnd(rSubPolygon.getB2DPoint(1));
+ const basegfx::B2DVector aLine(aEnd - aStart);
+
+ // #i102548# create new unit polygon for line (horizontal)
+ static const basegfx::B2DPolygon aNewPolygon{basegfx::B2DPoint(0.0, 0.0), 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.m_nRotationAngle ? toRadians(36000_deg100 - rGeoStat.m_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,
+ std::move(aUnitPolyPolygon),
+ std::move(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 0000000000..46cdd21ad0
--- /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.m_nRotationAngle ? toRadians(36000_deg100 - rGeoStat.m_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 0000000000..9e10d0130d
--- /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 0000000000..3018551d81
--- /dev/null
+++ b/svx/source/sdr/contact/viewcontactofunocontrol.cxx
@@ -0,0 +1,143 @@
+/* -*- 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())
+ {
+ void const* pAnchorKey(nullptr);
+ if (auto const pUserCall = GetSdrObject().GetUserCall())
+ {
+ pAnchorKey = pUserCall->GetPDFAnchorStructureElementKey(GetSdrObject());
+ }
+
+ // 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,
+ nullptr,
+ GetSdrObject().GetTitle(),
+ GetSdrObject().GetDescription(),
+ pAnchorKey));
+
+ 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 0000000000..f4087d036b
--- /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 0000000000..55ea968178
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontact.cxx
@@ -0,0 +1,630 @@
+/* -*- 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/svdomedia.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdotext.hxx>
+#include <vcl/pdfwriter.hxx>
+#include <vcl/pdfextoutdevdata.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() { 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()
+{
+ // if the object range is empty, then we have never had the primitive range change, so nothing to invalidate
+ if (!maObjectRange.isEmpty())
+ {
+ // 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);
+}
+
+bool ViewObjectContact::isExportPDFTags() const
+{
+ return GetObjectContact().isExportTaggedPDF();
+}
+
+/** Check if we need to embed to a StructureTagPrimitive2D, too. This
+ was done at ImplRenderPaintProc::createRedirectedPrimitive2DSequence before
+*/
+void ViewObjectContact::createStructureTag(drawinglayer::primitive2d::Primitive2DContainer & rNewPrimitiveSequence) const
+{
+ SdrObject *const pSdrObj(mrViewContact.TryToGetSdrObject());
+
+ // Check if we need to embed to a StructureTagPrimitive2D, too. This
+ // was done at ImplRenderPaintProc::createRedirectedPrimitive2DSequence before
+ if (!rNewPrimitiveSequence.empty() && isExportPDFTags()
+ // ISO 14289-1:2014, Clause: 7.3
+ && (!pSdrObj || pSdrObj->getParentSdrObjectFromSdrObject() == nullptr))
+ {
+ if (nullptr != pSdrObj && !pSdrObj->IsDecorative())
+ {
+ vcl::PDFWriter::StructElement eElement(vcl::PDFWriter::NonStructElement);
+ const SdrInventor nInventor(pSdrObj->GetObjInventor());
+ const SdrObjKind nIdentifier(pSdrObj->GetObjIdentifier());
+ const bool bIsTextObj(nullptr != DynCastSdrTextObj(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::Figure;
+ else if (nIdentifier == SdrObjKind::Table)
+ eElement = vcl::PDFWriter::Table;
+ else if (nIdentifier == SdrObjKind::Media)
+ eElement = vcl::PDFWriter::Annot;
+ 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
+ void const* pAnchorKey(nullptr);
+ if (auto const pUserCall = pSdrObj->GetUserCall())
+ {
+ pAnchorKey = pUserCall->GetPDFAnchorStructureElementKey(*pSdrObj);
+ }
+
+ ::std::vector<sal_Int32> annotIds;
+ if (eElement == vcl::PDFWriter::Annot
+ && !static_cast<SdrMediaObj*>(pSdrObj)->getURL().isEmpty())
+ {
+ auto const pPDFExtOutDevData(GetObjectContact().GetPDFExtOutDevData());
+ assert(pPDFExtOutDevData);
+ annotIds = pPDFExtOutDevData->GetScreenAnnotIds(pSdrObj);
+ }
+
+ drawinglayer::primitive2d::Primitive2DReference xReference(
+ new drawinglayer::primitive2d::StructureTagPrimitive2D(
+ eElement,
+ bBackground,
+ bImage,
+ std::move(rNewPrimitiveSequence),
+ pAnchorKey,
+ &annotIds));
+ rNewPrimitiveSequence = drawinglayer::primitive2d::Primitive2DContainer { xReference };
+ }
+ }
+ }
+ else
+ {
+ // page backgrounds etc should be tagged as artifacts:
+ rNewPrimitiveSequence = drawinglayer::primitive2d::Primitive2DContainer {
+ new drawinglayer::primitive2d::StructureTagPrimitive2D(
+ // lies to force silly VclMetafileProcessor2D to emit NonStructElement
+ vcl::PDFWriter::Division,
+ true,
+ true,
+ std::move(rNewPrimitiveSequence))
+ };
+ }
+ }
+}
+
+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 };
+ }
+ }
+
+ createStructureTag(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 resources)
+ 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
+{
+ ViewContact& rViewContact = GetViewContact();
+ const sal_uInt32 nSubHierarchyCount(rViewContact.GetObjectCount());
+
+ for(sal_uInt32 a(0); a < nSubHierarchyCount; a++)
+ rViewContact.getPrimitive2DSequenceHierarchyOfIndex(a, rDisplayInfo, GetObjectContact(), 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 (GetObjectContact().supportsGridOffsets())
+ {
+ if (fabs(maGridOffset.getX()) > 1000.0)
+ {
+ // Huge offsets are a hint for error -> usually the conditions for
+ // calculation have changed. E.g. - I saw errors with +/-5740, that
+ // was in the environment of massive external UNO API using LO as
+ // target.
+ // If conditions for this calculation change, it is usually required to call
+ // - ViewObjectContact::resetGridOffset(), or
+ // - ObjectContact::resetAllGridOffsets() or
+ // - ScDrawView::resetGridOffsetsForAllSdrPageViews()
+ // as it is done e.g. when zoom changes (see ScDrawView::RecalcScale()).
+ // Theoretically these resets have to be done for any precondition
+ // changed that is used in the calculation of that value (see
+ // ScDrawView::calculateGridOffsetForSdrObject).
+ // This is not complete and would be hard to do so.
+ // Since it is just a buffered value and re-calculation is not
+ // expensive (linear O(n)) we can just reset suspicious values here.
+ // Hopefully - when that non-linear ViewTransformation problem for
+ // the calc-view gets solved one day - all this can be removed
+ // again. For now, let's just reset here and force re-calculation.
+ // Add a SAL_WARN to inform about this.
+ SAL_WARN("svx", "Suspicious GridOffset value resetted (!)");
+ const_cast<ViewObjectContact*>(this)->maGridOffset.setX(0.0);
+ const_cast<ViewObjectContact*>(this)->maGridOffset.setY(0.0);
+ }
+
+ if(0.0 == maGridOffset.getX() && 0.0 == maGridOffset.getY() && GetObjectContact().supportsGridOffsets())
+ {
+ // create on-demand
+ GetObjectContact().calculateGridOffsetForViewObjectContact(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 0000000000..c6d41bdc95
--- /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 0000000000..ac7ad90f13
--- /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 0000000000..601ec28df1
--- /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 0000000000..6a59cfc335
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofgroup.cxx
@@ -0,0 +1,93 @@
+/* -*- 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;
+
+ drawinglayer::primitive2d::Primitive2DContainer primitiveSequence;
+
+ 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, primitiveSequence);
+
+ 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, primitiveSequence);
+ }
+
+ primitiveSequence = GetViewContact().embedToObjectSpecificInformation(primitiveSequence);
+
+ // ISO 14289-1:2014, Clause: 7.3
+ createStructureTag(primitiveSequence);
+
+ rVisitor.visit(primitiveSequence);
+ }
+
+ bool ViewObjectContactOfGroup::isPrimitiveVisibleOnAnyLayer(const SdrLayerIDSet& aLayers) const
+ {
+ return getSdrObject().isVisibleOnAnyOfTheseLayers(aLayers);
+ }
+
+} // 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 0000000000..baa039b1bb
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofmasterpagedescriptor.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 <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;
+ }
+
+ // display mster page content?
+ if (!GetObjectContact().isMasterPageActive())
+ {
+ 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 0000000000..9430ac55ba
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofpageobj.cxx
@@ -0,0 +1,324 @@
+/* -*- 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 isPageDecorationActive() const override;
+ virtual bool isMasterPageActive() const override;
+ virtual bool isOutputToRecordingMetaFile() const override;
+ virtual bool isOutputToPDFFile() const override;
+ virtual bool isExportTaggedPDF() const override;
+ virtual ::vcl::PDFExtOutDevData const* GetPDFExtOutDevData() 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();
+ drawinglayer::geometry::ViewInformation2D aNewViewInformation2D(rOriginalViewInformation);
+
+ // #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)
+ aNewViewInformation2D.setViewport(basegfx::B2DRange());
+
+ aNewViewInformation2D.setVisualizedPage(GetXDrawPageForSdrPage(pStartPage));
+
+ // no time; page previews are not animated
+ aNewViewInformation2D.setViewTime(0.0);
+
+ 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::isPageDecorationActive() const { return mrViewObjectContactOfPageObj.GetObjectContact().isPageDecorationActive(); }
+bool PagePrimitiveExtractor::isMasterPageActive() const { return mrViewObjectContactOfPageObj.GetObjectContact().isMasterPageActive(); }
+bool PagePrimitiveExtractor::isOutputToRecordingMetaFile() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToRecordingMetaFile(); }
+bool PagePrimitiveExtractor::isOutputToPDFFile() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToPDFFile(); }
+bool PagePrimitiveExtractor::isExportTaggedPDF() const { return mrViewObjectContactOfPageObj.GetObjectContact().isExportTaggedPDF(); }
+::vcl::PDFExtOutDevData const* PagePrimitiveExtractor::GetPDFExtOutDevData() const { return mrViewObjectContactOfPageObj.GetObjectContact().GetPDFExtOutDevData(); }
+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);
+ 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(std::move(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(std::move(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 0000000000..777017472b
--- /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 0000000000..0cc353a5b6
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofsdrobj.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 <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::isObjectVisibleOnAnyLayer(const SdrObject& rSdrObject, const SdrLayerIDSet& rLayers)
+{
+ return rLayers.IsSet(rSdrObject.GetLayer());
+}
+
+bool ViewObjectContactOfSdrObj::isPrimitiveVisibleOnAnyLayer(const SdrLayerIDSet& rLayers) const
+{
+ return ViewObjectContactOfSdrObj::isObjectVisibleOnAnyLayer(getSdrObject(), rLayers);
+}
+
+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 0000000000..103e3e05cb
--- /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
+ 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(),
+ std::move(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 0000000000..3cc27104c3
--- /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(!GetObjectContact().isPageDecorationActive())
+ {
+ 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 0000000000..e5292b1515
--- /dev/null
+++ b/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
@@ -0,0 +1,1798 @@
+/* -*- 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/beans/XPropertySetInfo.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/lok.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <tools/debug.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/controlprimitive2d.hxx>
+
+#include <utility>
+/*
+
+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::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::beans::XPropertySetInfo;
+ 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 )
+ {
+ // In the LOK case, control geometry is handled by LokControlHandler
+ if (comphelper::LibreOfficeKit::isActive())
+ return;
+
+ 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( ::rtl::Reference< ViewObjectContactOfUnoControl_Impl > _pVOCImpl )
+ :m_pVOCImpl(std::move( _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 );
+
+ // tdf#150886 for calc/writer/impress make forms ignore the platform theme
+ Reference<XPropertySet> xModelProperties(xControlModel, UNO_QUERY);
+ Reference<XPropertySetInfo> xInfo = xModelProperties ? xModelProperties->getPropertySetInfo() : nullptr;
+ if (xInfo && xInfo->hasPropertyByName("StandardTheme"))
+ xModelProperties->setPropertyValue("StandardTheme", Any(!_rUnoObject.getSdrModelFromSdrObject().AreControlsThemed()));
+
+ // 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;
+ }
+
+ SdrObject const& rSdrObj(m_pVOCImpl->getViewContact().GetSdrObject());
+ void const* pAnchorKey(nullptr);
+ if (auto const pUserCall = rSdrObj.GetUserCall())
+ {
+ pAnchorKey = pUserCall->GetPDFAnchorStructureElementKey(rSdrObj);
+ }
+
+ // 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(),
+ rSdrObj.GetTitle(), rSdrObj.GetDescription(), pAnchorKey) );
+ }
+
+ 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 0000000000..c499093270
--- /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: */