Bump version to 24.04.3.4
[LibreOffice.git] / svx / source / svdraw / sdrpaintwindow.cxx
blobebed55326a57a873cfa43c56048ba47a9c862325
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 <comphelper/lok.hxx>
21 #include <osl/diagnose.h>
22 #include <svx/sdrpaintwindow.hxx>
23 #include <sdr/overlay/overlaymanagerbuffered.hxx>
24 #include <svx/svdpntv.hxx>
25 #include <vcl/gdimtf.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/settings.hxx>
28 #include <vcl/window.hxx>
29 #include <svtools/optionsdrawinglayer.hxx>
30 #include <set>
31 #include <vector>
33 namespace {
35 //rhbz#1007697 do this in two loops, one to collect the candidates
36 //and another to update them because updating a candidate can
37 //trigger the candidate to be deleted, so asking for its
38 //sibling after that is going to fail hard
39 class CandidateMgr
41 std::vector<VclPtr<vcl::Window> > m_aCandidates;
42 std::set<VclPtr<vcl::Window> > m_aDeletedCandidates;
43 DECL_LINK(WindowEventListener, VclWindowEvent&, void);
44 public:
45 void PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect);
46 ~CandidateMgr();
51 IMPL_LINK(CandidateMgr, WindowEventListener, VclWindowEvent&, rEvent, void)
53 vcl::Window* pWindow = rEvent.GetWindow();
54 if (rEvent.GetId() == VclEventId::ObjectDying)
56 m_aDeletedCandidates.insert(pWindow);
60 CandidateMgr::~CandidateMgr()
62 for (VclPtr<vcl::Window>& pCandidate : m_aCandidates)
64 if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
65 continue;
66 pCandidate->RemoveEventListener(LINK(this, CandidateMgr, WindowEventListener));
70 void PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect)
72 if (!rWindow.IsChildTransparentModeEnabled())
73 return;
75 CandidateMgr aManager;
76 aManager.PaintTransparentChildren(rWindow, rPixelRect);
79 void CandidateMgr::PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect)
81 vcl::Window * pCandidate = rWindow.GetWindow( GetWindowType::FirstChild );
82 while (pCandidate)
84 if (pCandidate->IsPaintTransparent())
86 const tools::Rectangle aCandidatePosSizePixel(
87 pCandidate->GetPosPixel(),
88 pCandidate->GetSizePixel());
90 if (aCandidatePosSizePixel.Overlaps(rPixelRect))
92 m_aCandidates.emplace_back(pCandidate);
93 pCandidate->AddEventListener(LINK(this, CandidateMgr, WindowEventListener));
96 pCandidate = pCandidate->GetWindow( GetWindowType::Next );
99 for (const auto& rpCandidate : m_aCandidates)
101 pCandidate = rpCandidate.get();
102 if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
103 continue;
104 //rhbz#1007697 this can cause the window itself to be
105 //deleted. So we are listening to see if that happens
106 //and if so, then skip the update
107 pCandidate->Invalidate(InvalidateFlags::NoTransparent|InvalidateFlags::Children);
108 // important: actually paint the child here!
109 if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
110 continue;
111 pCandidate->PaintImmediately();
115 SdrPreRenderDevice::SdrPreRenderDevice(OutputDevice& rOriginal)
116 : mpOutputDevice(&rOriginal),
117 mpPreRenderDevice(VclPtr<VirtualDevice>::Create())
121 SdrPreRenderDevice::~SdrPreRenderDevice()
123 mpPreRenderDevice.disposeAndClear();
126 void SdrPreRenderDevice::PreparePreRenderDevice()
128 // compare size of mpPreRenderDevice with size of visible area
129 if(mpPreRenderDevice->GetOutputSizePixel() != mpOutputDevice->GetOutputSizePixel())
131 mpPreRenderDevice->SetOutputSizePixel(mpOutputDevice->GetOutputSizePixel());
134 // Also compare the MapModes for zoom/scroll changes
135 if(mpPreRenderDevice->GetMapMode() != mpOutputDevice->GetMapMode())
137 mpPreRenderDevice->SetMapMode(mpOutputDevice->GetMapMode());
140 // #i29186#
141 mpPreRenderDevice->SetDrawMode(mpOutputDevice->GetDrawMode());
142 mpPreRenderDevice->SetSettings(mpOutputDevice->GetSettings());
145 void SdrPreRenderDevice::OutputPreRenderDevice(const vcl::Region& rExpandedRegion)
147 // region to pixels
148 const vcl::Region aRegionPixel(mpOutputDevice->LogicToPixel(rExpandedRegion));
149 //RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects());
150 //Rectangle aRegionRectanglePixel;
152 // MapModes off
153 bool bMapModeWasEnabledDest(mpOutputDevice->IsMapModeEnabled());
154 bool bMapModeWasEnabledSource(mpPreRenderDevice->IsMapModeEnabled());
155 mpOutputDevice->EnableMapMode(false);
156 mpPreRenderDevice->EnableMapMode(false);
158 RectangleVector aRectangles;
159 aRegionPixel.GetRegionRectangles(aRectangles);
161 for(const auto& rRect : aRectangles)
163 // for each rectangle, copy the area
164 const Point aTopLeft(rRect.TopLeft());
165 const Size aSize(rRect.GetSize());
167 mpOutputDevice->DrawOutDev(
168 aTopLeft, aSize,
169 aTopLeft, aSize,
170 *mpPreRenderDevice);
173 mpOutputDevice->EnableMapMode(bMapModeWasEnabledDest);
174 mpPreRenderDevice->EnableMapMode(bMapModeWasEnabledSource);
177 void SdrPaintView::InitOverlayManager(rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager)
179 Color aColA(SvtOptionsDrawinglayer::GetStripeColorA());
180 Color aColB(SvtOptionsDrawinglayer::GetStripeColorB());
182 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode())
184 aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor();
185 aColB.Invert();
188 xOverlayManager->setStripeColorA(aColA);
189 xOverlayManager->setStripeColorB(aColB);
190 xOverlayManager->setStripeLengthPixel(SvtOptionsDrawinglayer::GetStripeLength());
193 rtl::Reference<sdr::overlay::OverlayManager> SdrPaintView::CreateOverlayManager(OutputDevice& rOutputDevice) const
195 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager;
196 // is it a window?
197 if (OUTDEV_WINDOW == rOutputDevice.GetOutDevType())
199 vcl::Window* pWindow = rOutputDevice.GetOwnerWindow();
200 // decide which OverlayManager to use
201 if (IsBufferedOverlayAllowed() && !pWindow->SupportsDoubleBuffering())
203 // buffered OverlayManager, buffers its background and refreshes from there
204 // for pure overlay changes (no system redraw). The 3rd parameter specifies
205 // whether that refresh itself will use a 2nd vdev to avoid flickering.
206 // Also hand over the old OverlayManager if existent; this means to take over
207 // the registered OverlayObjects from it
208 xOverlayManager = sdr::overlay::OverlayManagerBuffered::create(rOutputDevice);
210 else
212 // unbuffered OverlayManager, just invalidates places where changes
213 // take place
214 // Also hand over the old OverlayManager if existent; this means to take over
215 // the registered OverlayObjects from it
216 xOverlayManager = sdr::overlay::OverlayManager::create(rOutputDevice);
219 OSL_ENSURE(xOverlayManager.is(), "SdrPaintWindow::SdrPaintWindow: Could not allocate an overlayManager (!)");
221 // Request a repaint so that the buffered overlay manager fills
222 // its buffer properly. This is a workaround for missing buffer
223 // updates.
224 if (!comphelper::LibreOfficeKit::isActive())
226 pWindow->Invalidate();
229 InitOverlayManager(xOverlayManager);
231 return xOverlayManager;
234 void SdrPaintWindow::impCreateOverlayManager()
236 // not yet one created?
237 if(!mxOverlayManager.is())
238 mxOverlayManager = mrPaintView.CreateOverlayManager(GetOutputDevice());
241 SdrPaintWindow::SdrPaintWindow(SdrPaintView& rNewPaintView, OutputDevice& rOut, vcl::Window* pWindow)
242 : mpOutputDevice(&rOut),
243 mpWindow(pWindow),
244 mrPaintView(rNewPaintView),
245 mbTemporaryTarget(false), // #i72889#
246 mbOutputToWindow(OUTDEV_WINDOW == mpOutputDevice->GetOutDevType()),
247 mpPatched(nullptr)
251 SdrPaintWindow::~SdrPaintWindow()
253 mxOverlayManager.clear();
255 mpPreRenderDevice.reset();
258 rtl::Reference< sdr::overlay::OverlayManager > const & SdrPaintWindow::GetOverlayManager() const
260 if(!mxOverlayManager.is())
262 // Create buffered overlay manager by default.
263 const_cast< SdrPaintWindow* >(this)->impCreateOverlayManager();
266 return mxOverlayManager;
269 tools::Rectangle SdrPaintWindow::GetVisibleArea() const
271 Size aVisSizePixel(GetOutputDevice().GetOutputSizePixel());
272 return GetOutputDevice().PixelToLogic(tools::Rectangle(Point(0,0), aVisSizePixel));
275 bool SdrPaintWindow::OutputToRecordingMetaFile() const
277 GDIMetaFile* pMetaFile = mpOutputDevice->GetConnectMetaFile();
278 return (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
281 void SdrPaintWindow::PreparePreRenderDevice()
283 const bool bPrepareBufferedOutput(
284 mrPaintView.IsBufferedOutputAllowed()
285 && !OutputToPrinter()
286 && !mpOutputDevice->IsVirtual()
287 && !OutputToRecordingMetaFile());
289 if(bPrepareBufferedOutput)
291 if(!mpPreRenderDevice)
293 mpPreRenderDevice.reset(new SdrPreRenderDevice(*mpOutputDevice));
295 mpPreRenderDevice->PreparePreRenderDevice();
297 else
299 mpPreRenderDevice.reset();
303 void SdrPaintWindow::OutputPreRenderDevice(const vcl::Region& rExpandedRegion)
305 if(mpPreRenderDevice)
307 mpPreRenderDevice->OutputPreRenderDevice(rExpandedRegion);
311 // #i73602# add flag if buffer shall be used
312 void SdrPaintWindow::DrawOverlay(const vcl::Region& rRegion)
314 // ## force creation of OverlayManager since the first repaint needs to
315 // save the background to get a controlled start into overlay mechanism
316 impCreateOverlayManager();
318 if(mxOverlayManager.is() && !OutputToPrinter())
320 if(mpPreRenderDevice)
322 mxOverlayManager->completeRedraw(rRegion, &mpPreRenderDevice->GetPreRenderDevice());
324 else
326 mxOverlayManager->completeRedraw(rRegion);
332 void SdrPaintWindow::SetRedrawRegion(const vcl::Region& rNew)
334 maRedrawRegion = rNew;
337 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */