1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
{
34 static const sal_Int32 gnMaximumLayerCount
= 8;
36 class LayerInvalidator
: public ILayerInvalidator
40 const ::boost::shared_ptr
<LayeredDevice
>& rpLayeredDevice
,
41 sd::Window
*pTargetWindow
,
43 : mpLayeredDevice(rpLayeredDevice
),
44 mpTargetWindow(pTargetWindow
),
49 virtual ~LayerInvalidator ( )
53 virtual void Invalidate (const Rectangle
& rInvalidationBox
) SAL_OVERRIDE
55 mpLayeredDevice
->Invalidate(rInvalidationBox
, mnLayer
);
56 mpTargetWindow
->Invalidate(rInvalidationBox
);
60 const ::boost::shared_ptr
<LayeredDevice
> mpLayeredDevice
;
61 VclPtr
<sd::Window
> mpTargetWindow
;
66 vcl::RenderContext
& rTargetDevice
,
67 vcl::RenderContext
& rSourceDevice
,
68 const Rectangle
& rBox
)
70 rTargetDevice
.DrawOutDev(
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());
90 for(RectangleVector::const_iterator
aRectIter(aRectangles
.begin()); aRectIter
!= aRectangles
.end(); ++aRectIter
)
92 aFunction(*aRectIter
);
95 //Region aMutableRegionCopy (rRegion);
96 //RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects());
98 //while (aMutableRegionCopy.GetEnumRects(aHandle, aBox))
100 //aMutableRegionCopy.EndEnumRects(aHandle);
104 class Layer
: private ::boost::noncopyable
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
);
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;
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
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
]; }
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());
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
);
207 OSL_ASSERT(rpPainter
);
210 if (nLayer
<0 || nLayer
>=gnMaximumLayerCount
)
212 OSL_ASSERT(nLayer
>=0 && nLayer
<gnMaximumLayerCount
);
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
);
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
)
240 OSL_ASSERT(rpPainter
);
243 if (nLayer
<0 || size_t(nLayer
)>=mpLayers
->size())
245 OSL_ASSERT(nLayer
>=0 && size_t(nLayer
)<mpLayers
->size());
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.)
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())
273 else if (mpLayers
->size() == 1)
275 // Just copy the main layer into the target device.
276 (*mpLayers
)[0]->Repaint(*mpTargetWindow
, rRepaintRectangle
);
280 // Paint all layers first into the back buffer (to avoid flickering
281 // due to synchronous paints) and then copy that into the target
283 mpBackBuffer
->SetMapMode(mpTargetWindow
->GetMapMode());
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
));
306 bool LayeredDevice::HandleMapModeChange()
308 const MapMode
& rMapMode (mpTargetWindow
->GetMapMode());
309 if (maSavedMapMode
== rMapMode
)
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
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());
334 InvalidateAllLayers(mpTargetWindow
->PixelToLogic(Rectangle(
336 aWindowBox
.Bottom()+aDelta
.Y(),
338 aWindowBox
.Bottom())));
339 else if (aDelta
.Y() > 0)
340 InvalidateAllLayers(mpTargetWindow
->PixelToLogic(Rectangle(
344 aWindowBox
.Top()+aDelta
.Y())));
346 InvalidateAllLayers(mpTargetWindow
->PixelToLogic(Rectangle(
347 aWindowBox
.Right()+aDelta
.X(),
350 aWindowBox
.Bottom())));
351 else if (aDelta
.X() > 0)
352 InvalidateAllLayers(mpTargetWindow
->PixelToLogic(Rectangle(
355 aWindowBox
.Left()+aDelta
.X(),
356 aWindowBox
.Bottom())));
360 // Can this happen? Lets trigger a warning when it does.
364 maSavedMapMode
= rMapMode
;
369 //===== Layer =================================================================
374 maInvalidationRegion()
382 void Layer::Initialize (sd::Window
*pTargetWindow
)
387 if ( ! mpLayerDevice
)
389 mpLayerDevice
.reset(VclPtr
<VirtualDevice
>::Create(*pTargetWindow
));
390 mpLayerDevice
->SetOutputSizePixel(pTargetWindow
->GetSizePixel());
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
);
415 ::boost::bind(&Layer::ValidateRectangle
, this, _1
));
419 void Layer::ValidateRectangle (const Rectangle
& rBox
)
421 if ( ! mpLayerDevice
)
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());
432 (*iPainter
)->Paint(*mpLayerDevice
, rBox
);
435 mpLayerDevice
->SetClipRegion(aSavedClipRegion
);
438 void Layer::Repaint (
439 OutputDevice
& rTargetDevice
,
440 const Rectangle
& rRepaintRectangle
)
444 DeviceCopy(rTargetDevice
, *mpLayerDevice
, rRepaintRectangle
);
451 ::boost::bind(&ILayerPainter::Paint
,
453 ::boost::ref(rTargetDevice
),
458 void Layer::Resize (const Size
& rSize
)
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
);
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()
498 } } } // end of namespace ::sd::slidesorter::view
500 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */