Line data Source code
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 :
20 : #include <svx/sdr/overlay/overlaymanager.hxx>
21 : #include <basegfx/point/b2dpoint.hxx>
22 : #include <basegfx/range/b2drange.hxx>
23 : #include <tools/gen.hxx>
24 : #include <vcl/outdev.hxx>
25 : #include <vcl/window.hxx>
26 : #include <svx/sdr/overlay/overlayobject.hxx>
27 : #include <basegfx/matrix/b2dhommatrix.hxx>
28 : #include <drawinglayer/processor2d/processor2dtools.hxx>
29 : #include <boost/scoped_ptr.hpp>
30 :
31 :
32 : using namespace com::sun::star;
33 :
34 :
35 :
36 : namespace sdr
37 : {
38 : namespace overlay
39 : {
40 3545 : void OverlayManager::ImpDrawMembers(const basegfx::B2DRange& rRange, OutputDevice& rDestinationDevice) const
41 : {
42 3545 : const sal_uInt32 nSize(maOverlayObjects.size());
43 :
44 3545 : if(nSize)
45 : {
46 3511 : const AntialiasingFlags nOriginalAA(rDestinationDevice.GetAntialiasing());
47 3511 : const bool bIsAntiAliasing(getDrawinglayerOpt().IsAntiAliasing());
48 :
49 : // create processor
50 : boost::scoped_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
51 : rDestinationDevice,
52 3511 : getCurrentViewInformation2D()));
53 :
54 3511 : if(pProcessor)
55 : {
56 10978 : for(OverlayObjectVector::const_iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); ++aIter)
57 : {
58 : OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)");
59 7467 : const OverlayObject& rCandidate = **aIter;
60 :
61 7467 : if(rCandidate.isVisible())
62 : {
63 7467 : const drawinglayer::primitive2d::Primitive2DSequence& rSequence = rCandidate.getOverlayObjectPrimitive2DSequence();
64 :
65 7467 : if(rSequence.hasElements())
66 : {
67 7467 : if(rRange.overlaps(rCandidate.getBaseRange()))
68 : {
69 3748 : if(bIsAntiAliasing && rCandidate.allowsAntiAliase())
70 : {
71 0 : rDestinationDevice.SetAntialiasing(nOriginalAA | AntialiasingFlags::EnableB2dDraw);
72 : }
73 : else
74 : {
75 3748 : rDestinationDevice.SetAntialiasing(nOriginalAA & ~AntialiasingFlags::EnableB2dDraw);
76 : }
77 :
78 3748 : pProcessor->process(rSequence);
79 : }
80 7467 : }
81 : }
82 : }
83 :
84 3511 : pProcessor.reset();
85 : }
86 :
87 : // restore AA settings
88 3511 : rDestinationDevice.SetAntialiasing(nOriginalAA);
89 : }
90 3545 : }
91 :
92 1312 : void OverlayManager::ImpStripeDefinitionChanged()
93 : {
94 1312 : const sal_uInt32 nSize(maOverlayObjects.size());
95 :
96 1312 : if(nSize)
97 : {
98 0 : for(OverlayObjectVector::iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); ++aIter)
99 : {
100 : OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)");
101 0 : OverlayObject& rCandidate = **aIter;
102 0 : rCandidate.stripeDefinitionHasChanged();
103 : }
104 : }
105 1312 : }
106 :
107 0 : double OverlayManager::getDiscreteOne() const
108 : {
109 0 : if(basegfx::fTools::equalZero(mfDiscreteOne))
110 : {
111 0 : const basegfx::B2DVector aDiscreteInLogic(getOutputDevice().GetInverseViewTransformation() * basegfx::B2DVector(1.0, 0.0));
112 0 : const_cast< OverlayManager* >(this)->mfDiscreteOne = aDiscreteInLogic.getLength();
113 : }
114 :
115 0 : return mfDiscreteOne;
116 : }
117 :
118 1312 : OverlayManager::OverlayManager(OutputDevice& rOutputDevice, const SdrModel* pModel)
119 : : Scheduler(),
120 : mrOutputDevice(rOutputDevice),
121 : mpModel(pModel),
122 : maOverlayObjects(),
123 : maStripeColorA(Color(COL_BLACK)),
124 : maStripeColorB(Color(COL_WHITE)),
125 : mnStripeLengthPixel(5),
126 : maDrawinglayerOpt(),
127 : maViewTransformation(),
128 : maViewInformation2D(),
129 1312 : mfDiscreteOne(0.0)
130 : {
131 : // set Property 'ReducedDisplayQuality' to true to allow simpler interaction
132 : // visualisations
133 : static bool bUseReducedDisplayQualityForDrag(true);
134 :
135 1312 : if(bUseReducedDisplayQualityForDrag)
136 : {
137 1312 : uno::Sequence< beans::PropertyValue > xProperties(1);
138 1312 : xProperties[0].Name = "ReducedDisplayQuality";
139 1312 : xProperties[0].Value <<= true;
140 1312 : maViewInformation2D = drawinglayer::geometry::ViewInformation2D(xProperties);
141 : }
142 1312 : }
143 :
144 9 : rtl::Reference<OverlayManager> OverlayManager::create(OutputDevice& rOutputDevice, const SdrModel* pModel)
145 : {
146 9 : return rtl::Reference<OverlayManager>(new OverlayManager(rOutputDevice, pModel));
147 : }
148 :
149 10596 : const drawinglayer::geometry::ViewInformation2D OverlayManager::getCurrentViewInformation2D() const
150 : {
151 10596 : if(getOutputDevice().GetViewTransformation() != maViewTransformation)
152 : {
153 820 : basegfx::B2DRange aViewRange(maViewInformation2D.getViewport());
154 :
155 820 : if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
156 : {
157 820 : const Size aOutputSizePixel(getOutputDevice().GetOutputSizePixel());
158 :
159 : // only set when we *have* a output size, else let aViewRange
160 : // stay on empty
161 820 : if(aOutputSizePixel.Width() && aOutputSizePixel.Height())
162 : {
163 601 : aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
164 601 : aViewRange.transform(getOutputDevice().GetInverseViewTransformation());
165 : }
166 : }
167 :
168 820 : OverlayManager* pThis = const_cast< OverlayManager* >(this);
169 :
170 820 : pThis->maViewTransformation = getOutputDevice().GetViewTransformation();
171 3280 : pThis->maViewInformation2D = drawinglayer::geometry::ViewInformation2D(
172 820 : maViewInformation2D.getObjectTransformation(),
173 : maViewTransformation,
174 : aViewRange,
175 820 : maViewInformation2D.getVisualizedPage(),
176 : maViewInformation2D.getViewTime(),
177 1640 : maViewInformation2D.getExtendedInformationSequence());
178 820 : pThis->mfDiscreteOne = 0.0;
179 : }
180 :
181 10596 : return maViewInformation2D;
182 : }
183 :
184 6317 : void OverlayManager::impApplyRemoveActions(OverlayObject& rTarget)
185 : {
186 : // handle evtl. animation
187 6317 : if(rTarget.allowsAnimation())
188 : {
189 : // remove from event chain
190 12 : RemoveEvent(&rTarget);
191 : }
192 :
193 : // make invisible
194 6317 : invalidateRange(rTarget.getBaseRange());
195 :
196 : // clear manager
197 6317 : rTarget.mpOverlayManager = 0;
198 6317 : }
199 :
200 6328 : void OverlayManager::impApplyAddActions(OverlayObject& rTarget)
201 : {
202 : // set manager
203 6328 : rTarget.mpOverlayManager = this;
204 :
205 : // make visible
206 6328 : invalidateRange(rTarget.getBaseRange());
207 :
208 : // handle evtl. animation
209 6328 : if(rTarget.allowsAnimation())
210 : {
211 : // Trigger at current time to get alive. This will do the
212 : // object-specific next time calculation and hand over adding
213 : // again to the scheduler to the animated object, too. This works for
214 : // a paused or non-paused animator.
215 12 : rTarget.Trigger(GetTime());
216 : }
217 6328 : }
218 :
219 2591 : OverlayManager::~OverlayManager()
220 : {
221 : // The OverlayManager is not the owner of the OverlayObjects
222 : // and thus will not delete them, but remove them. Profit here
223 : // from knowing that all will be removed
224 1291 : const sal_uInt32 nSize(maOverlayObjects.size());
225 :
226 1291 : if(nSize)
227 : {
228 871 : for(OverlayObjectVector::iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); ++aIter)
229 : {
230 : OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)");
231 593 : OverlayObject& rCandidate = **aIter;
232 593 : impApplyRemoveActions(rCandidate);
233 : }
234 :
235 : // erase vector
236 278 : maOverlayObjects.clear();
237 : }
238 1300 : }
239 :
240 13773 : void OverlayManager::completeRedraw(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice) const
241 : {
242 13773 : if(!rRegion.IsEmpty() && maOverlayObjects.size())
243 : {
244 : // check for changed MapModes. That may influence the
245 : // logical size of pixel based OverlayObjects (like BitmapHandles)
246 : //ImpCheckMapModeChange();
247 :
248 : // paint members
249 2958 : const Rectangle aRegionBoundRect(rRegion.GetBoundRect());
250 : const basegfx::B2DRange aRegionRange(
251 5916 : aRegionBoundRect.Left(), aRegionBoundRect.Top(),
252 8874 : aRegionBoundRect.Right(), aRegionBoundRect.Bottom());
253 :
254 2958 : OutputDevice& rTarget = (pPreRenderDevice) ? *pPreRenderDevice : getOutputDevice();
255 2958 : ImpDrawMembers(aRegionRange, rTarget);
256 : }
257 13773 : }
258 :
259 0 : void OverlayManager::flush()
260 : {
261 : // default has nothing to do
262 0 : }
263 :
264 : // #i68597# part of content gets copied, react on it
265 0 : void OverlayManager::copyArea(const Point& /*rDestPt*/, const Point& /*rSrcPt*/, const Size& /*rSrcSize*/)
266 : {
267 : // unbuffered versions do nothing here
268 0 : }
269 :
270 0 : void OverlayManager::restoreBackground(const vcl::Region& /*rRegion*/) const
271 : {
272 : // unbuffered versions do nothing here
273 0 : }
274 :
275 6328 : void OverlayManager::add(OverlayObject& rOverlayObject)
276 : {
277 : OSL_ENSURE(0 == rOverlayObject.mpOverlayManager, "OverlayObject is added twice to an OverlayManager (!)");
278 :
279 : // add to the end of chain to preserve display order in paint
280 6328 : maOverlayObjects.push_back(&rOverlayObject);
281 :
282 : // execute add actions
283 6328 : impApplyAddActions(rOverlayObject);
284 6328 : }
285 :
286 5724 : void OverlayManager::remove(OverlayObject& rOverlayObject)
287 : {
288 : OSL_ENSURE(rOverlayObject.mpOverlayManager == this, "OverlayObject is removed from wrong OverlayManager (!)");
289 :
290 : // execute remove actions
291 5724 : impApplyRemoveActions(rOverlayObject);
292 :
293 : // remove from vector
294 5724 : const OverlayObjectVector::iterator aFindResult = ::std::find(maOverlayObjects.begin(), maOverlayObjects.end(), &rOverlayObject);
295 5724 : const bool bFound(aFindResult != maOverlayObjects.end());
296 : OSL_ENSURE(bFound, "OverlayObject NOT found at OverlayManager (!)");
297 :
298 5724 : if(bFound)
299 : {
300 5724 : maOverlayObjects.erase(aFindResult);
301 : }
302 5724 : }
303 :
304 593 : void OverlayManager::invalidateRange(const basegfx::B2DRange& rRange)
305 : {
306 593 : if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
307 : {
308 593 : if(getDrawinglayerOpt().IsAntiAliasing())
309 : {
310 : // assume AA needs one pixel more and invalidate one pixel more
311 0 : const double fDiscreteOne(getDiscreteOne());
312 : const Rectangle aInvalidateRectangle(
313 0 : (sal_Int32)floor(rRange.getMinX() - fDiscreteOne),
314 0 : (sal_Int32)floor(rRange.getMinY() - fDiscreteOne),
315 0 : (sal_Int32)ceil(rRange.getMaxX() + fDiscreteOne),
316 0 : (sal_Int32)ceil(rRange.getMaxY() + fDiscreteOne));
317 :
318 : // simply invalidate
319 0 : static_cast<vcl::Window&>(getOutputDevice()).Invalidate(aInvalidateRectangle, InvalidateFlags::NoErase);
320 : }
321 : else
322 : {
323 : // #i77674# transform to rectangle. Use floor/ceil to get all covered
324 : // discrete pixels, see #i75163# and OverlayManagerBuffered::invalidateRange
325 : const Rectangle aInvalidateRectangle(
326 1186 : (sal_Int32)floor(rRange.getMinX()), (sal_Int32)floor(rRange.getMinY()),
327 1779 : (sal_Int32)ceil(rRange.getMaxX()), (sal_Int32)ceil(rRange.getMaxY()));
328 :
329 : // simply invalidate
330 593 : static_cast<vcl::Window&>(getOutputDevice()).Invalidate(aInvalidateRectangle, InvalidateFlags::NoErase);
331 : }
332 : }
333 593 : }
334 :
335 : // stripe support ColA
336 1312 : void OverlayManager::setStripeColorA(Color aNew)
337 : {
338 1312 : if(aNew != maStripeColorA)
339 : {
340 0 : maStripeColorA = aNew;
341 0 : ImpStripeDefinitionChanged();
342 : }
343 1312 : }
344 :
345 : // stripe support ColB
346 1312 : void OverlayManager::setStripeColorB(Color aNew)
347 : {
348 1312 : if(aNew != maStripeColorB)
349 : {
350 0 : maStripeColorB = aNew;
351 0 : ImpStripeDefinitionChanged();
352 : }
353 1312 : }
354 :
355 : // stripe support StripeLengthPixel
356 1312 : void OverlayManager::setStripeLengthPixel(sal_uInt32 nNew)
357 : {
358 1312 : if(nNew != mnStripeLengthPixel)
359 : {
360 1312 : mnStripeLengthPixel = nNew;
361 1312 : ImpStripeDefinitionChanged();
362 : }
363 1312 : }
364 :
365 : } // end of namespace overlay
366 : } // end of namespace sdr
367 :
368 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|