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