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