bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / ui / slidesorter / view / SlsLayeredDevice.cxx
blob38a0aa9fec598320cdc55b88264939bdf248a984
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/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>
31 #include <functional>
33 namespace sd { namespace slidesorter { namespace view {
35 namespace {
36 static const sal_Int32 gnMaximumLayerCount = 8;
38 class LayerInvalidator : public ILayerInvalidator
40 public:
41 LayerInvalidator (
42 const std::shared_ptr<LayeredDevice>& rpLayeredDevice,
43 sd::Window *pTargetWindow,
44 const int nLayer)
45 : mpLayeredDevice(rpLayeredDevice),
46 mpTargetWindow(pTargetWindow),
47 mnLayer(nLayer)
51 virtual void Invalidate (const ::tools::Rectangle& rInvalidationBox) override
53 mpLayeredDevice->Invalidate(rInvalidationBox, mnLayer);
54 mpTargetWindow->Invalidate(rInvalidationBox);
57 private:
58 const std::shared_ptr<LayeredDevice> mpLayeredDevice;
59 VclPtr<sd::Window> mpTargetWindow;
60 const int mnLayer;
63 void DeviceCopy (
64 vcl::RenderContext& rTargetDevice,
65 vcl::RenderContext const & rSourceDevice,
66 const ::tools::Rectangle& rBox)
68 rTargetDevice.DrawOutDev(
69 rBox.TopLeft(),
70 rBox.GetSize(),
71 rBox.TopLeft(),
72 rBox.GetSize(),
73 rSourceDevice);
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());
86 else
88 for(const auto& rRect : aRectangles)
90 aFunction(rRect);
93 //Region aMutableRegionCopy (rRegion);
94 //RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects());
95 //Rectangle aBox;
96 //while (aMutableRegionCopy.GetEnumRects(aHandle, aBox))
97 // aFunction(aBox);
98 //aMutableRegionCopy.EndEnumRects(aHandle);
102 class Layer
104 public:
105 Layer();
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);
113 void Repaint (
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;
120 void Dispose();
122 private:
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
135 public:
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]; }
155 private:
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());
181 return;
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);
204 if ( ! rpPainter)
206 OSL_ASSERT(rpPainter);
207 return;
209 if (nLayer<0 || nLayer>=gnMaximumLayerCount)
211 OSL_ASSERT(nLayer>=0 && nLayer<gnMaximumLayerCount);
212 return;
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);
226 if (nLayer == 0)
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)
237 if ( ! rpPainter)
239 OSL_ASSERT(rpPainter);
240 return;
242 if (nLayer<0 || size_t(nLayer)>=mpLayers->size())
244 OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size());
245 return;
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())
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 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)
298 it->Resize(aSize);
302 void LayeredDevice::Dispose()
304 for (auto const& it : *mpLayers)
306 it->Dispose();
308 mpLayers->clear();
311 bool LayeredDevice::HandleMapModeChange()
313 const MapMode& rMapMode (mpTargetWindow->GetMapMode());
314 if (maSavedMapMode == rMapMode)
315 return false;
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
329 // layer devices.
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());
338 if (aDelta.Y() < 0)
339 InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
340 aWindowBox.Left(),
341 aWindowBox.Bottom()+aDelta.Y(),
342 aWindowBox.Right(),
343 aWindowBox.Bottom())));
344 else if (aDelta.Y() > 0)
345 InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
346 aWindowBox.Left(),
347 aWindowBox.Top(),
348 aWindowBox.Right(),
349 aWindowBox.Top()+aDelta.Y())));
350 if (aDelta.X() < 0)
351 InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
352 aWindowBox.Right()+aDelta.X(),
353 aWindowBox.Top(),
354 aWindowBox.Right(),
355 aWindowBox.Bottom())));
356 else if (aDelta.X() > 0)
357 InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
358 aWindowBox.Left(),
359 aWindowBox.Top(),
360 aWindowBox.Left()+aDelta.X(),
361 aWindowBox.Bottom())));
363 else
365 // Can this happen? Lets trigger a warning when it does.
366 OSL_ASSERT(false);
369 maSavedMapMode = rMapMode;
371 return true;
374 //===== Layer =================================================================
376 Layer::Layer()
377 : mpLayerDevice(),
378 maPainters(),
379 maInvalidationRegion()
383 void Layer::Initialize (sd::Window *pTargetWindow)
385 #if 0
386 (void)pTargetWindow;
387 #else
388 if ( ! mpLayerDevice)
390 mpLayerDevice.disposeAndReset(VclPtr<VirtualDevice>::Create(*pTargetWindow));
391 mpLayerDevice->SetOutputSizePixel(pTargetWindow->GetSizePixel());
393 #endif
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);
414 ForAllRectangles(
415 aRegion,
416 [this] (::tools::Rectangle const& r) { return this->ValidateRectangle(r); });
420 void Layer::ValidateRectangle (const ::tools::Rectangle& rBox)
422 if ( ! mpLayerDevice)
423 return;
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)
439 if (mpLayerDevice)
441 DeviceCopy(rTargetDevice, *mpLayerDevice, rRepaintRectangle);
443 else
445 for (auto const& it : maPainters)
447 it->Paint(rTargetDevice, rRepaintRectangle);
452 void Layer::Resize (const Size& rSize)
454 if (mpLayerDevice)
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);
476 else
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()
489 maPainters.clear();
492 } } } // end of namespace ::sd::slidesorter::view
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */