1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/idle.hxx>
21 #include <sdr/contact/viewobjectcontactofpageobj.hxx>
22 #include <sdr/contact/viewcontactofpageobj.hxx>
23 #include <svx/svdopage.hxx>
24 #include <svx/sdr/contact/displayinfo.hxx>
25 #include <svtools/colorcfg.hxx>
26 #include <basegfx/polygon/b2dpolygontools.hxx>
27 #include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
28 #include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
29 #include <sdr/contact/objectcontactofobjlistpainter.hxx>
30 #include <basegfx/matrix/b2dhommatrix.hxx>
31 #include <svx/svdpage.hxx>
32 #include <svx/unoapi.hxx>
33 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
34 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
35 #include <vcl/canvastools.hxx>
37 using namespace com::sun::star
;
39 namespace sdr::contact
{
41 class PagePrimitiveExtractor
: public ObjectContactOfPagePainter
, public Idle
44 // the ViewObjectContactOfPageObj using this painter
45 ViewObjectContactOfPageObj
& mrViewObjectContactOfPageObj
;
48 // basic constructor/destructor
49 explicit PagePrimitiveExtractor(ViewObjectContactOfPageObj
& rVOC
);
50 virtual ~PagePrimitiveExtractor() override
;
52 // LazyInvalidate request. Supported here to not automatically
53 // invalidate the second interaction state all the time at the
55 virtual void setLazyInvalidate(ViewObjectContact
& rVOC
) override
;
57 // From baseclass Timer, the timeout call triggered by the LazyInvalidate mechanism
58 virtual void Invoke() final override
;
60 // get primitive visualization
61 drawinglayer::primitive2d::Primitive2DContainer
createPrimitive2DSequenceForPage();
63 // Own reaction on changes which will be forwarded to the OC of the owner-VOC
64 virtual void InvalidatePartOfView(const basegfx::B2DRange
& rRange
) const override
;
66 // forward access to SdrPageView of ViewObjectContactOfPageObj
67 virtual bool isOutputToPrinter() const override
;
68 virtual bool isPageDecorationActive() const override
;
69 virtual bool isMasterPageActive() const override
;
70 virtual bool isOutputToRecordingMetaFile() const override
;
71 virtual bool isOutputToPDFFile() const override
;
72 virtual bool isExportTaggedPDF() const override
;
73 virtual ::vcl::PDFExtOutDevData
const* GetPDFExtOutDevData() const override
;
74 virtual bool isDrawModeGray() const override
;
75 virtual bool isDrawModeHighContrast() const override
;
76 virtual SdrPageView
* TryToGetSdrPageView() const override
;
77 virtual OutputDevice
* TryToGetOutputDevice() const override
;
80 PagePrimitiveExtractor::PagePrimitiveExtractor(
81 ViewObjectContactOfPageObj
& rVOC
)
82 : ObjectContactOfPagePainter(rVOC
.GetObjectContact()), Idle("svx PagePrimitiveExtractor"),
83 mrViewObjectContactOfPageObj(rVOC
)
85 // make this renderer a preview renderer
86 setPreviewRenderer(true);
89 SetPriority(TaskPriority::HIGH_IDLE
);
93 PagePrimitiveExtractor::~PagePrimitiveExtractor()
95 // execute missing LazyInvalidates and stop timer
99 void PagePrimitiveExtractor::setLazyInvalidate(ViewObjectContact
& /*rVOC*/)
101 // do NOT call parent, but remember that something is to do by
102 // starting the LazyInvalidateTimer
106 // From baseclass Timer, the timeout call triggered by the LazyInvalidate mechanism
107 void PagePrimitiveExtractor::Invoke()
112 // invalidate all LazyInvalidate VOCs new situations
113 const sal_uInt32
nVOCCount(getViewObjectContactCount());
115 for(sal_uInt32
a(0); a
< nVOCCount
; a
++)
117 ViewObjectContact
* pCandidate
= getViewObjectContact(a
);
118 pCandidate
->triggerLazyInvalidate();
122 drawinglayer::primitive2d::Primitive2DContainer
PagePrimitiveExtractor::createPrimitive2DSequenceForPage()
124 drawinglayer::primitive2d::Primitive2DContainer xRetval
;
125 SdrPage
* pStartPage
= GetStartPage();
129 // update own ViewInformation2D for visualized page
130 const drawinglayer::geometry::ViewInformation2D
& rOriginalViewInformation
= mrViewObjectContactOfPageObj
.GetObjectContact().getViewInformation2D();
131 drawinglayer::geometry::ViewInformation2D
aNewViewInformation2D(rOriginalViewInformation
);
133 // #i101075# use empty range for page content here to force
134 // the content not to be physically clipped in any way. This
135 // would be possible, but would require the internal transformation
136 // which maps between the page visualisation object and the page
137 // content, including the aspect ratios (for details see in
138 // PagePreviewPrimitive2D::create2DDecomposition)
139 aNewViewInformation2D
.setViewport(basegfx::B2DRange());
141 aNewViewInformation2D
.setVisualizedPage(GetXDrawPageForSdrPage(pStartPage
));
143 // no time; page previews are not animated
144 aNewViewInformation2D
.setViewTime(0.0);
146 updateViewInformation2D(aNewViewInformation2D
);
148 // create copy of DisplayInfo to set PagePainting
149 DisplayInfo aDisplayInfo
;
152 ViewObjectContact
& rDrawPageVOContact
= pStartPage
->GetViewContact().GetViewObjectContact(*this);
154 // get whole Primitive2DContainer
155 rDrawPageVOContact
.getPrimitive2DSequenceHierarchy(aDisplayInfo
, xRetval
);
161 void PagePrimitiveExtractor::InvalidatePartOfView(const basegfx::B2DRange
& rRange
) const
163 // an invalidate is called at this view, this needs to be translated to an invalidate
164 // for the using VOC. Coordinates are in page coordinate system.
165 const SdrPage
* pStartPage
= GetStartPage();
167 if(pStartPage
&& !rRange
.isEmpty())
169 const basegfx::B2DRange
aPageRange(0.0, 0.0, static_cast<double>(pStartPage
->GetWidth()), static_cast<double>(pStartPage
->GetHeight()));
171 if(rRange
.overlaps(aPageRange
))
173 // if object on the page is inside or overlapping with page, create ActionChanged() for
175 mrViewObjectContactOfPageObj
.ActionChanged();
180 // forward access to SdrPageView to VOCOfPageObj
181 bool PagePrimitiveExtractor::isOutputToPrinter() const { return mrViewObjectContactOfPageObj
.GetObjectContact().isOutputToPrinter(); }
182 bool PagePrimitiveExtractor::isPageDecorationActive() const { return mrViewObjectContactOfPageObj
.GetObjectContact().isPageDecorationActive(); }
183 bool PagePrimitiveExtractor::isMasterPageActive() const { return mrViewObjectContactOfPageObj
.GetObjectContact().isMasterPageActive(); }
184 bool PagePrimitiveExtractor::isOutputToRecordingMetaFile() const { return mrViewObjectContactOfPageObj
.GetObjectContact().isOutputToRecordingMetaFile(); }
185 bool PagePrimitiveExtractor::isOutputToPDFFile() const { return mrViewObjectContactOfPageObj
.GetObjectContact().isOutputToPDFFile(); }
186 bool PagePrimitiveExtractor::isExportTaggedPDF() const { return mrViewObjectContactOfPageObj
.GetObjectContact().isExportTaggedPDF(); }
187 ::vcl::PDFExtOutDevData
const* PagePrimitiveExtractor::GetPDFExtOutDevData() const { return mrViewObjectContactOfPageObj
.GetObjectContact().GetPDFExtOutDevData(); }
188 bool PagePrimitiveExtractor::isDrawModeGray() const { return mrViewObjectContactOfPageObj
.GetObjectContact().isDrawModeGray(); }
189 bool PagePrimitiveExtractor::isDrawModeHighContrast() const { return mrViewObjectContactOfPageObj
.GetObjectContact().isDrawModeHighContrast(); }
190 SdrPageView
* PagePrimitiveExtractor::TryToGetSdrPageView() const { return mrViewObjectContactOfPageObj
.GetObjectContact().TryToGetSdrPageView(); }
191 OutputDevice
* PagePrimitiveExtractor::TryToGetOutputDevice() const { return mrViewObjectContactOfPageObj
.GetObjectContact().TryToGetOutputDevice(); }
193 void ViewObjectContactOfPageObj::createPrimitive2DSequence(const DisplayInfo
& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor
& rVisitor
) const
195 const SdrPageObj
& rPageObject(static_cast< ViewContactOfPageObj
& >(GetViewContact()).GetPageObj());
196 const SdrPage
* pPage
= rPageObject
.GetReferencedPage();
197 const svtools::ColorConfig aColorConfig
;
199 // get PageObject's geometry
200 basegfx::B2DHomMatrix aPageObjectTransform
;
202 const tools::Rectangle
aPageObjectModelData(rPageObject
.GetLastBoundRect());
203 const basegfx::B2DRange aPageObjectBound
= vcl::unotools::b2DRectangleFromRectangle(aPageObjectModelData
);
205 aPageObjectTransform
.set(0, 0, aPageObjectBound
.getWidth());
206 aPageObjectTransform
.set(1, 1, aPageObjectBound
.getHeight());
207 aPageObjectTransform
.set(0, 2, aPageObjectBound
.getMinX());
208 aPageObjectTransform
.set(1, 2, aPageObjectBound
.getMinY());
211 // #i102637# add gray frame also when printing and page exists (handout pages)
212 const bool bCreateGrayFrame(!GetObjectContact().isOutputToPrinter() || pPage
);
214 // get displayed page's content. This is the unscaled page content
215 if(mpExtractor
&& pPage
)
217 // get displayed page's geometry
218 drawinglayer::primitive2d::Primitive2DContainer xPageContent
;
219 const Size
aPageSize(pPage
->GetSize());
220 const double fPageWidth(aPageSize
.getWidth());
221 const double fPageHeight(aPageSize
.getHeight());
223 // The case that a PageObject contains another PageObject which visualizes the
224 // same page again would lead to a recursion. Limit that recursion depth to one
225 // by using a local static bool
226 static bool bInCreatePrimitive2D(false);
228 if(bInCreatePrimitive2D
)
230 // Recursion is possible. Create a replacement primitive
231 xPageContent
.resize(2);
232 const Color
aDocColor(aColorConfig
.GetColorValue(svtools::DOCCOLOR
).nColor
);
233 svtools::ColorConfigValue aBorderConfig
= aColorConfig
.GetColorValue(svtools::DOCBOUNDARIES
);
234 const Color aBorderColor
= aBorderConfig
.bIsVisible
? aBorderConfig
.nColor
: aDocColor
;
235 const basegfx::B2DRange
aPageBound(0.0, 0.0, fPageWidth
, fPageHeight
);
236 basegfx::B2DPolygon
aOutline(basegfx::utils::createPolygonFromRect(aPageBound
));
238 // add replacement fill
239 xPageContent
[0] = drawinglayer::primitive2d::Primitive2DReference(
240 new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aOutline
), aDocColor
.getBColor()));
242 // add replacement border
243 xPageContent
[1] = drawinglayer::primitive2d::Primitive2DReference(
244 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(std::move(aOutline
), aBorderColor
.getBColor()));
248 // set recursion flag
249 bInCreatePrimitive2D
= true;
251 // init extractor, guarantee existence, set page there
252 mpExtractor
->SetStartPage(pPage
);
254 // #i105548# also need to copy the VOCRedirector for sub-content creation
255 mpExtractor
->SetViewObjectContactRedirector(GetObjectContact().GetViewObjectContactRedirector());
257 // create page content
258 xPageContent
= mpExtractor
->createPrimitive2DSequenceForPage();
260 // #i105548# reset VOCRedirector to not accidentally have a pointer to a
261 // temporary class, so calls to it are avoided safely
262 mpExtractor
->SetViewObjectContactRedirector(nullptr);
264 // reset recursion flag
265 bInCreatePrimitive2D
= false;
269 if(!xPageContent
.empty())
271 const uno::Reference
< drawing::XDrawPage
> xDrawPage(GetXDrawPageForSdrPage(const_cast< SdrPage
*>(pPage
)));
272 const drawinglayer::primitive2d::Primitive2DReference
xPagePreview(new drawinglayer::primitive2d::PagePreviewPrimitive2D(
273 xDrawPage
, aPageObjectTransform
, fPageWidth
, fPageHeight
, std::move(xPageContent
)));
274 rVisitor
.visit(xPagePreview
);
277 else if(bCreateGrayFrame
)
279 // #i105146# no content, but frame display. To make hitting the page preview objects
280 // on the handout page more simple, add hidden fill geometry
281 const drawinglayer::primitive2d::Primitive2DReference
xFrameHit(
282 drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
283 aPageObjectTransform
));
284 rVisitor
.visit(xFrameHit
);
287 // add a gray outline frame, except not when printing
290 const Color
aFrameColor(aColorConfig
.GetColorValue(svtools::DOCBOUNDARIES
).nColor
);
291 basegfx::B2DPolygon
aOwnOutline(basegfx::utils::createUnitPolygon());
292 aOwnOutline
.transform(aPageObjectTransform
);
294 const drawinglayer::primitive2d::Primitive2DReference
xGrayFrame(
295 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(std::move(aOwnOutline
), aFrameColor
.getBColor()));
297 rVisitor
.visit(xGrayFrame
);
301 ViewObjectContactOfPageObj::ViewObjectContactOfPageObj(ObjectContact
& rObjectContact
, ViewContact
& rViewContact
)
302 : ViewObjectContactOfSdrObj(rObjectContact
, rViewContact
),
303 mpExtractor(new PagePrimitiveExtractor(*this))
307 ViewObjectContactOfPageObj::~ViewObjectContactOfPageObj()
309 // delete the helper OC
312 // remember candidate and reset own pointer to avoid action when createPrimitive2DSequence()
313 // would be called for any reason
314 std::unique_ptr
<PagePrimitiveExtractor
> pCandidate
= std::move(mpExtractor
);
316 // also reset the StartPage to avoid ActionChanged() forwardings in the
317 // PagePrimitiveExtractor::InvalidatePartOfView() implementation
318 pCandidate
->SetStartPage(nullptr);
324 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */