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 <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>
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
41 std::vector
<VclPtr
<vcl::Window
> > m_aCandidates
;
42 std::set
<VclPtr
<vcl::Window
> > m_aDeletedCandidates
;
43 DECL_LINK(WindowEventListener
, VclWindowEvent
&, void);
45 void PaintTransparentChildren(vcl::Window
const & rWindow
, tools::Rectangle
const& rPixelRect
);
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())
66 pCandidate
->RemoveEventListener(LINK(this, CandidateMgr
, WindowEventListener
));
70 void PaintTransparentChildren(vcl::Window
const & rWindow
, tools::Rectangle
const& rPixelRect
)
72 if (!rWindow
.IsChildTransparentModeEnabled())
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
);
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())
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())
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());
141 mpPreRenderDevice
->SetDrawMode(mpOutputDevice
->GetDrawMode());
142 mpPreRenderDevice
->SetSettings(mpOutputDevice
->GetSettings());
145 void SdrPreRenderDevice::OutputPreRenderDevice(const vcl::Region
& rExpandedRegion
)
148 const vcl::Region
aRegionPixel(mpOutputDevice
->LogicToPixel(rExpandedRegion
));
149 //RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects());
150 //Rectangle aRegionRectanglePixel;
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(
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();
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
;
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
);
212 // unbuffered OverlayManager, just invalidates places where changes
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
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
),
244 mrPaintView(rNewPaintView
),
245 mbTemporaryTarget(false), // #i72889#
246 mbOutputToWindow(OUTDEV_WINDOW
== mpOutputDevice
->GetOutDevType()),
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();
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());
326 mxOverlayManager
->completeRedraw(rRegion
);
332 void SdrPaintWindow::SetRedrawRegion(const vcl::Region
& rNew
)
334 maRedrawRegion
= rNew
;
337 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */