bump product version to 6.4.0.3
[LibreOffice.git] / sd / source / ui / slidesorter / view / SlsLayeredDevice.cxx
blob199d6ec1d26c2e27fcc2b97252850bd5e08f7b5f
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"
21 #include <Window.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>
30 #include <functional>
32 namespace sd { namespace slidesorter { namespace view {
34 namespace {
35 static const sal_Int32 gnMaximumLayerCount = 8;
37 class LayerInvalidator : public ILayerInvalidator
39 public:
40 LayerInvalidator (
41 const std::shared_ptr<LayeredDevice>& rpLayeredDevice,
42 sd::Window *pTargetWindow,
43 const int nLayer)
44 : mpLayeredDevice(rpLayeredDevice),
45 mpTargetWindow(pTargetWindow),
46 mnLayer(nLayer)
50 virtual void Invalidate (const ::tools::Rectangle& rInvalidationBox) override
52 mpLayeredDevice->Invalidate(rInvalidationBox, mnLayer);
53 mpTargetWindow->Invalidate(rInvalidationBox);
56 private:
57 const std::shared_ptr<LayeredDevice> mpLayeredDevice;
58 VclPtr<sd::Window> mpTargetWindow;
59 const int mnLayer;
62 void DeviceCopy (
63 vcl::RenderContext& rTargetDevice,
64 vcl::RenderContext const & rSourceDevice,
65 const ::tools::Rectangle& rBox)
67 rTargetDevice.DrawOutDev(
68 rBox.TopLeft(),
69 rBox.GetSize(),
70 rBox.TopLeft(),
71 rBox.GetSize(),
72 rSourceDevice);
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());
85 else
87 for(const auto& rRect : aRectangles)
89 aFunction(rRect);
92 //Region aMutableRegionCopy (rRegion);
93 //RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects());
94 //Rectangle aBox;
95 //while (aMutableRegionCopy.GetEnumRects(aHandle, aBox))
96 // aFunction(aBox);
97 //aMutableRegionCopy.EndEnumRects(aHandle);
101 class Layer
103 public:
104 Layer();
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);
112 void Repaint (
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;
119 void Dispose();
121 private:
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
134 public:
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]; }
154 private:
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());
180 return;
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);
203 if ( ! rpPainter)
205 OSL_ASSERT(rpPainter);
206 return;
208 if (nLayer<0 || nLayer>=gnMaximumLayerCount)
210 OSL_ASSERT(nLayer>=0 && nLayer<gnMaximumLayerCount);
211 return;
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);
225 if (nLayer == 0)
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)
236 if ( ! rpPainter)
238 OSL_ASSERT(rpPainter);
239 return;
241 if (nLayer<0 || size_t(nLayer)>=mpLayers->size())
243 OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size());
244 return;
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())
271 return;
272 else if (mpLayers->size() == 1)
274 // Just copy the main layer into the target device.
275 (*mpLayers)[0]->Repaint(*mpTargetWindow, rRepaintRectangle);
277 else
279 // Paint all layers first into the back buffer (to avoid flickering
280 // due to synchronous paints) and then copy that into the target
281 // device.
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)
297 it->Resize(aSize);
301 void LayeredDevice::Dispose()
303 for (auto const& it : *mpLayers)
305 it->Dispose();
307 mpLayers->clear();
310 bool LayeredDevice::HandleMapModeChange()
312 const MapMode& rMapMode (mpTargetWindow->GetMapMode());
313 if (maSavedMapMode == rMapMode)
314 return false;
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
328 // layer devices.
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());
337 if (aDelta.Y() < 0)
338 InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
339 aWindowBox.Left(),
340 aWindowBox.Bottom()+aDelta.Y(),
341 aWindowBox.Right(),
342 aWindowBox.Bottom())));
343 else if (aDelta.Y() > 0)
344 InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
345 aWindowBox.Left(),
346 aWindowBox.Top(),
347 aWindowBox.Right(),
348 aWindowBox.Top()+aDelta.Y())));
349 if (aDelta.X() < 0)
350 InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
351 aWindowBox.Right()+aDelta.X(),
352 aWindowBox.Top(),
353 aWindowBox.Right(),
354 aWindowBox.Bottom())));
355 else if (aDelta.X() > 0)
356 InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
357 aWindowBox.Left(),
358 aWindowBox.Top(),
359 aWindowBox.Left()+aDelta.X(),
360 aWindowBox.Bottom())));
362 else
364 // Can this happen? Lets trigger a warning when it does.
365 OSL_ASSERT(false);
368 maSavedMapMode = rMapMode;
370 return true;
373 //===== Layer =================================================================
375 Layer::Layer()
376 : mpLayerDevice(),
377 maPainters(),
378 maInvalidationRegion()
382 void Layer::Initialize (sd::Window *pTargetWindow)
384 #if 0
385 (void)pTargetWindow;
386 #else
387 if ( ! mpLayerDevice)
389 mpLayerDevice.disposeAndReset(VclPtr<VirtualDevice>::Create(*pTargetWindow));
390 mpLayerDevice->SetOutputSizePixel(pTargetWindow->GetSizePixel());
392 #endif
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);
413 ForAllRectangles(
414 aRegion,
415 [this] (::tools::Rectangle const& r) { return this->ValidateRectangle(r); });
419 void Layer::ValidateRectangle (const ::tools::Rectangle& rBox)
421 if ( ! mpLayerDevice)
422 return;
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)
438 if (mpLayerDevice)
440 DeviceCopy(rTargetDevice, *mpLayerDevice, rRepaintRectangle);
442 else
444 for (auto const& it : maPainters)
446 it->Paint(rTargetDevice, rRepaintRectangle);
451 void Layer::Resize (const Size& rSize)
453 if (mpLayerDevice)
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);
475 else
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()
488 maPainters.clear();
491 } } } // end of namespace ::sd::slidesorter::view
493 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */