Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
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>
27 : #include <set>
28 : #include <vector>
29 :
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
34 5044 : class CandidateMgr
35 : {
36 : std::vector<VclPtr<vcl::Window> > m_aCandidates;
37 : std::set<VclPtr<vcl::Window> > m_aDeletedCandidates;
38 : DECL_LINK(WindowEventListener, VclSimpleEvent*);
39 : public:
40 : void PaintTransparentChildren(vcl::Window & rWindow, Rectangle const& rPixelRect);
41 : ~CandidateMgr();
42 : };
43 :
44 0 : IMPL_LINK(CandidateMgr, WindowEventListener, VclSimpleEvent*, pEvent)
45 : {
46 0 : VclWindowEvent* pWinEvent = dynamic_cast< VclWindowEvent* >( pEvent );
47 0 : if (pWinEvent)
48 : {
49 0 : vcl::Window* pWindow = pWinEvent->GetWindow();
50 0 : if (pWinEvent->GetId() == VCLEVENT_OBJECT_DYING)
51 : {
52 0 : m_aDeletedCandidates.insert(pWindow);
53 : }
54 : }
55 :
56 0 : return 0;
57 : }
58 :
59 10088 : CandidateMgr::~CandidateMgr()
60 : {
61 5182 : for (auto aI = m_aCandidates.begin(); aI != m_aCandidates.end(); ++aI)
62 : {
63 138 : VclPtr<vcl::Window> pCandidate = *aI;
64 138 : if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
65 0 : continue;
66 138 : pCandidate->RemoveEventListener(LINK(this, CandidateMgr, WindowEventListener));
67 138 : }
68 5044 : }
69 :
70 5044 : void PaintTransparentChildren(vcl::Window & rWindow, Rectangle const& rPixelRect)
71 : {
72 5044 : if (!rWindow.IsChildTransparentModeEnabled())
73 5044 : return;
74 :
75 5044 : CandidateMgr aManager;
76 5044 : aManager.PaintTransparentChildren(rWindow, rPixelRect);
77 : }
78 :
79 5044 : void CandidateMgr::PaintTransparentChildren(vcl::Window & rWindow, Rectangle const& rPixelRect)
80 : {
81 5044 : vcl::Window * pCandidate = rWindow.GetWindow( GetWindowType::FirstChild );
82 12213 : while (pCandidate)
83 : {
84 2125 : if (pCandidate->IsPaintTransparent())
85 : {
86 : const Rectangle aCandidatePosSizePixel(
87 451 : pCandidate->GetPosPixel(),
88 902 : pCandidate->GetSizePixel());
89 :
90 451 : if (aCandidatePosSizePixel.IsOver(rPixelRect))
91 : {
92 138 : m_aCandidates.push_back(pCandidate);
93 138 : pCandidate->AddEventListener(LINK(this, CandidateMgr, WindowEventListener));
94 : }
95 : }
96 2125 : pCandidate = pCandidate->GetWindow( GetWindowType::Next );
97 : }
98 :
99 5182 : for (auto aI = m_aCandidates.begin(); aI != m_aCandidates.end(); ++aI)
100 : {
101 138 : pCandidate = *aI;
102 138 : if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
103 0 : 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 138 : pCandidate->Invalidate(InvalidateFlags::NoTransparent|InvalidateFlags::Children);
108 : // important: actually paint the child here!
109 138 : if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
110 0 : continue;
111 138 : pCandidate->Update();
112 : }
113 5044 : }
114 :
115 1079 : SdrPreRenderDevice::SdrPreRenderDevice(OutputDevice& rOriginal)
116 : : mrOutputDevice(rOriginal),
117 1079 : mpPreRenderDevice(VclPtr<VirtualDevice>::Create())
118 : {
119 1079 : }
120 :
121 2120 : SdrPreRenderDevice::~SdrPreRenderDevice()
122 : {
123 1060 : mpPreRenderDevice.disposeAndClear();
124 1060 : }
125 :
126 13751 : void SdrPreRenderDevice::PreparePreRenderDevice()
127 : {
128 : // compare size of mpPreRenderDevice with size of visible area
129 13751 : if(mpPreRenderDevice->GetOutputSizePixel() != mrOutputDevice.GetOutputSizePixel())
130 : {
131 1225 : mpPreRenderDevice->SetOutputSizePixel(mrOutputDevice.GetOutputSizePixel());
132 : }
133 :
134 : // Also compare the MapModes for zoom/scroll changes
135 13751 : if(mpPreRenderDevice->GetMapMode() != mrOutputDevice.GetMapMode())
136 : {
137 4181 : mpPreRenderDevice->SetMapMode(mrOutputDevice.GetMapMode());
138 : }
139 :
140 : // #i29186#
141 13751 : mpPreRenderDevice->SetDrawMode(mrOutputDevice.GetDrawMode());
142 13751 : mpPreRenderDevice->SetSettings(mrOutputDevice.GetSettings());
143 13751 : }
144 :
145 13751 : void SdrPreRenderDevice::OutputPreRenderDevice(const vcl::Region& rExpandedRegion)
146 : {
147 : // region to pixels
148 13751 : const vcl::Region aRegionPixel(mrOutputDevice.LogicToPixel(rExpandedRegion));
149 : //RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects());
150 : //Rectangle aRegionRectanglePixel;
151 :
152 : // MapModes off
153 13751 : bool bMapModeWasEnabledDest(mrOutputDevice.IsMapModeEnabled());
154 13751 : bool bMapModeWasEnabledSource(mpPreRenderDevice->IsMapModeEnabled());
155 13751 : mrOutputDevice.EnableMapMode(false);
156 13751 : mpPreRenderDevice->EnableMapMode(false);
157 :
158 27502 : RectangleVector aRectangles;
159 13751 : aRegionPixel.GetRegionRectangles(aRectangles);
160 :
161 27904 : for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
162 : {
163 : // for each rectangle, copy the area
164 14153 : const Point aTopLeft(aRectIter->TopLeft());
165 14153 : const Size aSize(aRectIter->GetSize());
166 :
167 : mrOutputDevice.DrawOutDev(
168 : aTopLeft, aSize,
169 : aTopLeft, aSize,
170 14153 : *mpPreRenderDevice.get());
171 :
172 : #ifdef DBG_UTIL
173 : // #i74769#
174 : static bool bDoPaintForVisualControlRegion(false);
175 :
176 : if(bDoPaintForVisualControlRegion)
177 : {
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));
182 :
183 : mrOutputDevice.SetLineColor(aColor);
184 : mrOutputDevice.SetFillColor();
185 : mrOutputDevice.DrawRect(*aRectIter);
186 : }
187 : #endif
188 : }
189 :
190 13751 : mrOutputDevice.EnableMapMode(bMapModeWasEnabledDest);
191 27502 : mpPreRenderDevice->EnableMapMode(bMapModeWasEnabledSource);
192 13751 : }
193 :
194 :
195 :
196 14758 : void SdrPaintWindow::impCreateOverlayManager()
197 : {
198 : // not yet one created?
199 14758 : if(!mxOverlayManager.is())
200 : {
201 : // is it a window?
202 1882 : if(OUTDEV_WINDOW == GetOutputDevice().GetOutDevType())
203 : {
204 : // decide which OverlayManager to use
205 1312 : if(GetPaintView().IsBufferedOverlayAllowed() && mbUseBuffer)
206 : {
207 : // buffered OverlayManager, buffers its background and refreshes from there
208 : // for pure overlay changes (no system redraw). The 3rd parameter specifies
209 : // whether that refresh itself will use a 2nd vdev to avoid flickering.
210 : // Also hand over the old OverlayManager if existent; this means to take over
211 : // the registered OverlayObjects from it
212 1303 : mxOverlayManager = sdr::overlay::OverlayManagerBuffered::create(GetOutputDevice(), GetPaintView().GetModel(), true);
213 : }
214 : else
215 : {
216 : // unbuffered OverlayManager, just invalidates places where changes
217 : // take place
218 : // Also hand over the old OverlayManager if existent; this means to take over
219 : // the registered OverlayObjects from it
220 9 : mxOverlayManager = sdr::overlay::OverlayManager::create(GetOutputDevice(), GetPaintView().GetModel());
221 : }
222 :
223 : OSL_ENSURE(mxOverlayManager.is(), "SdrPaintWindow::SdrPaintWindow: Could not allocate an overlayManager (!)");
224 :
225 : // Request a repaint so that the buffered overlay manager fills
226 : // its buffer properly. This is a workaround for missing buffer
227 : // updates.
228 1312 : vcl::Window* pWindow = dynamic_cast<vcl::Window*>(&GetOutputDevice());
229 1312 : if (pWindow != NULL)
230 1312 : pWindow->Invalidate();
231 :
232 1312 : Color aColA(GetPaintView().getOptionsDrawinglayer().GetStripeColorA());
233 1312 : Color aColB(GetPaintView().getOptionsDrawinglayer().GetStripeColorB());
234 :
235 1312 : if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
236 : {
237 0 : aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor();
238 0 : aColB.Invert();
239 : }
240 :
241 1312 : mxOverlayManager->setStripeColorA(aColA);
242 1312 : mxOverlayManager->setStripeColorB(aColB);
243 1312 : mxOverlayManager->setStripeLengthPixel(GetPaintView().getOptionsDrawinglayer().GetStripeLength());
244 : }
245 : }
246 14758 : }
247 :
248 41631 : SdrPaintWindow::SdrPaintWindow(SdrPaintView& rNewPaintView, OutputDevice& rOut)
249 : : mrOutputDevice(rOut),
250 : mrPaintView(rNewPaintView),
251 : mpPreRenderDevice(0L),
252 : mbTemporaryTarget(false), // #i72889#
253 41631 : mbUseBuffer(true)
254 : {
255 41631 : }
256 :
257 83216 : SdrPaintWindow::~SdrPaintWindow()
258 : {
259 41608 : mxOverlayManager.clear();
260 :
261 41608 : DestroyPreRenderDevice();
262 41608 : }
263 :
264 6330 : rtl::Reference< sdr::overlay::OverlayManager > SdrPaintWindow::GetOverlayManager() const
265 : {
266 6330 : if(!mxOverlayManager.is())
267 : {
268 : // Create buffered overlay manager by default.
269 415 : const_cast< SdrPaintWindow* >(this)->impCreateOverlayManager();
270 : }
271 :
272 6330 : return mxOverlayManager;
273 : }
274 :
275 458 : Rectangle SdrPaintWindow::GetVisibleArea() const
276 : {
277 458 : Size aVisSizePixel(GetOutputDevice().GetOutputSizePixel());
278 458 : return Rectangle(GetOutputDevice().PixelToLogic(Rectangle(Point(0,0), aVisSizePixel)));
279 : }
280 :
281 13751 : bool SdrPaintWindow::OutputToRecordingMetaFile() const
282 : {
283 13751 : GDIMetaFile* pMetaFile = mrOutputDevice.GetConnectMetaFile();
284 13751 : return (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
285 : }
286 :
287 14343 : void SdrPaintWindow::PreparePreRenderDevice()
288 : {
289 : const bool bPrepareBufferedOutput(
290 14343 : mrPaintView.IsBufferedOutputAllowed()
291 14309 : && !OutputToPrinter()
292 14309 : && !OutputToVirtualDevice()
293 28094 : && !OutputToRecordingMetaFile());
294 :
295 14343 : if(bPrepareBufferedOutput)
296 : {
297 13751 : if(!mpPreRenderDevice)
298 : {
299 1079 : mpPreRenderDevice = new SdrPreRenderDevice(mrOutputDevice);
300 : }
301 : }
302 : else
303 : {
304 592 : DestroyPreRenderDevice();
305 : }
306 :
307 14343 : if(mpPreRenderDevice)
308 : {
309 13751 : mpPreRenderDevice->PreparePreRenderDevice();
310 : }
311 14343 : }
312 :
313 42200 : void SdrPaintWindow::DestroyPreRenderDevice()
314 : {
315 42200 : if(mpPreRenderDevice)
316 : {
317 1060 : delete mpPreRenderDevice;
318 1060 : mpPreRenderDevice = 0L;
319 : }
320 42200 : }
321 :
322 14343 : void SdrPaintWindow::OutputPreRenderDevice(const vcl::Region& rExpandedRegion)
323 : {
324 14343 : if(mpPreRenderDevice)
325 : {
326 13751 : mpPreRenderDevice->OutputPreRenderDevice(rExpandedRegion);
327 : }
328 14343 : }
329 :
330 : // #i73602# add flag if buffer shall be used
331 14343 : void SdrPaintWindow::DrawOverlay(const vcl::Region& rRegion)
332 : {
333 : // ## force creation of OverlayManager since the first repaint needs to
334 : // save the background to get a controlled start into overlay mechanism
335 14343 : impCreateOverlayManager();
336 :
337 14343 : if(mxOverlayManager.is() && !OutputToPrinter())
338 : {
339 13773 : if(mpPreRenderDevice)
340 : {
341 13751 : mxOverlayManager->completeRedraw(rRegion, &mpPreRenderDevice->GetPreRenderDevice());
342 : }
343 : else
344 : {
345 22 : mxOverlayManager->completeRedraw(rRegion);
346 : }
347 : }
348 14343 : }
349 :
350 :
351 77578 : void SdrPaintWindow::SetRedrawRegion(const vcl::Region& rNew)
352 : {
353 77578 : maRedrawRegion = rNew;
354 77578 : }
355 :
356 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|