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/random.hxx>
21 #include <svx/sdrpaintwindow.hxx>
22 #include <sdr/overlay/overlaymanagerbuffered.hxx>
23 #include <svx/svdpntv.hxx>
24 #include <vcl/gdimtf.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/settings.hxx>
30 //rhbz#1007697 do this in two loops, one to collect the candidates
31 //and another to update them because updating a candidate can
32 //trigger the candidate to be deleted, so asking for its
33 //sibling after that is going to fail hard
36 std::vector
<VclPtr
<vcl::Window
> > m_aCandidates
;
37 std::set
<VclPtr
<vcl::Window
> > m_aDeletedCandidates
;
38 DECL_LINK(WindowEventListener
, VclSimpleEvent
*);
40 void PaintTransparentChildren(vcl::Window
& rWindow
, Rectangle
const& rPixelRect
);
44 IMPL_LINK(CandidateMgr
, WindowEventListener
, VclSimpleEvent
*, pEvent
)
46 VclWindowEvent
* pWinEvent
= dynamic_cast< VclWindowEvent
* >( pEvent
);
49 vcl::Window
* pWindow
= pWinEvent
->GetWindow();
50 if (pWinEvent
->GetId() == VCLEVENT_OBJECT_DYING
)
52 m_aDeletedCandidates
.insert(pWindow
);
59 CandidateMgr::~CandidateMgr()
61 for (auto aI
= m_aCandidates
.begin(); aI
!= m_aCandidates
.end(); ++aI
)
63 VclPtr
<vcl::Window
> pCandidate
= *aI
;
64 if (m_aDeletedCandidates
.find(pCandidate
) != m_aDeletedCandidates
.end())
66 pCandidate
->RemoveEventListener(LINK(this, CandidateMgr
, WindowEventListener
));
70 void PaintTransparentChildren(vcl::Window
& rWindow
, Rectangle
const& rPixelRect
)
72 if (!rWindow
.IsChildTransparentModeEnabled())
75 CandidateMgr aManager
;
76 aManager
.PaintTransparentChildren(rWindow
, rPixelRect
);
79 void CandidateMgr::PaintTransparentChildren(vcl::Window
& rWindow
, Rectangle
const& rPixelRect
)
81 vcl::Window
* pCandidate
= rWindow
.GetWindow( GetWindowType::FirstChild
);
84 if (pCandidate
->IsPaintTransparent())
86 const Rectangle
aCandidatePosSizePixel(
87 pCandidate
->GetPosPixel(),
88 pCandidate
->GetSizePixel());
90 if (aCandidatePosSizePixel
.IsOver(rPixelRect
))
92 m_aCandidates
.push_back(pCandidate
);
93 pCandidate
->AddEventListener(LINK(this, CandidateMgr
, WindowEventListener
));
96 pCandidate
= pCandidate
->GetWindow( GetWindowType::Next
);
99 for (auto aI
= m_aCandidates
.begin(); aI
!= m_aCandidates
.end(); ++aI
)
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(INVALIDATE_NOTRANSPARENT
|INVALIDATE_CHILDREN
);
108 // important: actually paint the child here!
109 if (m_aDeletedCandidates
.find(pCandidate
) != m_aDeletedCandidates
.end())
111 pCandidate
->Update();
115 SdrPreRenderDevice::SdrPreRenderDevice(OutputDevice
& rOriginal
)
116 : mrOutputDevice(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() != mrOutputDevice
.GetOutputSizePixel())
131 mpPreRenderDevice
->SetOutputSizePixel(mrOutputDevice
.GetOutputSizePixel());
134 // Also compare the MapModes for zoom/scroll changes
135 if(mpPreRenderDevice
->GetMapMode() != mrOutputDevice
.GetMapMode())
137 mpPreRenderDevice
->SetMapMode(mrOutputDevice
.GetMapMode());
141 mpPreRenderDevice
->SetDrawMode(mrOutputDevice
.GetDrawMode());
142 mpPreRenderDevice
->SetSettings(mrOutputDevice
.GetSettings());
145 void SdrPreRenderDevice::OutputPreRenderDevice(const vcl::Region
& rExpandedRegion
)
148 const vcl::Region
aRegionPixel(mrOutputDevice
.LogicToPixel(rExpandedRegion
));
149 //RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects());
150 //Rectangle aRegionRectanglePixel;
153 bool bMapModeWasEnabledDest(mrOutputDevice
.IsMapModeEnabled());
154 bool bMapModeWasEnabledSource(mpPreRenderDevice
->IsMapModeEnabled());
155 mrOutputDevice
.EnableMapMode(false);
156 mpPreRenderDevice
->EnableMapMode(false);
158 RectangleVector aRectangles
;
159 aRegionPixel
.GetRegionRectangles(aRectangles
);
161 for(RectangleVector::const_iterator
aRectIter(aRectangles
.begin()); aRectIter
!= aRectangles
.end(); ++aRectIter
)
163 // for each rectangle, copy the area
164 const Point
aTopLeft(aRectIter
->TopLeft());
165 const Size
aSize(aRectIter
->GetSize());
167 mrOutputDevice
.DrawOutDev(
170 *mpPreRenderDevice
.get());
174 static bool bDoPaintForVisualControlRegion(false);
176 if(bDoPaintForVisualControlRegion
)
178 int nR
= comphelper::rng::uniform_int_distribution(0, 0x7F-1);
179 int nG
= comphelper::rng::uniform_int_distribution(0, 0x7F-1);
180 int nB
= comphelper::rng::uniform_int_distribution(0, 0x7F-1);
181 const Color
aColor(((((nR
|0x80)<<8L)|(nG
|0x80))<<8L)|(nB
|0x80));
183 mrOutputDevice
.SetLineColor(aColor
);
184 mrOutputDevice
.SetFillColor();
185 mrOutputDevice
.DrawRect(*aRectIter
);
190 mrOutputDevice
.EnableMapMode(bMapModeWasEnabledDest
);
191 mpPreRenderDevice
->EnableMapMode(bMapModeWasEnabledSource
);
196 void SdrPaintWindow::impCreateOverlayManager()
198 // not yet one created?
199 if(!mxOverlayManager
.is())
202 if(OUTDEV_WINDOW
== GetOutputDevice().GetOutDevType())
204 vcl::Window
* pWindow
= dynamic_cast<vcl::Window
*>(&GetOutputDevice());
205 // decide which OverlayManager to use
206 if(GetPaintView().IsBufferedOverlayAllowed() && mbUseBuffer
&& !pWindow
->SupportsDoubleBuffering())
208 // buffered OverlayManager, buffers its background and refreshes from there
209 // for pure overlay changes (no system redraw). The 3rd parameter specifies
210 // whether that refresh itself will use a 2nd vdev to avoid flickering.
211 // Also hand over the old OverlayManager if existent; this means to take over
212 // the registered OverlayObjects from it
213 mxOverlayManager
= sdr::overlay::OverlayManagerBuffered::create(GetOutputDevice(), GetPaintView().GetModel(), true);
217 // unbuffered OverlayManager, just invalidates places where changes
219 // Also hand over the old OverlayManager if existent; this means to take over
220 // the registered OverlayObjects from it
221 mxOverlayManager
= sdr::overlay::OverlayManager::create(GetOutputDevice(), GetPaintView().GetModel());
224 OSL_ENSURE(mxOverlayManager
.is(), "SdrPaintWindow::SdrPaintWindow: Could not allocate an overlayManager (!)");
226 // Request a repaint so that the buffered overlay manager fills
227 // its buffer properly. This is a workaround for missing buffer
230 pWindow
->Invalidate();
232 Color
aColA(GetPaintView().getOptionsDrawinglayer().GetStripeColorA());
233 Color
aColB(GetPaintView().getOptionsDrawinglayer().GetStripeColorB());
235 if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
237 aColA
= aColB
= Application::GetSettings().GetStyleSettings().GetHighlightColor();
241 mxOverlayManager
->setStripeColorA(aColA
);
242 mxOverlayManager
->setStripeColorB(aColB
);
243 mxOverlayManager
->setStripeLengthPixel(GetPaintView().getOptionsDrawinglayer().GetStripeLength());
248 SdrPaintWindow::SdrPaintWindow(SdrPaintView
& rNewPaintView
, OutputDevice
& rOut
, vcl::Window
* pWindow
)
249 : mrOutputDevice(rOut
),
251 mrPaintView(rNewPaintView
),
252 mpPreRenderDevice(0L),
253 mbTemporaryTarget(false), // #i72889#
258 SdrPaintWindow::~SdrPaintWindow()
260 mxOverlayManager
.clear();
262 DestroyPreRenderDevice();
265 rtl::Reference
< sdr::overlay::OverlayManager
> SdrPaintWindow::GetOverlayManager() const
267 if(!mxOverlayManager
.is())
269 // Create buffered overlay manager by default.
270 const_cast< SdrPaintWindow
* >(this)->impCreateOverlayManager();
273 return mxOverlayManager
;
276 Rectangle
SdrPaintWindow::GetVisibleArea() const
278 Size
aVisSizePixel(GetOutputDevice().GetOutputSizePixel());
279 return Rectangle(GetOutputDevice().PixelToLogic(Rectangle(Point(0,0), aVisSizePixel
)));
282 bool SdrPaintWindow::OutputToRecordingMetaFile() const
284 GDIMetaFile
* pMetaFile
= mrOutputDevice
.GetConnectMetaFile();
285 return (pMetaFile
&& pMetaFile
->IsRecord() && !pMetaFile
->IsPause());
288 void SdrPaintWindow::PreparePreRenderDevice()
290 const bool bPrepareBufferedOutput(
291 mrPaintView
.IsBufferedOutputAllowed()
292 && !OutputToPrinter()
293 && !OutputToVirtualDevice()
294 && !OutputToRecordingMetaFile());
296 if(bPrepareBufferedOutput
)
298 if(!mpPreRenderDevice
)
300 mpPreRenderDevice
= new SdrPreRenderDevice(mrOutputDevice
);
305 DestroyPreRenderDevice();
308 if(mpPreRenderDevice
)
310 mpPreRenderDevice
->PreparePreRenderDevice();
314 void SdrPaintWindow::DestroyPreRenderDevice()
316 if(mpPreRenderDevice
)
318 delete mpPreRenderDevice
;
319 mpPreRenderDevice
= 0L;
323 void SdrPaintWindow::OutputPreRenderDevice(const vcl::Region
& rExpandedRegion
)
325 if(mpPreRenderDevice
)
327 mpPreRenderDevice
->OutputPreRenderDevice(rExpandedRegion
);
331 // #i73602# add flag if buffer shall be used
332 void SdrPaintWindow::DrawOverlay(const vcl::Region
& rRegion
)
334 // ## force creation of OverlayManager since the first repaint needs to
335 // save the background to get a controlled start into overlay mechanism
336 impCreateOverlayManager();
338 if(mxOverlayManager
.is() && !OutputToPrinter())
340 if(mpPreRenderDevice
)
342 mxOverlayManager
->completeRedraw(rRegion
, &mpPreRenderDevice
->GetPreRenderDevice());
346 mxOverlayManager
->completeRedraw(rRegion
);
352 void SdrPaintWindow::SetRedrawRegion(const vcl::Region
& rNew
)
354 maRedrawRegion
= rNew
;
357 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */