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 "SlsLayeredDevice.hxx"
21 :
22 : #include <vcl/window.hxx>
23 : #include <vcl/virdev.hxx>
24 :
25 : #include <boost/bind.hpp>
26 : #include <boost/function.hpp>
27 :
28 : #include <tools/gen.hxx>
29 :
30 : namespace sd { namespace slidesorter { namespace view {
31 :
32 : namespace {
33 : static const sal_Int32 gnMaximumLayerCount = 8;
34 :
35 : class LayerInvalidator : public ILayerInvalidator
36 : {
37 : public:
38 252 : LayerInvalidator (
39 : const ::boost::shared_ptr<LayeredDevice>& rpLayeredDevice,
40 : const SharedSdWindow& rpTargetWindow,
41 : const int nLayer)
42 : : mpLayeredDevice(rpLayeredDevice),
43 : mpTargetWindow(rpTargetWindow),
44 252 : mnLayer(nLayer)
45 : {
46 252 : }
47 :
48 504 : virtual ~LayerInvalidator ( )
49 252 : {
50 504 : }
51 :
52 0 : virtual void Invalidate (const Rectangle& rInvalidationBox) SAL_OVERRIDE
53 : {
54 0 : mpLayeredDevice->Invalidate(rInvalidationBox, mnLayer);
55 0 : mpTargetWindow->Invalidate(rInvalidationBox);
56 0 : }
57 :
58 : private:
59 : const ::boost::shared_ptr<LayeredDevice> mpLayeredDevice;
60 : SharedSdWindow mpTargetWindow;
61 : const int mnLayer;
62 : };
63 :
64 431 : void DeviceCopy (
65 : OutputDevice& rTargetDevice,
66 : OutputDevice& rSourceDevice,
67 : const Rectangle& rBox)
68 : {
69 : rTargetDevice.DrawOutDev(
70 : rBox.TopLeft(),
71 : rBox.GetSize(),
72 : rBox.TopLeft(),
73 : rBox.GetSize(),
74 431 : rSourceDevice);
75 431 : }
76 :
77 431 : void ForAllRectangles (const vcl::Region& rRegion, ::boost::function<void(const Rectangle&)> aFunction)
78 : {
79 : OSL_ASSERT(aFunction);
80 431 : RectangleVector aRectangles;
81 431 : rRegion.GetRegionRectangles(aRectangles);
82 :
83 431 : if(0 == aRectangles.size())
84 : {
85 0 : aFunction(Rectangle());
86 : }
87 : else
88 : {
89 862 : for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
90 : {
91 431 : aFunction(*aRectIter);
92 : }
93 :
94 : //Region aMutableRegionCopy (rRegion);
95 : //RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects());
96 : //Rectangle aBox;
97 : //while (aMutableRegionCopy.GetEnumRects(aHandle, aBox))
98 : // aFunction(aBox);
99 : //aMutableRegionCopy.EndEnumRects(aHandle);
100 431 : }
101 431 : }
102 :
103 : class Layer : private ::boost::noncopyable
104 : {
105 : public:
106 : Layer (void);
107 : ~Layer (void);
108 :
109 : void Initialize (const SharedSdWindow& rpTargetWindow);
110 : void InvalidateRectangle (const Rectangle& rInvalidationBox);
111 : void InvalidateRegion (const vcl::Region& rInvalidationRegion);
112 : void Validate (const MapMode& rMapMode);
113 : void Repaint (
114 : OutputDevice& rTargetDevice,
115 : const Rectangle& rRepaintRectangle);
116 : void Resize (const Size& rSize);
117 : void AddPainter (const SharedILayerPainter& rpPainter);
118 : void RemovePainter (const SharedILayerPainter& rpPainter);
119 : bool HasPainter (void) const;
120 : void Dispose (void);
121 :
122 : private:
123 : ::boost::shared_ptr<VirtualDevice> mpLayerDevice;
124 : ::std::vector<SharedILayerPainter> maPainters;
125 : vcl::Region maInvalidationRegion;
126 :
127 : void ValidateRectangle (const Rectangle& rBox);
128 : };
129 : typedef ::boost::shared_ptr<Layer> SharedLayer;
130 :
131 : } // end of anonymous namespace
132 :
133 126 : class LayeredDevice::LayerContainer
134 : {
135 : public:
136 126 : LayerContainer() : mvLayers() {}
137 :
138 431 : bool empty() const { return mvLayers.empty(); }
139 :
140 5237 : size_t size() const { return mvLayers.size(); }
141 :
142 0 : const SharedLayer& back() const { return mvLayers.back(); }
143 :
144 1234 : const ::std::vector<SharedLayer>::const_iterator begin() const { return mvLayers.begin(); }
145 1234 : const ::std::vector<SharedLayer>::const_iterator end() const { return mvLayers.end(); }
146 :
147 126 : void clear() { mvLayers.clear(); }
148 :
149 0 : void pop_back() { mvLayers.pop_back(); }
150 :
151 126 : void resize(size_t n) { mvLayers.resize(n); }
152 :
153 3204 : SharedLayer& operator[](size_t i) { return mvLayers[i]; }
154 :
155 : private:
156 : ::std::vector<SharedLayer> mvLayers;
157 : };
158 :
159 : //===== LayeredDevice =========================================================
160 :
161 126 : LayeredDevice::LayeredDevice (const SharedSdWindow& rpTargetWindow)
162 : : mpTargetWindow(rpTargetWindow),
163 : mpLayers(new LayerContainer()),
164 252 : mpBackBuffer(new VirtualDevice(*mpTargetWindow)),
165 378 : maSavedMapMode(rpTargetWindow->GetMapMode())
166 : {
167 126 : mpBackBuffer->SetOutputSizePixel(mpTargetWindow->GetSizePixel());
168 126 : }
169 :
170 126 : LayeredDevice::~LayeredDevice (void)
171 : {
172 126 : }
173 :
174 0 : void LayeredDevice::Invalidate (
175 : const Rectangle& rInvalidationArea,
176 : const sal_Int32 nLayer)
177 : {
178 0 : if (nLayer<0 || size_t(nLayer)>=mpLayers->size())
179 : {
180 : OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size());
181 0 : return;
182 : }
183 :
184 0 : (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea);
185 : }
186 :
187 1350 : void LayeredDevice::InvalidateAllLayers (const Rectangle& rInvalidationArea)
188 : {
189 4050 : for (sal_uInt32 nLayer=0; nLayer<mpLayers->size(); ++nLayer)
190 2700 : (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea);
191 1350 : }
192 :
193 0 : void LayeredDevice::InvalidateAllLayers (const vcl::Region& rInvalidationRegion)
194 : {
195 0 : for (sal_uInt32 nLayer=0; nLayer<mpLayers->size(); ++nLayer)
196 0 : (*mpLayers)[nLayer]->InvalidateRegion(rInvalidationRegion);
197 0 : }
198 :
199 252 : void LayeredDevice::RegisterPainter (
200 : const SharedILayerPainter& rpPainter,
201 : const sal_Int32 nLayer)
202 : {
203 : OSL_ASSERT(mpLayers);
204 252 : if ( ! rpPainter)
205 : {
206 : OSL_ASSERT(rpPainter);
207 0 : return;
208 : }
209 252 : if (nLayer<0 || nLayer>=gnMaximumLayerCount)
210 : {
211 : OSL_ASSERT(nLayer>=0 && nLayer<gnMaximumLayerCount);
212 0 : return;
213 : }
214 :
215 : // Provide the layers.
216 252 : if (sal_uInt32(nLayer) >= mpLayers->size())
217 : {
218 126 : const sal_Int32 nOldLayerCount (mpLayers->size());
219 126 : mpLayers->resize(nLayer+1);
220 :
221 378 : for (size_t nIndex=nOldLayerCount; nIndex<mpLayers->size(); ++nIndex)
222 252 : (*mpLayers)[nIndex].reset(new Layer());
223 : }
224 :
225 252 : (*mpLayers)[nLayer]->AddPainter(rpPainter);
226 252 : if (nLayer == 0)
227 0 : (*mpLayers)[nLayer]->Initialize(mpTargetWindow);
228 :
229 252 : rpPainter->SetLayerInvalidator(
230 252 : SharedILayerInvalidator(new LayerInvalidator(shared_from_this(),mpTargetWindow,nLayer)));
231 : }
232 :
233 0 : void LayeredDevice::RemovePainter (
234 : const SharedILayerPainter& rpPainter,
235 : const sal_Int32 nLayer)
236 : {
237 0 : if ( ! rpPainter)
238 : {
239 : OSL_ASSERT(rpPainter);
240 0 : return;
241 : }
242 0 : if (nLayer<0 || size_t(nLayer)>=mpLayers->size())
243 : {
244 : OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size());
245 0 : return;
246 : }
247 :
248 0 : rpPainter->SetLayerInvalidator(SharedILayerInvalidator());
249 :
250 0 : (*mpLayers)[nLayer]->RemovePainter(rpPainter);
251 :
252 : // Remove top most layers that do not contain any painters.
253 0 : while ( ! mpLayers->empty() && ! mpLayers->back()->HasPainter())
254 0 : mpLayers->pop_back();
255 : }
256 :
257 431 : void LayeredDevice::Repaint (const vcl::Region& rRepaintRegion)
258 : {
259 : // Validate the contents of all layers (that have their own devices.)
260 : ::std::for_each(
261 : mpLayers->begin(),
262 : mpLayers->end(),
263 431 : ::boost::bind(&Layer::Validate, _1, mpTargetWindow->GetMapMode()));
264 :
265 431 : ForAllRectangles(rRepaintRegion, ::boost::bind(&LayeredDevice::RepaintRectangle, this, _1));
266 431 : }
267 :
268 431 : void LayeredDevice::RepaintRectangle (const Rectangle& rRepaintRectangle)
269 : {
270 431 : if (mpLayers->empty())
271 431 : return;
272 431 : else if (mpLayers->size() == 1)
273 : {
274 : // Just copy the main layer into the target device.
275 0 : (*mpLayers)[0]->Repaint(*mpTargetWindow, rRepaintRectangle);
276 : }
277 : else
278 : {
279 : // Paint all layers first into the back buffer (to avoid flickering
280 : // due to synchronous paints) and then copy that into the target
281 : // device.
282 431 : mpBackBuffer->SetMapMode(mpTargetWindow->GetMapMode());
283 : ::std::for_each(
284 : mpLayers->begin(),
285 : mpLayers->end(),
286 431 : ::boost::bind(&Layer::Repaint, _1, ::boost::ref(*mpBackBuffer), rRepaintRectangle));
287 :
288 431 : DeviceCopy(*mpTargetWindow, *mpBackBuffer, rRepaintRectangle);
289 : }
290 : }
291 :
292 246 : void LayeredDevice::Resize (void)
293 : {
294 246 : const Size aSize (mpTargetWindow->GetSizePixel());
295 246 : mpBackBuffer->SetOutputSizePixel(aSize);
296 246 : ::std::for_each(mpLayers->begin(), mpLayers->end(), ::boost::bind(&Layer::Resize, _1, aSize));
297 246 : }
298 :
299 126 : void LayeredDevice::Dispose (void)
300 : {
301 126 : ::std::for_each(mpLayers->begin(), mpLayers->end(), ::boost::bind(&Layer::Dispose, _1));
302 126 : mpLayers->clear();
303 126 : }
304 :
305 431 : bool LayeredDevice::HandleMapModeChange (void)
306 : {
307 431 : const MapMode& rMapMode (mpTargetWindow->GetMapMode());
308 431 : if (maSavedMapMode == rMapMode)
309 322 : return false;
310 :
311 : const Rectangle aLogicWindowBox (
312 109 : mpTargetWindow->PixelToLogic(Rectangle(Point(0,0), mpTargetWindow->GetSizePixel())));
313 218 : if (maSavedMapMode.GetScaleX() != rMapMode.GetScaleX()
314 109 : || maSavedMapMode.GetScaleY() != rMapMode.GetScaleY()
315 218 : || maSavedMapMode.GetMapUnit() != rMapMode.GetMapUnit())
316 : {
317 : // When the scale has changed then we have to paint everything.
318 109 : InvalidateAllLayers(aLogicWindowBox);
319 : }
320 0 : else if (maSavedMapMode.GetOrigin() != rMapMode.GetOrigin())
321 : {
322 : // Window has been scrolled. Adapt contents of backbuffers and
323 : // layer devices.
324 0 : const Point aDelta (rMapMode.GetOrigin() - maSavedMapMode.GetOrigin());
325 0 : mpBackBuffer->CopyArea(
326 : aLogicWindowBox.TopLeft(),
327 0 : mpTargetWindow->PixelToLogic(Point(0,0), maSavedMapMode),
328 0 : aLogicWindowBox.GetSize());
329 :
330 : // Invalidate the area(s) that have been exposed.
331 0 : const Rectangle aWindowBox (Point(0,0), mpTargetWindow->GetSizePixel());
332 0 : if (aDelta.Y() < 0)
333 0 : InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle(
334 : aWindowBox.Left(),
335 0 : aWindowBox.Bottom()+aDelta.Y(),
336 : aWindowBox.Right(),
337 0 : aWindowBox.Bottom())));
338 0 : else if (aDelta.Y() > 0)
339 0 : InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle(
340 : aWindowBox.Left(),
341 : aWindowBox.Top(),
342 : aWindowBox.Right(),
343 0 : aWindowBox.Top()+aDelta.Y())));
344 0 : if (aDelta.X() < 0)
345 0 : InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle(
346 0 : aWindowBox.Right()+aDelta.X(),
347 : aWindowBox.Top(),
348 : aWindowBox.Right(),
349 0 : aWindowBox.Bottom())));
350 0 : else if (aDelta.X() > 0)
351 0 : InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle(
352 : aWindowBox.Left(),
353 : aWindowBox.Top(),
354 0 : aWindowBox.Left()+aDelta.X(),
355 0 : aWindowBox.Bottom())));
356 : }
357 : else
358 : {
359 : // Can this happen? Lets trigger a warning when it does.
360 : OSL_ASSERT(false);
361 : }
362 :
363 109 : maSavedMapMode = rMapMode;
364 :
365 109 : return true;
366 : }
367 :
368 : //===== Layer =================================================================
369 :
370 252 : Layer::Layer (void)
371 : : mpLayerDevice(),
372 : maPainters(),
373 252 : maInvalidationRegion()
374 : {
375 252 : }
376 :
377 252 : Layer::~Layer (void)
378 : {
379 252 : }
380 :
381 0 : void Layer::Initialize (const SharedSdWindow& rpTargetWindow)
382 : {
383 : #if 0
384 : (void)rpTargetWindow;
385 : #else
386 0 : if ( ! mpLayerDevice)
387 : {
388 0 : mpLayerDevice.reset(new VirtualDevice(*rpTargetWindow));
389 0 : mpLayerDevice->SetOutputSizePixel(rpTargetWindow->GetSizePixel());
390 : }
391 : #endif
392 0 : }
393 :
394 2700 : void Layer::InvalidateRectangle (const Rectangle& rInvalidationBox)
395 : {
396 2700 : maInvalidationRegion.Union(rInvalidationBox);
397 2700 : }
398 :
399 0 : void Layer::InvalidateRegion (const vcl::Region& rInvalidationRegion)
400 : {
401 0 : maInvalidationRegion.Union(rInvalidationRegion);
402 0 : }
403 :
404 862 : void Layer::Validate (const MapMode& rMapMode)
405 : {
406 862 : if (mpLayerDevice && ! maInvalidationRegion.IsEmpty())
407 : {
408 0 : vcl::Region aRegion (maInvalidationRegion);
409 0 : maInvalidationRegion.SetEmpty();
410 :
411 0 : mpLayerDevice->SetMapMode(rMapMode);
412 : ForAllRectangles(
413 : aRegion,
414 0 : ::boost::bind(&Layer::ValidateRectangle, this, _1));
415 : }
416 862 : }
417 :
418 0 : void Layer::ValidateRectangle (const Rectangle& rBox)
419 : {
420 0 : if ( ! mpLayerDevice)
421 0 : return;
422 0 : const vcl::Region aSavedClipRegion (mpLayerDevice->GetClipRegion());
423 0 : mpLayerDevice->IntersectClipRegion(rBox);
424 :
425 0 : for (::std::vector<SharedILayerPainter>::const_iterator
426 0 : iPainter(maPainters.begin()),
427 0 : iEnd(maPainters.end());
428 : iPainter!=iEnd;
429 : ++iPainter)
430 : {
431 0 : (*iPainter)->Paint(*mpLayerDevice, rBox);
432 : }
433 :
434 0 : mpLayerDevice->SetClipRegion(aSavedClipRegion);
435 : }
436 :
437 862 : void Layer::Repaint (
438 : OutputDevice& rTargetDevice,
439 : const Rectangle& rRepaintRectangle)
440 : {
441 862 : if (mpLayerDevice)
442 : {
443 0 : DeviceCopy(rTargetDevice, *mpLayerDevice, rRepaintRectangle);
444 : }
445 : else
446 : {
447 : ::std::for_each(
448 : maPainters.begin(),
449 : maPainters.end(),
450 : ::boost::bind(&ILayerPainter::Paint,
451 : _1,
452 : ::boost::ref(rTargetDevice),
453 862 : rRepaintRectangle));
454 : }
455 862 : }
456 :
457 492 : void Layer::Resize (const Size& rSize)
458 : {
459 492 : if (mpLayerDevice)
460 : {
461 0 : mpLayerDevice->SetOutputSizePixel(rSize);
462 0 : maInvalidationRegion = Rectangle(Point(0,0), rSize);
463 : }
464 492 : }
465 :
466 252 : void Layer::AddPainter (const SharedILayerPainter& rpPainter)
467 : {
468 : OSL_ASSERT(::std::find(maPainters.begin(), maPainters.end(), rpPainter) == maPainters.end());
469 :
470 252 : maPainters.push_back(rpPainter);
471 252 : }
472 :
473 0 : void Layer::RemovePainter (const SharedILayerPainter& rpPainter)
474 : {
475 : const ::std::vector<SharedILayerPainter>::iterator iPainter (
476 0 : ::std::find(maPainters.begin(), maPainters.end(), rpPainter));
477 0 : if (iPainter != maPainters.end())
478 : {
479 0 : maPainters.erase(iPainter);
480 : }
481 : else
482 : {
483 : DBG_ASSERT(false,"LayeredDevice::RemovePainter called for painter that is not registered");
484 : }
485 0 : }
486 :
487 0 : bool Layer::HasPainter (void) const
488 : {
489 0 : return !maPainters.empty();
490 : }
491 :
492 252 : void Layer::Dispose (void)
493 : {
494 252 : maPainters.clear();
495 252 : }
496 :
497 114 : } } } // end of namespace ::sd::slidesorter::view
498 :
499 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|