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 <config_feature_desktop.h>
22 #include <svx/sdr/contact/objectcontactofpageview.hxx>
23 #include <sdr/contact/viewobjectcontactofunocontrol.hxx>
24 #include <svx/svdpagv.hxx>
25 #include <svx/svdpage.hxx>
26 #include <svx/sdr/contact/displayinfo.hxx>
27 #include <svx/sdr/contact/viewobjectcontact.hxx>
28 #include <svx/svdview.hxx>
29 #include <svx/sdr/contact/viewcontact.hxx>
30 #include <svx/sdr/animation/objectanimator.hxx>
31 #include <svx/sdrpagewindow.hxx>
32 #include <svx/sdrpaintwindow.hxx>
33 #include <svtools/colorcfg.hxx>
34 #include <sfx2/viewsh.hxx>
35 #include <basegfx/matrix/b2dhommatrix.hxx>
36 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
37 #include <drawinglayer/processor2d/processor2dtools.hxx>
38 #include <osl/diagnose.h>
39 #include <officecfg/Office/Common.hxx>
40 #include <svx/unoapi.hxx>
41 #include <comphelper/configuration.hxx>
42 #include <vcl/canvastools.hxx>
43 #include <vcl/pdfextoutdevdata.hxx>
44 #include <comphelper/lok.hxx>
48 using namespace com::sun::star
;
50 namespace sdr::contact
52 // internal access to SdrPage of SdrPageView
53 SdrPage
* ObjectContactOfPageView::GetSdrPage() const
55 return GetPageWindow().GetPageView().GetPage();
58 ObjectContactOfPageView::ObjectContactOfPageView(
59 SdrPageWindow
& rPageWindow
, const char *pDebugName
)
61 , mrPageWindow(rPageWindow
)
63 // init PreviewRenderer flag
64 setPreviewRenderer(static_cast<SdrPaintView
&>(rPageWindow
.GetPageView().GetView()).IsPreviewRenderer());
67 SetPriority(TaskPriority::HIGH_IDLE
);
71 ObjectContactOfPageView::~ObjectContactOfPageView()
77 // LazyInvalidate request. Take action.
78 void ObjectContactOfPageView::setLazyInvalidate(ViewObjectContact
& /*rVOC*/)
80 // do NOT call parent, but remember that something is to do by
81 // starting the LazyInvalidateTimer
85 // call this to support evtl. preparations for repaint
86 void ObjectContactOfPageView::PrepareProcessDisplay()
89 // there are still non-triggered LazyInvalidate events, trigger these
93 // From baseclass Timer, the timeout call triggered by the LazyInvalidate mechanism
94 void ObjectContactOfPageView::Invoke()
99 // invalidate all LazyInvalidate VOCs new situations
100 const sal_uInt32
nVOCCount(getViewObjectContactCount());
102 for(sal_uInt32
a(0); a
< nVOCCount
; a
++)
104 ViewObjectContact
* pCandidate
= getViewObjectContact(a
);
105 pCandidate
->triggerLazyInvalidate();
109 // Process the whole displaying
110 void ObjectContactOfPageView::ProcessDisplay(DisplayInfo
& rDisplayInfo
)
112 const SdrPage
* pStartPage
= GetSdrPage();
114 if(pStartPage
&& !rDisplayInfo
.GetProcessLayers().IsEmpty())
116 const ViewContact
& rDrawPageVC
= pStartPage
->GetViewContact();
118 if(rDrawPageVC
.GetObjectCount())
120 DoProcessDisplay(rDisplayInfo
);
125 // Process the whole displaying. Only use given DisplayInfo, do not access other
126 // OutputDevices then the given ones.
127 void ObjectContactOfPageView::DoProcessDisplay(DisplayInfo
& rDisplayInfo
)
129 OutputDevice
& rTargetOutDev
= GetPageWindow().GetPaintWindow().GetTargetOutputDevice();
130 const Size
aOutputSizePixel(rTargetOutDev
.GetOutputSizePixel());
131 if (!isOutputToRecordingMetaFile() // do those have outdev too?
132 && (0 == aOutputSizePixel
.getWidth() ||
133 0 == aOutputSizePixel
.getHeight()))
138 // visualize entered group when that feature is switched on and it's not
139 // a print output. #i29129# No ghosted display for printing.
140 bool bVisualizeEnteredGroup(DoVisualizeEnteredGroup() && !isOutputToPrinter());
142 // Visualize entered groups: Set to ghosted as default
143 // start. Do this only for the DrawPage, not for MasterPages
144 if(bVisualizeEnteredGroup
)
146 rDisplayInfo
.SetGhostedDrawMode();
149 // #114359# save old and set clip region
150 OutputDevice
* pOutDev
= TryToGetOutputDevice();
151 OSL_ENSURE(nullptr != pOutDev
, "ObjectContactOfPageView without OutDev, someone has overridden TryToGetOutputDevice wrong (!)");
152 bool bClipRegionPushed(false);
153 const vcl::Region
& rRedrawArea(rDisplayInfo
.GetRedrawArea());
155 // tdf#153102 using the given RedrawArea is needed e.g. for Writer's
156 // visual clipping against PageBounds (also for android viewer)
157 if(!rRedrawArea
.IsEmpty())
159 bClipRegionPushed
= true;
160 pOutDev
->Push(vcl::PushFlags::CLIPREGION
);
161 pOutDev
->IntersectClipRegion(rRedrawArea
);
164 // Get start node and process DrawPage contents
165 const ViewObjectContact
& rDrawPageVOContact
= GetSdrPage()->GetViewContact().GetViewObjectContact(*this);
167 // update current ViewInformation2D at the ObjectContact
168 const double fCurrentTime(getPrimitiveAnimator().GetTime());
169 basegfx::B2DRange aViewRange
;
172 if(isOutputToRecordingMetaFile())
174 if (!rDisplayInfo
.GetRedrawArea().IsEmpty())
176 // #i98402# if it's a PDF export, set the ClipRegion as ViewRange. This is
177 // mainly because SW does not use DrawingLayer Page-Oriented and if not doing this,
178 // all existing objects will be collected as primitives and processed.
179 // OD 2009-03-05 #i99876# perform the same also for SW on printing.
180 // fdo#78149 same thing also needed for plain MetaFile
181 // export, so why not do it always
182 const tools::Rectangle
aLogicClipRectangle(rDisplayInfo
.GetRedrawArea().GetBoundRect());
184 aViewRange
= vcl::unotools::b2DRectangleFromRectangle(aLogicClipRectangle
);
189 // use visible pixels, but transform to world coordinates
190 aViewRange
= basegfx::B2DRange(0.0, 0.0, aOutputSizePixel
.getWidth(), aOutputSizePixel
.getHeight());
191 // if a clip region is set, use it
192 if(!rDisplayInfo
.GetRedrawArea().IsEmpty())
194 // get logic clip range and create discrete one
195 const tools::Rectangle
aLogicClipRectangle(rDisplayInfo
.GetRedrawArea().GetBoundRect());
196 basegfx::B2DRange aDiscreteClipRange
= vcl::unotools::b2DRectangleFromRectangle(aLogicClipRectangle
);
197 aDiscreteClipRange
.transform(rTargetOutDev
.GetViewTransformation());
199 // align the discrete one to discrete boundaries (pixel bounds). Also
200 // expand X and Y max by one due to Rectangle definition source
201 aDiscreteClipRange
.expand(basegfx::B2DTuple(
202 floor(aDiscreteClipRange
.getMinX()),
203 floor(aDiscreteClipRange
.getMinY())));
204 aDiscreteClipRange
.expand(basegfx::B2DTuple(
205 1.0 + ceil(aDiscreteClipRange
.getMaxX()),
206 1.0 + ceil(aDiscreteClipRange
.getMaxY())));
208 // intersect current ViewRange with ClipRange
209 aViewRange
.intersect(aDiscreteClipRange
);
212 // transform to world coordinates
213 aViewRange
.transform(rTargetOutDev
.GetInverseViewTransformation());
216 // update local ViewInformation2D
217 drawinglayer::geometry::ViewInformation2D aNewViewInformation2D
;
218 aNewViewInformation2D
.setViewTransformation(rTargetOutDev
.GetViewTransformation());
219 aNewViewInformation2D
.setViewport(aViewRange
);
220 aNewViewInformation2D
.setVisualizedPage(GetXDrawPageForSdrPage(GetSdrPage()));
221 aNewViewInformation2D
.setViewTime(fCurrentTime
);
222 if (const SfxViewShell
* pViewShell
= SfxViewShell::Current())
223 aNewViewInformation2D
.setAutoColor(pViewShell
->GetColorConfigColor(svtools::DOCCOLOR
));
224 if (static_cast<SdrPaintView
&>(mrPageWindow
.GetPageView().GetView()).IsTextEdit())
225 aNewViewInformation2D
.setTextEditActive(true);
227 // this is the EditView repaint, provide that information,
228 // but only if we do not export to metafile
229 if (!isOutputToRecordingMetaFile())
230 aNewViewInformation2D
.setEditViewActive(true);
232 updateViewInformation2D(aNewViewInformation2D
);
234 drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence
;
236 #if HAVE_FEATURE_DESKTOP || defined( ANDROID )
237 // get whole Primitive2DContainer; this will already make use of updated ViewInformation2D
238 // and may use the MapMode from the Target OutDev in the DisplayInfo
239 rDrawPageVOContact
.getPrimitive2DSequenceHierarchy(rDisplayInfo
, xPrimitiveSequence
);
241 // Hmm, !HAVE_FEATURE_DESKTOP && !ANDROID means iOS,
242 // right? But does it makes sense to use a different code
243 // path for iOS than for Android; both use tiled rendering
246 // HACK: this only works when we are drawing sdr shapes via
247 // drawinglayer; but it can happen that the hierarchy contains
248 // more than just the shapes, and then it fails.
250 // This is good enough for the tiled rendering for the moment, but
251 // we need to come up with the real solution shortly.
253 // Only get the expensive hierarchy if we can be sure that the
254 // returned sequence won't be empty anyway.
255 bool bGetHierarchy
= rRedrawArea
.IsEmpty();
258 // Not empty? Then not doing a full redraw, check if
259 // getPrimitive2DSequenceHierarchy() is still needed.
260 for (const rtl::Reference
<SdrObject
>& pObject
: *GetSdrPage())
262 if (rRedrawArea
.Overlaps(pObject
->GetCurrentBoundRect()))
264 bGetHierarchy
= true;
271 // get whole Primitive2DContainer; this will already make use of updated ViewInformation2D
272 // and may use the MapMode from the Target OutDev in the DisplayInfo
273 rDrawPageVOContact
.getPrimitive2DSequenceHierarchy(rDisplayInfo
, xPrimitiveSequence
);
276 // if there is something to show, use a primitive processor to render it. There
277 // is a choice between VCL and Canvas processors currently. The decision is made in
278 // createProcessor2DFromOutputDevice and takes into account things like the
279 // Target is a MetaFile, a VDev or something else. The Canvas renderer is triggered
280 // currently using the shown boolean. Canvas is not yet the default.
281 if(!xPrimitiveSequence
.empty())
283 // prepare OutputDevice (historical stuff, maybe soon removed)
284 rDisplayInfo
.ClearGhostedDrawMode(); // reset, else the VCL-paint with the processor will not do the right thing
285 pOutDev
->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::Default
); // reset, default is no BiDi/RTL
287 std::unique_ptr
<drawinglayer::processor2d::BaseProcessor2D
> pProcessor2D(
288 drawinglayer::processor2d::createProcessor2DFromOutputDevice(
289 rTargetOutDev
, getViewInformation2D()));
290 pProcessor2D
->process(xPrimitiveSequence
);
293 // #114359# restore old ClipReghion
294 if(bClipRegionPushed
)
299 // Visualize entered groups: Reset to original DrawMode
300 if(bVisualizeEnteredGroup
)
302 rDisplayInfo
.ClearGhostedDrawMode();
306 // test if visualizing of entered groups is switched on at all
307 bool ObjectContactOfPageView::DoVisualizeEnteredGroup() const
312 // get active group's (the entered group) ViewContact
313 const ViewContact
* ObjectContactOfPageView::getActiveViewContact() const
315 SdrObjList
* pActiveGroupList
= GetPageWindow().GetPageView().GetObjList();
320 // Here it is necessary to check for SdrObject 1st, that may
321 // return nullptr if it is not a SdrObject/SdrObjGroup.
322 // Checking for SrPage OTOH will *always* try to return
323 // something useful due to SdrObjGroup::getSdrPageFromSdrObjList
324 // using getSdrPageFromSdrObject which will recursively go up the
325 // hierarchy to get the SdrPage the SdrObject belongs to, so
326 // this will *not* be nullptr for e.g. a SdrObjGroup if the
327 // SdrObjGroup is inserted to a SdrPage.
328 // NOTE: It is also possible to use dynamic_cast<SdrObjGroup*>
329 // here, but getSdrObjectFromSdrObjList and
330 // getSdrPageFromSdrObjListexist to not need to do that
331 SdrObject
* pSdrObject(pActiveGroupList
->getSdrObjectFromSdrObjList());
333 if(nullptr != pSdrObject
)
335 // It is a group object
336 return &(pSdrObject
->GetViewContact());
340 SdrPage
* pSdrPage(pActiveGroupList
->getSdrPageFromSdrObjList());
342 if(nullptr != pSdrPage
)
344 // It's a Page itself
345 return &(pSdrPage
->GetViewContact());
349 else if(GetSdrPage())
351 // use page of associated SdrPageView
352 return &(GetSdrPage()->GetViewContact());
358 // Invalidate given rectangle at the window/output which is represented by
359 // this ObjectContact.
360 void ObjectContactOfPageView::InvalidatePartOfView(const basegfx::B2DRange
& rRange
) const
362 // invalidate at associated PageWindow
363 GetPageWindow().InvalidatePageWindow(rRange
);
366 // Get info about the need to visualize GluePoints
367 bool ObjectContactOfPageView::AreGluePointsVisible() const
369 bool bTiledRendering
= comphelper::LibreOfficeKit::isActive();
370 return !bTiledRendering
&& GetPageWindow().GetPageView().GetView().ImpIsGlueVisible();
373 // check if text animation is allowed.
374 bool ObjectContactOfPageView::IsTextAnimationAllowed() const
376 if (comphelper::IsFuzzing())
378 // tdf#161765: Let the user choose which animation settings to use: OS's / LO's
379 // New options: "System"/"No"/"Yes".
380 // Do respect OS's animation setting if the user has selected the option "System"
381 return MiscSettings::IsAnimatedTextAllowed();
384 // check if graphic animation is allowed.
385 bool ObjectContactOfPageView::IsGraphicAnimationAllowed() const
387 if (comphelper::IsFuzzing())
389 // tdf#161765: Let the user choose which animation settings to use: OS's / LO's and
390 // don't override here LO's animation settings with OS's all-or-nothing animation setting,
391 // but do respect OS's animation setting if the user has selected the option "System".
392 // New options: "System"/"No"/"Yes"
393 return MiscSettings::IsAnimatedGraphicAllowed();
397 bool ObjectContactOfPageView::isOutputToPrinter() const
399 return (OUTDEV_PRINTER
== mrPageWindow
.GetPaintWindow().GetOutputDevice().GetOutDevType());
402 // display page decoration? Default is true
403 bool ObjectContactOfPageView::isPageDecorationActive() const
405 return GetPageWindow().GetPageView().GetView().IsPageDecorationAllowed();
408 // display mster page content (ViewContactOfMasterPage)? Default is true
409 bool ObjectContactOfPageView::isMasterPageActive() const
411 return GetPageWindow().GetPageView().GetView().IsMasterPageVisualizationAllowed();
414 // recording MetaFile?
415 bool ObjectContactOfPageView::isOutputToRecordingMetaFile() const
417 GDIMetaFile
* pMetaFile
= mrPageWindow
.GetPaintWindow().GetOutputDevice().GetConnectMetaFile();
418 return (pMetaFile
&& pMetaFile
->IsRecord() && !pMetaFile
->IsPause());
422 bool ObjectContactOfPageView::isOutputToPDFFile() const
424 return OUTDEV_PDF
== mrPageWindow
.GetPaintWindow().GetOutputDevice().GetOutDevType();
427 bool ObjectContactOfPageView::isExportTaggedPDF() const
429 if (isOutputToPDFFile())
431 vcl::PDFExtOutDevData
* pPDFExtOutDevData(dynamic_cast<vcl::PDFExtOutDevData
*>(
432 mrPageWindow
.GetPaintWindow().GetOutputDevice().GetExtOutDevData()));
434 if (nullptr != pPDFExtOutDevData
)
436 return pPDFExtOutDevData
->GetIsExportTaggedPDF();
442 ::vcl::PDFExtOutDevData
const* ObjectContactOfPageView::GetPDFExtOutDevData() const
444 if (!isOutputToPDFFile())
448 vcl::PDFExtOutDevData
* pPDFExtOutDevData(dynamic_cast<vcl::PDFExtOutDevData
*>(
449 mrPageWindow
.GetPaintWindow().GetOutputDevice().GetExtOutDevData()));
450 return pPDFExtOutDevData
;
454 bool ObjectContactOfPageView::isDrawModeGray() const
456 const DrawModeFlags
nDrawMode(mrPageWindow
.GetPaintWindow().GetOutputDevice().GetDrawMode());
457 return (nDrawMode
== (DrawModeFlags::GrayLine
|DrawModeFlags::GrayFill
|DrawModeFlags::BlackText
|DrawModeFlags::GrayBitmap
|DrawModeFlags::GrayGradient
));
460 // high contrast display mode
461 bool ObjectContactOfPageView::isDrawModeHighContrast() const
463 const DrawModeFlags
nDrawMode(mrPageWindow
.GetPaintWindow().GetOutputDevice().GetDrawMode());
464 return (nDrawMode
== (DrawModeFlags::SettingsLine
|DrawModeFlags::SettingsFill
|DrawModeFlags::SettingsText
|DrawModeFlags::SettingsGradient
));
467 // access to SdrPageView
468 SdrPageView
* ObjectContactOfPageView::TryToGetSdrPageView() const
470 return &(mrPageWindow
.GetPageView());
474 // access to OutputDevice
475 OutputDevice
* ObjectContactOfPageView::TryToGetOutputDevice() const
477 SdrPreRenderDevice
* pPreRenderDevice
= mrPageWindow
.GetPaintWindow().GetPreRenderDevice();
481 return &(pPreRenderDevice
->GetPreRenderDevice());
485 return &(mrPageWindow
.GetPaintWindow().GetOutputDevice());
489 // set all UNO controls displayed in the view to design/alive mode
490 void ObjectContactOfPageView::SetUNOControlsDesignMode( bool _bDesignMode
) const
492 const sal_uInt32
nCount(getViewObjectContactCount());
494 for(sal_uInt32
a(0); a
< nCount
; a
++)
496 const ViewObjectContact
* pVOC
= getViewObjectContact(a
);
497 const ViewObjectContactOfUnoControl
* pUnoObjectVOC
= dynamic_cast< const ViewObjectContactOfUnoControl
* >(pVOC
);
501 pUnoObjectVOC
->setControlDesignMode(_bDesignMode
);
506 } // end of namespace
508 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */