android: Update app-specific/MIME type icons
[LibreOffice.git] / sd / source / ui / slidesorter / view / SlsLayeredDevice.cxx
blob4bd3808992e01231ad436f087291237b47d48382
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 <utility>
24 #include <vcl/virdev.hxx>
25 #include <sal/log.hxx>
26 #include <o3tl/safeint.hxx>
27 #include <osl/diagnose.h>
29 #include <tools/gen.hxx>
30 #include <tools/fract.hxx>
32 #include <functional>
34 namespace sd::slidesorter::view {
36 namespace {
37 const sal_Int32 gnMaximumLayerCount = 8;
39 class LayerInvalidator : public ILayerInvalidator
41 public:
42 LayerInvalidator (
43 std::shared_ptr<LayeredDevice> pLayeredDevice,
44 sd::Window *pTargetWindow,
45 const int nLayer)
46 : mpLayeredDevice(std::move(pLayeredDevice)),
47 mpTargetWindow(pTargetWindow),
48 mnLayer(nLayer)
52 virtual void Invalidate (const ::tools::Rectangle& rInvalidationBox) override
54 mpLayeredDevice->Invalidate(rInvalidationBox, mnLayer);
55 mpTargetWindow->Invalidate(rInvalidationBox);
58 private:
59 const std::shared_ptr<LayeredDevice> mpLayeredDevice;
60 VclPtr<sd::Window> mpTargetWindow;
61 const int mnLayer;
64 void DeviceCopy (
65 vcl::RenderContext& rTargetDevice,
66 vcl::RenderContext const & rSourceDevice,
67 const ::tools::Rectangle& rBox)
69 rTargetDevice.DrawOutDev(
70 rBox.TopLeft(),
71 rBox.GetSize(),
72 rBox.TopLeft(),
73 rBox.GetSize(),
74 rSourceDevice);
77 void ForAllRectangles (const vcl::Region& rRegion, const std::function<void (const ::tools::Rectangle&)>& aFunction)
79 OSL_ASSERT(aFunction);
80 RectangleVector aRectangles;
81 rRegion.GetRegionRectangles(aRectangles);
83 if(aRectangles.empty())
85 aFunction(::tools::Rectangle());
87 else
89 for(const auto& rRect : aRectangles)
91 aFunction(rRect);
94 //Region aMutableRegionCopy (rRegion);
95 //RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects());
96 //Rectangle aBox;
97 //while (aMutableRegionCopy.GetEnumRects(aHandle, aBox))
98 // aFunction(aBox);
99 //aMutableRegionCopy.EndEnumRects(aHandle);
103 class Layer
105 public:
106 Layer();
107 Layer(const Layer&) = delete;
108 Layer& operator=(const Layer&) = delete;
110 void Initialize (sd::Window *pTargetWindow);
111 void InvalidateRectangle (const ::tools::Rectangle& rInvalidationBox);
112 void InvalidateRegion (const vcl::Region& rInvalidationRegion);
113 void Validate (const MapMode& rMapMode);
114 void Repaint (
115 OutputDevice& rTargetDevice,
116 const ::tools::Rectangle& rRepaintRectangle);
117 void Resize (const Size& rSize);
118 void AddPainter (const SharedILayerPainter& rpPainter);
119 void RemovePainter (const SharedILayerPainter& rpPainter);
120 bool HasPainter() const;
121 void Dispose();
123 private:
124 ScopedVclPtr<VirtualDevice> mpLayerDevice;
125 ::std::vector<SharedILayerPainter> maPainters;
126 vcl::Region maInvalidationRegion;
128 void ValidateRectangle (const ::tools::Rectangle& rBox);
130 typedef std::shared_ptr<Layer> SharedLayer;
132 } // end of anonymous namespace
134 class LayeredDevice::LayerContainer
136 public:
137 LayerContainer() {}
139 bool empty() const { return mvLayers.empty(); }
141 size_t size() const { return mvLayers.size(); }
143 const SharedLayer& back() const { return mvLayers.back(); }
145 ::std::vector<SharedLayer>::const_iterator begin() const { return mvLayers.begin(); }
146 ::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]; }
156 private:
157 ::std::vector<SharedLayer> mvLayers;
160 //===== LayeredDevice =========================================================
162 LayeredDevice::LayeredDevice (const VclPtr<sd::Window>& pTargetWindow)
163 : mpTargetWindow(pTargetWindow),
164 mpLayers(new LayerContainer()),
165 mpBackBuffer(VclPtr<VirtualDevice>::Create(*mpTargetWindow->GetOutDev())),
166 maSavedMapMode(pTargetWindow->GetMapMode())
168 mpBackBuffer->SetOutputSizePixel(mpTargetWindow->GetSizePixel());
171 LayeredDevice::~LayeredDevice()
175 void LayeredDevice::Invalidate (
176 const ::tools::Rectangle& rInvalidationArea,
177 const sal_Int32 nLayer)
179 if (nLayer<0 || o3tl::make_unsigned(nLayer)>=mpLayers->size())
181 OSL_ASSERT(nLayer>=0 && o3tl::make_unsigned(nLayer)<mpLayers->size());
182 return;
185 (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea);
188 void LayeredDevice::InvalidateAllLayers (const ::tools::Rectangle& rInvalidationArea)
190 for (size_t nLayer=0; nLayer<mpLayers->size(); ++nLayer)
191 (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea);
194 void LayeredDevice::InvalidateAllLayers (const vcl::Region& rInvalidationRegion)
196 for (size_t 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);
205 if ( ! rpPainter)
207 OSL_ASSERT(rpPainter);
208 return;
210 if (nLayer<0 || nLayer>=gnMaximumLayerCount)
212 OSL_ASSERT(nLayer>=0 && nLayer<gnMaximumLayerCount);
213 return;
216 // Provide the layers.
217 if (o3tl::make_unsigned(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] = std::make_shared<Layer>();
226 (*mpLayers)[nLayer]->AddPainter(rpPainter);
227 if (nLayer == 0)
228 (*mpLayers)[nLayer]->Initialize(mpTargetWindow);
230 rpPainter->SetLayerInvalidator(
231 std::make_shared<LayerInvalidator>(shared_from_this(),mpTargetWindow,nLayer));
234 void LayeredDevice::RemovePainter (
235 const SharedILayerPainter& rpPainter,
236 const sal_Int32 nLayer)
238 if ( ! rpPainter)
240 OSL_ASSERT(rpPainter);
241 return;
243 if (nLayer<0 || o3tl::make_unsigned(nLayer)>=mpLayers->size())
245 OSL_ASSERT(nLayer>=0 && o3tl::make_unsigned(nLayer)<mpLayers->size());
246 return;
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.)
261 for (auto const& it : *mpLayers)
263 it->Validate(mpTargetWindow->GetMapMode());
266 ForAllRectangles(rRepaintRegion,
267 [this] (::tools::Rectangle const& r) { this->RepaintRectangle(r); });
270 void LayeredDevice::RepaintRectangle (const ::tools::Rectangle& rRepaintRectangle)
272 if (mpLayers->empty())
273 return;
274 else if (mpLayers->size() == 1)
276 // Just copy the main layer into the target device.
277 (*mpLayers)[0]->Repaint(*mpTargetWindow->GetOutDev(), rRepaintRectangle);
279 else
281 // Paint all layers first into the back buffer (to avoid flickering
282 // due to synchronous paints) and then copy that into the target
283 // device.
284 mpBackBuffer->SetMapMode(mpTargetWindow->GetMapMode());
285 for (auto const& it : *mpLayers)
287 it->Repaint(*mpBackBuffer, rRepaintRectangle);
289 DeviceCopy(*mpTargetWindow->GetOutDev(), *mpBackBuffer, rRepaintRectangle);
293 void LayeredDevice::Resize()
295 const Size aSize (mpTargetWindow->GetSizePixel());
296 mpBackBuffer->SetOutputSizePixel(aSize);
297 for (auto const& it : *mpLayers)
299 it->Resize(aSize);
303 void LayeredDevice::Dispose()
305 for (auto const& it : *mpLayers)
307 it->Dispose();
309 mpLayers->clear();
312 bool LayeredDevice::HandleMapModeChange()
314 const MapMode& rMapMode (mpTargetWindow->GetMapMode());
315 if (maSavedMapMode == rMapMode)
316 return false;
318 const ::tools::Rectangle aLogicWindowBox (
319 mpTargetWindow->PixelToLogic(::tools::Rectangle(Point(0,0), mpTargetWindow->GetSizePixel())));
320 if (maSavedMapMode.GetScaleX() != rMapMode.GetScaleX()
321 || maSavedMapMode.GetScaleY() != rMapMode.GetScaleY()
322 || maSavedMapMode.GetMapUnit() != rMapMode.GetMapUnit())
324 // When the scale has changed then we have to paint everything.
325 InvalidateAllLayers(aLogicWindowBox);
327 else if (maSavedMapMode.GetOrigin() != rMapMode.GetOrigin())
329 // Window has been scrolled. Adapt contents of backbuffers and
330 // layer devices.
331 const Point aDelta (rMapMode.GetOrigin() - maSavedMapMode.GetOrigin());
332 mpBackBuffer->CopyArea(
333 aLogicWindowBox.TopLeft(),
334 mpTargetWindow->PixelToLogic(Point(0,0), maSavedMapMode),
335 aLogicWindowBox.GetSize());
337 // Invalidate the area(s) that have been exposed.
338 const ::tools::Rectangle aWindowBox (Point(0,0), mpTargetWindow->GetSizePixel());
339 if (aDelta.Y() < 0)
340 InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
341 aWindowBox.Left(),
342 aWindowBox.Bottom()+aDelta.Y(),
343 aWindowBox.Right(),
344 aWindowBox.Bottom())));
345 else if (aDelta.Y() > 0)
346 InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
347 aWindowBox.Left(),
348 aWindowBox.Top(),
349 aWindowBox.Right(),
350 aWindowBox.Top()+aDelta.Y())));
351 if (aDelta.X() < 0)
352 InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
353 aWindowBox.Right()+aDelta.X(),
354 aWindowBox.Top(),
355 aWindowBox.Right(),
356 aWindowBox.Bottom())));
357 else if (aDelta.X() > 0)
358 InvalidateAllLayers(mpTargetWindow->PixelToLogic(::tools::Rectangle(
359 aWindowBox.Left(),
360 aWindowBox.Top(),
361 aWindowBox.Left()+aDelta.X(),
362 aWindowBox.Bottom())));
364 else
366 // Can this happen? Lets trigger a warning when it does.
367 OSL_ASSERT(false);
370 maSavedMapMode = rMapMode;
372 return true;
375 //===== Layer =================================================================
377 Layer::Layer()
381 void Layer::Initialize (sd::Window *pTargetWindow)
383 #if 0
384 (void)pTargetWindow;
385 #else
386 if ( ! mpLayerDevice)
388 mpLayerDevice.disposeAndReset(VclPtr<VirtualDevice>::Create(*pTargetWindow->GetOutDev()));
389 mpLayerDevice->SetOutputSizePixel(pTargetWindow->GetSizePixel());
391 #endif
394 void Layer::InvalidateRectangle (const ::tools::Rectangle& rInvalidationBox)
396 maInvalidationRegion.Union(rInvalidationBox);
399 void Layer::InvalidateRegion (const vcl::Region& rInvalidationRegion)
401 maInvalidationRegion.Union(rInvalidationRegion);
404 void Layer::Validate (const MapMode& rMapMode)
406 if (mpLayerDevice && ! maInvalidationRegion.IsEmpty())
408 vcl::Region aRegion (maInvalidationRegion);
409 maInvalidationRegion.SetEmpty();
411 mpLayerDevice->SetMapMode(rMapMode);
412 ForAllRectangles(
413 aRegion,
414 [this] (::tools::Rectangle const& r) { return this->ValidateRectangle(r); });
418 void Layer::ValidateRectangle (const ::tools::Rectangle& rBox)
420 if ( ! mpLayerDevice)
421 return;
422 const vcl::Region aSavedClipRegion (mpLayerDevice->GetClipRegion());
423 mpLayerDevice->IntersectClipRegion(rBox);
425 for (const auto& rxPainter : maPainters)
427 rxPainter->Paint(*mpLayerDevice, rBox);
430 mpLayerDevice->SetClipRegion(aSavedClipRegion);
433 void Layer::Repaint (
434 OutputDevice& rTargetDevice,
435 const ::tools::Rectangle& rRepaintRectangle)
437 if (mpLayerDevice)
439 DeviceCopy(rTargetDevice, *mpLayerDevice, rRepaintRectangle);
441 else
443 for (auto const& it : maPainters)
445 it->Paint(rTargetDevice, rRepaintRectangle);
450 void Layer::Resize (const Size& rSize)
452 if (mpLayerDevice)
454 mpLayerDevice->SetOutputSizePixel(rSize);
455 maInvalidationRegion = ::tools::Rectangle(Point(0,0), rSize);
459 void Layer::AddPainter (const SharedILayerPainter& rpPainter)
461 OSL_ASSERT(::std::find(maPainters.begin(), maPainters.end(), rpPainter) == maPainters.end());
463 maPainters.push_back(rpPainter);
466 void Layer::RemovePainter (const SharedILayerPainter& rpPainter)
468 const ::std::vector<SharedILayerPainter>::iterator iPainter (
469 ::std::find(maPainters.begin(), maPainters.end(), rpPainter));
470 if (iPainter != maPainters.end())
472 maPainters.erase(iPainter);
474 else
476 SAL_WARN("sd", "LayeredDevice::RemovePainter called for painter that is not registered");
480 bool Layer::HasPainter() const
482 return !maPainters.empty();
485 void Layer::Dispose()
487 maPainters.clear();
490 } // end of namespace ::sd::slidesorter::view
492 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */