LibreOffice Module svx (master)  1
viewobjectcontactofpageobj.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <vcl/idle.hxx>
23 #include <svx/svdopage.hxx>
25 #include <svtools/colorcfg.hxx>
31 #include <svx/svdpage.hxx>
32 #include <svx/unoapi.hxx>
35 #include <vcl/canvastools.hxx>
36 
37 using namespace com::sun::star;
38 
39 namespace sdr::contact {
40 
42 {
43 private:
44  // the ViewObjectContactOfPageObj using this painter
46 
47 public:
48  // basic constructor/destructor
50  virtual ~PagePrimitiveExtractor() override;
51 
52  // LazyInvalidate request. Supported here to not automatically
53  // invalidate the second interaction state all the time at the
54  // original OC
55  virtual void setLazyInvalidate(ViewObjectContact& rVOC) override;
56 
57  // From baseclass Timer, the timeout call triggered by the LazyInvalidate mechanism
58  virtual void Invoke() final override;
59 
60  // get primitive visualization
61  drawinglayer::primitive2d::Primitive2DContainer createPrimitive2DSequenceForPage();
62 
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;
65 
66  // forward access to SdrPageView of ViewObjectContactOfPageObj
67  virtual bool isOutputToPrinter() const override;
68  virtual bool isOutputToRecordingMetaFile() const override;
69  virtual bool isOutputToPDFFile() const override;
70  virtual bool isDrawModeGray() const override;
71  virtual bool isDrawModeHighContrast() const override;
72  virtual SdrPageView* TryToGetSdrPageView() const override;
73  virtual OutputDevice* TryToGetOutputDevice() const override;
74 };
75 
78 : ObjectContactOfPagePainter(rVOC.GetObjectContact()), Idle("svx PagePrimitiveExtractor"),
79  mrViewObjectContactOfPageObj(rVOC)
80 {
81  // make this renderer a preview renderer
82  setPreviewRenderer(true);
83 
84  // init timer
85  SetPriority(TaskPriority::HIGH_IDLE);
86  Stop();
87 }
88 
89 PagePrimitiveExtractor::~PagePrimitiveExtractor()
90 {
91  // execute missing LazyInvalidates and stop timer
92  Invoke();
93 }
94 
95 void PagePrimitiveExtractor::setLazyInvalidate(ViewObjectContact& /*rVOC*/)
96 {
97  // do NOT call parent, but remember that something is to do by
98  // starting the LazyInvalidateTimer
99  Start();
100 }
101 
102 // From baseclass Timer, the timeout call triggered by the LazyInvalidate mechanism
103 void PagePrimitiveExtractor::Invoke()
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 drawinglayer::primitive2d::Primitive2DContainer PagePrimitiveExtractor::createPrimitive2DSequenceForPage()
119 {
121  SdrPage* pStartPage = GetStartPage();
122 
123  if(pStartPage)
124  {
125  // update own ViewInformation2D for visualized page
126  const drawinglayer::geometry::ViewInformation2D& rOriginalViewInformation = mrViewObjectContactOfPageObj.GetObjectContact().getViewInformation2D();
127  const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D(
128  rOriginalViewInformation.getObjectTransformation(),
129  rOriginalViewInformation.getViewTransformation(),
130 
131  // #i101075# use empty range for page content here to force
132  // the content not to be physically clipped in any way. This
133  // would be possible, but would require the internal transformation
134  // which maps between the page visualisation object and the page
135  // content, including the aspect ratios (for details see in
136  // PagePreviewPrimitive2D::create2DDecomposition)
138 
139  GetXDrawPageForSdrPage(pStartPage),
140  0.0); // no time; page previews are not animated
141  updateViewInformation2D(aNewViewInformation2D);
142 
143  // create copy of DisplayInfo to set PagePainting
144  DisplayInfo aDisplayInfo;
145 
146  // get page's VOC
147  ViewObjectContact& rDrawPageVOContact = pStartPage->GetViewContact().GetViewObjectContact(*this);
148 
149  // get whole Primitive2DContainer
150  rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo, xRetval);
151  }
152 
153  return xRetval;
154 }
155 
156 void PagePrimitiveExtractor::InvalidatePartOfView(const basegfx::B2DRange& rRange) const
157 {
158  // an invalidate is called at this view, this needs to be translated to an invalidate
159  // for the using VOC. Coordinates are in page coordinate system.
160  const SdrPage* pStartPage = GetStartPage();
161 
162  if(pStartPage && !rRange.isEmpty())
163  {
164  const basegfx::B2DRange aPageRange(0.0, 0.0, static_cast<double>(pStartPage->GetWidth()), static_cast<double>(pStartPage->GetHeight()));
165 
166  if(rRange.overlaps(aPageRange))
167  {
168  // if object on the page is inside or overlapping with page, create ActionChanged() for
169  // involved VOC
170  mrViewObjectContactOfPageObj.ActionChanged();
171  }
172  }
173 }
174 
175 // forward access to SdrPageView to VOCOfPageObj
176 bool PagePrimitiveExtractor::isOutputToPrinter() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToPrinter(); }
177 bool PagePrimitiveExtractor::isOutputToRecordingMetaFile() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToRecordingMetaFile(); }
178 bool PagePrimitiveExtractor::isOutputToPDFFile() const { return mrViewObjectContactOfPageObj.GetObjectContact().isOutputToPDFFile(); }
179 bool PagePrimitiveExtractor::isDrawModeGray() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeGray(); }
180 bool PagePrimitiveExtractor::isDrawModeHighContrast() const { return mrViewObjectContactOfPageObj.GetObjectContact().isDrawModeHighContrast(); }
181 SdrPageView* PagePrimitiveExtractor::TryToGetSdrPageView() const { return mrViewObjectContactOfPageObj.GetObjectContact().TryToGetSdrPageView(); }
182 OutputDevice* PagePrimitiveExtractor::TryToGetOutputDevice() const { return mrViewObjectContactOfPageObj.GetObjectContact().TryToGetOutputDevice(); }
183 
184 void ViewObjectContactOfPageObj::createPrimitive2DSequence(const DisplayInfo& /*rDisplayInfo*/, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
185 {
186  const SdrPageObj& rPageObject(static_cast< ViewContactOfPageObj& >(GetViewContact()).GetPageObj());
187  const SdrPage* pPage = rPageObject.GetReferencedPage();
188  const svtools::ColorConfig aColorConfig;
189 
190  // get PageObject's geometry
191  basegfx::B2DHomMatrix aPageObjectTransform;
192  {
193  const tools::Rectangle aPageObjectModelData(rPageObject.GetLastBoundRect());
194  const basegfx::B2DRange aPageObjectBound = vcl::unotools::b2DRectangleFromRectangle(aPageObjectModelData);
195 
196  aPageObjectTransform.set(0, 0, aPageObjectBound.getWidth());
197  aPageObjectTransform.set(1, 1, aPageObjectBound.getHeight());
198  aPageObjectTransform.set(0, 2, aPageObjectBound.getMinX());
199  aPageObjectTransform.set(1, 2, aPageObjectBound.getMinY());
200  }
201 
202  // #i102637# add gray frame also when printing and page exists (handout pages)
203  const bool bCreateGrayFrame(!GetObjectContact().isOutputToPrinter() || pPage);
204 
205  // get displayed page's content. This is the unscaled page content
206  if(mpExtractor && pPage)
207  {
208  // get displayed page's geometry
210  const Size aPageSize(pPage->GetSize());
211  const double fPageWidth(aPageSize.getWidth());
212  const double fPageHeight(aPageSize.getHeight());
213 
214  // The case that a PageObject contains another PageObject which visualizes the
215  // same page again would lead to a recursion. Limit that recursion depth to one
216  // by using a local static bool
217  static bool bInCreatePrimitive2D(false);
218 
219  if(bInCreatePrimitive2D)
220  {
221  // Recursion is possible. Create a replacement primitive
222  xPageContent.resize(2);
223  const Color aDocColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
224  svtools::ColorConfigValue aBorderConfig = aColorConfig.GetColorValue(svtools::DOCBOUNDARIES);
225  const Color aBorderColor = aBorderConfig.bIsVisible ? aBorderConfig.nColor : aDocColor;
226  const basegfx::B2DRange aPageBound(0.0, 0.0, fPageWidth, fPageHeight);
228 
229  // add replacement fill
232 
233  // add replacement border
235  new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(std::move(aOutline), aBorderColor.getBColor()));
236  }
237  else
238  {
239  // set recursion flag
240  bInCreatePrimitive2D = true;
241 
242  // init extractor, guarantee existence, set page there
243  mpExtractor->SetStartPage(pPage);
244 
245  // #i105548# also need to copy the VOCRedirector for sub-content creation
246  mpExtractor->SetViewObjectContactRedirector(GetObjectContact().GetViewObjectContactRedirector());
247 
248  // create page content
249  xPageContent = mpExtractor->createPrimitive2DSequenceForPage();
250 
251  // #i105548# reset VOCRedirector to not accidentally have a pointer to a
252  // temporary class, so calls to it are avoided safely
253  mpExtractor->SetViewObjectContactRedirector(nullptr);
254 
255  // reset recursion flag
256  bInCreatePrimitive2D = false;
257  }
258 
259  // prepare retval
260  if(!xPageContent.empty())
261  {
262  const uno::Reference< drawing::XDrawPage > xDrawPage(GetXDrawPageForSdrPage(const_cast< SdrPage*>(pPage)));
264  xDrawPage, aPageObjectTransform, fPageWidth, fPageHeight, std::move(xPageContent)));
265  rVisitor.visit(xPagePreview);
266  }
267  }
268  else if(bCreateGrayFrame)
269  {
270  // #i105146# no content, but frame display. To make hitting the page preview objects
271  // on the handout page more simple, add hidden fill geometry
274  aPageObjectTransform));
275  rVisitor.visit(xFrameHit);
276  }
277 
278  // add a gray outline frame, except not when printing
279  if(bCreateGrayFrame)
280  {
281  const Color aFrameColor(aColorConfig.GetColorValue(svtools::OBJECTBOUNDARIES).nColor);
283  aOwnOutline.transform(aPageObjectTransform);
284 
286  new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(std::move(aOwnOutline), aFrameColor.getBColor()));
287 
288  rVisitor.visit(xGrayFrame);
289  }
290 }
291 
292 ViewObjectContactOfPageObj::ViewObjectContactOfPageObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
293 : ViewObjectContactOfSdrObj(rObjectContact, rViewContact),
294  mpExtractor(new PagePrimitiveExtractor(*this))
295 {
296 }
297 
299 {
300  // delete the helper OC
301  if(mpExtractor)
302  {
303  // remember candidate and reset own pointer to avoid action when createPrimitive2DSequence()
304  // would be called for any reason
305  std::unique_ptr<PagePrimitiveExtractor> pCandidate = std::move(mpExtractor);
306 
307  // also reset the StartPage to avoid ActionChanged() forwardings in the
308  // PagePrimitiveExtractor::InvalidatePartOfView() implementation
309  pCandidate->SetStartPage(nullptr);
310  }
311 }
312 
313 }
314 
315 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual bool isDrawModeHighContrast() const
void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
std::unique_ptr< PagePrimitiveExtractor > mpExtractor
tools::Long GetWidth() const
Definition: svdpage.cxx:1448
B2DPolygon const & createUnitPolygon()
rtl::Reference< BasePrimitive2D > Primitive2DReference
ViewObjectContact & GetViewObjectContact(ObjectContact &rObjectContact)
Definition: viewcontact.cxx:65
bool overlaps(const Range2D &rRange) const
const basegfx::B2DHomMatrix & getObjectTransformation() const
virtual bool isOutputToPrinter() const
ObjectContact & GetObjectContact() const
virtual bool isOutputToPDFFile() const
virtual void getPrimitive2DSequenceHierarchy(DisplayInfo &rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor &rVisitor) const
uno_Any a
const drawinglayer::geometry::ViewInformation2D & getViewInformation2D() const
virtual void visit(const Primitive2DReference &)=0
tools::Long GetHeight() const
Definition: svdpage.cxx:1474
Size GetSize() const
Definition: svdpage.cxx:1443
const basegfx::B2DHomMatrix & getViewTransformation() const
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
ViewObjectContactOfPageObj & mrViewObjectContactOfPageObj
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
uno::Reference< drawing::XDrawPage > GetXDrawPageForSdrPage(SdrPage *pPage) noexcept
returns a StarOffice API wrapper for the given SdrPage
Definition: unopage.cxx:870
virtual bool isOutputToRecordingMetaFile() const
virtual const tools::Rectangle & GetLastBoundRect() const
Definition: svdobj.cxx:968
ColorConfigValue GetColorValue(ColorConfigEntry eEntry, bool bSmart=true) const
SdrPage * GetReferencedPage() const
Definition: svdopage.hxx:55
const sdr::contact::ViewContact & GetViewContact() const
Definition: svdpage.cxx:1150
Primitive2DReference createHiddenGeometryPrimitives2D(const basegfx::B2DHomMatrix &rMatrix)
virtual OutputDevice * TryToGetOutputDevice() const
access to OutputDevice. May return 0L like the default implementations do. Override as needed...
basegfx::BColor getBColor() const
aCursorMoveIdle Stop()
A SdrPage contains exactly one SdrObjList and a description of the physical page dimensions (size / m...
Definition: svdpage.hxx:373
virtual bool isDrawModeGray() const
virtual SdrPageView * TryToGetSdrPageView() const
access to SdrPageView. May return 0L like the default implementations do. Override as needed...