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