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 <comphelper/random.hxx>
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>
31 //rhbz#1007697 do this in two loops, one to collect the candidates
32 //and another to update them because updating a candidate can
33 //trigger the candidate to be deleted, so asking for its
34 //sibling after that is going to fail hard
37 std::vector
<VclPtr
<vcl::Window
> > m_aCandidates
;
38 std::set
<VclPtr
<vcl::Window
> > m_aDeletedCandidates
;
39 DECL_LINK(WindowEventListener
, VclWindowEvent
&, void);
41 void PaintTransparentChildren(vcl::Window
const & rWindow
, tools::Rectangle
const& rPixelRect
);
45 IMPL_LINK(CandidateMgr
, WindowEventListener
, VclWindowEvent
&, rEvent
, void)
47 vcl::Window
* pWindow
= rEvent
.GetWindow();
48 if (rEvent
.GetId() == VclEventId::ObjectDying
)
50 m_aDeletedCandidates
.insert(pWindow
);
54 CandidateMgr::~CandidateMgr()
56 for (auto aI
= m_aCandidates
.begin(); aI
!= m_aCandidates
.end(); ++aI
)
58 VclPtr
<vcl::Window
> pCandidate
= *aI
;
59 if (m_aDeletedCandidates
.find(pCandidate
) != m_aDeletedCandidates
.end())
61 pCandidate
->RemoveEventListener(LINK(this, CandidateMgr
, WindowEventListener
));
65 void PaintTransparentChildren(vcl::Window
const & rWindow
, tools::Rectangle
const& rPixelRect
)
67 if (!rWindow
.IsChildTransparentModeEnabled())
70 CandidateMgr aManager
;
71 aManager
.PaintTransparentChildren(rWindow
, rPixelRect
);
74 void CandidateMgr::PaintTransparentChildren(vcl::Window
const & rWindow
, tools::Rectangle
const& rPixelRect
)
76 vcl::Window
* pCandidate
= rWindow
.GetWindow( GetWindowType::FirstChild
);
79 if (pCandidate
->IsPaintTransparent())
81 const tools::Rectangle
aCandidatePosSizePixel(
82 pCandidate
->GetPosPixel(),
83 pCandidate
->GetSizePixel());
85 if (aCandidatePosSizePixel
.IsOver(rPixelRect
))
87 m_aCandidates
.emplace_back(pCandidate
);
88 pCandidate
->AddEventListener(LINK(this, CandidateMgr
, WindowEventListener
));
91 pCandidate
= pCandidate
->GetWindow( GetWindowType::Next
);
94 for (auto aI
= m_aCandidates
.begin(); aI
!= m_aCandidates
.end(); ++aI
)
96 pCandidate
= aI
->get();
97 if (m_aDeletedCandidates
.find(pCandidate
) != m_aDeletedCandidates
.end())
99 //rhbz#1007697 this can cause the window itself to be
100 //deleted. So we are listening to see if that happens
101 //and if so, then skip the update
102 pCandidate
->Invalidate(InvalidateFlags::NoTransparent
|InvalidateFlags::Children
);
103 // important: actually paint the child here!
104 if (m_aDeletedCandidates
.find(pCandidate
) != m_aDeletedCandidates
.end())
106 pCandidate
->Update();
110 SdrPreRenderDevice::SdrPreRenderDevice(OutputDevice
& rOriginal
)
111 : mpOutputDevice(&rOriginal
),
112 mpPreRenderDevice(VclPtr
<VirtualDevice
>::Create())
116 SdrPreRenderDevice::~SdrPreRenderDevice()
118 mpPreRenderDevice
.disposeAndClear();
121 void SdrPreRenderDevice::PreparePreRenderDevice()
123 // compare size of mpPreRenderDevice with size of visible area
124 if(mpPreRenderDevice
->GetOutputSizePixel() != mpOutputDevice
->GetOutputSizePixel())
126 mpPreRenderDevice
->SetOutputSizePixel(mpOutputDevice
->GetOutputSizePixel());
129 // Also compare the MapModes for zoom/scroll changes
130 if(mpPreRenderDevice
->GetMapMode() != mpOutputDevice
->GetMapMode())
132 mpPreRenderDevice
->SetMapMode(mpOutputDevice
->GetMapMode());
136 mpPreRenderDevice
->SetDrawMode(mpOutputDevice
->GetDrawMode());
137 mpPreRenderDevice
->SetSettings(mpOutputDevice
->GetSettings());
140 void SdrPreRenderDevice::OutputPreRenderDevice(const vcl::Region
& rExpandedRegion
)
143 const vcl::Region
aRegionPixel(mpOutputDevice
->LogicToPixel(rExpandedRegion
));
144 //RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects());
145 //Rectangle aRegionRectanglePixel;
148 bool bMapModeWasEnabledDest(mpOutputDevice
->IsMapModeEnabled());
149 bool bMapModeWasEnabledSource(mpPreRenderDevice
->IsMapModeEnabled());
150 mpOutputDevice
->EnableMapMode(false);
151 mpPreRenderDevice
->EnableMapMode(false);
153 RectangleVector aRectangles
;
154 aRegionPixel
.GetRegionRectangles(aRectangles
);
156 for(RectangleVector::const_iterator
aRectIter(aRectangles
.begin()); aRectIter
!= aRectangles
.end(); ++aRectIter
)
158 // for each rectangle, copy the area
159 const Point
aTopLeft(aRectIter
->TopLeft());
160 const Size
aSize(aRectIter
->GetSize());
162 mpOutputDevice
->DrawOutDev(
165 *mpPreRenderDevice
.get());
169 static bool bDoPaintForVisualControlRegion(false);
171 if(bDoPaintForVisualControlRegion
)
173 int nR
= comphelper::rng::uniform_int_distribution(0, 0x7F-1);
174 int nG
= comphelper::rng::uniform_int_distribution(0, 0x7F-1);
175 int nB
= comphelper::rng::uniform_int_distribution(0, 0x7F-1);
176 const Color
aColor(((((nR
|0x80)<<8)|(nG
|0x80))<<8)|(nB
|0x80));
178 mpOutputDevice
->SetLineColor(aColor
);
179 mpOutputDevice
->SetFillColor();
180 mpOutputDevice
->DrawRect(*aRectIter
);
185 mpOutputDevice
->EnableMapMode(bMapModeWasEnabledDest
);
186 mpPreRenderDevice
->EnableMapMode(bMapModeWasEnabledSource
);
190 void SdrPaintWindow::impCreateOverlayManager()
192 // not yet one created?
193 if(!mxOverlayManager
.is())
196 if(OUTDEV_WINDOW
== GetOutputDevice().GetOutDevType())
198 vcl::Window
& rWindow
= dynamic_cast<vcl::Window
&>(GetOutputDevice());
199 // decide which OverlayManager to use
200 if(GetPaintView().IsBufferedOverlayAllowed() && !rWindow
.SupportsDoubleBuffering())
202 // buffered OverlayManager, buffers its background and refreshes from there
203 // for pure overlay changes (no system redraw). The 3rd parameter specifies
204 // whether that refresh itself will use a 2nd vdev to avoid flickering.
205 // Also hand over the old OverlayManager if existent; this means to take over
206 // the registered OverlayObjects from it
207 mxOverlayManager
= sdr::overlay::OverlayManagerBuffered::create(GetOutputDevice());
211 // unbuffered OverlayManager, just invalidates places where changes
213 // Also hand over the old OverlayManager if existent; this means to take over
214 // the registered OverlayObjects from it
215 mxOverlayManager
= sdr::overlay::OverlayManager::create(GetOutputDevice());
218 OSL_ENSURE(mxOverlayManager
.is(), "SdrPaintWindow::SdrPaintWindow: Could not allocate an overlayManager (!)");
220 // Request a repaint so that the buffered overlay manager fills
221 // its buffer properly. This is a workaround for missing buffer
223 if (!comphelper::LibreOfficeKit::isActive())
225 rWindow
.Invalidate();
228 Color
aColA(GetPaintView().getOptionsDrawinglayer().GetStripeColorA());
229 Color
aColB(GetPaintView().getOptionsDrawinglayer().GetStripeColorB());
231 if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
233 aColA
= aColB
= Application::GetSettings().GetStyleSettings().GetHighlightColor();
237 mxOverlayManager
->setStripeColorA(aColA
);
238 mxOverlayManager
->setStripeColorB(aColB
);
239 mxOverlayManager
->setStripeLengthPixel(GetPaintView().getOptionsDrawinglayer().GetStripeLength());
244 SdrPaintWindow::SdrPaintWindow(SdrPaintView
& rNewPaintView
, OutputDevice
& rOut
, vcl::Window
* pWindow
)
245 : mpOutputDevice(&rOut
),
247 mrPaintView(rNewPaintView
),
248 mpPreRenderDevice(nullptr),
249 mbTemporaryTarget(false) // #i72889#
253 SdrPaintWindow::~SdrPaintWindow()
255 mxOverlayManager
.clear();
257 DestroyPreRenderDevice();
260 rtl::Reference
< sdr::overlay::OverlayManager
> const & SdrPaintWindow::GetOverlayManager() const
262 if(!mxOverlayManager
.is())
264 // Create buffered overlay manager by default.
265 const_cast< SdrPaintWindow
* >(this)->impCreateOverlayManager();
268 return mxOverlayManager
;
271 tools::Rectangle
SdrPaintWindow::GetVisibleArea() const
273 Size
aVisSizePixel(GetOutputDevice().GetOutputSizePixel());
274 return tools::Rectangle(GetOutputDevice().PixelToLogic(tools::Rectangle(Point(0,0), aVisSizePixel
)));
277 bool SdrPaintWindow::OutputToRecordingMetaFile() const
279 GDIMetaFile
* pMetaFile
= mpOutputDevice
->GetConnectMetaFile();
280 return (pMetaFile
&& pMetaFile
->IsRecord() && !pMetaFile
->IsPause());
283 void SdrPaintWindow::PreparePreRenderDevice()
285 const bool bPrepareBufferedOutput(
286 mrPaintView
.IsBufferedOutputAllowed()
287 && !OutputToPrinter()
288 && !OutputToVirtualDevice()
289 && !OutputToRecordingMetaFile());
291 if(bPrepareBufferedOutput
)
293 if(!mpPreRenderDevice
)
295 mpPreRenderDevice
= new SdrPreRenderDevice(*mpOutputDevice
.get());
300 DestroyPreRenderDevice();
303 if(mpPreRenderDevice
)
305 mpPreRenderDevice
->PreparePreRenderDevice();
309 void SdrPaintWindow::DestroyPreRenderDevice()
311 if(mpPreRenderDevice
)
313 delete mpPreRenderDevice
;
314 mpPreRenderDevice
= nullptr;
318 void SdrPaintWindow::OutputPreRenderDevice(const vcl::Region
& rExpandedRegion
)
320 if(mpPreRenderDevice
)
322 mpPreRenderDevice
->OutputPreRenderDevice(rExpandedRegion
);
326 // #i73602# add flag if buffer shall be used
327 void SdrPaintWindow::DrawOverlay(const vcl::Region
& rRegion
)
329 // ## force creation of OverlayManager since the first repaint needs to
330 // save the background to get a controlled start into overlay mechanism
331 impCreateOverlayManager();
333 if(mxOverlayManager
.is() && !OutputToPrinter())
335 if(mpPreRenderDevice
)
337 mxOverlayManager
->completeRedraw(rRegion
, &mpPreRenderDevice
->GetPreRenderDevice());
341 mxOverlayManager
->completeRedraw(rRegion
);
347 void SdrPaintWindow::SetRedrawRegion(const vcl::Region
& rNew
)
349 maRedrawRegion
= rNew
;
352 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */