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