/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #include "precompiled_sd.hxx" #include "SlsLayeredDevice.hxx" #include #include #include #include namespace sd { namespace slidesorter { namespace view { namespace { static const sal_Int32 gnMaximumLayerCount = 8; class LayerInvalidator : public ILayerInvalidator { public: LayerInvalidator ( const ::boost::shared_ptr& 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 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 aFunction) { OSL_ASSERT(aFunction); RectangleVector aRectangles; rRegion.GetRegionRectangles(aRectangles); if(0 == aRectangles.size()) { aFunction(Rectangle()); } else { for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) { aFunction(*aRectIter); } //Region aMutableRegionCopy (rRegion); //RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects()); //Rectangle aBox; //while (aMutableRegionCopy.GetEnumRects(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 mpLayerDevice; ::std::vector maPainters; Region maInvalidationRegion; void ValidateRectangle (const Rectangle& rBox); }; typedef ::boost::shared_ptr SharedLayer; } // end of anonymous namespace class LayeredDevice::LayerContainer : public ::std::vector { 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)size()); return; } (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea); } void LayeredDevice::InvalidateAllLayers (const Rectangle& rInvalidationArea) { for (sal_uInt32 nLayer=0; nLayersize(); ++nLayer) (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea); } void LayeredDevice::InvalidateAllLayers (const Region& rInvalidationRegion) { for (sal_uInt32 nLayer=0; nLayersize(); ++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= mpLayers->size()) { const sal_Int32 nOldLayerCount (mpLayers->size()); mpLayers->resize(nLayer+1); for (size_t nIndex=nOldLayerCount; nIndexsize(); ++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)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)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? Let's 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::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::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