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/virdev.hxx>
24 #include <sal/log.hxx>
25 #include <osl/diagnose.h>
27 #include <tools/gen.hxx>
28 #include <tools/fract.hxx>
32 namespace sd
{ namespace slidesorter
{ namespace view
{
35 static const sal_Int32 gnMaximumLayerCount
= 8;
37 class LayerInvalidator
: public ILayerInvalidator
41 const std::shared_ptr
<LayeredDevice
>& rpLayeredDevice
,
42 sd::Window
*pTargetWindow
,
44 : mpLayeredDevice(rpLayeredDevice
),
45 mpTargetWindow(pTargetWindow
),
50 virtual void Invalidate (const ::tools::Rectangle
& rInvalidationBox
) override
52 mpLayeredDevice
->Invalidate(rInvalidationBox
, mnLayer
);
53 mpTargetWindow
->Invalidate(rInvalidationBox
);
57 const std::shared_ptr
<LayeredDevice
> mpLayeredDevice
;
58 VclPtr
<sd::Window
> mpTargetWindow
;
63 vcl::RenderContext
& rTargetDevice
,
64 vcl::RenderContext
const & rSourceDevice
,
65 const ::tools::Rectangle
& rBox
)
67 rTargetDevice
.DrawOutDev(
75 void ForAllRectangles (const vcl::Region
& rRegion
, const std::function
<void (const ::tools::Rectangle
&)>& aFunction
)
77 OSL_ASSERT(aFunction
);
78 RectangleVector aRectangles
;
79 rRegion
.GetRegionRectangles(aRectangles
);
81 if(aRectangles
.empty())
83 aFunction(::tools::Rectangle());
87 for(const auto& rRect
: aRectangles
)
92 //Region aMutableRegionCopy (rRegion);
93 //RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects());
95 //while (aMutableRegionCopy.GetEnumRects(aHandle, aBox))
97 //aMutableRegionCopy.EndEnumRects(aHandle);
105 Layer(const Layer
&) = delete;
106 Layer
& operator=(const Layer
&) = delete;
108 void Initialize (sd::Window
*pTargetWindow
);
109 void InvalidateRectangle (const ::tools::Rectangle
& rInvalidationBox
);
110 void InvalidateRegion (const vcl::Region
& rInvalidationRegion
);
111 void Validate (const MapMode
& rMapMode
);
113 OutputDevice
& rTargetDevice
,
114 const ::tools::Rectangle
& rRepaintRectangle
);
115 void Resize (const Size
& rSize
);
116 void AddPainter (const SharedILayerPainter
& rpPainter
);
117 void RemovePainter (const SharedILayerPainter
& rpPainter
);
118 bool HasPainter() const;
122 ScopedVclPtr
<VirtualDevice
> mpLayerDevice
;
123 ::std::vector
<SharedILayerPainter
> maPainters
;
124 vcl::Region maInvalidationRegion
;
126 void ValidateRectangle (const ::tools::Rectangle
& rBox
);
128 typedef std::shared_ptr
<Layer
> SharedLayer
;
130 } // end of anonymous namespace
132 class LayeredDevice::LayerContainer
135 LayerContainer() : mvLayers() {}
137 bool empty() const { return mvLayers
.empty(); }
139 size_t size() const { return mvLayers
.size(); }
141 const SharedLayer
& back() const { return mvLayers
.back(); }
143 ::std::vector
<SharedLayer
>::const_iterator
begin() const { return mvLayers
.begin(); }
144 ::std::vector
<SharedLayer
>::const_iterator
end() const { return mvLayers
.end(); }
146 void clear() { mvLayers
.clear(); }
148 void pop_back() { mvLayers
.pop_back(); }
150 void resize(size_t n
) { mvLayers
.resize(n
); }
152 SharedLayer
& operator[](size_t i
) { return mvLayers
[i
]; }
155 ::std::vector
<SharedLayer
> mvLayers
;
158 //===== LayeredDevice =========================================================
160 LayeredDevice::LayeredDevice (const VclPtr
<sd::Window
>& pTargetWindow
)
161 : mpTargetWindow(pTargetWindow
),
162 mpLayers(new LayerContainer()),
163 mpBackBuffer(VclPtr
<VirtualDevice
>::Create(*mpTargetWindow
)),
164 maSavedMapMode(pTargetWindow
->GetMapMode())
166 mpBackBuffer
->SetOutputSizePixel(mpTargetWindow
->GetSizePixel());
169 LayeredDevice::~LayeredDevice()
173 void LayeredDevice::Invalidate (
174 const ::tools::Rectangle
& rInvalidationArea
,
175 const sal_Int32 nLayer
)
177 if (nLayer
<0 || size_t(nLayer
)>=mpLayers
->size())
179 OSL_ASSERT(nLayer
>=0 && size_t(nLayer
)<mpLayers
->size());
183 (*mpLayers
)[nLayer
]->InvalidateRectangle(rInvalidationArea
);
186 void LayeredDevice::InvalidateAllLayers (const ::tools::Rectangle
& rInvalidationArea
)
188 for (size_t nLayer
=0; nLayer
<mpLayers
->size(); ++nLayer
)
189 (*mpLayers
)[nLayer
]->InvalidateRectangle(rInvalidationArea
);
192 void LayeredDevice::InvalidateAllLayers (const vcl::Region
& rInvalidationRegion
)
194 for (size_t nLayer
=0; nLayer
<mpLayers
->size(); ++nLayer
)
195 (*mpLayers
)[nLayer
]->InvalidateRegion(rInvalidationRegion
);
198 void LayeredDevice::RegisterPainter (
199 const SharedILayerPainter
& rpPainter
,
200 const sal_Int32 nLayer
)
202 OSL_ASSERT(mpLayers
);
205 OSL_ASSERT(rpPainter
);
208 if (nLayer
<0 || nLayer
>=gnMaximumLayerCount
)
210 OSL_ASSERT(nLayer
>=0 && nLayer
<gnMaximumLayerCount
);
214 // Provide the layers.
215 if (sal_uInt32(nLayer
) >= mpLayers
->size())
217 const sal_Int32
nOldLayerCount (mpLayers
->size());
218 mpLayers
->resize(nLayer
+1);
220 for (size_t nIndex
=nOldLayerCount
; nIndex
<mpLayers
->size(); ++nIndex
)
221 (*mpLayers
)[nIndex
].reset(new Layer());
224 (*mpLayers
)[nLayer
]->AddPainter(rpPainter
);
226 (*mpLayers
)[nLayer
]->Initialize(mpTargetWindow
);
228 rpPainter
->SetLayerInvalidator(
229 SharedILayerInvalidator(new LayerInvalidator(shared_from_this(),mpTargetWindow
,nLayer
)));
232 void LayeredDevice::RemovePainter (
233 const SharedILayerPainter
& rpPainter
,
234 const sal_Int32 nLayer
)
238 OSL_ASSERT(rpPainter
);
241 if (nLayer
<0 || size_t(nLayer
)>=mpLayers
->size())
243 OSL_ASSERT(nLayer
>=0 && size_t(nLayer
)<mpLayers
->size());
247 rpPainter
->SetLayerInvalidator(SharedILayerInvalidator());
249 (*mpLayers
)[nLayer
]->RemovePainter(rpPainter
);
251 // Remove top most layers that do not contain any painters.
252 while ( ! mpLayers
->empty() && ! mpLayers
->back()->HasPainter())
253 mpLayers
->pop_back();
256 void LayeredDevice::Repaint (const vcl::Region
& rRepaintRegion
)
258 // Validate the contents of all layers (that have their own devices.)
259 for (auto const& it
: *mpLayers
)
261 it
->Validate(mpTargetWindow
->GetMapMode());
264 ForAllRectangles(rRepaintRegion
,
265 [this] (::tools::Rectangle
const& r
) { this->RepaintRectangle(r
); });
268 void LayeredDevice::RepaintRectangle (const ::tools::Rectangle
& rRepaintRectangle
)
270 if (mpLayers
->empty())
272 else if (mpLayers
->size() == 1)
274 // Just copy the main layer into the target device.
275 (*mpLayers
)[0]->Repaint(*mpTargetWindow
, rRepaintRectangle
);
279 // Paint all layers first into the back buffer (to avoid flickering
280 // due to synchronous paints) and then copy that into the target
282 mpBackBuffer
->SetMapMode(mpTargetWindow
->GetMapMode());
283 for (auto const& it
: *mpLayers
)
285 it
->Repaint(*mpBackBuffer
, rRepaintRectangle
);
287 DeviceCopy(*mpTargetWindow
, *mpBackBuffer
, rRepaintRectangle
);
291 void LayeredDevice::Resize()
293 const Size
aSize (mpTargetWindow
->GetSizePixel());
294 mpBackBuffer
->SetOutputSizePixel(aSize
);
295 for (auto const& it
: *mpLayers
)
301 void LayeredDevice::Dispose()
303 for (auto const& it
: *mpLayers
)
310 bool LayeredDevice::HandleMapModeChange()
312 const MapMode
& rMapMode (mpTargetWindow
->GetMapMode());
313 if (maSavedMapMode
== rMapMode
)
316 const ::tools::Rectangle
aLogicWindowBox (
317 mpTargetWindow
->PixelToLogic(::tools::Rectangle(Point(0,0), mpTargetWindow
->GetSizePixel())));
318 if (maSavedMapMode
.GetScaleX() != rMapMode
.GetScaleX()
319 || maSavedMapMode
.GetScaleY() != rMapMode
.GetScaleY()
320 || maSavedMapMode
.GetMapUnit() != rMapMode
.GetMapUnit())
322 // When the scale has changed then we have to paint everything.
323 InvalidateAllLayers(aLogicWindowBox
);
325 else if (maSavedMapMode
.GetOrigin() != rMapMode
.GetOrigin())
327 // Window has been scrolled. Adapt contents of backbuffers and
329 const Point
aDelta (rMapMode
.GetOrigin() - maSavedMapMode
.GetOrigin());
330 mpBackBuffer
->CopyArea(
331 aLogicWindowBox
.TopLeft(),
332 mpTargetWindow
->PixelToLogic(Point(0,0), maSavedMapMode
),
333 aLogicWindowBox
.GetSize());
335 // Invalidate the area(s) that have been exposed.
336 const ::tools::Rectangle
aWindowBox (Point(0,0), mpTargetWindow
->GetSizePixel());
338 InvalidateAllLayers(mpTargetWindow
->PixelToLogic(::tools::Rectangle(
340 aWindowBox
.Bottom()+aDelta
.Y(),
342 aWindowBox
.Bottom())));
343 else if (aDelta
.Y() > 0)
344 InvalidateAllLayers(mpTargetWindow
->PixelToLogic(::tools::Rectangle(
348 aWindowBox
.Top()+aDelta
.Y())));
350 InvalidateAllLayers(mpTargetWindow
->PixelToLogic(::tools::Rectangle(
351 aWindowBox
.Right()+aDelta
.X(),
354 aWindowBox
.Bottom())));
355 else if (aDelta
.X() > 0)
356 InvalidateAllLayers(mpTargetWindow
->PixelToLogic(::tools::Rectangle(
359 aWindowBox
.Left()+aDelta
.X(),
360 aWindowBox
.Bottom())));
364 // Can this happen? Lets trigger a warning when it does.
368 maSavedMapMode
= rMapMode
;
373 //===== Layer =================================================================
378 maInvalidationRegion()
382 void Layer::Initialize (sd::Window
*pTargetWindow
)
387 if ( ! mpLayerDevice
)
389 mpLayerDevice
.disposeAndReset(VclPtr
<VirtualDevice
>::Create(*pTargetWindow
));
390 mpLayerDevice
->SetOutputSizePixel(pTargetWindow
->GetSizePixel());
395 void Layer::InvalidateRectangle (const ::tools::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 [this] (::tools::Rectangle
const& r
) { return this->ValidateRectangle(r
); });
419 void Layer::ValidateRectangle (const ::tools::Rectangle
& rBox
)
421 if ( ! mpLayerDevice
)
423 const vcl::Region
aSavedClipRegion (mpLayerDevice
->GetClipRegion());
424 mpLayerDevice
->IntersectClipRegion(rBox
);
426 for (const auto& rxPainter
: maPainters
)
428 rxPainter
->Paint(*mpLayerDevice
, rBox
);
431 mpLayerDevice
->SetClipRegion(aSavedClipRegion
);
434 void Layer::Repaint (
435 OutputDevice
& rTargetDevice
,
436 const ::tools::Rectangle
& rRepaintRectangle
)
440 DeviceCopy(rTargetDevice
, *mpLayerDevice
, rRepaintRectangle
);
444 for (auto const& it
: maPainters
)
446 it
->Paint(rTargetDevice
, rRepaintRectangle
);
451 void Layer::Resize (const Size
& rSize
)
455 mpLayerDevice
->SetOutputSizePixel(rSize
);
456 maInvalidationRegion
= ::tools::Rectangle(Point(0,0), rSize
);
460 void Layer::AddPainter (const SharedILayerPainter
& rpPainter
)
462 OSL_ASSERT(::std::find(maPainters
.begin(), maPainters
.end(), rpPainter
) == maPainters
.end());
464 maPainters
.push_back(rpPainter
);
467 void Layer::RemovePainter (const SharedILayerPainter
& rpPainter
)
469 const ::std::vector
<SharedILayerPainter
>::iterator
iPainter (
470 ::std::find(maPainters
.begin(), maPainters
.end(), rpPainter
));
471 if (iPainter
!= maPainters
.end())
473 maPainters
.erase(iPainter
);
477 SAL_WARN("sd", "LayeredDevice::RemovePainter called for painter that is not registered");
481 bool Layer::HasPainter() const
483 return !maPainters
.empty();
486 void Layer::Dispose()
491 } } } // end of namespace ::sd::slidesorter::view
493 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */