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