1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <svx/sdr/overlay/overlaymanager.hxx>
21 #include <basegfx/range/b2drange.hxx>
22 #include <comphelper/propertyvalue.hxx>
23 #include <tools/gen.hxx>
24 #include <vcl/canvastools.hxx>
25 #include <vcl/outdev.hxx>
26 #include <vcl/window.hxx>
27 #include <svx/sdr/overlay/overlayobject.hxx>
28 #include <basegfx/matrix/b2dhommatrix.hxx>
29 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
30 #include <drawinglayer/processor2d/processor2dtools.hxx>
31 #include <svtools/optionsdrawinglayer.hxx>
32 #include <osl/diagnose.h>
36 using namespace com::sun::star
;
39 namespace sdr::overlay
41 void OverlayManager::ImpDrawMembers(const basegfx::B2DRange
& rRange
, OutputDevice
& rDestinationDevice
) const
43 const sal_uInt32
nSize(maOverlayObjects
.size());
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());
56 std::unique_ptr
<drawinglayer::processor2d::BaseProcessor2D
> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
58 getCurrentViewInformation2D()));
60 for(const auto& rpOverlayObject
: maOverlayObjects
)
62 OSL_ENSURE(rpOverlayObject
, "Corrupted OverlayObject List (!)");
63 const OverlayObject
& rCandidate
= *rpOverlayObject
;
65 if(rCandidate
.isVisible())
67 const drawinglayer::primitive2d::Primitive2DContainer
& rSequence
= rCandidate
.getOverlayObjectPrimitive2DSequence();
69 if(!rSequence
.empty())
71 if(rRange
.overlaps(rCandidate
.getBaseRange()))
73 if(bIsAntiAliasing
&& rCandidate
.allowsAntiAliase())
75 rDestinationDevice
.SetAntialiasing(nOriginalAA
| AntialiasingFlags::Enable
);
79 rDestinationDevice
.SetAntialiasing(nOriginalAA
& ~AntialiasingFlags::Enable
);
82 const bool bIsHighContrastSelection
= rCandidate
.isHighContrastSelection();
83 if (bIsHighContrastSelection
)
85 // overrule DrawMode settings
86 rDestinationDevice
.SetDrawMode(nOriginalDrawMode
| DrawModeFlags::SettingsForSelection
);
89 pProcessor
->process(rSequence
);
91 if (bIsHighContrastSelection
)
93 // restore DrawMode settings
94 rDestinationDevice
.SetDrawMode(nOriginalDrawMode
);
103 // restore AA settings
104 rDestinationDevice
.SetAntialiasing(nOriginalAA
);
107 void OverlayManager::ImpStripeDefinitionChanged()
109 const sal_uInt32
nSize(maOverlayObjects
.size());
113 for(const auto& rpOverlayObject
: maOverlayObjects
)
115 OSL_ENSURE(rpOverlayObject
, "Corrupted OverlayObject List (!)");
116 OverlayObject
& rCandidate
= *rpOverlayObject
;
117 rCandidate
.stripeDefinitionHasChanged();
122 double OverlayManager::getDiscreteOne() const
124 if(basegfx::fTools::equalZero(mfDiscreteOne
))
126 const basegfx::B2DVector
aDiscreteInLogic(getOutputDevice().GetInverseViewTransformation() * basegfx::B2DVector(1.0, 0.0));
127 const_cast< OverlayManager
* >(this)->mfDiscreteOne
= aDiscreteInLogic
.getLength();
130 return mfDiscreteOne
;
133 OverlayManager::OverlayManager(OutputDevice
& rOutputDevice
)
134 : mrOutputDevice(rOutputDevice
),
135 maStripeColorA(COL_BLACK
),
136 maStripeColorB(COL_WHITE
),
137 mnStripeLengthPixel(5),
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)
145 maViewInformation2D
= drawinglayer::geometry::createViewInformation2D(xProperties
);
148 rtl::Reference
<OverlayManager
> OverlayManager::create(OutputDevice
& rOutputDevice
)
150 return rtl::Reference
<OverlayManager
>(new OverlayManager(rOutputDevice
));
153 drawinglayer::geometry::ViewInformation2D
const & OverlayManager::getCurrentViewInformation2D() const
155 if(getOutputDevice().GetViewTransformation() != maViewTransformation
)
157 basegfx::B2DRange
aViewRange(maViewInformation2D
.getViewport());
159 if(OUTDEV_WINDOW
== getOutputDevice().GetOutDevType())
161 const Size
aOutputSizePixel(getOutputDevice().GetOutputSizePixel());
163 // only set when we *have* an output size, else let aViewRange
165 if(aOutputSizePixel
.Width() && aOutputSizePixel
.Height())
167 aViewRange
= basegfx::B2DRange(0.0, 0.0, aOutputSizePixel
.getWidth(), aOutputSizePixel
.getHeight());
168 aViewRange
.transform(getOutputDevice().GetInverseViewTransformation());
172 OverlayManager
* pThis
= const_cast< OverlayManager
* >(this);
174 pThis
->maViewTransformation
= getOutputDevice().GetViewTransformation();
175 drawinglayer::geometry::ViewInformation2D
aViewInformation(maViewInformation2D
);
176 aViewInformation
.setViewTransformation(maViewTransformation
);
177 aViewInformation
.setViewport(aViewRange
);
178 pThis
->maViewInformation2D
= aViewInformation
;
180 pThis
->mfDiscreteOne
= 0.0;
183 return maViewInformation2D
;
186 void OverlayManager::impApplyRemoveActions(OverlayObject
& rTarget
)
188 // handle evtl. animation
189 if(rTarget
.allowsAnimation())
191 // remove from event chain
192 RemoveEvent(&rTarget
);
196 invalidateRange(rTarget
.getBaseRange());
199 rTarget
.mpOverlayManager
= nullptr;
202 void OverlayManager::impApplyAddActions(OverlayObject
& rTarget
)
205 rTarget
.mpOverlayManager
= this;
208 invalidateRange(rTarget
.getBaseRange());
210 // handle evtl. animation
211 if(rTarget
.allowsAnimation())
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());
221 OverlayManager::~OverlayManager()
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());
230 for(const auto& rpOverlayObject
: maOverlayObjects
)
232 OSL_ENSURE(rpOverlayObject
, "Corrupted OverlayObject List (!)");
233 OverlayObject
& rCandidate
= *rpOverlayObject
;
234 impApplyRemoveActions(rCandidate
);
238 maOverlayObjects
.clear();
242 void OverlayManager::completeRedraw(const vcl::Region
& rRegion
, OutputDevice
* pPreRenderDevice
) const
244 if(rRegion
.IsEmpty() || maOverlayObjects
.empty())
247 // check for changed MapModes. That may influence the
248 // logical size of pixel based OverlayObjects (like BitmapHandles)
249 //ImpCheckMapModeChange();
252 const tools::Rectangle
aRegionBoundRect(rRegion
.GetBoundRect());
253 const basegfx::B2DRange aRegionRange
= vcl::unotools::b2DRectangleFromRectangle(aRegionBoundRect
);
255 OutputDevice
& rTarget
= pPreRenderDevice
? *pPreRenderDevice
: getOutputDevice();
256 ImpDrawMembers(aRegionRange
, rTarget
);
259 void OverlayManager::flush()
261 // default has nothing to do
264 void OverlayManager::add(OverlayObject
& rOverlayObject
)
266 OSL_ENSURE(nullptr == rOverlayObject
.mpOverlayManager
, "OverlayObject is added twice to an OverlayManager (!)");
268 // add to the end of chain to preserve display order in paint
269 maOverlayObjects
.push_back(&rOverlayObject
);
271 // execute add actions
272 impApplyAddActions(rOverlayObject
);
275 void OverlayManager::remove(OverlayObject
& rOverlayObject
)
277 OSL_ENSURE(rOverlayObject
.mpOverlayManager
== this, "OverlayObject is removed from wrong OverlayManager (!)");
279 // execute remove actions
280 impApplyRemoveActions(rOverlayObject
);
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 (!)");
289 maOverlayObjects
.erase(aFindResult
);
293 tools::Rectangle
OverlayManager::RangeToInvalidateRectangle(const basegfx::B2DRange
& rRange
) const
295 if (rRange
.isEmpty()) {
298 if (getCurrentViewInformation2D().getUseAntiAliasing())
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
;
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
;
320 void OverlayManager::invalidateRange(const basegfx::B2DRange
& rRange
)
322 if (OUTDEV_WINDOW
== getOutputDevice().GetOutDevType())
324 tools::Rectangle
aInvalidateRectangle(RangeToInvalidateRectangle(rRange
));
326 getOutputDevice().GetOwnerWindow()->Invalidate(aInvalidateRectangle
, InvalidateFlags::NoErase
);
330 // stripe support ColA
331 void OverlayManager::setStripeColorA(Color aNew
)
333 if(aNew
!= maStripeColorA
)
335 maStripeColorA
= aNew
;
336 ImpStripeDefinitionChanged();
340 // stripe support ColB
341 void OverlayManager::setStripeColorB(Color aNew
)
343 if(aNew
!= maStripeColorB
)
345 maStripeColorB
= aNew
;
346 ImpStripeDefinitionChanged();
350 // stripe support StripeLengthPixel
351 void OverlayManager::setStripeLengthPixel(sal_uInt32 nNew
)
353 if(nNew
!= mnStripeLengthPixel
)
355 mnStripeLengthPixel
= nNew
;
356 ImpStripeDefinitionChanged();
360 } // end of namespace
362 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */