LibreOffice Module svx (master) 1
overlaymanager.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
23#include <tools/gen.hxx>
24#include <vcl/canvastools.hxx>
25#include <vcl/outdev.hxx>
26#include <vcl/window.hxx>
32#include <osl/diagnose.h>
33#include <memory>
34
35
36using namespace com::sun::star;
37
38
39namespace sdr::overlay
40{
41 void OverlayManager::ImpDrawMembers(const basegfx::B2DRange& rRange, OutputDevice& rDestinationDevice) const
42 {
43 const sal_uInt32 nSize(maOverlayObjects.size());
44
45 if(!nSize)
46 return;
47
48 const AntialiasingFlags nOriginalAA(rDestinationDevice.GetAntialiasing());
49 const bool bIsAntiAliasing(getCurrentViewInformation2D().getUseAntiAliasing());
50 // tdf#150622 for High Contrast we typically force colors to a single pair Fore/Back,
51 // but it seems reasonable to allow overlays to use the selection color
52 // taken from the system High Contrast settings
53 const DrawModeFlags nOriginalDrawMode(rDestinationDevice.GetDrawMode());
54
55 // create processor
56 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
57 rDestinationDevice,
59
60 for(const auto& rpOverlayObject : maOverlayObjects)
61 {
62 OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
63 const OverlayObject& rCandidate = *rpOverlayObject;
64
65 if(rCandidate.isVisible())
66 {
68
69 if(!rSequence.empty())
70 {
71 if(rRange.overlaps(rCandidate.getBaseRange()))
72 {
73 if(bIsAntiAliasing && rCandidate.allowsAntiAliase())
74 {
75 rDestinationDevice.SetAntialiasing(nOriginalAA | AntialiasingFlags::Enable);
76 }
77 else
78 {
79 rDestinationDevice.SetAntialiasing(nOriginalAA & ~AntialiasingFlags::Enable);
80 }
81
82 const bool bIsHighContrastSelection = rCandidate.isHighContrastSelection();
83 if (bIsHighContrastSelection)
84 {
85 // overrule DrawMode settings
86 rDestinationDevice.SetDrawMode(nOriginalDrawMode | DrawModeFlags::SettingsForSelection);
87 }
88
89 pProcessor->process(rSequence);
90
91 if (bIsHighContrastSelection)
92 {
93 // restore DrawMode settings
94 rDestinationDevice.SetDrawMode(nOriginalDrawMode);
95 }
96 }
97 }
98 }
99 }
100
101 pProcessor.reset();
102
103 // restore AA settings
104 rDestinationDevice.SetAntialiasing(nOriginalAA);
105 }
106
108 {
109 const sal_uInt32 nSize(maOverlayObjects.size());
110
111 if(nSize)
112 {
113 for(const auto& rpOverlayObject : maOverlayObjects)
114 {
115 OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
116 OverlayObject& rCandidate = *rpOverlayObject;
117 rCandidate.stripeDefinitionHasChanged();
118 }
119 }
120 }
121
123 {
125 {
126 const basegfx::B2DVector aDiscreteInLogic(getOutputDevice().GetInverseViewTransformation() * basegfx::B2DVector(1.0, 0.0));
127 const_cast< OverlayManager* >(this)->mfDiscreteOne = aDiscreteInLogic.getLength();
128 }
129
130 return mfDiscreteOne;
131 }
132
134 : mrOutputDevice(rOutputDevice),
135 maStripeColorA(COL_BLACK),
136 maStripeColorB(COL_WHITE),
137 mnStripeLengthPixel(5),
138 mfDiscreteOne(0.0)
139 {
140 // Set Property 'ReducedDisplayQuality' to true to allow simpler interaction
141 // visualisations. Note: Currently will use reduced quality for 3d scene soft renderer
142 uno::Sequence< beans::PropertyValue > xProperties{
143 comphelper::makePropertyValue("ReducedDisplayQuality", true)
144 };
146 }
147
149 {
150 return rtl::Reference<OverlayManager>(new OverlayManager(rOutputDevice));
151 }
152
154 {
155 if(getOutputDevice().GetViewTransformation() != maViewTransformation)
156 {
158
159 if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
160 {
161 const Size aOutputSizePixel(getOutputDevice().GetOutputSizePixel());
162
163 // only set when we *have* an output size, else let aViewRange
164 // stay on empty
165 if(aOutputSizePixel.Width() && aOutputSizePixel.Height())
166 {
167 aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
168 aViewRange.transform(getOutputDevice().GetInverseViewTransformation());
169 }
170 }
171
172 OverlayManager* pThis = const_cast< OverlayManager* >(this);
173
177 aViewInformation.setViewport(aViewRange);
178 pThis->maViewInformation2D = aViewInformation;
179
180 pThis->mfDiscreteOne = 0.0;
181 }
182
183 return maViewInformation2D;
184 }
185
187 {
188 // handle evtl. animation
189 if(rTarget.allowsAnimation())
190 {
191 // remove from event chain
193 }
194
195 // make invisible
196 invalidateRange(rTarget.getBaseRange());
197
198 // clear manager
199 rTarget.mpOverlayManager = nullptr;
200 }
201
203 {
204 // set manager
205 rTarget.mpOverlayManager = this;
206
207 // make visible
208 invalidateRange(rTarget.getBaseRange());
209
210 // handle evtl. animation
211 if(rTarget.allowsAnimation())
212 {
213 // Trigger at current time to get alive. This will do the
214 // object-specific next time calculation and hand over adding
215 // again to the scheduler to the animated object, too. This works for
216 // a paused or non-paused animator.
217 rTarget.Trigger(GetTime());
218 }
219 }
220
222 {
223 // The OverlayManager is not the owner of the OverlayObjects
224 // and thus will not delete them, but remove them. Profit here
225 // from knowing that all will be removed
226 const sal_uInt32 nSize(maOverlayObjects.size());
227
228 if(nSize)
229 {
230 for(const auto& rpOverlayObject : maOverlayObjects)
231 {
232 OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
233 OverlayObject& rCandidate = *rpOverlayObject;
234 impApplyRemoveActions(rCandidate);
235 }
236
237 // erase vector
238 maOverlayObjects.clear();
239 }
240 }
241
242 void OverlayManager::completeRedraw(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice) const
243 {
244 if(rRegion.IsEmpty() || maOverlayObjects.empty())
245 return;
246
247 // check for changed MapModes. That may influence the
248 // logical size of pixel based OverlayObjects (like BitmapHandles)
249 //ImpCheckMapModeChange();
250
251 // paint members
252 const tools::Rectangle aRegionBoundRect(rRegion.GetBoundRect());
253 const basegfx::B2DRange aRegionRange = vcl::unotools::b2DRectangleFromRectangle(aRegionBoundRect);
254
255 OutputDevice& rTarget = pPreRenderDevice ? *pPreRenderDevice : getOutputDevice();
256 ImpDrawMembers(aRegionRange, rTarget);
257 }
258
260 {
261 // default has nothing to do
262 }
263
264 void OverlayManager::add(OverlayObject& rOverlayObject)
265 {
266 OSL_ENSURE(nullptr == rOverlayObject.mpOverlayManager, "OverlayObject is added twice to an OverlayManager (!)");
267
268 // add to the end of chain to preserve display order in paint
269 maOverlayObjects.push_back(&rOverlayObject);
270
271 // execute add actions
272 impApplyAddActions(rOverlayObject);
273 }
274
276 {
277 OSL_ENSURE(rOverlayObject.mpOverlayManager == this, "OverlayObject is removed from wrong OverlayManager (!)");
278
279 // execute remove actions
280 impApplyRemoveActions(rOverlayObject);
281
282 // remove from vector
283 const OverlayObjectVector::iterator aFindResult = ::std::find(maOverlayObjects.begin(), maOverlayObjects.end(), &rOverlayObject);
284 const bool bFound(aFindResult != maOverlayObjects.end());
285 OSL_ENSURE(bFound, "OverlayObject NOT found at OverlayManager (!)");
286
287 if(bFound)
288 {
289 maOverlayObjects.erase(aFindResult);
290 }
291 }
292
294 {
295 if (rRange.isEmpty()) {
296 return {};
297 }
298 if (getCurrentViewInformation2D().getUseAntiAliasing())
299 {
300 // assume AA needs one pixel more and invalidate one pixel more
301 const double fDiscreteOne(getDiscreteOne());
302 const tools::Rectangle aInvalidateRectangle(
303 static_cast<tools::Long>(floor(rRange.getMinX() - fDiscreteOne)),
304 static_cast<tools::Long>(floor(rRange.getMinY() - fDiscreteOne)),
305 static_cast<tools::Long>(ceil(rRange.getMaxX() + fDiscreteOne)),
306 static_cast<tools::Long>(ceil(rRange.getMaxY() + fDiscreteOne)));
307 return aInvalidateRectangle;
308 }
309 else
310 {
311 // #i77674# transform to rectangle. Use floor/ceil to get all covered
312 // discrete pixels, see #i75163# and OverlayManagerBuffered::invalidateRange
313 const tools::Rectangle aInvalidateRectangle(
314 static_cast<sal_Int32>(floor(rRange.getMinX())), static_cast<sal_Int32>(floor(rRange.getMinY())),
315 static_cast<sal_Int32>(ceil(rRange.getMaxX())), static_cast<sal_Int32>(ceil(rRange.getMaxY())));
316 return aInvalidateRectangle;
317 }
318 }
319
321 {
322 if (OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
323 {
324 tools::Rectangle aInvalidateRectangle(RangeToInvalidateRectangle(rRange));
325 // simply invalidate
326 getOutputDevice().GetOwnerWindow()->Invalidate(aInvalidateRectangle, InvalidateFlags::NoErase);
327 }
328 }
329
330 // stripe support ColA
332 {
333 if(aNew != maStripeColorA)
334 {
335 maStripeColorA = aNew;
337 }
338 }
339
340 // stripe support ColB
342 {
343 if(aNew != maStripeColorB)
344 {
345 maStripeColorB = aNew;
347 }
348 }
349
350 // stripe support StripeLengthPixel
352 {
353 if(nNew != mnStripeLengthPixel)
354 {
355 mnStripeLengthPixel = nNew;
357 }
358 }
359
360} // end of namespace
361
362/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
AntialiasingFlags
DrawModeFlags
basegfx::B2DHomMatrix GetViewTransformation() const
void SetAntialiasing(AntialiasingFlags nMode)
void SetDrawMode(DrawModeFlags nDrawMode)
AntialiasingFlags GetAntialiasing() const
DrawModeFlags GetDrawMode() const
virtual vcl::Window * GetOwnerWindow() const
constexpr tools::Long getHeight() const
constexpr tools::Long Height() const
constexpr tools::Long getWidth() const
constexpr tools::Long Width() const
BASEGFX_DLLPUBLIC void transform(const B2DHomMatrix &rMatrix)
double getLength() const
TYPE getMaxX() const
TYPE getMinX() const
TYPE getMinY() const
TYPE getMaxY() const
bool isEmpty() const
bool overlaps(const Range2D &rRange) const
const basegfx::B2DRange & getViewport() const
void setViewport(const basegfx::B2DRange &rNew)
void setViewTransformation(const basegfx::B2DHomMatrix &rNew)
SAL_DLLPRIVATE sal_uInt32 GetTime() const
Definition: scheduler.hxx:74
SAL_DLLPRIVATE void RemoveEvent(Event *pOld)
Definition: scheduler.cxx:153
void impApplyRemoveActions(OverlayObject &rTarget)
void remove(OverlayObject &rOverlayObject)
static rtl::Reference< OverlayManager > create(OutputDevice &rOutputDevice)
void impApplyAddActions(OverlayObject &rTarget)
tools::Rectangle RangeToInvalidateRectangle(const basegfx::B2DRange &rRange) const
void add(OverlayObject &rOverlayObject)
drawinglayer::geometry::ViewInformation2D const & getCurrentViewInformation2D() const
virtual void invalidateRange(const basegfx::B2DRange &rRange)
virtual ~OverlayManager() override
drawinglayer::geometry::ViewInformation2D maViewInformation2D
OverlayManager(const OverlayManager &)=delete
OverlayObjectVector maOverlayObjects
void ImpDrawMembers(const basegfx::B2DRange &rRange, OutputDevice &rDestinationDevice) const
OutputDevice & getOutputDevice() const
void setStripeLengthPixel(sal_uInt32 nNew)
basegfx::B2DHomMatrix maViewTransformation
virtual void completeRedraw(const vcl::Region &rRegion, OutputDevice *pPreRenderDevice=nullptr) const
const basegfx::B2DRange & getBaseRange() const
OverlayManager * mpOverlayManager
virtual void stripeDefinitionHasChanged()
virtual drawinglayer::primitive2d::Primitive2DContainer getOverlayObjectPrimitive2DSequence() const
bool IsEmpty() const
tools::Rectangle GetBoundRect() const
void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
constexpr ::Color COL_WHITE(0xFF, 0xFF, 0xFF)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
FilterGroup & rTarget
bool equalZero(const T &rfVal)
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
ViewInformation2D createViewInformation2D(const css::uno::Sequence< css::beans::PropertyValue > &rViewParameters)
std::unique_ptr< BaseProcessor2D > createProcessor2DFromOutputDevice(OutputDevice &rTargetOutDev, const drawinglayer::geometry::ViewInformation2D &rViewInformation2D)
long Long
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
OUTDEV_WINDOW