Get the style color and number just once
[LibreOffice.git] / svx / source / sdr / overlay / overlaymanager.cxx
blob3e0098eb26cf03a531ca59777b2e61d95ad36e77
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svx/sdr/overlay/overlaymanager.hxx>
21 #include <basegfx/range/b2drange.hxx>
22 #include <comphelper/propertyvalue.hxx>
23 #include <tools/gen.hxx>
24 #include <vcl/canvastools.hxx>
25 #include <vcl/outdev.hxx>
26 #include <vcl/window.hxx>
27 #include <svx/sdr/overlay/overlayobject.hxx>
28 #include <basegfx/matrix/b2dhommatrix.hxx>
29 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
30 #include <drawinglayer/processor2d/processor2dtools.hxx>
31 #include <osl/diagnose.h>
32 #include <memory>
35 using namespace com::sun::star;
38 namespace sdr::overlay
40 void OverlayManager::ImpDrawMembers(const basegfx::B2DRange& rRange, OutputDevice& rDestinationDevice) const
42 const sal_uInt32 nSize(maOverlayObjects.size());
44 if(!nSize)
45 return;
47 const AntialiasingFlags nOriginalAA(rDestinationDevice.GetAntialiasing());
48 const bool bIsAntiAliasing(getCurrentViewInformation2D().getUseAntiAliasing());
49 // tdf#150622 for High Contrast we typically force colors to a single pair Fore/Back,
50 // but it seems reasonable to allow overlays to use the selection color
51 // taken from the system High Contrast settings
52 const DrawModeFlags nOriginalDrawMode(rDestinationDevice.GetDrawMode());
54 // create processor
55 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
56 rDestinationDevice,
57 getCurrentViewInformation2D()));
59 for(const auto& rpOverlayObject : maOverlayObjects)
61 OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
62 const OverlayObject& rCandidate = *rpOverlayObject;
64 if(rCandidate.isVisible())
66 const drawinglayer::primitive2d::Primitive2DContainer aSequence = rCandidate.getOverlayObjectPrimitive2DSequence();
68 if(!aSequence.empty())
70 if(rRange.overlaps(rCandidate.getBaseRange()))
72 if(bIsAntiAliasing && rCandidate.allowsAntiAliase())
74 rDestinationDevice.SetAntialiasing(nOriginalAA | AntialiasingFlags::Enable);
76 else
78 rDestinationDevice.SetAntialiasing(nOriginalAA & ~AntialiasingFlags::Enable);
81 const bool bIsHighContrastSelection = rCandidate.isHighContrastSelection();
82 if (bIsHighContrastSelection)
84 // overrule DrawMode settings
85 rDestinationDevice.SetDrawMode(nOriginalDrawMode | DrawModeFlags::SettingsForSelection);
88 pProcessor->process(aSequence);
90 if (bIsHighContrastSelection)
92 // restore DrawMode settings
93 rDestinationDevice.SetDrawMode(nOriginalDrawMode);
100 pProcessor.reset();
102 // restore AA settings
103 rDestinationDevice.SetAntialiasing(nOriginalAA);
106 void OverlayManager::ImpStripeDefinitionChanged()
108 const sal_uInt32 nSize(maOverlayObjects.size());
110 if(nSize)
112 for(const auto& rpOverlayObject : maOverlayObjects)
114 OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
115 OverlayObject& rCandidate = *rpOverlayObject;
116 rCandidate.stripeDefinitionHasChanged();
121 double OverlayManager::getDiscreteOne() const
123 if(basegfx::fTools::equalZero(mfDiscreteOne))
125 const basegfx::B2DVector aDiscreteInLogic(getOutputDevice().GetInverseViewTransformation() * basegfx::B2DVector(1.0, 0.0));
126 const_cast< OverlayManager* >(this)->mfDiscreteOne = aDiscreteInLogic.getLength();
129 return mfDiscreteOne;
132 OverlayManager::OverlayManager(OutputDevice& rOutputDevice)
133 : mrOutputDevice(rOutputDevice),
134 maStripeColorA(COL_BLACK),
135 maStripeColorB(COL_WHITE),
136 mnStripeLengthPixel(5),
137 mfDiscreteOne(0.0)
139 // Set Property 'ReducedDisplayQuality' to true to allow simpler interaction
140 // visualisations. Note: Currently will use reduced quality for 3d scene soft renderer
141 uno::Sequence< beans::PropertyValue > xProperties{
142 comphelper::makePropertyValue(u"ReducedDisplayQuality"_ustr, true)
144 maViewInformation2D = drawinglayer::geometry::createViewInformation2D(xProperties);
147 rtl::Reference<OverlayManager> OverlayManager::create(OutputDevice& rOutputDevice)
149 return rtl::Reference<OverlayManager>(new OverlayManager(rOutputDevice));
152 drawinglayer::geometry::ViewInformation2D const & OverlayManager::getCurrentViewInformation2D() const
154 if(getOutputDevice().GetViewTransformation() != maViewTransformation)
156 basegfx::B2DRange aViewRange(maViewInformation2D.getViewport());
158 if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
160 const Size aOutputSizePixel(getOutputDevice().GetOutputSizePixel());
162 // only set when we *have* an output size, else let aViewRange
163 // stay on empty
164 if(aOutputSizePixel.Width() && aOutputSizePixel.Height())
166 aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
167 aViewRange.transform(getOutputDevice().GetInverseViewTransformation());
171 OverlayManager* pThis = const_cast< OverlayManager* >(this);
173 pThis->maViewTransformation = getOutputDevice().GetViewTransformation();
174 drawinglayer::geometry::ViewInformation2D aViewInformation(maViewInformation2D);
175 aViewInformation.setViewTransformation(maViewTransformation);
176 aViewInformation.setViewport(aViewRange);
177 pThis->maViewInformation2D = std::move(aViewInformation);
179 pThis->mfDiscreteOne = 0.0;
182 return maViewInformation2D;
185 void OverlayManager::impApplyRemoveActions(OverlayObject& rTarget)
187 // handle evtl. animation
188 if(rTarget.allowsAnimation())
190 // remove from event chain
191 RemoveEvent(&rTarget);
194 // make invisible
195 invalidateRange(rTarget.getBaseRange());
197 // clear manager
198 rTarget.mpOverlayManager = nullptr;
201 void OverlayManager::impApplyAddActions(OverlayObject& rTarget)
203 // set manager
204 rTarget.mpOverlayManager = this;
206 // make visible
207 invalidateRange(rTarget.getBaseRange());
209 // handle evtl. animation
210 if(rTarget.allowsAnimation())
212 // Trigger at current time to get alive. This will do the
213 // object-specific next time calculation and hand over adding
214 // again to the scheduler to the animated object, too. This works for
215 // a paused or non-paused animator.
216 rTarget.Trigger(GetTime());
220 OverlayManager::~OverlayManager()
222 // The OverlayManager is not the owner of the OverlayObjects
223 // and thus will not delete them, but remove them. Profit here
224 // from knowing that all will be removed
225 const sal_uInt32 nSize(maOverlayObjects.size());
227 if(nSize)
229 for(const auto& rpOverlayObject : maOverlayObjects)
231 OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
232 OverlayObject& rCandidate = *rpOverlayObject;
233 impApplyRemoveActions(rCandidate);
236 // erase vector
237 maOverlayObjects.clear();
241 void OverlayManager::completeRedraw(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice) const
243 if(rRegion.IsEmpty() || maOverlayObjects.empty())
244 return;
246 // check for changed MapModes. That may influence the
247 // logical size of pixel based OverlayObjects (like BitmapHandles)
248 //ImpCheckMapModeChange();
250 // paint members
251 const tools::Rectangle aRegionBoundRect(rRegion.GetBoundRect());
252 const basegfx::B2DRange aRegionRange = vcl::unotools::b2DRectangleFromRectangle(aRegionBoundRect);
254 OutputDevice& rTarget = pPreRenderDevice ? *pPreRenderDevice : getOutputDevice();
255 ImpDrawMembers(aRegionRange, rTarget);
258 void OverlayManager::flush()
260 // default has nothing to do
263 void OverlayManager::add(OverlayObject& rOverlayObject)
265 OSL_ENSURE(nullptr == rOverlayObject.mpOverlayManager, "OverlayObject is added twice to an OverlayManager (!)");
267 // add to the end of chain to preserve display order in paint
268 maOverlayObjects.push_back(&rOverlayObject);
270 // execute add actions
271 impApplyAddActions(rOverlayObject);
274 void OverlayManager::remove(OverlayObject& rOverlayObject)
276 OSL_ENSURE(rOverlayObject.mpOverlayManager == this, "OverlayObject is removed from wrong OverlayManager (!)");
278 // execute remove actions
279 impApplyRemoveActions(rOverlayObject);
281 // remove from vector
282 const OverlayObjectVector::iterator aFindResult = ::std::find(maOverlayObjects.begin(), maOverlayObjects.end(), &rOverlayObject);
283 const bool bFound(aFindResult != maOverlayObjects.end());
284 OSL_ENSURE(bFound, "OverlayObject NOT found at OverlayManager (!)");
286 if(bFound)
288 maOverlayObjects.erase(aFindResult);
292 tools::Rectangle OverlayManager::RangeToInvalidateRectangle(const basegfx::B2DRange& rRange) const
294 if (rRange.isEmpty()) {
295 return {};
297 if (getCurrentViewInformation2D().getUseAntiAliasing())
299 // assume AA needs one pixel more and invalidate one pixel more
300 const double fDiscreteOne(getDiscreteOne());
301 const tools::Rectangle aInvalidateRectangle(
302 static_cast<tools::Long>(floor(rRange.getMinX() - fDiscreteOne)),
303 static_cast<tools::Long>(floor(rRange.getMinY() - fDiscreteOne)),
304 static_cast<tools::Long>(ceil(rRange.getMaxX() + fDiscreteOne)),
305 static_cast<tools::Long>(ceil(rRange.getMaxY() + fDiscreteOne)));
306 return aInvalidateRectangle;
308 else
310 // #i77674# transform to rectangle. Use floor/ceil to get all covered
311 // discrete pixels, see #i75163# and OverlayManagerBuffered::invalidateRange
312 const tools::Rectangle aInvalidateRectangle(
313 static_cast<sal_Int32>(floor(rRange.getMinX())), static_cast<sal_Int32>(floor(rRange.getMinY())),
314 static_cast<sal_Int32>(ceil(rRange.getMaxX())), static_cast<sal_Int32>(ceil(rRange.getMaxY())));
315 return aInvalidateRectangle;
319 void OverlayManager::invalidateRange(const basegfx::B2DRange& rRange)
321 if (OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
323 tools::Rectangle aInvalidateRectangle(RangeToInvalidateRectangle(rRange));
324 // simply invalidate
325 getOutputDevice().GetOwnerWindow()->Invalidate(aInvalidateRectangle, InvalidateFlags::NoErase);
329 // stripe support ColA
330 void OverlayManager::setStripeColorA(Color aNew)
332 if(aNew != maStripeColorA)
334 maStripeColorA = aNew;
335 ImpStripeDefinitionChanged();
339 // stripe support ColB
340 void OverlayManager::setStripeColorB(Color aNew)
342 if(aNew != maStripeColorB)
344 maStripeColorB = aNew;
345 ImpStripeDefinitionChanged();
349 // stripe support StripeLengthPixel
350 void OverlayManager::setStripeLengthPixel(sal_uInt32 nNew)
352 if(nNew != mnStripeLengthPixel)
354 mnStripeLengthPixel = nNew;
355 ImpStripeDefinitionChanged();
359 } // end of namespace
361 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */