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 :
30 :
31 :
32 : using namespace com::sun::star;
33 :
34 :
35 :
36 : namespace sdr
37 : {
38 : namespace overlay
39 : {
40 0 : void OverlayManager::ImpDrawMembers(const basegfx::B2DRange& rRange, OutputDevice& rDestinationDevice) const
41 : {
42 0 : const sal_uInt32 nSize(maOverlayObjects.size());
43 :
44 0 : if(nSize)
45 : {
46 0 : const sal_uInt16 nOriginalAA(rDestinationDevice.GetAntialiasing());
47 0 : const bool bIsAntiAliasing(getDrawinglayerOpt().IsAntiAliasing());
48 :
49 : // create processor
50 : drawinglayer::processor2d::BaseProcessor2D* pProcessor = drawinglayer::processor2d::createProcessor2DFromOutputDevice(
51 : rDestinationDevice,
52 0 : getCurrentViewInformation2D());
53 :
54 0 : if(pProcessor)
55 : {
56 0 : for(OverlayObjectVector::const_iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); ++aIter)
57 : {
58 : OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)");
59 0 : const OverlayObject& rCandidate = **aIter;
60 :
61 0 : if(rCandidate.isVisible())
62 : {
63 0 : const drawinglayer::primitive2d::Primitive2DSequence& rSequence = rCandidate.getOverlayObjectPrimitive2DSequence();
64 :
65 0 : if(rSequence.hasElements())
66 : {
67 0 : if(rRange.overlaps(rCandidate.getBaseRange()))
68 : {
69 0 : if(bIsAntiAliasing && rCandidate.allowsAntiAliase())
70 : {
71 0 : rDestinationDevice.SetAntialiasing(nOriginalAA | ANTIALIASING_ENABLE_B2DDRAW);
72 : }
73 : else
74 : {
75 0 : rDestinationDevice.SetAntialiasing(nOriginalAA & ~ANTIALIASING_ENABLE_B2DDRAW);
76 : }
77 :
78 0 : pProcessor->process(rSequence);
79 : }
80 0 : }
81 : }
82 : }
83 :
84 0 : delete pProcessor;
85 : }
86 :
87 : // restore AA settings
88 0 : rDestinationDevice.SetAntialiasing(nOriginalAA);
89 : }
90 0 : }
91 :
92 0 : void OverlayManager::ImpStripeDefinitionChanged()
93 : {
94 0 : const sal_uInt32 nSize(maOverlayObjects.size());
95 :
96 0 : 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 0 : }
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 0 : OverlayManager::OverlayManager(OutputDevice& rOutputDevice)
119 : : Scheduler(),
120 : mnRefCount(0),
121 : rmOutputDevice(rOutputDevice),
122 : maOverlayObjects(),
123 : maStripeColorA(Color(COL_BLACK)),
124 : maStripeColorB(Color(COL_WHITE)),
125 : mnStripeLengthPixel(5),
126 : maDrawinglayerOpt(),
127 : maViewTransformation(),
128 : maViewInformation2D(),
129 0 : mfDiscreteOne(0.0)
130 : {
131 : // set Property 'ReducedDisplayQuality' to true to allow simpler interaction
132 : // visualisations
133 : static bool bUseReducedDisplayQualityForDrag(true);
134 :
135 0 : if(bUseReducedDisplayQualityForDrag)
136 : {
137 0 : uno::Sequence< beans::PropertyValue > xProperties(1);
138 0 : xProperties[0].Name = "ReducedDisplayQuality";
139 0 : xProperties[0].Value <<= true;
140 0 : maViewInformation2D = drawinglayer::geometry::ViewInformation2D(xProperties);
141 : }
142 0 : }
143 :
144 0 : rtl::Reference<OverlayManager> OverlayManager::create(OutputDevice& rOutputDevice)
145 : {
146 0 : return rtl::Reference<OverlayManager>(new OverlayManager(rOutputDevice));
147 : }
148 :
149 0 : const drawinglayer::geometry::ViewInformation2D OverlayManager::getCurrentViewInformation2D() const
150 : {
151 0 : if(getOutputDevice().GetViewTransformation() != maViewTransformation)
152 : {
153 0 : basegfx::B2DRange aViewRange(maViewInformation2D.getViewport());
154 :
155 0 : if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
156 : {
157 0 : const Size aOutputSizePixel(getOutputDevice().GetOutputSizePixel());
158 :
159 : // only set when we *have* a output size, else let aViewRange
160 : // stay on empty
161 0 : if(aOutputSizePixel.Width() && aOutputSizePixel.Height())
162 : {
163 0 : aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
164 0 : aViewRange.transform(getOutputDevice().GetInverseViewTransformation());
165 : }
166 : }
167 :
168 0 : OverlayManager* pThis = const_cast< OverlayManager* >(this);
169 :
170 0 : pThis->maViewTransformation = getOutputDevice().GetViewTransformation();
171 0 : pThis->maViewInformation2D = drawinglayer::geometry::ViewInformation2D(
172 0 : maViewInformation2D.getObjectTransformation(),
173 : maViewTransformation,
174 : aViewRange,
175 0 : maViewInformation2D.getVisualizedPage(),
176 : maViewInformation2D.getViewTime(),
177 0 : maViewInformation2D.getExtendedInformationSequence());
178 0 : pThis->mfDiscreteOne = 0.0;
179 : }
180 :
181 0 : return maViewInformation2D;
182 : }
183 :
184 0 : void OverlayManager::impApplyRemoveActions(OverlayObject& rTarget)
185 : {
186 : // handle evtl. animation
187 0 : if(rTarget.allowsAnimation())
188 : {
189 : // remove from event chain
190 0 : RemoveEvent(&rTarget);
191 : }
192 :
193 : // make invisible
194 0 : invalidateRange(rTarget.getBaseRange());
195 :
196 : // clear manager
197 0 : rTarget.mpOverlayManager = 0;
198 0 : }
199 :
200 0 : void OverlayManager::impApplyAddActions(OverlayObject& rTarget)
201 : {
202 : // set manager
203 0 : rTarget.mpOverlayManager = this;
204 :
205 : // make visible
206 0 : invalidateRange(rTarget.getBaseRange());
207 :
208 : // handle evtl. animation
209 0 : 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 0 : rTarget.Trigger(GetTime());
216 : }
217 0 : }
218 :
219 0 : 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 0 : const sal_uInt32 nSize(maOverlayObjects.size());
225 :
226 0 : if(nSize)
227 : {
228 0 : for(OverlayObjectVector::iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); ++aIter)
229 : {
230 : OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)");
231 0 : OverlayObject& rCandidate = **aIter;
232 0 : impApplyRemoveActions(rCandidate);
233 : }
234 :
235 : // erase vector
236 0 : maOverlayObjects.clear();
237 : }
238 0 : }
239 :
240 0 : void OverlayManager::completeRedraw(const Region& rRegion, OutputDevice* pPreRenderDevice) const
241 : {
242 0 : 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 0 : const Rectangle aRegionBoundRect(rRegion.GetBoundRect());
250 : const basegfx::B2DRange aRegionRange(
251 0 : aRegionBoundRect.Left(), aRegionBoundRect.Top(),
252 0 : aRegionBoundRect.Right(), aRegionBoundRect.Bottom());
253 :
254 0 : OutputDevice& rTarget = (pPreRenderDevice) ? *pPreRenderDevice : getOutputDevice();
255 0 : ImpDrawMembers(aRegionRange, rTarget);
256 : }
257 0 : }
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 Region& /*rRegion*/) const
271 : {
272 : // unbuffered versions do nothing here
273 0 : }
274 :
275 0 : 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 0 : maOverlayObjects.push_back(&rOverlayObject);
281 :
282 : // execute add actions
283 0 : impApplyAddActions(rOverlayObject);
284 0 : }
285 :
286 0 : void OverlayManager::remove(OverlayObject& rOverlayObject)
287 : {
288 : OSL_ENSURE(rOverlayObject.mpOverlayManager == this, "OverlayObject is removed from wrong OverlayManager (!)");
289 :
290 : // execute remove actions
291 0 : impApplyRemoveActions(rOverlayObject);
292 :
293 : // remove from vector
294 0 : const OverlayObjectVector::iterator aFindResult = ::std::find(maOverlayObjects.begin(), maOverlayObjects.end(), &rOverlayObject);
295 0 : const bool bFound(aFindResult != maOverlayObjects.end());
296 : OSL_ENSURE(bFound, "OverlayObject NOT found at OverlayManager (!)");
297 :
298 0 : if(bFound)
299 : {
300 0 : maOverlayObjects.erase(aFindResult);
301 : }
302 0 : }
303 :
304 0 : void OverlayManager::invalidateRange(const basegfx::B2DRange& rRange)
305 : {
306 0 : if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
307 : {
308 0 : 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 : ((Window&)getOutputDevice()).Invalidate(aInvalidateRectangle, INVALIDATE_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 0 : (sal_Int32)floor(rRange.getMinX()), (sal_Int32)floor(rRange.getMinY()),
327 0 : (sal_Int32)ceil(rRange.getMaxX()), (sal_Int32)ceil(rRange.getMaxY()));
328 :
329 : // simply invalidate
330 0 : ((Window&)getOutputDevice()).Invalidate(aInvalidateRectangle, INVALIDATE_NOERASE);
331 : }
332 : }
333 0 : }
334 :
335 : // stripe support ColA
336 0 : void OverlayManager::setStripeColorA(Color aNew)
337 : {
338 0 : if(aNew != maStripeColorA)
339 : {
340 0 : maStripeColorA = aNew;
341 0 : ImpStripeDefinitionChanged();
342 : }
343 0 : }
344 :
345 : // stripe support ColB
346 0 : void OverlayManager::setStripeColorB(Color aNew)
347 : {
348 0 : if(aNew != maStripeColorB)
349 : {
350 0 : maStripeColorB = aNew;
351 0 : ImpStripeDefinitionChanged();
352 : }
353 0 : }
354 :
355 : // stripe support StripeLengthPixel
356 0 : void OverlayManager::setStripeLengthPixel(sal_uInt32 nNew)
357 : {
358 0 : if(nNew != mnStripeLengthPixel)
359 : {
360 0 : mnStripeLengthPixel = nNew;
361 0 : ImpStripeDefinitionChanged();
362 : }
363 0 : }
364 :
365 0 : oslInterlockedCount OverlayManager::acquire()
366 : {
367 0 : return osl_atomic_increment( &mnRefCount );
368 : }
369 :
370 0 : oslInterlockedCount OverlayManager::release()
371 : {
372 0 : oslInterlockedCount nCount( osl_atomic_decrement( &mnRefCount ) );
373 0 : if ( nCount == 0 )
374 0 : delete this;
375 0 : return nCount;
376 : }
377 :
378 : } // end of namespace overlay
379 : } // end of namespace sdr
380 :
381 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|