Bump version to 24.04.3.4
[LibreOffice.git] / svx / source / sdr / contact / objectcontactofpageview.cxx
blob005f90f3c97d3777ed7105326e054a971bb45cfd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
45 #include <memory>
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)
59 : Idle(pDebugName)
60 , mrPageWindow(rPageWindow)
62 // init PreviewRenderer flag
63 setPreviewRenderer(static_cast<SdrPaintView&>(rPageWindow.GetPageView().GetView()).IsPreviewRenderer());
65 // init timer
66 SetPriority(TaskPriority::HIGH_IDLE);
67 Stop();
70 ObjectContactOfPageView::~ObjectContactOfPageView()
72 // execute missing LazyInvalidates and stop timer
73 Invoke();
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
81 Start();
84 // call this to support evtl. preparations for repaint
85 void ObjectContactOfPageView::PrepareProcessDisplay()
87 if(IsActive())
88 // there are still non-triggered LazyInvalidate events, trigger these
89 Invoke();
92 // From baseclass Timer, the timeout call triggered by the LazyInvalidate mechanism
93 void ObjectContactOfPageView::Invoke()
95 // stop the timer
96 Stop();
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()))
134 return;
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;
170 // create ViewRange
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);
186 else
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);
231 #else
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
235 // etc now.
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();
247 if (!bGetHierarchy)
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;
256 break;
261 if (bGetHierarchy)
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);
265 #endif
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
277 // create renderer
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)
287 pOutDev->Pop();
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
300 return true;
303 // get active group's (the entered group) ViewContact
304 const ViewContact* ObjectContactOfPageView::getActiveViewContact() const
306 SdrObjList* pActiveGroupList = GetPageWindow().GetPageView().GetObjList();
308 if(pActiveGroupList)
310 // tdf#122735
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());
329 else
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());
346 return nullptr;
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())
368 return true;
369 return SvtAccessibilityOptions::GetIsAllowAnimatedText();
372 // check if graphic animation is allowed.
373 bool ObjectContactOfPageView::IsGraphicAnimationAllowed() const
375 if (utl::ConfigManager::IsFuzzing())
376 return true;
378 // Related tdf#156630 respect system animation setting
379 return SvtAccessibilityOptions::GetIsAllowAnimatedGraphics() && !MiscSettings::GetUseReducedAnimation();
382 // print?
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());
407 // pdf export?
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();
425 return false;
428 ::vcl::PDFExtOutDevData const* ObjectContactOfPageView::GetPDFExtOutDevData() const
430 if (!isOutputToPDFFile())
432 return nullptr;
434 vcl::PDFExtOutDevData* pPDFExtOutDevData(dynamic_cast<vcl::PDFExtOutDevData*>(
435 mrPageWindow.GetPaintWindow().GetOutputDevice().GetExtOutDevData()));
436 return pPDFExtOutDevData;
439 // gray display mode
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();
465 if(pPreRenderDevice)
467 return &(pPreRenderDevice->GetPreRenderDevice());
469 else
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);
485 if(pUnoObjectVOC)
487 pUnoObjectVOC->setControlDesignMode(_bDesignMode);
492 } // end of namespace
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */