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 <svx/unoapi.hxx>
40 #include <unotools/configmgr.hxx>
41 #include <vcl/canvastools.hxx>
42 #include <vcl/pdfextoutdevdata.hxx>
43 #include <comphelper/lok.hxx>
47 using namespace com::sun::star
;
49 namespace sdr::contact
51 // internal access to SdrPage of SdrPageView
52 SdrPage
* ObjectContactOfPageView::GetSdrPage() const
54 return GetPageWindow().GetPageView().GetPage();
57 ObjectContactOfPageView::ObjectContactOfPageView(
58 SdrPageWindow
& rPageWindow
, const char *pDebugName
)
60 , mrPageWindow(rPageWindow
)
62 // init PreviewRenderer flag
63 setPreviewRenderer(static_cast<SdrPaintView
&>(rPageWindow
.GetPageView().GetView()).IsPreviewRenderer());
66 SetPriority(TaskPriority::HIGH_IDLE
);
70 ObjectContactOfPageView::~ObjectContactOfPageView()
72 // execute missing LazyInvalidates and stop timer
76 // LazyInvalidate request. Take action.
77 void ObjectContactOfPageView::setLazyInvalidate(ViewObjectContact
& /*rVOC*/)
79 // do NOT call parent, but remember that something is to do by
80 // starting the LazyInvalidateTimer
84 // call this to support evtl. preparations for repaint
85 void ObjectContactOfPageView::PrepareProcessDisplay()
88 // there are still non-triggered LazyInvalidate events, trigger these
92 // From baseclass Timer, the timeout call triggered by the LazyInvalidate mechanism
93 void ObjectContactOfPageView::Invoke()
98 // invalidate all LazyInvalidate VOCs new situations
99 const sal_uInt32
nVOCCount(getViewObjectContactCount());
101 for(sal_uInt32
a(0); a
< nVOCCount
; a
++)
103 ViewObjectContact
* pCandidate
= getViewObjectContact(a
);
104 pCandidate
->triggerLazyInvalidate();
108 // Process the whole displaying
109 void ObjectContactOfPageView::ProcessDisplay(DisplayInfo
& rDisplayInfo
)
111 const SdrPage
* pStartPage
= GetSdrPage();
113 if(pStartPage
&& !rDisplayInfo
.GetProcessLayers().IsEmpty())
115 const ViewContact
& rDrawPageVC
= pStartPage
->GetViewContact();
117 if(rDrawPageVC
.GetObjectCount())
119 DoProcessDisplay(rDisplayInfo
);
124 // Process the whole displaying. Only use given DisplayInfo, do not access other
125 // OutputDevices then the given ones.
126 void ObjectContactOfPageView::DoProcessDisplay(DisplayInfo
& rDisplayInfo
)
128 OutputDevice
& rTargetOutDev
= GetPageWindow().GetPaintWindow().GetTargetOutputDevice();
129 const Size
aOutputSizePixel(rTargetOutDev
.GetOutputSizePixel());
130 if (!isOutputToRecordingMetaFile() // do those have outdev too?
131 && (0 == aOutputSizePixel
.getWidth() ||
132 0 == aOutputSizePixel
.getHeight()))
137 // visualize entered group when that feature is switched on and it's not
138 // a print output. #i29129# No ghosted display for printing.
139 bool bVisualizeEnteredGroup(DoVisualizeEnteredGroup() && !isOutputToPrinter());
141 // Visualize entered groups: Set to ghosted as default
142 // start. Do this only for the DrawPage, not for MasterPages
143 if(bVisualizeEnteredGroup
)
145 rDisplayInfo
.SetGhostedDrawMode();
148 // #114359# save old and set clip region
149 OutputDevice
* pOutDev
= TryToGetOutputDevice();
150 OSL_ENSURE(nullptr != pOutDev
, "ObjectContactOfPageView without OutDev, someone has overridden TryToGetOutputDevice wrong (!)");
151 bool bClipRegionPushed(false);
152 const vcl::Region
& rRedrawArea(rDisplayInfo
.GetRedrawArea());
154 // tdf#153102 using the given RedrawArea is needed e.g. for Writer's
155 // visual clipping against PageBounds (also for android viewer)
156 if(!rRedrawArea
.IsEmpty())
158 bClipRegionPushed
= true;
159 pOutDev
->Push(vcl::PushFlags::CLIPREGION
);
160 pOutDev
->IntersectClipRegion(rRedrawArea
);
163 // Get start node and process DrawPage contents
164 const ViewObjectContact
& rDrawPageVOContact
= GetSdrPage()->GetViewContact().GetViewObjectContact(*this);
166 // update current ViewInformation2D at the ObjectContact
167 const double fCurrentTime(getPrimitiveAnimator().GetTime());
168 basegfx::B2DRange aViewRange
;
171 if(isOutputToRecordingMetaFile())
173 if (!rDisplayInfo
.GetRedrawArea().IsEmpty())
175 // #i98402# if it's a PDF export, set the ClipRegion as ViewRange. This is
176 // mainly because SW does not use DrawingLayer Page-Oriented and if not doing this,
177 // all existing objects will be collected as primitives and processed.
178 // OD 2009-03-05 #i99876# perform the same also for SW on printing.
179 // fdo#78149 same thing also needed for plain MetaFile
180 // export, so why not do it always
181 const tools::Rectangle
aLogicClipRectangle(rDisplayInfo
.GetRedrawArea().GetBoundRect());
183 aViewRange
= vcl::unotools::b2DRectangleFromRectangle(aLogicClipRectangle
);
188 // use visible pixels, but transform to world coordinates
189 aViewRange
= basegfx::B2DRange(0.0, 0.0, aOutputSizePixel
.getWidth(), aOutputSizePixel
.getHeight());
190 // if a clip region is set, use it
191 if(!rDisplayInfo
.GetRedrawArea().IsEmpty())
193 // get logic clip range and create discrete one
194 const tools::Rectangle
aLogicClipRectangle(rDisplayInfo
.GetRedrawArea().GetBoundRect());
195 basegfx::B2DRange aDiscreteClipRange
= vcl::unotools::b2DRectangleFromRectangle(aLogicClipRectangle
);
196 aDiscreteClipRange
.transform(rTargetOutDev
.GetViewTransformation());
198 // align the discrete one to discrete boundaries (pixel bounds). Also
199 // expand X and Y max by one due to Rectangle definition source
200 aDiscreteClipRange
.expand(basegfx::B2DTuple(
201 floor(aDiscreteClipRange
.getMinX()),
202 floor(aDiscreteClipRange
.getMinY())));
203 aDiscreteClipRange
.expand(basegfx::B2DTuple(
204 1.0 + ceil(aDiscreteClipRange
.getMaxX()),
205 1.0 + ceil(aDiscreteClipRange
.getMaxY())));
207 // intersect current ViewRange with ClipRange
208 aViewRange
.intersect(aDiscreteClipRange
);
211 // transform to world coordinates
212 aViewRange
.transform(rTargetOutDev
.GetInverseViewTransformation());
215 // update local ViewInformation2D
216 drawinglayer::geometry::ViewInformation2D aNewViewInformation2D
;
217 aNewViewInformation2D
.setViewTransformation(rTargetOutDev
.GetViewTransformation());
218 aNewViewInformation2D
.setViewport(aViewRange
);
219 aNewViewInformation2D
.setVisualizedPage(GetXDrawPageForSdrPage(GetSdrPage()));
220 aNewViewInformation2D
.setViewTime(fCurrentTime
);
221 if (SfxViewShell::Current())
222 aNewViewInformation2D
.setAutoColor(SfxViewShell::Current()->GetColorConfigColor(svtools::DOCCOLOR
));
223 updateViewInformation2D(aNewViewInformation2D
);
225 drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence
;
227 #if HAVE_FEATURE_DESKTOP || defined( ANDROID )
228 // get whole Primitive2DContainer; this will already make use of updated ViewInformation2D
229 // and may use the MapMode from the Target OutDev in the DisplayInfo
230 rDrawPageVOContact
.getPrimitive2DSequenceHierarchy(rDisplayInfo
, xPrimitiveSequence
);
232 // Hmm, !HAVE_FEATURE_DESKTOP && !ANDROID means iOS,
233 // right? But does it makes sense to use a different code
234 // path for iOS than for Android; both use tiled rendering
237 // HACK: this only works when we are drawing sdr shapes via
238 // drawinglayer; but it can happen that the hierarchy contains
239 // more than just the shapes, and then it fails.
241 // This is good enough for the tiled rendering for the moment, but
242 // we need to come up with the real solution shortly.
244 // Only get the expensive hierarchy if we can be sure that the
245 // returned sequence won't be empty anyway.
246 bool bGetHierarchy
= rRedrawArea
.IsEmpty();
249 // Not empty? Then not doing a full redraw, check if
250 // getPrimitive2DSequenceHierarchy() is still needed.
251 for (const rtl::Reference
<SdrObject
>& pObject
: *GetSdrPage())
253 if (rRedrawArea
.Overlaps(pObject
->GetCurrentBoundRect()))
255 bGetHierarchy
= true;
262 // get whole Primitive2DContainer; this will already make use of updated ViewInformation2D
263 // and may use the MapMode from the Target OutDev in the DisplayInfo
264 rDrawPageVOContact
.getPrimitive2DSequenceHierarchy(rDisplayInfo
, xPrimitiveSequence
);
267 // if there is something to show, use a primitive processor to render it. There
268 // is a choice between VCL and Canvas processors currently. The decision is made in
269 // createProcessor2DFromOutputDevice and takes into account things like the
270 // Target is a MetaFile, a VDev or something else. The Canvas renderer is triggered
271 // currently using the shown boolean. Canvas is not yet the default.
272 if(!xPrimitiveSequence
.empty())
274 // prepare OutputDevice (historical stuff, maybe soon removed)
275 rDisplayInfo
.ClearGhostedDrawMode(); // reset, else the VCL-paint with the processor will not do the right thing
276 pOutDev
->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::Default
); // reset, default is no BiDi/RTL
278 std::unique_ptr
<drawinglayer::processor2d::BaseProcessor2D
> pProcessor2D(
279 drawinglayer::processor2d::createProcessor2DFromOutputDevice(
280 rTargetOutDev
, getViewInformation2D()));
281 pProcessor2D
->process(xPrimitiveSequence
);
284 // #114359# restore old ClipReghion
285 if(bClipRegionPushed
)
290 // Visualize entered groups: Reset to original DrawMode
291 if(bVisualizeEnteredGroup
)
293 rDisplayInfo
.ClearGhostedDrawMode();
297 // test if visualizing of entered groups is switched on at all
298 bool ObjectContactOfPageView::DoVisualizeEnteredGroup() const
303 // get active group's (the entered group) ViewContact
304 const ViewContact
* ObjectContactOfPageView::getActiveViewContact() const
306 SdrObjList
* pActiveGroupList
= GetPageWindow().GetPageView().GetObjList();
311 // Here it is necessary to check for SdrObject 1st, that may
312 // return nullptr if it is not a SdrObject/SdrObjGroup.
313 // Checking for SrPage OTOH will *always* try to return
314 // something useful due to SdrObjGroup::getSdrPageFromSdrObjList
315 // using getSdrPageFromSdrObject which will recursively go up the
316 // hierarchy to get the SdrPage the SdrObject belongs to, so
317 // this will *not* be nullptr for e.g. a SdrObjGroup if the
318 // SdrObjGroup is inserted to a SdrPage.
319 // NOTE: It is also possible to use dynamic_cast<SdrObjGroup*>
320 // here, but getSdrObjectFromSdrObjList and
321 // getSdrPageFromSdrObjListexist to not need to do that
322 SdrObject
* pSdrObject(pActiveGroupList
->getSdrObjectFromSdrObjList());
324 if(nullptr != pSdrObject
)
326 // It is a group object
327 return &(pSdrObject
->GetViewContact());
331 SdrPage
* pSdrPage(pActiveGroupList
->getSdrPageFromSdrObjList());
333 if(nullptr != pSdrPage
)
335 // It's a Page itself
336 return &(pSdrPage
->GetViewContact());
340 else if(GetSdrPage())
342 // use page of associated SdrPageView
343 return &(GetSdrPage()->GetViewContact());
349 // Invalidate given rectangle at the window/output which is represented by
350 // this ObjectContact.
351 void ObjectContactOfPageView::InvalidatePartOfView(const basegfx::B2DRange
& rRange
) const
353 // invalidate at associated PageWindow
354 GetPageWindow().InvalidatePageWindow(rRange
);
357 // Get info about the need to visualize GluePoints
358 bool ObjectContactOfPageView::AreGluePointsVisible() const
360 bool bTiledRendering
= comphelper::LibreOfficeKit::isActive();
361 return !bTiledRendering
&& GetPageWindow().GetPageView().GetView().ImpIsGlueVisible();
364 // check if text animation is allowed.
365 bool ObjectContactOfPageView::IsTextAnimationAllowed() const
367 if (utl::ConfigManager::IsFuzzing())
369 return SvtAccessibilityOptions::GetIsAllowAnimatedText();
372 // check if graphic animation is allowed.
373 bool ObjectContactOfPageView::IsGraphicAnimationAllowed() const
375 if (utl::ConfigManager::IsFuzzing())
378 // Related tdf#156630 respect system animation setting
379 return SvtAccessibilityOptions::GetIsAllowAnimatedGraphics() && !MiscSettings::GetUseReducedAnimation();
383 bool ObjectContactOfPageView::isOutputToPrinter() const
385 return (OUTDEV_PRINTER
== mrPageWindow
.GetPaintWindow().GetOutputDevice().GetOutDevType());
388 // display page decoration? Default is true
389 bool ObjectContactOfPageView::isPageDecorationActive() const
391 return GetPageWindow().GetPageView().GetView().IsPageDecorationAllowed();
394 // display mster page content (ViewContactOfMasterPage)? Default is true
395 bool ObjectContactOfPageView::isMasterPageActive() const
397 return GetPageWindow().GetPageView().GetView().IsMasterPageVisualizationAllowed();
400 // recording MetaFile?
401 bool ObjectContactOfPageView::isOutputToRecordingMetaFile() const
403 GDIMetaFile
* pMetaFile
= mrPageWindow
.GetPaintWindow().GetOutputDevice().GetConnectMetaFile();
404 return (pMetaFile
&& pMetaFile
->IsRecord() && !pMetaFile
->IsPause());
408 bool ObjectContactOfPageView::isOutputToPDFFile() const
410 return OUTDEV_PDF
== mrPageWindow
.GetPaintWindow().GetOutputDevice().GetOutDevType();
413 bool ObjectContactOfPageView::isExportTaggedPDF() const
415 if (isOutputToPDFFile())
417 vcl::PDFExtOutDevData
* pPDFExtOutDevData(dynamic_cast<vcl::PDFExtOutDevData
*>(
418 mrPageWindow
.GetPaintWindow().GetOutputDevice().GetExtOutDevData()));
420 if (nullptr != pPDFExtOutDevData
)
422 return pPDFExtOutDevData
->GetIsExportTaggedPDF();
428 ::vcl::PDFExtOutDevData
const* ObjectContactOfPageView::GetPDFExtOutDevData() const
430 if (!isOutputToPDFFile())
434 vcl::PDFExtOutDevData
* pPDFExtOutDevData(dynamic_cast<vcl::PDFExtOutDevData
*>(
435 mrPageWindow
.GetPaintWindow().GetOutputDevice().GetExtOutDevData()));
436 return pPDFExtOutDevData
;
440 bool ObjectContactOfPageView::isDrawModeGray() const
442 const DrawModeFlags
nDrawMode(mrPageWindow
.GetPaintWindow().GetOutputDevice().GetDrawMode());
443 return (nDrawMode
== (DrawModeFlags::GrayLine
|DrawModeFlags::GrayFill
|DrawModeFlags::BlackText
|DrawModeFlags::GrayBitmap
|DrawModeFlags::GrayGradient
));
446 // high contrast display mode
447 bool ObjectContactOfPageView::isDrawModeHighContrast() const
449 const DrawModeFlags
nDrawMode(mrPageWindow
.GetPaintWindow().GetOutputDevice().GetDrawMode());
450 return (nDrawMode
== (DrawModeFlags::SettingsLine
|DrawModeFlags::SettingsFill
|DrawModeFlags::SettingsText
|DrawModeFlags::SettingsGradient
));
453 // access to SdrPageView
454 SdrPageView
* ObjectContactOfPageView::TryToGetSdrPageView() const
456 return &(mrPageWindow
.GetPageView());
460 // access to OutputDevice
461 OutputDevice
* ObjectContactOfPageView::TryToGetOutputDevice() const
463 SdrPreRenderDevice
* pPreRenderDevice
= mrPageWindow
.GetPaintWindow().GetPreRenderDevice();
467 return &(pPreRenderDevice
->GetPreRenderDevice());
471 return &(mrPageWindow
.GetPaintWindow().GetOutputDevice());
475 // set all UNO controls displayed in the view to design/alive mode
476 void ObjectContactOfPageView::SetUNOControlsDesignMode( bool _bDesignMode
) const
478 const sal_uInt32
nCount(getViewObjectContactCount());
480 for(sal_uInt32
a(0); a
< nCount
; a
++)
482 const ViewObjectContact
* pVOC
= getViewObjectContact(a
);
483 const ViewObjectContactOfUnoControl
* pUnoObjectVOC
= dynamic_cast< const ViewObjectContactOfUnoControl
* >(pVOC
);
487 pUnoObjectVOC
->setControlDesignMode(_bDesignMode
);
492 } // end of namespace
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */