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