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 10396 : class CandidateMgr
35 : {
36 : std::vector<vcl::Window*> m_aCandidates;
37 : std::set<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 20792 : CandidateMgr::~CandidateMgr()
60 : {
61 31890 : for (std::vector<vcl::Window*>::iterator aI = m_aCandidates.begin();
62 21260 : aI != m_aCandidates.end(); ++aI)
63 : {
64 234 : vcl::Window* pCandidate = *aI;
65 234 : if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
66 0 : continue;
67 234 : pCandidate->RemoveEventListener(LINK(this, CandidateMgr, WindowEventListener));
68 : }
69 10396 : }
70 :
71 10396 : void PaintTransparentChildren(vcl::Window & rWindow, Rectangle const& rPixelRect)
72 : {
73 10396 : if (!rWindow.IsChildTransparentModeEnabled())
74 10396 : return;
75 :
76 10396 : CandidateMgr aManager;
77 10396 : aManager.PaintTransparentChildren(rWindow, rPixelRect);
78 : }
79 :
80 10396 : void CandidateMgr::PaintTransparentChildren(vcl::Window & rWindow, Rectangle const& rPixelRect)
81 : {
82 10396 : vcl::Window * pCandidate = rWindow.GetWindow( WINDOW_FIRSTCHILD );
83 23505 : while (pCandidate)
84 : {
85 2713 : if (pCandidate->IsPaintTransparent())
86 : {
87 : const Rectangle aCandidatePosSizePixel(
88 716 : pCandidate->GetPosPixel(),
89 1432 : pCandidate->GetSizePixel());
90 :
91 716 : if (aCandidatePosSizePixel.IsOver(rPixelRect))
92 : {
93 234 : m_aCandidates.push_back(pCandidate);
94 234 : pCandidate->AddEventListener(LINK(this, CandidateMgr, WindowEventListener));
95 : }
96 : }
97 2713 : pCandidate = pCandidate->GetWindow( WINDOW_NEXT );
98 : }
99 :
100 31890 : for (std::vector<vcl::Window*>::iterator aI = m_aCandidates.begin();
101 21260 : aI != m_aCandidates.end(); ++aI)
102 : {
103 234 : pCandidate = *aI;
104 234 : if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
105 0 : continue;
106 : //rhbz#1007697 this can cause the window itself to be
107 : //deleted. So we are listening to see if that happens
108 : //and if so, then skip the update
109 234 : pCandidate->Invalidate(INVALIDATE_NOTRANSPARENT|INVALIDATE_CHILDREN);
110 : // important: actually paint the child here!
111 234 : if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
112 0 : continue;
113 234 : pCandidate->Update();
114 : }
115 10396 : }
116 :
117 1903 : SdrPreRenderDevice::SdrPreRenderDevice(OutputDevice& rOriginal)
118 1903 : : mrOutputDevice(rOriginal)
119 : {
120 1903 : }
121 :
122 1876 : SdrPreRenderDevice::~SdrPreRenderDevice()
123 : {
124 1876 : }
125 :
126 14411 : void SdrPreRenderDevice::PreparePreRenderDevice()
127 : {
128 : // compare size of maPreRenderDevice with size of visible area
129 14411 : if(maPreRenderDevice.GetOutputSizePixel() != mrOutputDevice.GetOutputSizePixel())
130 : {
131 2109 : maPreRenderDevice.SetOutputSizePixel(mrOutputDevice.GetOutputSizePixel());
132 : }
133 :
134 : // Also compare the MapModes for zoom/scroll changes
135 14411 : if(maPreRenderDevice.GetMapMode() != mrOutputDevice.GetMapMode())
136 : {
137 4475 : maPreRenderDevice.SetMapMode(mrOutputDevice.GetMapMode());
138 : }
139 :
140 : // #i29186#
141 14411 : maPreRenderDevice.SetDrawMode(mrOutputDevice.GetDrawMode());
142 14411 : maPreRenderDevice.SetSettings(mrOutputDevice.GetSettings());
143 14411 : }
144 :
145 14411 : void SdrPreRenderDevice::OutputPreRenderDevice(const vcl::Region& rExpandedRegion)
146 : {
147 : // region to pixels
148 14411 : const vcl::Region aRegionPixel(mrOutputDevice.LogicToPixel(rExpandedRegion));
149 : //RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects());
150 : //Rectangle aRegionRectanglePixel;
151 :
152 : // MapModes off
153 14411 : bool bMapModeWasEnabledDest(mrOutputDevice.IsMapModeEnabled());
154 14411 : bool bMapModeWasEnabledSource(maPreRenderDevice.IsMapModeEnabled());
155 14411 : mrOutputDevice.EnableMapMode(false);
156 14411 : maPreRenderDevice.EnableMapMode(false);
157 :
158 28822 : RectangleVector aRectangles;
159 14411 : aRegionPixel.GetRegionRectangles(aRectangles);
160 :
161 29603 : for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
162 : {
163 : // for each rectangle, copy the area
164 15192 : const Point aTopLeft(aRectIter->TopLeft());
165 15192 : const Size aSize(aRectIter->GetSize());
166 :
167 : mrOutputDevice.DrawOutDev(
168 : aTopLeft, aSize,
169 : aTopLeft, aSize,
170 15192 : maPreRenderDevice);
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 14411 : mrOutputDevice.EnableMapMode(bMapModeWasEnabledDest);
191 28822 : maPreRenderDevice.EnableMapMode(bMapModeWasEnabledSource);
192 14411 : }
193 :
194 :
195 :
196 16050 : void SdrPaintWindow::impCreateOverlayManager()
197 : {
198 : // not yet one created?
199 16050 : if(!mxOverlayManager.is())
200 : {
201 : // is it a window?
202 3180 : if(OUTDEV_WINDOW == GetOutputDevice().GetOutDevType())
203 : {
204 : // decide which OverlayManager to use
205 2255 : 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 2237 : mxOverlayManager = ::sdr::overlay::OverlayManagerBuffered::create(GetOutputDevice(), 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 18 : mxOverlayManager = ::sdr::overlay::OverlayManager::create(GetOutputDevice());
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 2255 : vcl::Window* pWindow = dynamic_cast<vcl::Window*>(&GetOutputDevice());
229 2255 : if (pWindow != NULL)
230 2255 : pWindow->Invalidate();
231 :
232 2255 : Color aColA(GetPaintView().getOptionsDrawinglayer().GetStripeColorA());
233 2255 : Color aColB(GetPaintView().getOptionsDrawinglayer().GetStripeColorB());
234 :
235 2255 : if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
236 : {
237 0 : aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor();
238 0 : aColB.Invert();
239 : }
240 :
241 2255 : mxOverlayManager->setStripeColorA(aColA);
242 2255 : mxOverlayManager->setStripeColorB(aColB);
243 2255 : mxOverlayManager->setStripeLengthPixel(GetPaintView().getOptionsDrawinglayer().GetStripeLength());
244 : }
245 : }
246 16050 : }
247 :
248 48677 : SdrPaintWindow::SdrPaintWindow(SdrPaintView& rNewPaintView, OutputDevice& rOut)
249 : : mrOutputDevice(rOut),
250 : mrPaintView(rNewPaintView),
251 : mpPreRenderDevice(0L),
252 : mbTemporaryTarget(false), // #i72889#
253 48677 : mbUseBuffer(true)
254 : {
255 48677 : }
256 :
257 97286 : SdrPaintWindow::~SdrPaintWindow()
258 : {
259 48643 : mxOverlayManager.clear();
260 :
261 48643 : DestroyPreRenderDevice();
262 48643 : }
263 :
264 8718 : rtl::Reference< ::sdr::overlay::OverlayManager > SdrPaintWindow::GetOverlayManager() const
265 : {
266 8718 : if(!mxOverlayManager.is())
267 : {
268 : // Create buffered overlay manager by default.
269 648 : const_cast< SdrPaintWindow* >(this)->impCreateOverlayManager();
270 : }
271 :
272 8718 : return mxOverlayManager;
273 : }
274 :
275 1076 : Rectangle SdrPaintWindow::GetVisibleArea() const
276 : {
277 1076 : Size aVisSizePixel(GetOutputDevice().GetOutputSizePixel());
278 1076 : return Rectangle(GetOutputDevice().PixelToLogic(Rectangle(Point(0,0), aVisSizePixel)));
279 : }
280 :
281 14411 : bool SdrPaintWindow::OutputToRecordingMetaFile() const
282 : {
283 14411 : GDIMetaFile* pMetaFile = mrOutputDevice.GetConnectMetaFile();
284 14411 : return (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
285 : }
286 :
287 15402 : void SdrPaintWindow::PreparePreRenderDevice()
288 : {
289 : const bool bPrepareBufferedOutput(
290 15402 : mrPaintView.IsBufferedOutputAllowed()
291 15324 : && !OutputToPrinter()
292 15324 : && !OutputToVirtualDevice()
293 29813 : && !OutputToRecordingMetaFile());
294 :
295 15402 : if(bPrepareBufferedOutput)
296 : {
297 14411 : if(!mpPreRenderDevice)
298 : {
299 1903 : mpPreRenderDevice = new SdrPreRenderDevice(mrOutputDevice);
300 : }
301 : }
302 : else
303 : {
304 991 : DestroyPreRenderDevice();
305 : }
306 :
307 15402 : if(mpPreRenderDevice)
308 : {
309 14411 : mpPreRenderDevice->PreparePreRenderDevice();
310 : }
311 15402 : }
312 :
313 49634 : void SdrPaintWindow::DestroyPreRenderDevice()
314 : {
315 49634 : if(mpPreRenderDevice)
316 : {
317 1876 : delete mpPreRenderDevice;
318 1876 : mpPreRenderDevice = 0L;
319 : }
320 49634 : }
321 :
322 15402 : void SdrPaintWindow::OutputPreRenderDevice(const vcl::Region& rExpandedRegion)
323 : {
324 15402 : if(mpPreRenderDevice)
325 : {
326 14411 : mpPreRenderDevice->OutputPreRenderDevice(rExpandedRegion);
327 : }
328 15402 : }
329 :
330 : // #i73602# add flag if buffer shall be used
331 15402 : 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 15402 : impCreateOverlayManager();
336 :
337 15402 : if(mxOverlayManager.is() && !OutputToPrinter())
338 : {
339 14477 : if(mpPreRenderDevice)
340 : {
341 14411 : mxOverlayManager->completeRedraw(rRegion, &mpPreRenderDevice->GetPreRenderDevice());
342 : }
343 : else
344 : {
345 66 : mxOverlayManager->completeRedraw(rRegion);
346 : }
347 : }
348 15402 : }
349 :
350 :
351 93339 : void SdrPaintWindow::SetRedrawRegion(const vcl::Region& rNew)
352 : {
353 93339 : maRedrawRegion = rNew;
354 93990 : }
355 :
356 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|