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 
36 using namespace com::sun::star;
37 
38 
39 namespace 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(SvtOptionsDrawinglayer::IsAntiAliasing());
50 
51  // create processor
52  std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
53  rDestinationDevice,
54  getCurrentViewInformation2D()));
55 
56  for(const auto& rpOverlayObject : maOverlayObjects)
57  {
58  OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
59  const OverlayObject& rCandidate = *rpOverlayObject;
60 
61  if(rCandidate.isVisible())
62  {
64 
65  if(!rSequence.empty())
66  {
67  if(rRange.overlaps(rCandidate.getBaseRange()))
68  {
69  if(bIsAntiAliasing && rCandidate.allowsAntiAliase())
70  {
71  rDestinationDevice.SetAntialiasing(nOriginalAA | AntialiasingFlags::Enable);
72  }
73  else
74  {
75  rDestinationDevice.SetAntialiasing(nOriginalAA & ~AntialiasingFlags::Enable);
76  }
77 
78  pProcessor->process(rSequence);
79  }
80  }
81  }
82  }
83 
84  pProcessor.reset();
85 
86  // restore AA settings
87  rDestinationDevice.SetAntialiasing(nOriginalAA);
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  : mrOutputDevice(rOutputDevice),
118  maStripeColorA(COL_BLACK),
119  maStripeColorB(COL_WHITE),
120  mnStripeLengthPixel(5),
121  mfDiscreteOne(0.0)
122  {
123  // set Property 'ReducedDisplayQuality' to true to allow simpler interaction
124  // visualisations
125  uno::Sequence< beans::PropertyValue > xProperties{
126  comphelper::makePropertyValue("ReducedDisplayQuality", true)
127  };
129  }
130 
132  {
133  return rtl::Reference<OverlayManager>(new OverlayManager(rOutputDevice));
134  }
135 
137  {
138  if(getOutputDevice().GetViewTransformation() != maViewTransformation)
139  {
141 
143  {
144  const Size aOutputSizePixel(getOutputDevice().GetOutputSizePixel());
145 
146  // only set when we *have* an output size, else let aViewRange
147  // stay on empty
148  if(aOutputSizePixel.Width() && aOutputSizePixel.Height())
149  {
150  aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
151  aViewRange.transform(getOutputDevice().GetInverseViewTransformation());
152  }
153  }
154 
155  OverlayManager* pThis = const_cast< OverlayManager* >(this);
156 
161  aViewRange,
164  pThis->mfDiscreteOne = 0.0;
165  }
166 
167  return maViewInformation2D;
168  }
169 
171  {
172  // handle evtl. animation
173  if(rTarget.allowsAnimation())
174  {
175  // remove from event chain
176  RemoveEvent(&rTarget);
177  }
178 
179  // make invisible
180  invalidateRange(rTarget.getBaseRange());
181 
182  // clear manager
183  rTarget.mpOverlayManager = nullptr;
184  }
185 
187  {
188  // set manager
189  rTarget.mpOverlayManager = this;
190 
191  // make visible
192  invalidateRange(rTarget.getBaseRange());
193 
194  // handle evtl. animation
195  if(rTarget.allowsAnimation())
196  {
197  // Trigger at current time to get alive. This will do the
198  // object-specific next time calculation and hand over adding
199  // again to the scheduler to the animated object, too. This works for
200  // a paused or non-paused animator.
201  rTarget.Trigger(GetTime());
202  }
203  }
204 
206  {
207  // The OverlayManager is not the owner of the OverlayObjects
208  // and thus will not delete them, but remove them. Profit here
209  // from knowing that all will be removed
210  const sal_uInt32 nSize(maOverlayObjects.size());
211 
212  if(nSize)
213  {
214  for(const auto& rpOverlayObject : maOverlayObjects)
215  {
216  OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)");
217  OverlayObject& rCandidate = *rpOverlayObject;
218  impApplyRemoveActions(rCandidate);
219  }
220 
221  // erase vector
222  maOverlayObjects.clear();
223  }
224  }
225 
226  void OverlayManager::completeRedraw(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice) const
227  {
228  if(rRegion.IsEmpty() || maOverlayObjects.empty())
229  return;
230 
231  // check for changed MapModes. That may influence the
232  // logical size of pixel based OverlayObjects (like BitmapHandles)
233  //ImpCheckMapModeChange();
234 
235  // paint members
236  const tools::Rectangle aRegionBoundRect(rRegion.GetBoundRect());
237  const basegfx::B2DRange aRegionRange = vcl::unotools::b2DRectangleFromRectangle(aRegionBoundRect);
238 
239  OutputDevice& rTarget = pPreRenderDevice ? *pPreRenderDevice : getOutputDevice();
240  ImpDrawMembers(aRegionRange, rTarget);
241  }
242 
244  {
245  // default has nothing to do
246  }
247 
248  void OverlayManager::add(OverlayObject& rOverlayObject)
249  {
250  OSL_ENSURE(nullptr == rOverlayObject.mpOverlayManager, "OverlayObject is added twice to an OverlayManager (!)");
251 
252  // add to the end of chain to preserve display order in paint
253  maOverlayObjects.push_back(&rOverlayObject);
254 
255  // execute add actions
256  impApplyAddActions(rOverlayObject);
257  }
258 
259  void OverlayManager::remove(OverlayObject& rOverlayObject)
260  {
261  OSL_ENSURE(rOverlayObject.mpOverlayManager == this, "OverlayObject is removed from wrong OverlayManager (!)");
262 
263  // execute remove actions
264  impApplyRemoveActions(rOverlayObject);
265 
266  // remove from vector
267  const OverlayObjectVector::iterator aFindResult = ::std::find(maOverlayObjects.begin(), maOverlayObjects.end(), &rOverlayObject);
268  const bool bFound(aFindResult != maOverlayObjects.end());
269  OSL_ENSURE(bFound, "OverlayObject NOT found at OverlayManager (!)");
270 
271  if(bFound)
272  {
273  maOverlayObjects.erase(aFindResult);
274  }
275  }
276 
278  {
279  if (rRange.isEmpty()) {
280  return {};
281  }
283  {
284  // assume AA needs one pixel more and invalidate one pixel more
285  const double fDiscreteOne(getDiscreteOne());
286  const tools::Rectangle aInvalidateRectangle(
287  static_cast<tools::Long>(floor(rRange.getMinX() - fDiscreteOne)),
288  static_cast<tools::Long>(floor(rRange.getMinY() - fDiscreteOne)),
289  static_cast<tools::Long>(ceil(rRange.getMaxX() + fDiscreteOne)),
290  static_cast<tools::Long>(ceil(rRange.getMaxY() + fDiscreteOne)));
291  return aInvalidateRectangle;
292  }
293  else
294  {
295  // #i77674# transform to rectangle. Use floor/ceil to get all covered
296  // discrete pixels, see #i75163# and OverlayManagerBuffered::invalidateRange
297  const tools::Rectangle aInvalidateRectangle(
298  static_cast<sal_Int32>(floor(rRange.getMinX())), static_cast<sal_Int32>(floor(rRange.getMinY())),
299  static_cast<sal_Int32>(ceil(rRange.getMaxX())), static_cast<sal_Int32>(ceil(rRange.getMaxY())));
300  return aInvalidateRectangle;
301  }
302  }
303 
305  {
306  if (OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
307  {
308  tools::Rectangle aInvalidateRectangle(RangeToInvalidateRectangle(rRange));
309  // simply invalidate
310  getOutputDevice().GetOwnerWindow()->Invalidate(aInvalidateRectangle, InvalidateFlags::NoErase);
311  }
312  }
313 
314  // stripe support ColA
316  {
317  if(aNew != maStripeColorA)
318  {
319  maStripeColorA = aNew;
321  }
322  }
323 
324  // stripe support ColB
326  {
327  if(aNew != maStripeColorB)
328  {
329  maStripeColorB = aNew;
331  }
332  }
333 
334  // stripe support StripeLengthPixel
336  {
337  if(nNew != mnStripeLengthPixel)
338  {
339  mnStripeLengthPixel = nNew;
341  }
342  }
343 
344 } // end of namespace
345 
346 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SAL_DLLPRIVATE void RemoveEvent(Event *pOld)
Definition: scheduler.cxx:153
OutDevType GetOutDevType() const
drawinglayer::geometry::ViewInformation2D maViewInformation2D
const basegfx::B2DRange & getViewport() const
void SetAntialiasing(AntialiasingFlags nMode)
AntialiasingFlags
virtual ~OverlayManager() override
void impApplyAddActions(OverlayObject &rTarget)
bool equalZero(const T &rfVal)
ViewInformation2D createViewInformation2D(const css::uno::Sequence< css::beans::PropertyValue > &rViewParameters)
long Long
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
virtual void stripeDefinitionHasChanged()
FilterGroup & rTarget
bool overlaps(const Range2D &rRange) const
static rtl::Reference< OverlayManager > create(OutputDevice &rOutputDevice)
tools::Rectangle GetBoundRect() 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
const basegfx::B2DHomMatrix & getObjectTransformation() 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
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
constexpr tools::Long getWidth() const
basegfx::B2DHomMatrix GetViewTransformation() const
virtual vcl::Window * GetOwnerWindow() const
virtual void invalidateRange(const basegfx::B2DRange &rRange)