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 
31 #include <svx/sdr/contact/viewobjectcontactofpageobj.hxx>
32 #include <svx/sdr/contact/viewcontactofpageobj.hxx>
33 #include <svx/svdopage.hxx>
34 #include <svx/sdr/contact/displayinfo.hxx>
35 #include <basegfx/polygon/b2dpolygontools.hxx>
36 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
37 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
38 #include <svx/sdr/contact/objectcontactofobjlistpainter.hxx>
39 #include <basegfx/matrix/b2dhommatrix.hxx>
40 #include <svx/svdpage.hxx>
41 #include <svx/unoapi.hxx>
42 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
43 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
44 
45 //////////////////////////////////////////////////////////////////////////////
46 
47 using namespace com::sun::star;
48 
49 //////////////////////////////////////////////////////////////////////////////
50 
51 namespace sdr
52 {
53     namespace contact
54     {
55         class PagePrimitiveExtractor : public ObjectContactOfPagePainter, public Timer
56 	    {
57 	    private:
58 		    // the ViewObjectContactOfPageObj using this painter
59 		    ViewObjectContactOfPageObj&			mrViewObjectContactOfPageObj;
60 
61 	    public:
62 		    // basic constructor/destructor
63 		    PagePrimitiveExtractor(ViewObjectContactOfPageObj& rVOC);
64 		    virtual ~PagePrimitiveExtractor();
65 
66 		    // LazyInvalidate request. Supported here to not automatically
67 		    // invalidate the second interaction state all the time at the
68 		    // original OC
69 		    virtual void setLazyInvalidate(ViewObjectContact& rVOC);
70 
71 		    // From baseclass Timer, the timeout call triggered by te LazyInvalidate mechanism
72 		    virtual void Timeout();
73 
74 		    // get primitive visualization
75 		    drawinglayer::primitive2d::Primitive2DSequence createPrimitive2DSequenceForPage(const DisplayInfo& rDisplayInfo);
76 
77 		    // Own reaction on changes which will be forwarded to the OC of the owner-VOC
78 		    virtual void InvalidatePartOfView(const basegfx::B2DRange& rRange) const;
79 
80             // forward access to SdrPageView of ViewObjectContactOfPageObj
81 		    virtual bool isOutputToPrinter() const;
82 		    virtual bool isOutputToWindow() const;
83 		    virtual bool isOutputToVirtualDevice() const;
84 		    virtual bool isOutputToRecordingMetaFile() const;
85 			virtual bool isOutputToPDFFile() const;
86 		    virtual bool isDrawModeGray() const;
87 		    virtual bool isDrawModeBlackWhite() const;
88 		    virtual bool isDrawModeHighContrast() const;
89 		    virtual SdrPageView* TryToGetSdrPageView() const;
90 		    virtual OutputDevice* TryToGetOutputDevice() const;
91 	    };
92 
93 	    PagePrimitiveExtractor::PagePrimitiveExtractor(
94 		    ViewObjectContactOfPageObj& rVOC)
95 	    :	ObjectContactOfPagePainter(0, rVOC.GetObjectContact()),
96 		    mrViewObjectContactOfPageObj(rVOC)
97 	    {
98 		    // make this renderer a preview renderer
99 		    setPreviewRenderer(true);
100 
101 		    // init timer
102 		    SetTimeout(1);
103 		    Stop();
104 	    }
105 
106 	    PagePrimitiveExtractor::~PagePrimitiveExtractor()
107 	    {
108 		    // execute missing LazyInvalidates and stop timer
109 		    Timeout();
110 	    }
111 
112 	    void PagePrimitiveExtractor::setLazyInvalidate(ViewObjectContact& /*rVOC*/)
113 	    {
114 		    // do NOT call parent, but remember that something is to do by
115 		    // starting the LazyInvalidateTimer
116 		    Start();
117 	    }
118 
119 	    // From baseclass Timer, the timeout call triggered by te LazyInvalidate mechanism
120 	    void PagePrimitiveExtractor::Timeout()
121 	    {
122 		    // stop the timer
123 		    Stop();
124 
125 		    // invalidate all LazyInvalidate VOCs new situations
126 		    const sal_uInt32 nVOCCount(getViewObjectContactCount());
127 
128 		    for(sal_uInt32 a(0); a < nVOCCount; a++)
129 		    {
130 			    ViewObjectContact* pCandidate = getViewObjectContact(a);
131 			    pCandidate->triggerLazyInvalidate();
132 		    }
133 	    }
134 
135 	    drawinglayer::primitive2d::Primitive2DSequence PagePrimitiveExtractor::createPrimitive2DSequenceForPage(const DisplayInfo& /*rDisplayInfo*/)
136 	    {
137 		    drawinglayer::primitive2d::Primitive2DSequence xRetval;
138 		    const SdrPage* pStartPage = GetStartPage();
139 
140 		    if(pStartPage)
141 		    {
142                 // update own ViewInformation2D for visualized page
143 			    const drawinglayer::geometry::ViewInformation2D& rOriginalViewInformation = mrViewObjectContactOfPageObj.GetObjectContact().getViewInformation2D();
144                 const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D(
145 				    rOriginalViewInformation.getObjectTransformation(),
146 				    rOriginalViewInformation.getViewTransformation(),
147 
148                     // #i101075# use empty range for page content here to force
149                     // the content not to be physically clipped in any way. This
150                     // would be possible, but would require the internal transformation
151                     // which maps between the page visualisation object and the page
152                     // content, including the aspect ratios (for details see in
153                     // PagePreviewPrimitive2D::create2DDecomposition)
154                     basegfx::B2DRange(),
155 
156                     GetXDrawPageForSdrPage(const_cast< SdrPage* >(pStartPage)),
157 				    0.0, // no time; page previews are not animated
158 				    rOriginalViewInformation.getExtendedInformationSequence());
159 			    updateViewInformation2D(aNewViewInformation2D);
160 
161 			    // create copy of DisplayInfo to set PagePainting
162 			    DisplayInfo aDisplayInfo;
163 
164 			    // get page's VOC
165 			    ViewObjectContact& rDrawPageVOContact = pStartPage->GetViewContact().GetViewObjectContact(*this);
166 
167 			    // get whole Primitive2DSequence
168 			    xRetval = rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo);
169 		    }
170 
171 		    return xRetval;
172 	    }
173 
174 	    void PagePrimitiveExtractor::InvalidatePartOfView(const basegfx::B2DRange& rRange) const
175 	    {
176 		    // an invalidate is called at this view, this needs to be translated to an invalidate
177 		    // for the using VOC. Coordinates are in page coordinate system.
178 		    const SdrPage* pStartPage = GetStartPage();
179 
180 		    if(pStartPage && !rRange.isEmpty())
181 		    {
182 			    const basegfx::B2DRange aPageRange(0.0, 0.0, (double)pStartPage->GetWdt(), (double)pStartPage->GetHgt());
183 
184 			    if(rRange.overlaps(aPageRange))
185 			    {
186 				    // if object on the page is inside or overlapping with page, create ActionChanged() for
187 				    // involved VOC
188 				    mrViewObjectContactOfPageObj.ActionChanged();
189 			    }
190 		    }
191 	    }
192 
193         // forward access to SdrPageView to VOCOfPageObj
194 	    bool PagePrimitiveExtractor::isOutputToPrinter() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToPrinter(); }
195 	    bool PagePrimitiveExtractor::isOutputToWindow() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToWindow(); }
196 	    bool PagePrimitiveExtractor::isOutputToVirtualDevice() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToVirtualDevice(); }
197 	    bool PagePrimitiveExtractor::isOutputToRecordingMetaFile() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToRecordingMetaFile(); }
198 		bool PagePrimitiveExtractor::isOutputToPDFFile() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToPDFFile(); }
199 	    bool PagePrimitiveExtractor::isDrawModeGray() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeGray(); }
200 	    bool PagePrimitiveExtractor::isDrawModeBlackWhite() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeBlackWhite(); }
201 	    bool PagePrimitiveExtractor::isDrawModeHighContrast() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeHighContrast(); }
202 	    SdrPageView* PagePrimitiveExtractor::TryToGetSdrPageView() const { return mrViewObjectContactOfPageObj.GetObjectContact().TryToGetSdrPageView(); }
203 	    OutputDevice* PagePrimitiveExtractor::TryToGetOutputDevice() const { return mrViewObjectContactOfPageObj.GetObjectContact().TryToGetOutputDevice(); }
204 	} // end of namespace contact
205 } // end of namespace sdr
206 
207 //////////////////////////////////////////////////////////////////////////////
208 
209 namespace sdr
210 {
211 	namespace contact
212 	{
213 		drawinglayer::primitive2d::Primitive2DSequence ViewObjectContactOfPageObj::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const
214 		{
215 			drawinglayer::primitive2d::Primitive2DSequence xRetval;
216 			const SdrPageObj& rPageObject((static_cast< ViewContactOfPageObj& >(GetViewContact())).GetPageObj());
217 			const SdrPage* pPage = rPageObject.GetReferencedPage();
218 			const svtools::ColorConfig aColorConfig;
219 
220             // get PageObject's geometry
221             basegfx::B2DHomMatrix aPageObjectTransform;
222 			{
223 				const Rectangle aPageObjectModelData(rPageObject.GetLastBoundRect());
224 				const basegfx::B2DRange aPageObjectBound(
225 					aPageObjectModelData.Left(), aPageObjectModelData.Top(),
226 					aPageObjectModelData.Right(), aPageObjectModelData.Bottom());
227 
228 				aPageObjectTransform.set(0, 0, aPageObjectBound.getWidth());
229 				aPageObjectTransform.set(1, 1, aPageObjectBound.getHeight());
230 				aPageObjectTransform.set(0, 2, aPageObjectBound.getMinX());
231 				aPageObjectTransform.set(1, 2, aPageObjectBound.getMinY());
232 			}
233 
234 			// #i102637# add gray frame also when printing and page exists (handout pages)
235 			const bool bCreateGrayFrame(!GetObjectContact().isOutputToPrinter() || pPage);
236 
237 			// get displayed page's content. This is the uscaled page content
238             if(mpExtractor && pPage)
239 			{
240 	            // get displayed page's geometry
241 	   			drawinglayer::primitive2d::Primitive2DSequence xPageContent;
242 				const Size aPageSize(pPage->GetSize());
243 				const double fPageWidth(aPageSize.getWidth());
244 				const double fPageHeight(aPageSize.getHeight());
245 
246 				// The case that a PageObject contains another PageObject which visualizes the
247 				// same page again would lead to a recursion. Limit that recursion depth to one
248 				// by using a local static bool
249 				static bool bInCreatePrimitive2D(false);
250 
251 				if(bInCreatePrimitive2D)
252 				{
253 					// Recursion is possible. Create a replacement primitive
254 					xPageContent.realloc(2);
255 					const Color aDocColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
256 					const Color aBorderColor(aColorConfig.GetColorValue(svtools::DOCBOUNDARIES).nColor);
257 					const basegfx::B2DRange aPageBound(0.0, 0.0, fPageWidth, fPageHeight);
258 					const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aPageBound));
259 
260 					// add replacement fill
261 					xPageContent[0L] = drawinglayer::primitive2d::Primitive2DReference(
262 						new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aOutline), aDocColor.getBColor()));
263 
264 					// add replacement border
265 					xPageContent[1L] = drawinglayer::primitive2d::Primitive2DReference(
266 						new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aBorderColor.getBColor()));
267 				}
268 				else
269 				{
270 					// set recursion flag
271 					bInCreatePrimitive2D = true;
272 
273 					// init extractor, guarantee existance, set page there
274 					mpExtractor->SetStartPage(pPage);
275 
276                     // #i105548# also need to copy the VOCRedirector for sub-content creation
277                     mpExtractor->SetViewObjectContactRedirector(GetObjectContact().GetViewObjectContactRedirector());
278 
279 					// create page content
280 					xPageContent = mpExtractor->createPrimitive2DSequenceForPage(rDisplayInfo);
281 
282                     // #i105548# reset VOCRedirector to not accidentially have a pointer to a
283                     // temporary class, so calls to it are avoided safely
284                     mpExtractor->SetViewObjectContactRedirector(0);
285 
286                     // reset recursion flag
287 					bInCreatePrimitive2D = false;
288 				}
289 
290 				// prepare retval
291 				if(xPageContent.hasElements())
292 				{
293 					const uno::Reference< drawing::XDrawPage > xDrawPage(GetXDrawPageForSdrPage(const_cast< SdrPage*>(pPage)));
294     				const drawinglayer::primitive2d::Primitive2DReference xPagePreview(new drawinglayer::primitive2d::PagePreviewPrimitive2D(
295 						xDrawPage, aPageObjectTransform, fPageWidth, fPageHeight, xPageContent, true));
296 					xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xPagePreview, 1);
297 				}
298             }
299             else if(bCreateGrayFrame)
300             {
301                 // #i105146# no content, but frame display. To make hitting the page preview objects
302                 // on the handout page more simple, add hidden fill geometry
303                 const drawinglayer::primitive2d::Primitive2DReference xFrameHit(
304                     drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
305                         false,
306                         aPageObjectTransform));
307                 xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xFrameHit, 1);
308             }
309 
310 			// add a gray outline frame, except not when printing
311 			if(bCreateGrayFrame)
312 			{
313 				const Color aFrameColor(aColorConfig.GetColorValue(svtools::OBJECTBOUNDARIES).nColor);
314 				basegfx::B2DPolygon aOwnOutline(basegfx::tools::createUnitPolygon());
315 				aOwnOutline.transform(aPageObjectTransform);
316 
317 				const drawinglayer::primitive2d::Primitive2DReference xGrayFrame(
318 					new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOwnOutline, aFrameColor.getBColor()));
319 
320 				drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval, xGrayFrame);
321 			}
322 
323 			return xRetval;
324 		}
325 
326 		ViewObjectContactOfPageObj::ViewObjectContactOfPageObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
327 		:	ViewObjectContactOfSdrObj(rObjectContact, rViewContact),
328 			mpExtractor(new PagePrimitiveExtractor(*this))
329 		{
330 		}
331 
332 		ViewObjectContactOfPageObj::~ViewObjectContactOfPageObj()
333 		{
334 			// delete the helper OC
335 			if(mpExtractor)
336 			{
337 				// remember candidate and reset own pointer to avoid action when createPrimitive2DSequence()
338 				// would be called for any reason
339 				PagePrimitiveExtractor* pCandidate = mpExtractor;
340 				mpExtractor = 0;
341 
342 				// also reset the StartPage to avoid ActionChanged() forwardings in the
343 				// PagePrimitiveExtractor::InvalidatePartOfView() implementation
344 				pCandidate->SetStartPage(0);
345 				delete pCandidate;
346 			}
347 		}
348 	} // end of namespace contact
349 } // end of namespace sdr
350 
351 //////////////////////////////////////////////////////////////////////////////
352 // eof
353