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 <svx/sdrpaintwindow.hxx>
21 : #include <svx/sdr/overlay/overlaymanagerbuffered.hxx>
22 : #include <svx/svdpntv.hxx>
23 : #include <vcl/gdimtf.hxx>
24 : #include <vcl/svapp.hxx>
25 : #include <vcl/settings.hxx>
26 : #include <set>
27 : #include <vector>
28 :
29 : //rhbz#1007697 do this in two loops, one to collect the candidates
30 : //and another to update them because updating a candidate can
31 : //trigger the candidate to be deleted, so asking for its
32 : //sibling after that is going to fail hard
33 0 : class CandidateMgr
34 : {
35 : std::vector<Window*> m_aCandidates;
36 : std::set<Window*> m_aDeletedCandidates;
37 : DECL_LINK(WindowEventListener, VclSimpleEvent*);
38 : public:
39 : void PaintTransparentChildren(Window & rWindow, Rectangle const& rPixelRect);
40 : ~CandidateMgr();
41 : };
42 :
43 0 : IMPL_LINK(CandidateMgr, WindowEventListener, VclSimpleEvent*, pEvent)
44 : {
45 0 : VclWindowEvent* pWinEvent = dynamic_cast< VclWindowEvent* >( pEvent );
46 0 : if (pWinEvent)
47 : {
48 0 : Window* pWindow = pWinEvent->GetWindow();
49 0 : if (pWinEvent->GetId() == VCLEVENT_OBJECT_DYING)
50 : {
51 0 : m_aDeletedCandidates.insert(pWindow);
52 : }
53 : }
54 :
55 0 : return 0;
56 : }
57 :
58 0 : CandidateMgr::~CandidateMgr()
59 : {
60 0 : for (std::vector<Window*>::iterator aI = m_aCandidates.begin();
61 0 : aI != m_aCandidates.end(); ++aI)
62 : {
63 0 : Window* pCandidate = *aI;
64 0 : if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
65 0 : continue;
66 0 : pCandidate->RemoveEventListener(LINK(this, CandidateMgr, WindowEventListener));
67 : }
68 0 : }
69 :
70 0 : void PaintTransparentChildren(Window & rWindow, Rectangle const& rPixelRect)
71 : {
72 0 : if (!rWindow.IsChildTransparentModeEnabled())
73 0 : return;
74 :
75 0 : CandidateMgr aManager;
76 0 : aManager.PaintTransparentChildren(rWindow, rPixelRect);
77 : }
78 :
79 0 : void CandidateMgr::PaintTransparentChildren(Window & rWindow, Rectangle const& rPixelRect)
80 : {
81 0 : Window * pCandidate = rWindow.GetWindow( WINDOW_FIRSTCHILD );
82 0 : while (pCandidate)
83 : {
84 0 : if (pCandidate->IsPaintTransparent())
85 : {
86 : const Rectangle aCandidatePosSizePixel(
87 0 : pCandidate->GetPosPixel(),
88 0 : pCandidate->GetSizePixel());
89 :
90 0 : if (aCandidatePosSizePixel.IsOver(rPixelRect))
91 : {
92 0 : m_aCandidates.push_back(pCandidate);
93 0 : pCandidate->AddEventListener(LINK(this, CandidateMgr, WindowEventListener));
94 : }
95 : }
96 0 : pCandidate = pCandidate->GetWindow( WINDOW_NEXT );
97 : }
98 :
99 0 : for (std::vector<Window*>::iterator aI = m_aCandidates.begin();
100 0 : aI != m_aCandidates.end(); ++aI)
101 : {
102 0 : pCandidate = *aI;
103 0 : if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
104 0 : continue;
105 : //rhbz#1007697 this can cause the window itself to be
106 : //deleted. So we are listening to see if that happens
107 : //and if so, then skip the update
108 0 : pCandidate->Invalidate(INVALIDATE_NOTRANSPARENT|INVALIDATE_CHILDREN);
109 : // important: actually paint the child here!
110 0 : if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
111 0 : continue;
112 0 : pCandidate->Update();
113 : }
114 0 : }
115 :
116 0 : SdrPreRenderDevice::SdrPreRenderDevice(OutputDevice& rOriginal)
117 0 : : mrOutputDevice(rOriginal)
118 : {
119 0 : }
120 :
121 0 : SdrPreRenderDevice::~SdrPreRenderDevice()
122 : {
123 0 : }
124 :
125 0 : void SdrPreRenderDevice::PreparePreRenderDevice()
126 : {
127 : // compare size of maPreRenderDevice with size of visible area
128 0 : if(maPreRenderDevice.GetOutputSizePixel() != mrOutputDevice.GetOutputSizePixel())
129 : {
130 0 : maPreRenderDevice.SetOutputSizePixel(mrOutputDevice.GetOutputSizePixel());
131 : }
132 :
133 : // Also compare the MapModes for zoom/scroll changes
134 0 : if(maPreRenderDevice.GetMapMode() != mrOutputDevice.GetMapMode())
135 : {
136 0 : maPreRenderDevice.SetMapMode(mrOutputDevice.GetMapMode());
137 : }
138 :
139 : // #i29186#
140 0 : maPreRenderDevice.SetDrawMode(mrOutputDevice.GetDrawMode());
141 0 : maPreRenderDevice.SetSettings(mrOutputDevice.GetSettings());
142 0 : }
143 :
144 0 : void SdrPreRenderDevice::OutputPreRenderDevice(const Region& rExpandedRegion)
145 : {
146 : // region to pixels
147 0 : const Region aRegionPixel(mrOutputDevice.LogicToPixel(rExpandedRegion));
148 : //RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects());
149 : //Rectangle aRegionRectanglePixel;
150 :
151 : // MapModes off
152 0 : sal_Bool bMapModeWasEnabledDest(mrOutputDevice.IsMapModeEnabled());
153 0 : sal_Bool bMapModeWasEnabledSource(maPreRenderDevice.IsMapModeEnabled());
154 0 : mrOutputDevice.EnableMapMode(false);
155 0 : maPreRenderDevice.EnableMapMode(false);
156 :
157 0 : RectangleVector aRectangles;
158 0 : aRegionPixel.GetRegionRectangles(aRectangles);
159 :
160 0 : for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
161 : {
162 : // for each rectangle, copy the area
163 0 : const Point aTopLeft(aRectIter->TopLeft());
164 0 : const Size aSize(aRectIter->GetSize());
165 :
166 : mrOutputDevice.DrawOutDev(
167 : aTopLeft, aSize,
168 : aTopLeft, aSize,
169 0 : maPreRenderDevice);
170 :
171 : #ifdef DBG_UTIL
172 : // #i74769#
173 : static bool bDoPaintForVisualControlRegion(false);
174 :
175 : if(bDoPaintForVisualControlRegion)
176 : {
177 : const Color aColor((((((rand()&0x7f)|0x80)<<8L)|((rand()&0x7f)|0x80))<<8L)|((rand()&0x7f)|0x80));
178 :
179 : mrOutputDevice.SetLineColor(aColor);
180 : mrOutputDevice.SetFillColor();
181 : mrOutputDevice.DrawRect(*aRectIter);
182 : }
183 : #endif
184 : }
185 :
186 : // while(aRegionPixel.GetEnumRects(aRegionHandle, aRegionRectanglePixel))
187 : // {
188 : // // for each rectangle, copy the area
189 : // const Point aTopLeft(aRegionRectanglePixel.TopLeft());
190 : // const Size aSize(aRegionRectanglePixel.GetSize());
191 :
192 : // mrOutputDevice.DrawOutDev(
193 : // aTopLeft, aSize,
194 : // aTopLeft, aSize,
195 : // maPreRenderDevice);
196 :
197 : //#ifdef DBG_UTIL
198 : // // #i74769#
199 : // static bool bDoPaintForVisualControlRegion(false);
200 : // if(bDoPaintForVisualControlRegion)
201 : // {
202 : // Color aColor((((((rand()&0x7f)|0x80)<<8L)|((rand()&0x7f)|0x80))<<8L)|((rand()&0x7f)|0x80));
203 : // mrOutputDevice.SetLineColor(aColor);
204 : // mrOutputDevice.SetFillColor();
205 : // mrOutputDevice.DrawRect(aRegionRectanglePixel);
206 : // }
207 : //#endif
208 : // }
209 :
210 : // aRegionPixel.EndEnumRects(aRegionHandle);
211 :
212 0 : mrOutputDevice.EnableMapMode(bMapModeWasEnabledDest);
213 0 : maPreRenderDevice.EnableMapMode(bMapModeWasEnabledSource);
214 0 : }
215 :
216 :
217 :
218 0 : void SdrPaintWindow::impCreateOverlayManager()
219 : {
220 : // not yet one created?
221 0 : if(!mxOverlayManager.is())
222 : {
223 : // is it a window?
224 0 : if(OUTDEV_WINDOW == GetOutputDevice().GetOutDevType())
225 : {
226 : // decide which OverlayManager to use
227 0 : if(GetPaintView().IsBufferedOverlayAllowed() && mbUseBuffer)
228 : {
229 : // buffered OverlayManager, buffers its background and refreshes from there
230 : // for pure overlay changes (no system redraw). The 3rd parameter specifies
231 : // whether that refresh itself will use a 2nd vdev to avoid flickering.
232 : // Also hand over the old OverlayManager if existent; this means to take over
233 : // the registered OverlayObjects from it
234 0 : mxOverlayManager = ::sdr::overlay::OverlayManagerBuffered::create(GetOutputDevice(), true);
235 : }
236 : else
237 : {
238 : // unbuffered OverlayManager, just invalidates places where changes
239 : // take place
240 : // Also hand over the old OverlayManager if existent; this means to take over
241 : // the registered OverlayObjects from it
242 0 : mxOverlayManager = ::sdr::overlay::OverlayManager::create(GetOutputDevice());
243 : }
244 :
245 : OSL_ENSURE(mxOverlayManager.is(), "SdrPaintWindow::SdrPaintWindow: Could not allocate an overlayManager (!)");
246 :
247 : // Request a repaint so that the buffered overlay manager fills
248 : // its buffer properly. This is a workaround for missing buffer
249 : // updates.
250 0 : Window* pWindow = dynamic_cast<Window*>(&GetOutputDevice());
251 0 : if (pWindow != NULL)
252 0 : pWindow->Invalidate();
253 :
254 0 : Color aColA(GetPaintView().getOptionsDrawinglayer().GetStripeColorA());
255 0 : Color aColB(GetPaintView().getOptionsDrawinglayer().GetStripeColorB());
256 :
257 0 : if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
258 : {
259 0 : aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor();
260 0 : aColB.Invert();
261 : }
262 :
263 0 : mxOverlayManager->setStripeColorA(aColA);
264 0 : mxOverlayManager->setStripeColorB(aColB);
265 0 : mxOverlayManager->setStripeLengthPixel(GetPaintView().getOptionsDrawinglayer().GetStripeLength());
266 : }
267 : }
268 0 : }
269 :
270 0 : SdrPaintWindow::SdrPaintWindow(SdrPaintView& rNewPaintView, OutputDevice& rOut)
271 : : mrOutputDevice(rOut),
272 : mrPaintView(rNewPaintView),
273 : mpPreRenderDevice(0L),
274 : mbTemporaryTarget(false), // #i72889#
275 0 : mbUseBuffer(true)
276 : {
277 0 : }
278 :
279 0 : SdrPaintWindow::~SdrPaintWindow()
280 : {
281 0 : mxOverlayManager.clear();
282 :
283 0 : DestroyPreRenderDevice();
284 0 : }
285 :
286 0 : rtl::Reference< ::sdr::overlay::OverlayManager > SdrPaintWindow::GetOverlayManager() const
287 : {
288 0 : if(!mxOverlayManager.is())
289 : {
290 : // Create buffered overlay manager by default.
291 0 : const_cast< SdrPaintWindow* >(this)->impCreateOverlayManager();
292 : }
293 :
294 0 : return mxOverlayManager;
295 : }
296 :
297 0 : Rectangle SdrPaintWindow::GetVisibleArea() const
298 : {
299 0 : Size aVisSizePixel(GetOutputDevice().GetOutputSizePixel());
300 0 : return Rectangle(GetOutputDevice().PixelToLogic(Rectangle(Point(0,0), aVisSizePixel)));
301 : }
302 :
303 0 : bool SdrPaintWindow::OutputToRecordingMetaFile() const
304 : {
305 0 : GDIMetaFile* pMetaFile = mrOutputDevice.GetConnectMetaFile();
306 0 : return (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
307 : }
308 :
309 0 : void SdrPaintWindow::PreparePreRenderDevice()
310 : {
311 : const bool bPrepareBufferedOutput(
312 0 : mrPaintView.IsBufferedOutputAllowed()
313 0 : && !OutputToPrinter()
314 0 : && !OutputToVirtualDevice()
315 0 : && !OutputToRecordingMetaFile());
316 :
317 0 : if(bPrepareBufferedOutput)
318 : {
319 0 : if(!mpPreRenderDevice)
320 : {
321 0 : mpPreRenderDevice = new SdrPreRenderDevice(mrOutputDevice);
322 : }
323 : }
324 : else
325 : {
326 0 : DestroyPreRenderDevice();
327 : }
328 :
329 0 : if(mpPreRenderDevice)
330 : {
331 0 : mpPreRenderDevice->PreparePreRenderDevice();
332 : }
333 0 : }
334 :
335 0 : void SdrPaintWindow::DestroyPreRenderDevice()
336 : {
337 0 : if(mpPreRenderDevice)
338 : {
339 0 : delete mpPreRenderDevice;
340 0 : mpPreRenderDevice = 0L;
341 : }
342 0 : }
343 :
344 0 : void SdrPaintWindow::OutputPreRenderDevice(const Region& rExpandedRegion)
345 : {
346 0 : if(mpPreRenderDevice)
347 : {
348 0 : mpPreRenderDevice->OutputPreRenderDevice(rExpandedRegion);
349 : }
350 0 : }
351 :
352 : // #i73602# add flag if buffer shall be used
353 0 : void SdrPaintWindow::DrawOverlay(const Region& rRegion)
354 : {
355 : // ## force creation of OverlayManager since the first repaint needs to
356 : // save the background to get a controlled start into overlay mechanism
357 0 : impCreateOverlayManager();
358 :
359 0 : if(mxOverlayManager.is() && !OutputToPrinter())
360 : {
361 0 : if(mpPreRenderDevice)
362 : {
363 0 : mxOverlayManager->completeRedraw(rRegion, &mpPreRenderDevice->GetPreRenderDevice());
364 : }
365 : else
366 : {
367 0 : mxOverlayManager->completeRedraw(rRegion);
368 : }
369 : }
370 0 : }
371 :
372 0 : const Region& SdrPaintWindow::GetRedrawRegion() const
373 : {
374 0 : return maRedrawRegion;
375 : }
376 :
377 0 : void SdrPaintWindow::SetRedrawRegion(const Region& rNew)
378 : {
379 0 : maRedrawRegion = rNew;
380 0 : }
381 :
382 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|