diff options
Diffstat (limited to 'sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx')
-rw-r--r-- | sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx | 565 |
1 files changed, 565 insertions, 0 deletions
diff --git a/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx b/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx new file mode 100644 index 000000000000..e3303278111f --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx @@ -0,0 +1,565 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlsLayeredDevice.hxx" + +#include <vcl/window.hxx> +#include <vcl/virdev.hxx> + +#include <boost/bind.hpp> +#include <boost/function.hpp> + + +namespace sd { namespace slidesorter { namespace view { + +namespace { +static const sal_Int32 gnMaximumLayerCount = 8; + +class LayerInvalidator : public ILayerInvalidator +{ +public: + LayerInvalidator ( + const ::boost::shared_ptr<LayeredDevice>& rpLayeredDevice, + const SharedSdWindow& rpTargetWindow, + const int nLayer) + : mpLayeredDevice(rpLayeredDevice), + mpTargetWindow(rpTargetWindow), + mnLayer(nLayer) + { + } + + virtual void Invalidate (const Rectangle& rInvalidationBox) + { + mpLayeredDevice->Invalidate(rInvalidationBox, mnLayer); + mpTargetWindow->Invalidate(rInvalidationBox); + } + +private: + const ::boost::shared_ptr<LayeredDevice> mpLayeredDevice; + SharedSdWindow mpTargetWindow; + const int mnLayer; +}; + +void DeviceCopy ( + OutputDevice& rTargetDevice, + OutputDevice& rSourceDevice, + const Rectangle& rBox) +{ + rTargetDevice.DrawOutDev( + rBox.TopLeft(), + rBox.GetSize(), + rBox.TopLeft(), + rBox.GetSize(), + rSourceDevice); +} + + +void ForAllRectangles (const Region& rRegion, ::boost::function<void(const Rectangle&)> aFunction) +{ + OSL_ASSERT(aFunction); + + if (rRegion.GetRectCount() <= 1) + { + aFunction(rRegion.GetBoundRect()); + } + else + { + Region aMutableRegionCopy (rRegion); + RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects()); + Rectangle aBox; + while (aMutableRegionCopy.GetNextEnumRect(aHandle, aBox)) + aFunction(aBox); + aMutableRegionCopy.EndEnumRects(aHandle); + } +} + +class Layer : private ::boost::noncopyable +{ +public: + Layer (void); + ~Layer (void); + + void Initialize (const SharedSdWindow& rpTargetWindow); + void InvalidateRectangle (const Rectangle& rInvalidationBox); + void InvalidateRegion (const Region& rInvalidationRegion); + void Validate (const MapMode& rMapMode); + void Repaint ( + OutputDevice& rTargetDevice, + const Rectangle& rRepaintRectangle); + void Resize (const Size& rSize); + void AddPainter (const SharedILayerPainter& rpPainter); + void RemovePainter (const SharedILayerPainter& rpPainter); + bool HasPainter (void) const; + void Dispose (void); + +private: + ::boost::shared_ptr<VirtualDevice> mpLayerDevice; + ::std::vector<SharedILayerPainter> maPainters; + Region maInvalidationRegion; + + void ValidateRectangle (const Rectangle& rBox); +}; +typedef ::boost::shared_ptr<Layer> SharedLayer; + + +} // end of anonymous namespace + + +class LayeredDevice::LayerContainer : public ::std::vector<SharedLayer> +{ +public: + LayerContainer (void) {} + ~LayerContainer (void) {} +}; + + + + +//===== LayeredDevice ========================================================= + +LayeredDevice::LayeredDevice (const SharedSdWindow& rpTargetWindow) + : mpTargetWindow(rpTargetWindow), + mpLayers(new LayerContainer()), + mpBackBuffer(new VirtualDevice(*mpTargetWindow)), + maSavedMapMode(rpTargetWindow->GetMapMode()) +{ + mpBackBuffer->SetOutputSizePixel(mpTargetWindow->GetSizePixel()); +} + + + + +LayeredDevice::~LayeredDevice (void) +{ +} + + + + +void LayeredDevice::Invalidate ( + const Rectangle& rInvalidationArea, + const sal_Int32 nLayer) +{ + if (nLayer<0 || size_t(nLayer)>=mpLayers->size()) + { + OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size()); + return; + } + + (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea); +} + + + + +void LayeredDevice::InvalidateAllLayers (const Rectangle& rInvalidationArea) +{ + for (sal_uInt32 nLayer=0; nLayer<mpLayers->size(); ++nLayer) + (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea); +} + + + + +void LayeredDevice::InvalidateAllLayers (const Region& rInvalidationRegion) +{ + for (sal_uInt32 nLayer=0; nLayer<mpLayers->size(); ++nLayer) + (*mpLayers)[nLayer]->InvalidateRegion(rInvalidationRegion); +} + + + + +void LayeredDevice::RegisterPainter ( + const SharedILayerPainter& rpPainter, + const sal_Int32 nLayer) +{ + OSL_ASSERT(mpLayers); + if ( ! rpPainter) + { + OSL_ASSERT(rpPainter); + return; + } + if (nLayer<0 || nLayer>=gnMaximumLayerCount) + { + OSL_ASSERT(nLayer>=0 && nLayer<gnMaximumLayerCount); + return; + } + + // Provide the layers. + if (sal_uInt32(nLayer) >= mpLayers->size()) + { + const sal_Int32 nOldLayerCount (mpLayers->size()); + mpLayers->resize(nLayer+1); + + for (size_t nIndex=nOldLayerCount; nIndex<mpLayers->size(); ++nIndex) + (*mpLayers)[nIndex].reset(new Layer()); + } + + (*mpLayers)[nLayer]->AddPainter(rpPainter); + if (nLayer == 0) + (*mpLayers)[nLayer]->Initialize(mpTargetWindow); + + rpPainter->SetLayerInvalidator( + SharedILayerInvalidator(new LayerInvalidator(shared_from_this(),mpTargetWindow,nLayer))); +} + + + + +void LayeredDevice::RemovePainter ( + const SharedILayerPainter& rpPainter, + const sal_Int32 nLayer) +{ + if ( ! rpPainter) + { + OSL_ASSERT(rpPainter); + return; + } + if (nLayer<0 || size_t(nLayer)>=mpLayers->size()) + { + OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size()); + return; + } + + rpPainter->SetLayerInvalidator(SharedILayerInvalidator()); + + (*mpLayers)[nLayer]->RemovePainter(rpPainter); + + // Remove top most layers that do not contain any painters. + while ( ! mpLayers->empty() && ! mpLayers->back()->HasPainter()) + mpLayers->erase(mpLayers->end()-1); +} + + + + +bool LayeredDevice::HasPainter (const sal_Int32 nLayer) +{ + return nLayer>=0 + && sal_uInt32(nLayer)<mpLayers->size() + && (*mpLayers)[nLayer]->HasPainter(); +} + + + + +void LayeredDevice::Repaint (const Region& rRepaintRegion) +{ + // Validate the contents of all layers (that have their own devices.) + ::std::for_each( + mpLayers->begin(), + mpLayers->end(), + ::boost::bind(&Layer::Validate, _1, mpTargetWindow->GetMapMode())); + + ForAllRectangles(rRepaintRegion, ::boost::bind(&LayeredDevice::RepaintRectangle, this, _1)); +} + + + + +void LayeredDevice::RepaintRectangle (const Rectangle& rRepaintRectangle) +{ + if (mpLayers->size() == 0) + return; + else if (mpLayers->size() == 1) + { + // Just copy the main layer into the target device. + (*mpLayers)[0]->Repaint(*mpTargetWindow, rRepaintRectangle); + } + else + { + // Paint all layers first into the back buffer (to avoid flickering + // due to synchronous paints) and then copy that into the target + // device. + mpBackBuffer->SetMapMode(mpTargetWindow->GetMapMode()); + ::std::for_each( + mpLayers->begin(), + mpLayers->end(), + ::boost::bind(&Layer::Repaint, _1, ::boost::ref(*mpBackBuffer), rRepaintRectangle)); + + DeviceCopy(*mpTargetWindow, *mpBackBuffer, rRepaintRectangle); + } +} + + + + +void LayeredDevice::Resize (void) +{ + const Size aSize (mpTargetWindow->GetSizePixel()); + mpBackBuffer->SetOutputSizePixel(aSize); + ::std::for_each(mpLayers->begin(), mpLayers->end(), ::boost::bind(&Layer::Resize, _1, aSize)); +} + + + + +void LayeredDevice::Dispose (void) +{ + ::std::for_each(mpLayers->begin(), mpLayers->end(), ::boost::bind(&Layer::Dispose, _1)); + mpLayers->clear(); +} + + + + +bool LayeredDevice::HandleMapModeChange (void) +{ + const MapMode& rMapMode (mpTargetWindow->GetMapMode()); + if (maSavedMapMode == rMapMode) + return false; + + const Rectangle aLogicWindowBox ( + mpTargetWindow->PixelToLogic(Rectangle(Point(0,0), mpTargetWindow->GetSizePixel()))); + if (maSavedMapMode.GetScaleX() != rMapMode.GetScaleX() + || maSavedMapMode.GetScaleY() != rMapMode.GetScaleY() + || maSavedMapMode.GetMapUnit() != rMapMode.GetMapUnit()) + { + // When the scale has changed then we have to paint everything. + InvalidateAllLayers(aLogicWindowBox); + } + else if (maSavedMapMode.GetOrigin() != rMapMode.GetOrigin()) + { + // Window has been scrolled. Adapt contents of backbuffers and + // layer devices. + const Point aDelta (rMapMode.GetOrigin() - maSavedMapMode.GetOrigin()); + mpBackBuffer->CopyArea( + aLogicWindowBox.TopLeft(), + mpTargetWindow->PixelToLogic(Point(0,0), maSavedMapMode), + aLogicWindowBox.GetSize()); + + // Invalidate the area(s) that have been exposed. + const Rectangle aWindowBox (Point(0,0), mpTargetWindow->GetSizePixel()); + if (aDelta.Y() < 0) + InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( + aWindowBox.Left(), + aWindowBox.Bottom()+aDelta.Y(), + aWindowBox.Right(), + aWindowBox.Bottom()))); + else if (aDelta.Y() > 0) + InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( + aWindowBox.Left(), + aWindowBox.Top(), + aWindowBox.Right(), + aWindowBox.Top()+aDelta.Y()))); + if (aDelta.X() < 0) + InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( + aWindowBox.Right()+aDelta.X(), + aWindowBox.Top(), + aWindowBox.Right(), + aWindowBox.Bottom()))); + else if (aDelta.X() > 0) + InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( + aWindowBox.Left(), + aWindowBox.Top(), + aWindowBox.Left()+aDelta.X(), + aWindowBox.Bottom()))); + } + else + { + // Can this happen? Lets trigger a warning when it does. + OSL_ASSERT(false); + } + + maSavedMapMode = rMapMode; + + return true; +} + + + + +//===== Layer ================================================================= + +Layer::Layer (void) + : mpLayerDevice(), + maPainters(), + maInvalidationRegion() +{ +} + + + + +Layer::~Layer (void) +{ +} + + + + +void Layer::Initialize (const SharedSdWindow& rpTargetWindow) +{ +#if 0 + (void)rpTargetWindow; +#else + if ( ! mpLayerDevice) + { + mpLayerDevice.reset(new VirtualDevice(*rpTargetWindow)); + mpLayerDevice->SetOutputSizePixel(rpTargetWindow->GetSizePixel()); + } +#endif +} + + + + +void Layer::InvalidateRectangle (const Rectangle& rInvalidationBox) +{ + maInvalidationRegion.Union(rInvalidationBox); +} + + + + +void Layer::InvalidateRegion (const Region& rInvalidationRegion) +{ + maInvalidationRegion.Union(rInvalidationRegion); +} + + + + +void Layer::Validate (const MapMode& rMapMode) +{ + if (mpLayerDevice && ! maInvalidationRegion.IsEmpty()) + { + Region aRegion (maInvalidationRegion); + maInvalidationRegion.SetEmpty(); + + mpLayerDevice->SetMapMode(rMapMode); + ForAllRectangles( + aRegion, + ::boost::bind(&Layer::ValidateRectangle, this, _1)); + } +} + + + + +void Layer::ValidateRectangle (const Rectangle& rBox) +{ + if ( ! mpLayerDevice) + return; + const Region aSavedClipRegion (mpLayerDevice->GetClipRegion()); + mpLayerDevice->IntersectClipRegion(rBox); + + for (::std::vector<SharedILayerPainter>::const_iterator + iPainter(maPainters.begin()), + iEnd(maPainters.end()); + iPainter!=iEnd; + ++iPainter) + { + (*iPainter)->Paint(*mpLayerDevice, rBox); + } + + mpLayerDevice->SetClipRegion(aSavedClipRegion); +} + + + + +void Layer::Repaint ( + OutputDevice& rTargetDevice, + const Rectangle& rRepaintRectangle) +{ + if (mpLayerDevice) + { + DeviceCopy(rTargetDevice, *mpLayerDevice, rRepaintRectangle); + } + else + { + ::std::for_each( + maPainters.begin(), + maPainters.end(), + ::boost::bind(&ILayerPainter::Paint, + _1, + ::boost::ref(rTargetDevice), + rRepaintRectangle)); + } +} + + + + +void Layer::Resize (const Size& rSize) +{ + if (mpLayerDevice) + { + mpLayerDevice->SetOutputSizePixel(rSize); + maInvalidationRegion = Rectangle(Point(0,0), rSize); + } +} + + + + +void Layer::AddPainter (const SharedILayerPainter& rpPainter) +{ + OSL_ASSERT(::std::find(maPainters.begin(), maPainters.end(), rpPainter) == maPainters.end()); + + maPainters.push_back(rpPainter); +} + + + + +void Layer::RemovePainter (const SharedILayerPainter& rpPainter) +{ + const ::std::vector<SharedILayerPainter>::iterator iPainter ( + ::std::find(maPainters.begin(), maPainters.end(), rpPainter)); + if (iPainter != maPainters.end()) + { + maPainters.erase(iPainter); + } + else + { + DBG_ASSERT(false,"LayeredDevice::RemovePainter called for painter that is not registered"); + } +} + + + + +bool Layer::HasPainter (void) const +{ + return !maPainters.empty(); +} + + + + +void Layer::Dispose (void) +{ + maPainters.clear(); +} + + +} } } // end of namespace ::sd::slidesorter::view |