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