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"
23 #include <vcl/window.hxx>
24 #include <vcl/virdev.hxx>
25 #include <sal/log.hxx>
26 #include <osl/diagnose.h>
28 #include <tools/gen.hxx>
29 #include <tools/fract.hxx>
33 namespace sd
{ namespace slidesorter
{ namespace view
{
36 static const sal_Int32 gnMaximumLayerCount
= 8;
38 class LayerInvalidator
: public ILayerInvalidator
42 const std::shared_ptr
<LayeredDevice
>& rpLayeredDevice
,
43 sd::Window
*pTargetWindow
,
45 : mpLayeredDevice(rpLayeredDevice
),
46 mpTargetWindow(pTargetWindow
),
51 virtual void Invalidate (const ::tools::Rectangle
& rInvalidationBox
) override
53 mpLayeredDevice
->Invalidate(rInvalidationBox
, mnLayer
);
54 mpTargetWindow
->Invalidate(rInvalidationBox
);
58 const std::shared_ptr
<LayeredDevice
> mpLayeredDevice
;
59 VclPtr
<sd::Window
> mpTargetWindow
;
64 vcl::RenderContext
& rTargetDevice
,
65 vcl::RenderContext
const & rSourceDevice
,
66 const ::tools::Rectangle
& rBox
)
68 rTargetDevice
.DrawOutDev(
76 void ForAllRectangles (const vcl::Region
& rRegion
, const std::function
<void (const ::tools::Rectangle
&)>& aFunction
)
78 OSL_ASSERT(aFunction
);
79 RectangleVector aRectangles
;
80 rRegion
.GetRegionRectangles(aRectangles
);
82 if(aRectangles
.empty())
84 aFunction(::tools::Rectangle());
88 for(const auto& rRect
: aRectangles
)
93 //Region aMutableRegionCopy (rRegion);
94 //RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects());
96 //while (aMutableRegionCopy.GetEnumRects(aHandle, aBox))
98 //aMutableRegionCopy.EndEnumRects(aHandle);
106 Layer(const Layer
&) = delete;
107 Layer
& operator=(const Layer
&) = delete;
109 void Initialize (sd::Window
*pTargetWindow
);
110 void InvalidateRectangle (const ::tools::Rectangle
& rInvalidationBox
);
111 void InvalidateRegion (const vcl::Region
& rInvalidationRegion
);
112 void Validate (const MapMode
& rMapMode
);
114 OutputDevice
& rTargetDevice
,
115 const ::tools::Rectangle
& rRepaintRectangle
);
116 void Resize (const Size
& rSize
);
117 void AddPainter (const SharedILayerPainter
& rpPainter
);
118 void RemovePainter (const SharedILayerPainter
& rpPainter
);
119 bool HasPainter() const;
123 ScopedVclPtr
<VirtualDevice
> mpLayerDevice
;
124 ::std::vector
<SharedILayerPainter
> maPainters
;
125 vcl::Region maInvalidationRegion
;
127 void ValidateRectangle (const ::tools::Rectangle
& rBox
);
129 typedef std::shared_ptr
<Layer
> SharedLayer
;
131 } // end of anonymous namespace
133 class LayeredDevice::LayerContainer
136 LayerContainer() : mvLayers() {}
138 bool empty() const { return mvLayers
.empty(); }
140 size_t size() const { return mvLayers
.size(); }
142 const SharedLayer
& back() const { return mvLayers
.back(); }
144 const ::std::vector
<SharedLayer
>::const_iterator
begin() const { return mvLayers
.begin(); }
145 const ::std::vector
<SharedLayer
>::const_iterator
end() const { return mvLayers
.end(); }
147 void clear() { mvLayers
.clear(); }
149 void pop_back() { mvLayers
.pop_back(); }
151 void resize(size_t n
) { mvLayers
.resize(n
); }
153 SharedLayer
& operator[](size_t i
) { return mvLayers
[i
]; }
156 ::std::vector
<SharedLayer
> mvLayers
;
159 //===== LayeredDevice =========================================================
161 LayeredDevice::LayeredDevice (const VclPtr
<sd::Window
>& pTargetWindow
)
162 : mpTargetWindow(pTargetWindow
),
163 mpLayers(new LayerContainer()),
164 mpBackBuffer(VclPtr
<VirtualDevice
>::Create(*mpTargetWindow
)),
165 maSavedMapMode(pTargetWindow
->GetMapMode())
167 mpBackBuffer
->SetOutputSizePixel(mpTargetWindow
->GetSizePixel());
170 LayeredDevice::~LayeredDevice()
174 void LayeredDevice::Invalidate (
175 const ::tools::Rectangle
& rInvalidationArea
,
176 const sal_Int32 nLayer
)
178 if (nLayer
<0 || size_t(nLayer
)>=mpLayers
->size())
180 OSL_ASSERT(nLayer
>=0 && size_t(nLayer
)<mpLayers
->size());
184 (*mpLayers
)[nLayer
]->InvalidateRectangle(rInvalidationArea
);
187 void LayeredDevice::InvalidateAllLayers (const ::tools::Rectangle
& rInvalidationArea
)
189 for (size_t nLayer
=0; nLayer
<mpLayers
->size(); ++nLayer
)
190 (*mpLayers
)[nLayer
]->InvalidateRectangle(rInvalidationArea
);
193 void LayeredDevice::InvalidateAllLayers (const vcl::Region
& rInvalidationRegion
)
195 for (size_t nLayer
=0; nLayer
<mpLayers
->size(); ++nLayer
)
196 (*mpLayers
)[nLayer
]->InvalidateRegion(rInvalidationRegion
);
199 void LayeredDevice::RegisterPainter (
200 const SharedILayerPainter
& rpPainter
,
201 const sal_Int32 nLayer
)
203 OSL_ASSERT(mpLayers
);
206 OSL_ASSERT(rpPainter
);
209 if (nLayer
<0 || nLayer
>=gnMaximumLayerCount
)
211 OSL_ASSERT(nLayer
>=0 && nLayer
<gnMaximumLayerCount
);
215 // Provide the layers.
216 if (sal_uInt32(nLayer
) >= mpLayers
->size())
218 const sal_Int32
nOldLayerCount (mpLayers
->size());
219 mpLayers
->resize(nLayer
+1);
221 for (size_t nIndex
=nOldLayerCount
; nIndex
<mpLayers
->size(); ++nIndex
)
222 (*mpLayers
)[nIndex
].reset(new Layer());
225 (*mpLayers
)[nLayer
]->AddPainter(rpPainter
);
227 (*mpLayers
)[nLayer
]->Initialize(mpTargetWindow
);
229 rpPainter
->SetLayerInvalidator(
230 SharedILayerInvalidator(new LayerInvalidator(shared_from_this(),mpTargetWindow
,nLayer
)));
233 void LayeredDevice::RemovePainter (
234 const SharedILayerPainter
& rpPainter
,
235 const sal_Int32 nLayer
)
239 OSL_ASSERT(rpPainter
);
242 if (nLayer
<0 || size_t(nLayer
)>=mpLayers
->size())
244 OSL_ASSERT(nLayer
>=0 && size_t(nLayer
)<mpLayers
->size());
248 rpPainter
->SetLayerInvalidator(SharedILayerInvalidator());
250 (*mpLayers
)[nLayer
]->RemovePainter(rpPainter
);
252 // Remove top most layers that do not contain any painters.
253 while ( ! mpLayers
->empty() && ! mpLayers
->back()->HasPainter())
254 mpLayers
->pop_back();
257 void LayeredDevice::Repaint (const vcl::Region
& rRepaintRegion
)
259 // Validate the contents of all layers (that have their own devices.)
260 for (auto const& it
: *mpLayers
)
262 it
->Validate(mpTargetWindow
->GetMapMode());
265 ForAllRectangles(rRepaintRegion
,
266 [this] (::tools::Rectangle
const& r
) { this->RepaintRectangle(r
); });
269 void LayeredDevice::RepaintRectangle (const ::tools::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());
284 for (auto const& it
: *mpLayers
)
286 it
->Repaint(*mpBackBuffer
, rRepaintRectangle
);
288 DeviceCopy(*mpTargetWindow
, *mpBackBuffer
, rRepaintRectangle
);
292 void LayeredDevice::Resize()
294 const Size
aSize (mpTargetWindow
->GetSizePixel());
295 mpBackBuffer
->SetOutputSizePixel(aSize
);
296 for (auto const& it
: *mpLayers
)
302 void LayeredDevice::Dispose()
304 for (auto const& it
: *mpLayers
)
311 bool LayeredDevice::HandleMapModeChange()
313 const MapMode
& rMapMode (mpTargetWindow
->GetMapMode());
314 if (maSavedMapMode
== rMapMode
)
317 const ::tools::Rectangle
aLogicWindowBox (
318 mpTargetWindow
->PixelToLogic(::tools::Rectangle(Point(0,0), mpTargetWindow
->GetSizePixel())));
319 if (maSavedMapMode
.GetScaleX() != rMapMode
.GetScaleX()
320 || maSavedMapMode
.GetScaleY() != rMapMode
.GetScaleY()
321 || maSavedMapMode
.GetMapUnit() != rMapMode
.GetMapUnit())
323 // When the scale has changed then we have to paint everything.
324 InvalidateAllLayers(aLogicWindowBox
);
326 else if (maSavedMapMode
.GetOrigin() != rMapMode
.GetOrigin())
328 // Window has been scrolled. Adapt contents of backbuffers and
330 const Point
aDelta (rMapMode
.GetOrigin() - maSavedMapMode
.GetOrigin());
331 mpBackBuffer
->CopyArea(
332 aLogicWindowBox
.TopLeft(),
333 mpTargetWindow
->PixelToLogic(Point(0,0), maSavedMapMode
),
334 aLogicWindowBox
.GetSize());
336 // Invalidate the area(s) that have been exposed.
337 const ::tools::Rectangle
aWindowBox (Point(0,0), mpTargetWindow
->GetSizePixel());
339 InvalidateAllLayers(mpTargetWindow
->PixelToLogic(::tools::Rectangle(
341 aWindowBox
.Bottom()+aDelta
.Y(),
343 aWindowBox
.Bottom())));
344 else if (aDelta
.Y() > 0)
345 InvalidateAllLayers(mpTargetWindow
->PixelToLogic(::tools::Rectangle(
349 aWindowBox
.Top()+aDelta
.Y())));
351 InvalidateAllLayers(mpTargetWindow
->PixelToLogic(::tools::Rectangle(
352 aWindowBox
.Right()+aDelta
.X(),
355 aWindowBox
.Bottom())));
356 else if (aDelta
.X() > 0)
357 InvalidateAllLayers(mpTargetWindow
->PixelToLogic(::tools::Rectangle(
360 aWindowBox
.Left()+aDelta
.X(),
361 aWindowBox
.Bottom())));
365 // Can this happen? Lets trigger a warning when it does.
369 maSavedMapMode
= rMapMode
;
374 //===== Layer =================================================================
379 maInvalidationRegion()
383 void Layer::Initialize (sd::Window
*pTargetWindow
)
388 if ( ! mpLayerDevice
)
390 mpLayerDevice
.disposeAndReset(VclPtr
<VirtualDevice
>::Create(*pTargetWindow
));
391 mpLayerDevice
->SetOutputSizePixel(pTargetWindow
->GetSizePixel());
396 void Layer::InvalidateRectangle (const ::tools::Rectangle
& rInvalidationBox
)
398 maInvalidationRegion
.Union(rInvalidationBox
);
401 void Layer::InvalidateRegion (const vcl::Region
& rInvalidationRegion
)
403 maInvalidationRegion
.Union(rInvalidationRegion
);
406 void Layer::Validate (const MapMode
& rMapMode
)
408 if (mpLayerDevice
&& ! maInvalidationRegion
.IsEmpty())
410 vcl::Region
aRegion (maInvalidationRegion
);
411 maInvalidationRegion
.SetEmpty();
413 mpLayerDevice
->SetMapMode(rMapMode
);
416 [this] (::tools::Rectangle
const& r
) { return this->ValidateRectangle(r
); });
420 void Layer::ValidateRectangle (const ::tools::Rectangle
& rBox
)
422 if ( ! mpLayerDevice
)
424 const vcl::Region
aSavedClipRegion (mpLayerDevice
->GetClipRegion());
425 mpLayerDevice
->IntersectClipRegion(rBox
);
427 for (const auto& rxPainter
: maPainters
)
429 rxPainter
->Paint(*mpLayerDevice
, rBox
);
432 mpLayerDevice
->SetClipRegion(aSavedClipRegion
);
435 void Layer::Repaint (
436 OutputDevice
& rTargetDevice
,
437 const ::tools::Rectangle
& rRepaintRectangle
)
441 DeviceCopy(rTargetDevice
, *mpLayerDevice
, rRepaintRectangle
);
445 for (auto const& it
: maPainters
)
447 it
->Paint(rTargetDevice
, rRepaintRectangle
);
452 void Layer::Resize (const Size
& rSize
)
456 mpLayerDevice
->SetOutputSizePixel(rSize
);
457 maInvalidationRegion
= ::tools::Rectangle(Point(0,0), rSize
);
461 void Layer::AddPainter (const SharedILayerPainter
& rpPainter
)
463 OSL_ASSERT(::std::find(maPainters
.begin(), maPainters
.end(), rpPainter
) == maPainters
.end());
465 maPainters
.push_back(rpPainter
);
468 void Layer::RemovePainter (const SharedILayerPainter
& rpPainter
)
470 const ::std::vector
<SharedILayerPainter
>::iterator
iPainter (
471 ::std::find(maPainters
.begin(), maPainters
.end(), rpPainter
));
472 if (iPainter
!= maPainters
.end())
474 maPainters
.erase(iPainter
);
478 SAL_WARN("sd", "LayeredDevice::RemovePainter called for painter that is not registered");
482 bool Layer::HasPainter() const
484 return !maPainters
.empty();
487 void Layer::Dispose()
492 } } } // end of namespace ::sd::slidesorter::view
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */