bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / slidesorter / view / SlsLayeredDevice.cxx
blobd22f5cf801ac8477e48dfc54556f18e616359a38
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "SlsLayeredDevice.hxx"
22 #include <vcl/window.hxx>
23 #include <vcl/virdev.hxx>
25 #include <boost/bind.hpp>
26 #include <boost/function.hpp>
28 #include <tools/gen.hxx>
29 #include <tools/fract.hxx>
31 namespace sd { namespace slidesorter { namespace view {
33 namespace {
34 static const sal_Int32 gnMaximumLayerCount = 8;
36 class LayerInvalidator : public ILayerInvalidator
38 public:
39 LayerInvalidator (
40 const ::boost::shared_ptr<LayeredDevice>& rpLayeredDevice,
41 sd::Window *pTargetWindow,
42 const int nLayer)
43 : mpLayeredDevice(rpLayeredDevice),
44 mpTargetWindow(pTargetWindow),
45 mnLayer(nLayer)
49 virtual ~LayerInvalidator ( )
53 virtual void Invalidate (const Rectangle& rInvalidationBox) SAL_OVERRIDE
55 mpLayeredDevice->Invalidate(rInvalidationBox, mnLayer);
56 mpTargetWindow->Invalidate(rInvalidationBox);
59 private:
60 const ::boost::shared_ptr<LayeredDevice> mpLayeredDevice;
61 VclPtr<sd::Window> mpTargetWindow;
62 const int mnLayer;
65 void DeviceCopy (
66 vcl::RenderContext& rTargetDevice,
67 vcl::RenderContext& rSourceDevice,
68 const Rectangle& rBox)
70 rTargetDevice.DrawOutDev(
71 rBox.TopLeft(),
72 rBox.GetSize(),
73 rBox.TopLeft(),
74 rBox.GetSize(),
75 rSourceDevice);
78 void ForAllRectangles (const vcl::Region& rRegion, ::boost::function<void(const Rectangle&)> aFunction)
80 OSL_ASSERT(aFunction);
81 RectangleVector aRectangles;
82 rRegion.GetRegionRectangles(aRectangles);
84 if(0 == aRectangles.size())
86 aFunction(Rectangle());
88 else
90 for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
92 aFunction(*aRectIter);
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);
104 class Layer : private ::boost::noncopyable
106 public:
107 Layer();
108 ~Layer();
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();
123 private:
124 ScopedVclPtr<VirtualDevice> mpLayerDevice;
125 ::std::vector<SharedILayerPainter> maPainters;
126 vcl::Region maInvalidationRegion;
128 void ValidateRectangle (const Rectangle& rBox);
130 typedef ::boost::shared_ptr<Layer> SharedLayer;
132 } // end of anonymous namespace
134 class LayeredDevice::LayerContainer
136 public:
137 LayerContainer() : mvLayers() {}
139 bool empty() const { return mvLayers.empty(); }
141 size_t size() const { return mvLayers.size(); }
143 const SharedLayer& back() const { return mvLayers.back(); }
145 const ::std::vector<SharedLayer>::const_iterator begin() const { return mvLayers.begin(); }
146 const ::std::vector<SharedLayer>::const_iterator end() const { return mvLayers.end(); }
148 void clear() { mvLayers.clear(); }
150 void pop_back() { mvLayers.pop_back(); }
152 void resize(size_t n) { mvLayers.resize(n); }
154 SharedLayer& operator[](size_t i) { return mvLayers[i]; }
156 private:
157 ::std::vector<SharedLayer> mvLayers;
160 //===== LayeredDevice =========================================================
162 LayeredDevice::LayeredDevice (VclPtr<sd::Window> pTargetWindow)
163 : mpTargetWindow(pTargetWindow),
164 mpLayers(new LayerContainer()),
165 mpBackBuffer(VclPtr<VirtualDevice>::Create(*mpTargetWindow)),
166 maSavedMapMode(pTargetWindow->GetMapMode())
168 mpBackBuffer->SetOutputSizePixel(mpTargetWindow->GetSizePixel());
171 LayeredDevice::~LayeredDevice()
175 void LayeredDevice::Invalidate (
176 const Rectangle& rInvalidationArea,
177 const sal_Int32 nLayer)
179 if (nLayer<0 || size_t(nLayer)>=mpLayers->size())
181 OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size());
182 return;
185 (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea);
188 void LayeredDevice::InvalidateAllLayers (const Rectangle& rInvalidationArea)
190 for (sal_uInt32 nLayer=0; nLayer<mpLayers->size(); ++nLayer)
191 (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea);
194 void LayeredDevice::InvalidateAllLayers (const vcl::Region& rInvalidationRegion)
196 for (sal_uInt32 nLayer=0; nLayer<mpLayers->size(); ++nLayer)
197 (*mpLayers)[nLayer]->InvalidateRegion(rInvalidationRegion);
200 void LayeredDevice::RegisterPainter (
201 const SharedILayerPainter& rpPainter,
202 const sal_Int32 nLayer)
204 OSL_ASSERT(mpLayers);
205 if ( ! rpPainter)
207 OSL_ASSERT(rpPainter);
208 return;
210 if (nLayer<0 || nLayer>=gnMaximumLayerCount)
212 OSL_ASSERT(nLayer>=0 && nLayer<gnMaximumLayerCount);
213 return;
216 // Provide the layers.
217 if (sal_uInt32(nLayer) >= mpLayers->size())
219 const sal_Int32 nOldLayerCount (mpLayers->size());
220 mpLayers->resize(nLayer+1);
222 for (size_t nIndex=nOldLayerCount; nIndex<mpLayers->size(); ++nIndex)
223 (*mpLayers)[nIndex].reset(new Layer());
226 (*mpLayers)[nLayer]->AddPainter(rpPainter);
227 if (nLayer == 0)
228 (*mpLayers)[nLayer]->Initialize(mpTargetWindow);
230 rpPainter->SetLayerInvalidator(
231 SharedILayerInvalidator(new LayerInvalidator(shared_from_this(),mpTargetWindow,nLayer)));
234 void LayeredDevice::RemovePainter (
235 const SharedILayerPainter& rpPainter,
236 const sal_Int32 nLayer)
238 if ( ! rpPainter)
240 OSL_ASSERT(rpPainter);
241 return;
243 if (nLayer<0 || size_t(nLayer)>=mpLayers->size())
245 OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size());
246 return;
249 rpPainter->SetLayerInvalidator(SharedILayerInvalidator());
251 (*mpLayers)[nLayer]->RemovePainter(rpPainter);
253 // Remove top most layers that do not contain any painters.
254 while ( ! mpLayers->empty() && ! mpLayers->back()->HasPainter())
255 mpLayers->pop_back();
258 void LayeredDevice::Repaint (const vcl::Region& rRepaintRegion)
260 // Validate the contents of all layers (that have their own devices.)
261 ::std::for_each(
262 mpLayers->begin(),
263 mpLayers->end(),
264 ::boost::bind(&Layer::Validate, _1, mpTargetWindow->GetMapMode()));
266 ForAllRectangles(rRepaintRegion, ::boost::bind(&LayeredDevice::RepaintRectangle, this, _1));
269 void LayeredDevice::RepaintRectangle (const Rectangle& rRepaintRectangle)
271 if (mpLayers->empty())
272 return;
273 else if (mpLayers->size() == 1)
275 // Just copy the main layer into the target device.
276 (*mpLayers)[0]->Repaint(*mpTargetWindow, rRepaintRectangle);
278 else
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 mpBackBuffer->SetMapMode(mpTargetWindow->GetMapMode());
284 ::std::for_each(
285 mpLayers->begin(),
286 mpLayers->end(),
287 ::boost::bind(&Layer::Repaint, _1, ::boost::ref(*mpBackBuffer), rRepaintRectangle));
289 DeviceCopy(*mpTargetWindow, *mpBackBuffer, rRepaintRectangle);
293 void LayeredDevice::Resize()
295 const Size aSize (mpTargetWindow->GetSizePixel());
296 mpBackBuffer->SetOutputSizePixel(aSize);
297 ::std::for_each(mpLayers->begin(), mpLayers->end(), ::boost::bind(&Layer::Resize, _1, aSize));
300 void LayeredDevice::Dispose()
302 ::std::for_each(mpLayers->begin(), mpLayers->end(), ::boost::bind(&Layer::Dispose, _1));
303 mpLayers->clear();
306 bool LayeredDevice::HandleMapModeChange()
308 const MapMode& rMapMode (mpTargetWindow->GetMapMode());
309 if (maSavedMapMode == rMapMode)
310 return false;
312 const Rectangle aLogicWindowBox (
313 mpTargetWindow->PixelToLogic(Rectangle(Point(0,0), mpTargetWindow->GetSizePixel())));
314 if (maSavedMapMode.GetScaleX() != rMapMode.GetScaleX()
315 || maSavedMapMode.GetScaleY() != rMapMode.GetScaleY()
316 || maSavedMapMode.GetMapUnit() != rMapMode.GetMapUnit())
318 // When the scale has changed then we have to paint everything.
319 InvalidateAllLayers(aLogicWindowBox);
321 else if (maSavedMapMode.GetOrigin() != rMapMode.GetOrigin())
323 // Window has been scrolled. Adapt contents of backbuffers and
324 // layer devices.
325 const Point aDelta (rMapMode.GetOrigin() - maSavedMapMode.GetOrigin());
326 mpBackBuffer->CopyArea(
327 aLogicWindowBox.TopLeft(),
328 mpTargetWindow->PixelToLogic(Point(0,0), maSavedMapMode),
329 aLogicWindowBox.GetSize());
331 // Invalidate the area(s) that have been exposed.
332 const Rectangle aWindowBox (Point(0,0), mpTargetWindow->GetSizePixel());
333 if (aDelta.Y() < 0)
334 InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle(
335 aWindowBox.Left(),
336 aWindowBox.Bottom()+aDelta.Y(),
337 aWindowBox.Right(),
338 aWindowBox.Bottom())));
339 else if (aDelta.Y() > 0)
340 InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle(
341 aWindowBox.Left(),
342 aWindowBox.Top(),
343 aWindowBox.Right(),
344 aWindowBox.Top()+aDelta.Y())));
345 if (aDelta.X() < 0)
346 InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle(
347 aWindowBox.Right()+aDelta.X(),
348 aWindowBox.Top(),
349 aWindowBox.Right(),
350 aWindowBox.Bottom())));
351 else if (aDelta.X() > 0)
352 InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle(
353 aWindowBox.Left(),
354 aWindowBox.Top(),
355 aWindowBox.Left()+aDelta.X(),
356 aWindowBox.Bottom())));
358 else
360 // Can this happen? Lets trigger a warning when it does.
361 OSL_ASSERT(false);
364 maSavedMapMode = rMapMode;
366 return true;
369 //===== Layer =================================================================
371 Layer::Layer()
372 : mpLayerDevice(),
373 maPainters(),
374 maInvalidationRegion()
378 Layer::~Layer()
382 void Layer::Initialize (sd::Window *pTargetWindow)
384 #if 0
385 (void)pTargetWindow;
386 #else
387 if ( ! mpLayerDevice)
389 mpLayerDevice.reset(VclPtr<VirtualDevice>::Create(*pTargetWindow));
390 mpLayerDevice->SetOutputSizePixel(pTargetWindow->GetSizePixel());
392 #endif
395 void Layer::InvalidateRectangle (const Rectangle& rInvalidationBox)
397 maInvalidationRegion.Union(rInvalidationBox);
400 void Layer::InvalidateRegion (const vcl::Region& rInvalidationRegion)
402 maInvalidationRegion.Union(rInvalidationRegion);
405 void Layer::Validate (const MapMode& rMapMode)
407 if (mpLayerDevice && ! maInvalidationRegion.IsEmpty())
409 vcl::Region aRegion (maInvalidationRegion);
410 maInvalidationRegion.SetEmpty();
412 mpLayerDevice->SetMapMode(rMapMode);
413 ForAllRectangles(
414 aRegion,
415 ::boost::bind(&Layer::ValidateRectangle, this, _1));
419 void Layer::ValidateRectangle (const Rectangle& rBox)
421 if ( ! mpLayerDevice)
422 return;
423 const vcl::Region aSavedClipRegion (mpLayerDevice->GetClipRegion());
424 mpLayerDevice->IntersectClipRegion(rBox);
426 for (::std::vector<SharedILayerPainter>::const_iterator
427 iPainter(maPainters.begin()),
428 iEnd(maPainters.end());
429 iPainter!=iEnd;
430 ++iPainter)
432 (*iPainter)->Paint(*mpLayerDevice, rBox);
435 mpLayerDevice->SetClipRegion(aSavedClipRegion);
438 void Layer::Repaint (
439 OutputDevice& rTargetDevice,
440 const Rectangle& rRepaintRectangle)
442 if (mpLayerDevice)
444 DeviceCopy(rTargetDevice, *mpLayerDevice, rRepaintRectangle);
446 else
448 ::std::for_each(
449 maPainters.begin(),
450 maPainters.end(),
451 ::boost::bind(&ILayerPainter::Paint,
453 ::boost::ref(rTargetDevice),
454 rRepaintRectangle));
458 void Layer::Resize (const Size& rSize)
460 if (mpLayerDevice)
462 mpLayerDevice->SetOutputSizePixel(rSize);
463 maInvalidationRegion = Rectangle(Point(0,0), rSize);
467 void Layer::AddPainter (const SharedILayerPainter& rpPainter)
469 OSL_ASSERT(::std::find(maPainters.begin(), maPainters.end(), rpPainter) == maPainters.end());
471 maPainters.push_back(rpPainter);
474 void Layer::RemovePainter (const SharedILayerPainter& rpPainter)
476 const ::std::vector<SharedILayerPainter>::iterator iPainter (
477 ::std::find(maPainters.begin(), maPainters.end(), rpPainter));
478 if (iPainter != maPainters.end())
480 maPainters.erase(iPainter);
482 else
484 DBG_ASSERT(false,"LayeredDevice::RemovePainter called for painter that is not registered");
488 bool Layer::HasPainter() const
490 return !maPainters.empty();
493 void Layer::Dispose()
495 maPainters.clear();
498 } } } // end of namespace ::sd::slidesorter::view
500 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */