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/contact/objectcontactofpageview.hxx>
27 #include <svx/sdr/contact/viewobjectcontactofunocontrol.hxx>
28 #include <svx/svdpagv.hxx>
29 #include <svx/svdpage.hxx>
30 #include <svx/sdr/contact/displayinfo.hxx>
31 #include <svx/sdr/contact/viewobjectcontact.hxx>
32 #include <svx/svdview.hxx>
33 #include <svx/sdr/contact/viewcontact.hxx>
34 #include <svx/sdr/animation/objectanimator.hxx>
35 #include <svx/sdr/event/eventhandler.hxx>
36 #include <svx/sdrpagewindow.hxx>
37 #include <svx/sdrpaintwindow.hxx>
38 #include <drawinglayer/processor2d/vclprocessor2d.hxx>
39 #include <basegfx/matrix/b2dhommatrix.hxx>
40 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
41 #include <svx/sdr/contact/objectcontacttools.hxx>
42 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
43 #include <svx/unoapi.hxx>
44 
45 //////////////////////////////////////////////////////////////////////////////
46 
47 using namespace com::sun::star;
48 
49 //////////////////////////////////////////////////////////////////////////////
50 
51 namespace sdr
52 {
53 	namespace contact
54 	{
55 		// internal access to SdrPage of SdrPageView
56 		SdrPage* ObjectContactOfPageView::GetSdrPage() const
57 		{
58 			return GetPageWindow().GetPageView().GetPage();
59 		}
60 
61 		ObjectContactOfPageView::ObjectContactOfPageView(SdrPageWindow& rPageWindow)
62 		:	ObjectContact(),
63 			mrPageWindow(rPageWindow)
64 		{
65 			// init PreviewRenderer flag
66 			setPreviewRenderer(((SdrPaintView&)rPageWindow.GetPageView().GetView()).IsPreviewRenderer());
67 
68 			// init timer
69 			SetTimeout(1);
70 			Stop();
71 		}
72 
73 		ObjectContactOfPageView::~ObjectContactOfPageView()
74 		{
75 			// execute missing LazyInvalidates and stop timer
76 			Timeout();
77 		}
78 
79 		// LazyInvalidate request. Take action.
80 		void ObjectContactOfPageView::setLazyInvalidate(ViewObjectContact& /*rVOC*/)
81 		{
82 			// do NOT call parent, but remember that something is to do by
83 			// starting the LazyInvalidateTimer
84 			Start();
85 		}
86 
87 		// call this to support evtl. preparations for repaint
88 		void ObjectContactOfPageView::PrepareProcessDisplay()
89 		{
90 			if(IsActive())
91 			{
92 				static bool bInvalidateDuringPaint(true);
93 
94 				if(bInvalidateDuringPaint)
95 				{
96 					// there are still non-triggered LazyInvalidate events, trigger these
97 					Timeout();
98 				}
99 			}
100 		}
101 
102 		// From baseclass Timer, the timeout call triggered by te LazyInvalidate mechanism
103 		void ObjectContactOfPageView::Timeout()
104 		{
105 			// stop the timer
106 			Stop();
107 
108 			// invalidate all LazyInvalidate VOCs new situations
109 			const sal_uInt32 nVOCCount(getViewObjectContactCount());
110 
111 			for(sal_uInt32 a(0); a < nVOCCount; a++)
112 			{
113 				ViewObjectContact* pCandidate = getViewObjectContact(a);
114 				pCandidate->triggerLazyInvalidate();
115 			}
116 		}
117 
118 		// Process the whole displaying
119 		void ObjectContactOfPageView::ProcessDisplay(DisplayInfo& rDisplayInfo)
120 		{
121 			const SdrPage* pStartPage = GetSdrPage();
122 
123 			if(pStartPage && !rDisplayInfo.GetProcessLayers().IsEmpty())
124 			{
125 				const ViewContact& rDrawPageVC = pStartPage->GetViewContact();
126 
127 				if(rDrawPageVC.GetObjectCount())
128 				{
129 					DoProcessDisplay(rDisplayInfo);
130 				}
131 			}
132 
133 			// after paint take care of the evtl. scheduled asynchronious commands.
134 			// Do this by resetting the timer contained there. Thus, after the paint
135 			// that timer will be triggered and the events will be executed.
136 			if(HasEventHandler())
137 			{
138 				sdr::event::TimerEventHandler& rEventHandler = GetEventHandler();
139 
140 				if(!rEventHandler.IsEmpty())
141 				{
142 					rEventHandler.Restart();
143 				}
144 			}
145 		}
146 
147 		// Process the whole displaying. Only use given DsiplayInfo, do not access other
148 		// OutputDevices then the given ones.
149 		void ObjectContactOfPageView::DoProcessDisplay(DisplayInfo& rDisplayInfo)
150 		{
151 			// visualize entered group when that feature is switched on and it's not
152 			// a print output. #i29129# No ghosted display for printing.
153 			sal_Bool bVisualizeEnteredGroup(DoVisualizeEnteredGroup() && !isOutputToPrinter());
154 
155 			// Visualize entered groups: Set to ghosted as default
156 			// start. Do this only for the DrawPage, not for MasterPages
157 			if(bVisualizeEnteredGroup)
158 			{
159 				rDisplayInfo.SetGhostedDrawMode();
160 			}
161 
162 			// #114359# save old and set clip region
163 			OutputDevice* pOutDev = TryToGetOutputDevice();
164 			OSL_ENSURE(0 != pOutDev, "ObjectContactOfPageView without OutDev, someone has overloaded TryToGetOutputDevice wrong (!)");
165 			sal_Bool bClipRegionPushed(sal_False);
166 			const Region& rRedrawArea(rDisplayInfo.GetRedrawArea());
167 
168 			if(!rRedrawArea.IsEmpty())
169 			{
170 				bClipRegionPushed = sal_True;
171 				pOutDev->Push(PUSH_CLIPREGION);
172 				pOutDev->IntersectClipRegion(rRedrawArea);
173 			}
174 
175 			// Get start node and process DrawPage contents
176 			const ViewObjectContact& rDrawPageVOContact = GetSdrPage()->GetViewContact().GetViewObjectContact(*this);
177 
178 			// update current ViewInformation2D at the ObjectContact
179 			const double fCurrentTime(getPrimitiveAnimator().GetTime());
180 			OutputDevice& rTargetOutDev = GetPageWindow().GetPaintWindow().GetTargetOutputDevice();
181             basegfx::B2DRange aViewRange;
182             basegfx::B2DHomMatrix aViewTransformation;
183 
184 			// create ViewRange
185             if(isOutputToRecordingMetaFile())
186             {
187                 if(isOutputToPDFFile() || isOutputToPrinter())
188                 {
189                     // #i98402# if it's a PDF export, set the ClipRegion as ViewRange. This is
190                     // mainly because SW does not use DrawingLayer Page-Oriented and if not doing this,
191                     // all existing objects will be collected as primitives and processed.
192                     // OD 2009-03-05 #i99876# perform the same also for SW on printing.
193                     const Rectangle aLogicClipRectangle(rDisplayInfo.GetRedrawArea().GetBoundRect());
194 
195                     aViewRange = basegfx::B2DRange(
196                         aLogicClipRectangle.Left(), aLogicClipRectangle.Top(),
197 						aLogicClipRectangle.Right(), aLogicClipRectangle.Bottom());
198                 }
199             }
200             else
201 			{
202 				// use visible pixels, but transform to world coordinates
203 				const Size aOutputSizePixel(rTargetOutDev.GetOutputSizePixel());
204 				aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
205 
206 				// if a clip region is set, use it
207 				if(!rDisplayInfo.GetRedrawArea().IsEmpty())
208 				{
209 					// get logic clip range and create discrete one
210 					const Rectangle aLogicClipRectangle(rDisplayInfo.GetRedrawArea().GetBoundRect());
211 					basegfx::B2DRange aLogicClipRange(
212 						aLogicClipRectangle.Left(), aLogicClipRectangle.Top(),
213 						aLogicClipRectangle.Right(), aLogicClipRectangle.Bottom());
214 					basegfx::B2DRange aDiscreteClipRange(aLogicClipRange);
215 					aDiscreteClipRange.transform(rTargetOutDev.GetViewTransformation());
216 
217 					// align the discrete one to discrete boundaries (pixel bounds). Also
218 					// expand X and Y max by one due to Rectangle definition source
219 					aDiscreteClipRange.expand(basegfx::B2DTuple(
220 						floor(aDiscreteClipRange.getMinX()),
221 						floor(aDiscreteClipRange.getMinY())));
222 					aDiscreteClipRange.expand(basegfx::B2DTuple(
223 						1.0 + ceil(aDiscreteClipRange.getMaxX()),
224 						1.0 + ceil(aDiscreteClipRange.getMaxY())));
225 
226 					// intersect current ViewRange with ClipRange
227 					aViewRange.intersect(aDiscreteClipRange);
228 				}
229 
230 				// transform to world coordinates
231                 aViewRange.transform(rTargetOutDev.GetInverseViewTransformation());
232 
233                 // for metafile, leave ViewTransformation empty, but for pixel renderer
234                 // get it from OutputDevice
235                 aViewTransformation = rTargetOutDev.GetViewTransformation();
236 			}
237 
238 			// update local ViewInformation2D
239 			const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D(
240 				basegfx::B2DHomMatrix(),
241 				aViewTransformation,
242 				aViewRange,
243 				GetXDrawPageForSdrPage(GetSdrPage()),
244 				fCurrentTime,
245 				uno::Sequence<beans::PropertyValue>());
246 			updateViewInformation2D(aNewViewInformation2D);
247 
248 			// get whole Primitive2DSequence; this will already make use of updated ViewInformation2D
249 			// and may use the MapMode from the Target OutDev in the DisplayInfo
250 			drawinglayer::primitive2d::Primitive2DSequence xPrimitiveSequence(rDrawPageVOContact.getPrimitive2DSequenceHierarchy(rDisplayInfo));
251 
252 			// if there is something to show, use a primitive processor to render it. There
253 			// is a choice between VCL and Canvas processors currently. The decision is made in
254 			// createBaseProcessor2DFromOutputDevice and takes into accout things like the
255 			// Target is a MetaFile, a VDev or something else. The Canvas renderer is triggered
256 			// currently using the shown boolean. Canvas is not yet the default.
257 			if(xPrimitiveSequence.hasElements())
258 			{
259 				// prepare OutputDevice (historical stuff, maybe soon removed)
260 				rDisplayInfo.ClearGhostedDrawMode(); // reset, else the VCL-paint with the processor will not do the right thing
261 				pOutDev->SetLayoutMode(0); // reset, default is no BiDi/RTL
262 
263 				// create renderer
264                 drawinglayer::processor2d::BaseProcessor2D* pProcessor2D = createBaseProcessor2DFromOutputDevice(
265                     rTargetOutDev, getViewInformation2D());
266 
267 				if(pProcessor2D)
268 				{
269 					pProcessor2D->process(xPrimitiveSequence);
270 					delete pProcessor2D;
271 				}
272 			}
273 
274 			// #114359# restore old ClipReghion
275 			if(bClipRegionPushed)
276 			{
277 				pOutDev->Pop();
278 			}
279 
280 			// Visualize entered groups: Reset to original DrawMode
281 			if(bVisualizeEnteredGroup)
282 			{
283 				rDisplayInfo.ClearGhostedDrawMode();
284 			}
285 		}
286 
287 		// test if visualizing of entered groups is switched on at all
288 		bool ObjectContactOfPageView::DoVisualizeEnteredGroup() const
289 		{
290 			SdrView& rView = GetPageWindow().GetPageView().GetView();
291 			return rView.DoVisualizeEnteredGroup();
292 		}
293 
294 		// get active group's (the entered group) ViewContact
295 		const ViewContact* ObjectContactOfPageView::getActiveViewContact() const
296 		{
297 			SdrObjList* pActiveGroupList = GetPageWindow().GetPageView().GetObjList();
298 
299 			if(pActiveGroupList)
300 			{
301 				if(pActiveGroupList->ISA(SdrPage))
302 				{
303 					// It's a Page itself
304 					return &(((SdrPage*)pActiveGroupList)->GetViewContact());
305 				}
306 				else if(pActiveGroupList->GetOwnerObj())
307 				{
308 					// Group object
309 					return &(pActiveGroupList->GetOwnerObj()->GetViewContact());
310 				}
311 			}
312 			else if(GetSdrPage())
313 			{
314 				// use page of associated SdrPageView
315 				return &(GetSdrPage()->GetViewContact());
316 			}
317 
318 			return 0;
319 		}
320 
321 		// Invalidate given rectangle at the window/output which is represented by
322 		// this ObjectContact.
323 		void ObjectContactOfPageView::InvalidatePartOfView(const basegfx::B2DRange& rRange) const
324 		{
325 			// invalidate at associated PageWindow
326             GetPageWindow().InvalidatePageWindow(rRange);
327 		}
328 
329 		// Get info if given Rectangle is visible in this view
330 		bool ObjectContactOfPageView::IsAreaVisible(const basegfx::B2DRange& rRange) const
331 		{
332 			// compare with the visible rectangle
333 			if(rRange.isEmpty())
334 			{
335 				// no range -> not visible
336 				return false;
337 			}
338 			else
339 			{
340 				const OutputDevice& rTargetOutDev = GetPageWindow().GetPaintWindow().GetTargetOutputDevice();
341 				const Size aOutputSizePixel(rTargetOutDev.GetOutputSizePixel());
342 				basegfx::B2DRange aLogicViewRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
343 
344 				aLogicViewRange.transform(rTargetOutDev.GetInverseViewTransformation());
345 
346 				if(!aLogicViewRange.isEmpty() && !aLogicViewRange.overlaps(rRange))
347 				{
348 					return false;
349 				}
350 			}
351 
352 			// call parent
353 			return ObjectContact::IsAreaVisible(rRange);
354 		}
355 
356 		// Get info about the need to visualize GluePoints
357 		bool ObjectContactOfPageView::AreGluePointsVisible() const
358 		{
359 			return GetPageWindow().GetPageView().GetView().ImpIsGlueVisible();
360 		}
361 
362 		// check if text animation is allowed.
363 		bool ObjectContactOfPageView::IsTextAnimationAllowed() const
364 		{
365 			SdrView& rView = GetPageWindow().GetPageView().GetView();
366 			const SvtAccessibilityOptions& rOpt = rView.getAccessibilityOptions();
367 			return rOpt.GetIsAllowAnimatedText();
368 		}
369 
370 		// check if graphic animation is allowed.
371 		bool ObjectContactOfPageView::IsGraphicAnimationAllowed() const
372 		{
373 			SdrView& rView = GetPageWindow().GetPageView().GetView();
374 			const SvtAccessibilityOptions& rOpt = rView.getAccessibilityOptions();
375 			return rOpt.GetIsAllowAnimatedGraphics();
376 		}
377 
378 		// check if asynchronious graphis loading is allowed. Default is sal_False.
379 		bool ObjectContactOfPageView::IsAsynchronGraphicsLoadingAllowed() const
380 		{
381 			SdrView& rView = GetPageWindow().GetPageView().GetView();
382 			return rView.IsSwapAsynchron();
383 		}
384 
385 		// check if buffering of MasterPages is allowed. Default is sal_False.
386 		bool ObjectContactOfPageView::IsMasterPageBufferingAllowed() const
387 		{
388 			SdrView& rView = GetPageWindow().GetPageView().GetView();
389 			return rView.IsMasterPagePaintCaching();
390 		}
391 
392 		// print?
393 		bool ObjectContactOfPageView::isOutputToPrinter() const
394 		{
395 			return (OUTDEV_PRINTER == mrPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType());
396 		}
397 
398 		// window?
399 		bool ObjectContactOfPageView::isOutputToWindow() const
400 		{
401 			return (OUTDEV_WINDOW == mrPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType());
402 		}
403 
404 		// VirtualDevice?
405 		bool ObjectContactOfPageView::isOutputToVirtualDevice() const
406 		{
407 			return (OUTDEV_VIRDEV == mrPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType());
408 		}
409 
410 		// recording MetaFile?
411 		bool ObjectContactOfPageView::isOutputToRecordingMetaFile() const
412 		{
413 			GDIMetaFile* pMetaFile = mrPageWindow.GetPaintWindow().GetOutputDevice().GetConnectMetaFile();
414 			return (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
415 		}
416 
417 		// pdf export?
418 		bool ObjectContactOfPageView::isOutputToPDFFile() const
419 		{
420             return (0 != mrPageWindow.GetPaintWindow().GetOutputDevice().GetPDFWriter());
421 		}
422 
423 		// gray display mode
424 		bool ObjectContactOfPageView::isDrawModeGray() const
425 		{
426 			const sal_uInt32 nDrawMode(mrPageWindow.GetPaintWindow().GetOutputDevice().GetDrawMode());
427 			return (nDrawMode == (DRAWMODE_GRAYLINE|DRAWMODE_GRAYFILL|DRAWMODE_BLACKTEXT|DRAWMODE_GRAYBITMAP|DRAWMODE_GRAYGRADIENT));
428 		}
429 
430 		// gray display mode
431 		bool ObjectContactOfPageView::isDrawModeBlackWhite() const
432 		{
433 			const sal_uInt32 nDrawMode(mrPageWindow.GetPaintWindow().GetOutputDevice().GetDrawMode());
434 			return (nDrawMode == (DRAWMODE_BLACKLINE|DRAWMODE_BLACKTEXT|DRAWMODE_WHITEFILL|DRAWMODE_GRAYBITMAP|DRAWMODE_WHITEGRADIENT));
435 		}
436 
437 		// high contrast display mode
438 		bool ObjectContactOfPageView::isDrawModeHighContrast() const
439 		{
440 			const sal_uInt32 nDrawMode(mrPageWindow.GetPaintWindow().GetOutputDevice().GetDrawMode());
441 			return (nDrawMode == (DRAWMODE_SETTINGSLINE|DRAWMODE_SETTINGSFILL|DRAWMODE_SETTINGSTEXT|DRAWMODE_SETTINGSGRADIENT));
442 		}
443 
444         // access to SdrPageView
445 		SdrPageView* ObjectContactOfPageView::TryToGetSdrPageView() const
446         {
447             return &(mrPageWindow.GetPageView());
448         }
449 
450 
451 		// access to OutputDevice
452 		OutputDevice* ObjectContactOfPageView::TryToGetOutputDevice() const
453 		{
454 			SdrPreRenderDevice* pPreRenderDevice = mrPageWindow.GetPaintWindow().GetPreRenderDevice();
455 
456 			if(pPreRenderDevice)
457 			{
458 				return &(pPreRenderDevice->GetPreRenderDevice());
459 			}
460 			else
461 			{
462 				return &(mrPageWindow.GetPaintWindow().GetOutputDevice());
463 			}
464 		}
465 
466 		// set all UNO controls displayed in the view to design/alive mode
467         void ObjectContactOfPageView::SetUNOControlsDesignMode( bool _bDesignMode ) const
468         {
469             const sal_uInt32 nCount(getViewObjectContactCount());
470 
471 			for(sal_uInt32 a(0); a < nCount; a++)
472             {
473                 const ViewObjectContact* pVOC = getViewObjectContact(a);
474 				const ViewObjectContactOfUnoControl* pUnoObjectVOC = dynamic_cast< const ViewObjectContactOfUnoControl* >(pVOC);
475 
476 				if(pUnoObjectVOC)
477 				{
478 	                pUnoObjectVOC->setControlDesignMode(_bDesignMode);
479 				}
480             }
481         }
482 	} // end of namespace contact
483 } // end of namespace sdr
484 
485 //////////////////////////////////////////////////////////////////////////////
486 // eof
487