1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 #include <svx/sdr/overlay/overlaymanager.hxx>
31 #include <basegfx/point/b2dpoint.hxx>
32 #include <basegfx/range/b2drange.hxx>
33 #include <tools/gen.hxx>
34 #include <vcl/salbtype.hxx>
35 #include <vcl/outdev.hxx>
36 #include <vcl/window.hxx>
37 #include <svx/sdr/overlay/overlayobject.hxx>
38 #include <basegfx/matrix/b2dhommatrix.hxx>
39 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
40 #include <svx/sdr/contact/objectcontacttools.hxx>
41 
42 //////////////////////////////////////////////////////////////////////////////
43 
44 using namespace com::sun::star;
45 
46 //////////////////////////////////////////////////////////////////////////////
47 
48 namespace sdr
49 {
50 	namespace overlay
51 	{
52 		void OverlayManager::ImpDrawMembers(const basegfx::B2DRange& rRange, OutputDevice& rDestinationDevice) const
53 		{
54 			const sal_uInt32 nSize(maOverlayObjects.size());
55 
56 			if(nSize)
57 			{
58 				const sal_uInt16 nOriginalAA(rDestinationDevice.GetAntialiasing());
59 				const bool bIsAntiAliasing(getDrawinglayerOpt().IsAntiAliasing());
60 
61 				// create processor
62 				drawinglayer::processor2d::BaseProcessor2D* pProcessor = ::sdr::contact::createBaseProcessor2DFromOutputDevice(
63 					rDestinationDevice,
64 					getCurrentViewInformation2D());
65 
66 				if(pProcessor)
67 				{
68 					for(OverlayObjectVector::const_iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); aIter++)
69 					{
70 						OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)");
71 						const OverlayObject& rCandidate = **aIter;
72 
73 						if(rCandidate.isVisible())
74 						{
75 							const drawinglayer::primitive2d::Primitive2DSequence& rSequence = rCandidate.getOverlayObjectPrimitive2DSequence();
76 
77 							if(rSequence.hasElements())
78 							{
79 								if(rRange.overlaps(rCandidate.getBaseRange()))
80 								{
81 									if(bIsAntiAliasing && rCandidate.allowsAntiAliase())
82 									{
83 										rDestinationDevice.SetAntialiasing(nOriginalAA | ANTIALIASING_ENABLE_B2DDRAW);
84 									}
85 									else
86 									{
87 										rDestinationDevice.SetAntialiasing(nOriginalAA & ~ANTIALIASING_ENABLE_B2DDRAW);
88 									}
89 
90 									pProcessor->process(rSequence);
91 								}
92 							}
93 						}
94 					}
95 
96 					delete pProcessor;
97 				}
98 
99 				// restore AA settings
100 				rDestinationDevice.SetAntialiasing(nOriginalAA);
101 			}
102 		}
103 
104 		void OverlayManager::ImpStripeDefinitionChanged()
105 		{
106 			const sal_uInt32 nSize(maOverlayObjects.size());
107 
108 			if(nSize)
109 			{
110 				for(OverlayObjectVector::iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); aIter++)
111 				{
112 					OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)");
113 					OverlayObject& rCandidate = **aIter;
114 					rCandidate.stripeDefinitionHasChanged();
115 				}
116 			}
117 		}
118 
119         double OverlayManager::getDiscreteOne() const
120         {
121 			if(basegfx::fTools::equalZero(mfDiscreteOne))
122             {
123                 const basegfx::B2DVector aDiscreteInLogic(getOutputDevice().GetInverseViewTransformation() * basegfx::B2DVector(1.0, 0.0));
124                 const_cast< OverlayManager* >(this)->mfDiscreteOne = aDiscreteInLogic.getLength();
125             }
126 
127             return mfDiscreteOne;
128         }
129 
130 		OverlayManager::OverlayManager(
131 			OutputDevice& rOutputDevice,
132 			OverlayManager* pOldOverlayManager)
133 		:	Scheduler(),
134 			rmOutputDevice(rOutputDevice),
135 			maOverlayObjects(),
136 			maStripeColorA(Color(COL_BLACK)),
137 			maStripeColorB(Color(COL_WHITE)),
138 			mnStripeLengthPixel(5),
139 			maDrawinglayerOpt(),
140             maViewTransformation(),
141 			maViewInformation2D(),
142             mfDiscreteOne(0.0)
143 		{
144             // set Property 'ReducedDisplayQuality' to true to allow simpler interaction
145             // visualisations
146             static bool bUseReducedDisplayQualityForDrag(true);
147 
148             if(bUseReducedDisplayQualityForDrag)
149             {
150 			    uno::Sequence< beans::PropertyValue > xProperties(1);
151 			    xProperties[0].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ReducedDisplayQuality"));
152 			    xProperties[0].Value <<= true;
153                 maViewInformation2D = drawinglayer::geometry::ViewInformation2D(xProperties);
154             }
155 
156 			if(pOldOverlayManager)
157 			{
158 				// take over OverlayObjects from given OverlayManager. Copy
159 				// the vector of pointers
160 				maOverlayObjects = pOldOverlayManager->maOverlayObjects;
161 				const sal_uInt32 nSize(maOverlayObjects.size());
162 
163 				if(nSize)
164 				{
165 					for(OverlayObjectVector::iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); aIter++)
166 					{
167 						OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)");
168 						OverlayObject& rCandidate = **aIter;
169 
170 						// remove from old and add to new OverlayManager
171 						pOldOverlayManager->impApplyRemoveActions(rCandidate);
172 						impApplyAddActions(rCandidate);
173 					}
174 
175 					pOldOverlayManager->maOverlayObjects.clear();
176 				}
177 			}
178 		}
179 
180 		const drawinglayer::geometry::ViewInformation2D OverlayManager::getCurrentViewInformation2D() const
181 		{
182             if(getOutputDevice().GetViewTransformation() != maViewTransformation)
183             {
184 				basegfx::B2DRange aViewRange(maViewInformation2D.getViewport());
185 
186 				if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
187 				{
188 					const Size aOutputSizePixel(getOutputDevice().GetOutputSizePixel());
189 					aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
190 			        aViewRange.transform(getOutputDevice().GetInverseViewTransformation());
191 				}
192 
193                 OverlayManager* pThis = const_cast< OverlayManager* >(this);
194 
195 				pThis->maViewTransformation = getOutputDevice().GetViewTransformation();
196 				pThis->maViewInformation2D = drawinglayer::geometry::ViewInformation2D(
197 					maViewInformation2D.getObjectTransformation(),
198 					maViewTransformation,
199 					aViewRange,
200 					maViewInformation2D.getVisualizedPage(),
201 					maViewInformation2D.getViewTime(),
202 					maViewInformation2D.getExtendedInformationSequence());
203 				pThis->mfDiscreteOne = 0.0;
204             }
205 
206 			return maViewInformation2D;
207 		}
208 
209 		void OverlayManager::impApplyRemoveActions(OverlayObject& rTarget)
210 		{
211 			// handle evtl. animation
212 			if(rTarget.allowsAnimation())
213 			{
214 				// remove from event chain
215 				RemoveEvent(&rTarget);
216 			}
217 
218 			// make invisible
219 			invalidateRange(rTarget.getBaseRange());
220 
221 			// clear manager
222 			rTarget.mpOverlayManager = 0;
223 		}
224 
225 		void OverlayManager::impApplyAddActions(OverlayObject& rTarget)
226 		{
227 			// set manager
228 			rTarget.mpOverlayManager = this;
229 
230 			// make visible
231 			invalidateRange(rTarget.getBaseRange());
232 
233 			// handle evtl. animation
234 			if(rTarget.allowsAnimation())
235 			{
236 				// Trigger at current time to get alive. This will do the
237 				// object-specific next time calculation and hand over adding
238 				// again to the scheduler to the animated object, too. This works for
239 				// a paused or non-paused animator.
240 				rTarget.Trigger(GetTime());
241 			}
242 		}
243 
244 		OverlayManager::~OverlayManager()
245 		{
246 			// The OverlayManager is not the owner of the OverlayObjects
247 			// and thus will not delete them, but remove them. Profit here
248 			// from knowing that all will be removed
249 			const sal_uInt32 nSize(maOverlayObjects.size());
250 
251 			if(nSize)
252 			{
253 				for(OverlayObjectVector::iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); aIter++)
254 				{
255 					OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)");
256 					OverlayObject& rCandidate = **aIter;
257 					impApplyRemoveActions(rCandidate);
258 				}
259 
260 				// erase vector
261 				maOverlayObjects.clear();
262 			}
263 		}
264 
265 		void OverlayManager::completeRedraw(const Region& rRegion, OutputDevice* pPreRenderDevice) const
266 		{
267 			if(!rRegion.IsEmpty() && maOverlayObjects.size())
268 			{
269 				// check for changed MapModes. That may influence the
270 				// logical size of pixel based OverlayObjects (like BitmapHandles)
271 				//ImpCheckMapModeChange();
272 
273 				// paint members
274 				const Rectangle aRegionBoundRect(rRegion.GetBoundRect());
275 				const basegfx::B2DRange aRegionRange(
276 					aRegionBoundRect.Left(), aRegionBoundRect.Top(),
277 					aRegionBoundRect.Right(), aRegionBoundRect.Bottom());
278 
279 				OutputDevice& rTarget = (pPreRenderDevice) ? *pPreRenderDevice : getOutputDevice();
280 				ImpDrawMembers(aRegionRange, rTarget);
281 			}
282 		}
283 
284 		void OverlayManager::flush()
285 		{
286 			// default has nothing to do
287 		}
288 
289 		// #i68597# part of content gets copied, react on it
290 		void OverlayManager::copyArea(const Point& /*rDestPt*/, const Point& /*rSrcPt*/, const Size& /*rSrcSize*/)
291 		{
292 			// unbuffered versions do nothing here
293 		}
294 
295 		void OverlayManager::restoreBackground(const Region& /*rRegion*/) const
296 		{
297 			// unbuffered versions do nothing here
298 		}
299 
300 		void OverlayManager::add(OverlayObject& rOverlayObject)
301 		{
302 			OSL_ENSURE(0 == rOverlayObject.mpOverlayManager, "OverlayObject is added twice to an OverlayManager (!)");
303 
304 			// add to the end of chain to preserve display order in paint
305 			maOverlayObjects.push_back(&rOverlayObject);
306 
307 			// execute add actions
308 			impApplyAddActions(rOverlayObject);
309 		}
310 
311 		void OverlayManager::remove(OverlayObject& rOverlayObject)
312 		{
313 			OSL_ENSURE(rOverlayObject.mpOverlayManager == this, "OverlayObject is removed from wrong OverlayManager (!)");
314 
315 			// execute remove actions
316 			impApplyRemoveActions(rOverlayObject);
317 
318 			// remove from vector
319 			const OverlayObjectVector::iterator aFindResult = ::std::find(maOverlayObjects.begin(), maOverlayObjects.end(), &rOverlayObject);
320 			const bool bFound(aFindResult != maOverlayObjects.end());
321 			OSL_ENSURE(bFound, "OverlayObject NOT found at OverlayManager (!)");
322 
323 			if(bFound)
324 			{
325 				maOverlayObjects.erase(aFindResult);
326 			}
327 		}
328 
329 		void OverlayManager::invalidateRange(const basegfx::B2DRange& rRange)
330 		{
331 			if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
332 			{
333 				if(getDrawinglayerOpt().IsAntiAliasing())
334 				{
335 					// assume AA needs one pixel more and invalidate one pixel more
336                     const double fDiscreteOne(getDiscreteOne());
337 					const Rectangle aInvalidateRectangle(
338 						(sal_Int32)floor(rRange.getMinX() - fDiscreteOne),
339 						(sal_Int32)floor(rRange.getMinY() - fDiscreteOne),
340 						(sal_Int32)ceil(rRange.getMaxX() + fDiscreteOne),
341 						(sal_Int32)ceil(rRange.getMaxY() + fDiscreteOne));
342 
343 					// simply invalidate
344 					((Window&)getOutputDevice()).Invalidate(aInvalidateRectangle, INVALIDATE_NOERASE);
345 				}
346 				else
347 				{
348 					// #i77674# transform to rectangle. Use floor/ceil to get all covered
349 					// discrete pixels, see #i75163# and OverlayManagerBuffered::invalidateRange
350 					const Rectangle aInvalidateRectangle(
351 						(sal_Int32)floor(rRange.getMinX()), (sal_Int32)floor(rRange.getMinY()),
352 						(sal_Int32)ceil(rRange.getMaxX()), (sal_Int32)ceil(rRange.getMaxY()));
353 
354 					// simply invalidate
355 					((Window&)getOutputDevice()).Invalidate(aInvalidateRectangle, INVALIDATE_NOERASE);
356 				}
357 			}
358 		}
359 
360 		// stripe support ColA
361 		void OverlayManager::setStripeColorA(Color aNew)
362 		{
363 			if(aNew != maStripeColorA)
364 			{
365 				maStripeColorA = aNew;
366 				ImpStripeDefinitionChanged();
367 			}
368 		}
369 
370 		// stripe support ColB
371 		void OverlayManager::setStripeColorB(Color aNew)
372 		{
373 			if(aNew != maStripeColorB)
374 			{
375 				maStripeColorB = aNew;
376 				ImpStripeDefinitionChanged();
377 			}
378 		}
379 
380 		// stripe support StripeLengthPixel
381 		void OverlayManager::setStripeLengthPixel(sal_uInt32 nNew)
382 		{
383 			if(nNew != mnStripeLengthPixel)
384 			{
385 				mnStripeLengthPixel = nNew;
386 				ImpStripeDefinitionChanged();
387 			}
388 		}
389 	} // end of namespace overlay
390 } // end of namespace sdr
391 
392 //////////////////////////////////////////////////////////////////////////////
393 // eof
394