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 
22 #include <tools/gen.hxx>
23 #include <vcl/canvastools.hxx>
24 #include <vcl/outdev.hxx>
25 #include <vcl/window.hxx>
30 #include <memory>
31 
32 
33 using namespace com::sun::star;
34 
35 
36 namespace sdr::overlay
37 {
38  void OverlayManager::ImpDrawMembers(const basegfx::B2DRange& rRange, OutputDevice& rDestinationDevice) const
39  {
40  const sal_uInt32 nSize(maOverlayObjects.size());
41 
42  if(nSize)
43  {
44  const AntialiasingFlags nOriginalAA(rDestinationDevice.GetAntialiasing());
45  const bool bIsAntiAliasing(getDrawinglayerOpt().IsAntiAliasing());
46 
47  // create processor
48  std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
49  rDestinationDevice,
50  getCurrentViewInformation2D()));
51 
52  if(pProcessor)
53  {
54  for(const auto& rpOverlayObject : maOverlayObjects)
55  {
56  OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
57  const OverlayObject& rCandidate = *rpOverlayObject;
58 
59  if(rCandidate.isVisible())
60  {
62 
63  if(!rSequence.empty())
64  {
65  if(rRange.overlaps(rCandidate.getBaseRange()))
66  {
67  if(bIsAntiAliasing && rCandidate.allowsAntiAliase())
68  {
69  rDestinationDevice.SetAntialiasing(nOriginalAA | AntialiasingFlags::EnableB2dDraw);
70  }
71  else
72  {
73  rDestinationDevice.SetAntialiasing(nOriginalAA & ~AntialiasingFlags::EnableB2dDraw);
74  }
75 
76  pProcessor->process(rSequence);
77  }
78  }
79  }
80  }
81 
82  pProcessor.reset();
83  }
84 
85  // restore AA settings
86  rDestinationDevice.SetAntialiasing(nOriginalAA);
87  }
88  }
89 
90  void OverlayManager::ImpStripeDefinitionChanged()
91  {
92  const sal_uInt32 nSize(maOverlayObjects.size());
93 
94  if(nSize)
95  {
96  for(const auto& rpOverlayObject : maOverlayObjects)
97  {
98  OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
99  OverlayObject& rCandidate = *rpOverlayObject;
100  rCandidate.stripeDefinitionHasChanged();
101  }
102  }
103  }
104 
105  double OverlayManager::getDiscreteOne() const
106  {
107  if(basegfx::fTools::equalZero(mfDiscreteOne))
108  {
109  const basegfx::B2DVector aDiscreteInLogic(getOutputDevice().GetInverseViewTransformation() * basegfx::B2DVector(1.0, 0.0));
110  const_cast< OverlayManager* >(this)->mfDiscreteOne = aDiscreteInLogic.getLength();
111  }
112 
113  return mfDiscreteOne;
114  }
115 
116  OverlayManager::OverlayManager(OutputDevice& rOutputDevice)
117  : Scheduler(),
118  mrOutputDevice(rOutputDevice),
119  maOverlayObjects(),
120  maStripeColorA(COL_BLACK),
121  maStripeColorB(COL_WHITE),
122  mnStripeLengthPixel(5),
123  maDrawinglayerOpt(),
124  maViewTransformation(),
125  maViewInformation2D(),
126  mfDiscreteOne(0.0)
127  {
128  // set Property 'ReducedDisplayQuality' to true to allow simpler interaction
129  // visualisations
130  uno::Sequence< beans::PropertyValue > xProperties(1);
131  xProperties[0].Name = "ReducedDisplayQuality";
132  xProperties[0].Value <<= true;
134  }
135 
137  {
138  return rtl::Reference<OverlayManager>(new OverlayManager(rOutputDevice));
139  }
140 
142  {
143  if(getOutputDevice().GetViewTransformation() != maViewTransformation)
144  {
146 
148  {
149  const Size aOutputSizePixel(getOutputDevice().GetOutputSizePixel());
150 
151  // only set when we *have* an output size, else let aViewRange
152  // stay on empty
153  if(aOutputSizePixel.Width() && aOutputSizePixel.Height())
154  {
155  aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
156  aViewRange.transform(getOutputDevice().GetInverseViewTransformation());
157  }
158  }
159 
160  OverlayManager* pThis = const_cast< OverlayManager* >(this);
161 
166  aViewRange,
170  pThis->mfDiscreteOne = 0.0;
171  }
172 
173  return maViewInformation2D;
174  }
175 
177  {
178  // handle evtl. animation
179  if(rTarget.allowsAnimation())
180  {
181  // remove from event chain
182  RemoveEvent(&rTarget);
183  }
184 
185  // make invisible
186  invalidateRange(rTarget.getBaseRange());
187 
188  // clear manager
189  rTarget.mpOverlayManager = nullptr;
190  }
191 
193  {
194  // set manager
195  rTarget.mpOverlayManager = this;
196 
197  // make visible
198  invalidateRange(rTarget.getBaseRange());
199 
200  // handle evtl. animation
201  if(rTarget.allowsAnimation())
202  {
203  // Trigger at current time to get alive. This will do the
204  // object-specific next time calculation and hand over adding
205  // again to the scheduler to the animated object, too. This works for
206  // a paused or non-paused animator.
207  rTarget.Trigger(GetTime());
208  }
209  }
210 
212  {
213  // The OverlayManager is not the owner of the OverlayObjects
214  // and thus will not delete them, but remove them. Profit here
215  // from knowing that all will be removed
216  const sal_uInt32 nSize(maOverlayObjects.size());
217 
218  if(nSize)
219  {
220  for(const auto& rpOverlayObject : maOverlayObjects)
221  {
222  OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
223  OverlayObject& rCandidate = *rpOverlayObject;
224  impApplyRemoveActions(rCandidate);
225  }
226 
227  // erase vector
228  maOverlayObjects.clear();
229  }
230  }
231 
232  void OverlayManager::completeRedraw(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice) const
233  {
234  if(!rRegion.IsEmpty() && !maOverlayObjects.empty())
235  {
236  // check for changed MapModes. That may influence the
237  // logical size of pixel based OverlayObjects (like BitmapHandles)
238  //ImpCheckMapModeChange();
239 
240  // paint members
241  const tools::Rectangle aRegionBoundRect(rRegion.GetBoundRect());
242  const basegfx::B2DRange aRegionRange = vcl::unotools::b2DRectangleFromRectangle(aRegionBoundRect);
243 
244  OutputDevice& rTarget = pPreRenderDevice ? *pPreRenderDevice : getOutputDevice();
245  ImpDrawMembers(aRegionRange, rTarget);
246  }
247  }
248 
250  {
251  // default has nothing to do
252  }
253 
254  void OverlayManager::add(OverlayObject& rOverlayObject)
255  {
256  OSL_ENSURE(nullptr == rOverlayObject.mpOverlayManager, "OverlayObject is added twice to an OverlayManager (!)");
257 
258  // add to the end of chain to preserve display order in paint
259  maOverlayObjects.push_back(&rOverlayObject);
260 
261  // execute add actions
262  impApplyAddActions(rOverlayObject);
263  }
264 
265  void OverlayManager::remove(OverlayObject& rOverlayObject)
266  {
267  OSL_ENSURE(rOverlayObject.mpOverlayManager == this, "OverlayObject is removed from wrong OverlayManager (!)");
268 
269  // execute remove actions
270  impApplyRemoveActions(rOverlayObject);
271 
272  // remove from vector
273  const OverlayObjectVector::iterator aFindResult = ::std::find(maOverlayObjects.begin(), maOverlayObjects.end(), &rOverlayObject);
274  const bool bFound(aFindResult != maOverlayObjects.end());
275  OSL_ENSURE(bFound, "OverlayObject NOT found at OverlayManager (!)");
276 
277  if(bFound)
278  {
279  maOverlayObjects.erase(aFindResult);
280  }
281  }
282 
284  {
285  if (getDrawinglayerOpt().IsAntiAliasing())
286  {
287  // assume AA needs one pixel more and invalidate one pixel more
288  const double fDiscreteOne(getDiscreteOne());
289  const tools::Rectangle aInvalidateRectangle(
290  static_cast<sal_Int32>(floor(rRange.getMinX() - fDiscreteOne)),
291  static_cast<sal_Int32>(floor(rRange.getMinY() - fDiscreteOne)),
292  static_cast<sal_Int32>(ceil(rRange.getMaxX() + fDiscreteOne)),
293  static_cast<sal_Int32>(ceil(rRange.getMaxY() + fDiscreteOne)));
294  return aInvalidateRectangle;
295  }
296  else
297  {
298  // #i77674# transform to rectangle. Use floor/ceil to get all covered
299  // discrete pixels, see #i75163# and OverlayManagerBuffered::invalidateRange
300  const tools::Rectangle aInvalidateRectangle(
301  static_cast<sal_Int32>(floor(rRange.getMinX())), static_cast<sal_Int32>(floor(rRange.getMinY())),
302  static_cast<sal_Int32>(ceil(rRange.getMaxX())), static_cast<sal_Int32>(ceil(rRange.getMaxY())));
303  return aInvalidateRectangle;
304  }
305  }
306 
308  {
309  if (OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
310  {
311  tools::Rectangle aInvalidateRectangle(RangeToInvalidateRectangle(rRange));
312  // simply invalidate
313  static_cast<vcl::Window&>(getOutputDevice()).Invalidate(aInvalidateRectangle, InvalidateFlags::NoErase);
314  }
315  }
316 
317  // stripe support ColA
319  {
320  if(aNew != maStripeColorA)
321  {
322  maStripeColorA = aNew;
324  }
325  }
326 
327  // stripe support ColB
329  {
330  if(aNew != maStripeColorB)
331  {
332  maStripeColorB = aNew;
334  }
335  }
336 
337  // stripe support StripeLengthPixel
339  {
340  if(nNew != mnStripeLengthPixel)
341  {
342  mnStripeLengthPixel = nNew;
344  }
345  }
346 
347 } // end of namespace
348 
349 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SAL_DLLPRIVATE void RemoveEvent(Event *pOld)
Definition: scheduler.cxx:151
long Width() const
OutDevType GetOutDevType() const
drawinglayer::geometry::ViewInformation2D maViewInformation2D
const basegfx::B2DRange & getViewport() const
constexpr::Color COL_BLACK(0x00, 0x00, 0x00)
void SetAntialiasing(AntialiasingFlags nMode)
virtual ~OverlayManager() override
void impApplyAddActions(OverlayObject &rTarget)
long Height() const
virtual void stripeDefinitionHasChanged()
FilterGroup & rTarget
static rtl::Reference< OverlayManager > create(OutputDevice &rOutputDevice)
tools::Rectangle GetBoundRect() const
double getMaxX() const
AntialiasingFlags GetAntialiasing() const
std::unique_ptr< BaseProcessor2D > createProcessor2DFromOutputDevice(OutputDevice &rTargetOutDev, const drawinglayer::geometry::ViewInformation2D &rViewInformation2D)
void add(OverlayObject &rOverlayObject)
const css::uno::Sequence< css::beans::PropertyValue > & getExtendedInformationSequence() const
OUTDEV_WINDOW
BASEGFX_DLLPUBLIC void transform(const B2DHomMatrix &rMatrix)
void remove(OverlayObject &rOverlayObject)
const basegfx::B2DRange & getBaseRange() const
const css::uno::Reference< css::drawing::XDrawPage > & getVisualizedPage() const
double getMaxY() const
const basegfx::B2DHomMatrix & getObjectTransformation() const
bool IsEmpty() const
OverlayManager * mpOverlayManager
static bool equalZero(const double &rfVal)
AntialiasingFlags
SAL_DLLPRIVATE sal_uInt32 GetTime() const
Definition: scheduler.hxx:76
virtual drawinglayer::primitive2d::Primitive2DContainer getOverlayObjectPrimitive2DSequence() const
tools::Rectangle RangeToInvalidateRectangle(const basegfx::B2DRange &rRange) const
void impApplyRemoveActions(OverlayObject &rTarget)
drawinglayer::geometry::ViewInformation2D const & getCurrentViewInformation2D() const
OverlayObjectVector maOverlayObjects
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
OverlayManager(const OverlayManager &)=delete
OutputDevice & getOutputDevice() const
virtual void Trigger(sal_uInt32 nTime) override
double getMinY() const
void setStripeLengthPixel(sal_uInt32 nNew)
basegfx::B2DHomMatrix maViewTransformation
virtual void completeRedraw(const vcl::Region &rRegion, OutputDevice *pPreRenderDevice=nullptr) const
const SvtOptionsDrawinglayer & getDrawinglayerOpt() const
void ImpDrawMembers(const basegfx::B2DRange &rRange, OutputDevice &rDestinationDevice) const
constexpr::Color COL_WHITE(0xFF, 0xFF, 0xFF)
double getLength() const
double getMinX() const
long getHeight() const
long getWidth() const
basegfx::B2DHomMatrix GetViewTransformation() const
bool overlaps(const B2DRange &rRange) const
virtual void invalidateRange(const basegfx::B2DRange &rRange)