summaryrefslogtreecommitdiff
path: root/slideshow/source/engine/slide/layermanager.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'slideshow/source/engine/slide/layermanager.cxx')
-rw-r--r--slideshow/source/engine/slide/layermanager.cxx926
1 files changed, 926 insertions, 0 deletions
diff --git a/slideshow/source/engine/slide/layermanager.cxx b/slideshow/source/engine/slide/layermanager.cxx
new file mode 100644
index 000000000000..251cff3a73b3
--- /dev/null
+++ b/slideshow/source/engine/slide/layermanager.cxx
@@ -0,0 +1,926 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: layermanager.cxx,v $
+ * $Revision: 1.6 $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_slideshow.hxx"
+
+#include <canvas/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <basegfx/range/b1drange.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+
+#include <comphelper/anytostring.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <boost/bind.hpp>
+#include <algorithm>
+
+#include "layermanager.hxx"
+
+using namespace ::com::sun::star;
+
+namespace boost
+{
+ // add operator!= for weak_ptr
+ inline bool operator!=( slideshow::internal::LayerWeakPtr const& rLHS,
+ slideshow::internal::LayerWeakPtr const& rRHS )
+ {
+ return (rLHS<rRHS) || (rRHS<rLHS);
+ }
+}
+
+namespace slideshow
+{
+ namespace internal
+ {
+ template<typename LayerFunc,
+ typename ShapeFunc> void LayerManager::manageViews(
+ LayerFunc layerFunc,
+ ShapeFunc shapeFunc )
+ {
+ LayerSharedPtr pCurrLayer;
+ ViewLayerSharedPtr pCurrViewLayer;
+ LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
+ const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
+ while( aIter != aEnd )
+ {
+ LayerSharedPtr pLayer = aIter->second.lock();
+ if( pLayer && pLayer != pCurrLayer )
+ {
+ pCurrLayer = pLayer;
+ pCurrViewLayer = layerFunc(pCurrLayer);
+ }
+
+ if( pCurrViewLayer )
+ shapeFunc(aIter->first,pCurrViewLayer);
+
+ ++aIter;
+ }
+ }
+
+ LayerManager::LayerManager( const UnoViewContainer& rViews,
+ const ::basegfx::B2DRange& rPageBounds,
+ bool bDisableAnimationZOrder ) :
+ mrViews(rViews),
+ maLayers(),
+ maXShapeHash( 101 ),
+ maAllShapes(),
+ maUpdateShapes(),
+ maPageBounds( rPageBounds ),
+ mnActiveSprites(0),
+ mbLayerAssociationDirty(false),
+ mbActive(false),
+ mbDisableAnimationZOrder(bDisableAnimationZOrder)
+ {
+ // prevent frequent resizes (won't have more than 4 layers
+ // for 99.9% of the cases)
+ maLayers.reserve(4);
+
+ // create initial background layer
+ maLayers.push_back(
+ Layer::createBackgroundLayer(
+ maPageBounds ));
+
+ // init views
+ std::for_each( mrViews.begin(),
+ mrViews.end(),
+ ::boost::bind(&LayerManager::viewAdded,
+ this,
+ _1) );
+ }
+
+ void LayerManager::activate( bool bSlideBackgoundPainted )
+ {
+ mbActive = true;
+ maUpdateShapes.clear(); // update gets forced via area, or
+ // has happend outside already
+
+ if( !bSlideBackgoundPainted )
+ {
+ std::for_each(mrViews.begin(),
+ mrViews.end(),
+ boost::mem_fn(&View::clearAll));
+
+ // force update of whole slide area
+ std::for_each( maLayers.begin(),
+ maLayers.end(),
+ boost::bind( &Layer::addUpdateRange,
+ _1,
+ boost::cref(maPageBounds) ));
+ }
+ else
+ {
+ // clear all possibly pending update areas - content
+ // is there, already
+ std::for_each( maLayers.begin(),
+ maLayers.end(),
+ boost::mem_fn( &Layer::clearUpdateRanges ));
+ }
+
+ updateShapeLayers( bSlideBackgoundPainted );
+ }
+
+ void LayerManager::deactivate()
+ {
+ // TODO(F3): This is mostly a hack. Problem is, there's
+ // currently no smart way of telling shapes "remove your
+ // sprites". Others, like MediaShapes, listen to
+ // start/stop animation events, which is too much overhead
+ // for all shapes, though.
+
+ const bool bMoreThanOneLayer(maLayers.size() > 1);
+ if( mnActiveSprites || bMoreThanOneLayer )
+ {
+ // clear all viewlayers, dump everything but the
+ // background layer - this will also remove all shape
+ // sprites
+ std::for_each(maAllShapes.begin(),
+ maAllShapes.end(),
+ boost::bind( &Shape::clearAllViewLayers,
+ boost::bind( std::select1st<LayerShapeMap::value_type>(),
+ _1 )));
+
+ for (LayerShapeMap::iterator
+ iShape (maAllShapes.begin()),
+ iEnd (maAllShapes.end());
+ iShape!=iEnd;
+ ++iShape)
+ {
+ iShape->second.reset();
+ }
+
+ if( bMoreThanOneLayer )
+ maLayers.erase(maLayers.begin()+1,
+ maLayers.end());
+
+ mbLayerAssociationDirty = true;
+ }
+
+ mbActive = false;
+
+ // only background layer left
+ OSL_ASSERT( maLayers.size() == 1 && maLayers.front()->isBackgroundLayer() );
+ }
+
+ void LayerManager::viewAdded( const UnoViewSharedPtr& rView )
+ {
+ // view must be member of mrViews container
+ OSL_ASSERT( std::find(mrViews.begin(),
+ mrViews.end(),
+ rView) != mrViews.end() );
+
+ // init view content
+ if( mbActive )
+ rView->clearAll();
+
+ // add View to all registered shapes
+ manageViews(
+ boost::bind(&Layer::addView,
+ _1,
+ boost::cref(rView)),
+ // repaint on view add
+ boost::bind(&Shape::addViewLayer,
+ _1,
+ _2,
+ true) );
+
+ // in case we haven't reached all layers from the
+ // maAllShapes, issue addView again for good measure
+ std::for_each( maLayers.begin(),
+ maLayers.end(),
+ boost::bind( &Layer::addView,
+ _1,
+ boost::cref(rView) ));
+ }
+
+ void LayerManager::viewRemoved( const UnoViewSharedPtr& rView )
+ {
+ // view must not be member of mrViews container anymore
+ OSL_ASSERT( std::find(mrViews.begin(),
+ mrViews.end(),
+ rView) == mrViews.end() );
+
+ // remove View from all registered shapes
+ manageViews(
+ boost::bind(&Layer::removeView,
+ _1,
+ boost::cref(rView)),
+ boost::bind(&Shape::removeViewLayer,
+ _1,
+ _2) );
+
+ // in case we haven't reached all layers from the
+ // maAllShapes, issue removeView again for good measure
+ std::for_each( maLayers.begin(),
+ maLayers.end(),
+ boost::bind( &Layer::removeView,
+ _1,
+ boost::cref(rView) ));
+ }
+
+ void LayerManager::viewChanged( const UnoViewSharedPtr& rView )
+ {
+ (void)rView;
+
+ // view must be member of mrViews container
+ OSL_ASSERT( std::find(mrViews.begin(),
+ mrViews.end(),
+ rView) != mrViews.end() );
+
+ // TODO(P2): selectively update only changed view
+ viewsChanged();
+ }
+
+ void LayerManager::viewsChanged()
+ {
+ if( !mbActive )
+ return;
+
+ // clear view area
+ ::std::for_each( mrViews.begin(),
+ mrViews.end(),
+ ::boost::mem_fn(&View::clearAll) );
+
+ // TODO(F3): resize and repaint all layers
+
+ // render all shapes
+ std::for_each( maAllShapes.begin(),
+ maAllShapes.end(),
+ boost::bind(&Shape::render,
+ boost::bind( ::std::select1st<LayerShapeMap::value_type>(), _1)) );
+ }
+
+ void LayerManager::addShape( const ShapeSharedPtr& rShape )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+ ENSURE_OR_THROW( rShape, "LayerManager::addShape(): invalid Shape" );
+
+ // add shape to XShape hash map
+ if( !maXShapeHash.insert(
+ XShapeHash::value_type( rShape->getXShape(),
+ rShape) ).second )
+ {
+ // entry already present, nothing to do
+ return;
+ }
+
+ // add shape to appropriate layer
+ implAddShape( rShape );
+ }
+
+ void LayerManager::putShape2BackgroundLayer( LayerShapeMap::value_type& rShapeEntry )
+ {
+ LayerSharedPtr& rBgLayer( maLayers.front() );
+ rBgLayer->setShapeViews(rShapeEntry.first);
+ rShapeEntry.second = rBgLayer;
+ }
+
+ void LayerManager::implAddShape( const ShapeSharedPtr& rShape )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+ ENSURE_OR_THROW( rShape, "LayerManager::implAddShape(): invalid Shape" );
+
+ LayerShapeMap::value_type aValue (rShape, LayerWeakPtr());
+
+ OSL_ASSERT( maAllShapes.find(rShape) == maAllShapes.end() ); // shape must not be added already
+ mbLayerAssociationDirty = true;
+
+ if( mbDisableAnimationZOrder )
+ putShape2BackgroundLayer(
+ *maAllShapes.insert(aValue).first );
+ else
+ maAllShapes.insert(aValue);
+
+ // update shape, it's just added and not yet painted
+ if( rShape->isVisible() )
+ notifyShapeUpdate( rShape );
+ }
+
+ bool LayerManager::removeShape( const ShapeSharedPtr& rShape )
+ {
+ // remove shape from XShape hash map
+ if( maXShapeHash.erase( rShape->getXShape() ) == 0 )
+ return false; // shape not in map
+
+ OSL_ASSERT( maAllShapes.find(rShape) != maAllShapes.end() );
+
+ implRemoveShape( rShape );
+
+ return true;
+ }
+
+ void LayerManager::implRemoveShape( const ShapeSharedPtr& rShape )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+ ENSURE_OR_THROW( rShape, "LayerManager::implRemoveShape(): invalid Shape" );
+
+ const LayerShapeMap::iterator aShapeEntry( maAllShapes.find(rShape) );
+
+ if( aShapeEntry == maAllShapes.end() )
+ return;
+
+ const bool bShapeUpdateNotified = maUpdateShapes.erase( rShape ) != 0;
+
+ // Enter shape area to the update area, but only if shape
+ // is visible and not in sprite mode (otherwise, updating
+ // the area doesn't do actual harm, but costs time)
+ // Actually, also add it if it was listed in
+ // maUpdateShapes (might have just gone invisible).
+ if( bShapeUpdateNotified ||
+ (rShape->isVisible() &&
+ !rShape->isBackgroundDetached()) )
+ {
+ LayerSharedPtr pLayer = aShapeEntry->second.lock();
+ if( pLayer )
+ {
+ // store area early, once the shape is removed from
+ // the layers, it no longer has any view references
+ pLayer->addUpdateRange( rShape->getUpdateArea() );
+ }
+ }
+
+ rShape->clearAllViewLayers();
+ maAllShapes.erase( aShapeEntry );
+
+ mbLayerAssociationDirty = true;
+ }
+
+ ShapeSharedPtr LayerManager::lookupShape( const uno::Reference< drawing::XShape >& xShape ) const
+ {
+ ENSURE_OR_THROW( xShape.is(), "LayerManager::lookupShape(): invalid Shape" );
+
+ const XShapeHash::const_iterator aIter( maXShapeHash.find( xShape ));
+ if( aIter == maXShapeHash.end() )
+ return ShapeSharedPtr(); // not found
+
+ // found, return data part of entry pair.
+ return aIter->second;
+ }
+
+ AttributableShapeSharedPtr LayerManager::getSubsetShape( const AttributableShapeSharedPtr& rOrigShape,
+ const DocTreeNode& rTreeNode )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+
+ AttributableShapeSharedPtr pSubset;
+
+ // shape already added?
+ if( rOrigShape->createSubset( pSubset,
+ rTreeNode ) )
+ {
+ OSL_ENSURE( pSubset, "LayerManager::getSubsetShape(): failed to create subset" );
+
+ // don't add to shape hash, we're dupes to the
+ // original XShape anyway - all subset shapes return
+ // the same XShape as the original one.
+
+ // add shape to corresponding layer
+ implAddShape( pSubset );
+
+ // update original shape, it now shows less content
+ // (the subset is removed from its displayed
+ // output). Subset shape is updated within
+ // implAddShape().
+ if( rOrigShape->isVisible() )
+ notifyShapeUpdate( rOrigShape );
+ }
+
+ return pSubset;
+ }
+
+ void LayerManager::revokeSubset( const AttributableShapeSharedPtr& rOrigShape,
+ const AttributableShapeSharedPtr& rSubsetShape )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+
+ if( rOrigShape->revokeSubset( rSubsetShape ) )
+ {
+ OSL_ASSERT( maAllShapes.find(rSubsetShape) != maAllShapes.end() );
+
+ implRemoveShape( rSubsetShape );
+
+ // update original shape, it now shows more content
+ // (the subset is added back to its displayed output)
+ if( rOrigShape->isVisible() )
+ notifyShapeUpdate( rOrigShape );
+ }
+ }
+
+ void LayerManager::enterAnimationMode( const AnimatableShapeSharedPtr& rShape )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+ ENSURE_OR_THROW( rShape, "LayerManager::enterAnimationMode(): invalid Shape" );
+
+ const bool bPrevAnimState( rShape->isBackgroundDetached() );
+
+ rShape->enterAnimationMode();
+
+ // if this call _really_ enabled the animation mode at
+ // rShape, insert it to our enter animation queue, to
+ // perform the necessary layer reorg lazily on
+ // LayerManager::update()/render().
+ if( bPrevAnimState != rShape->isBackgroundDetached() )
+ {
+ ++mnActiveSprites;
+ mbLayerAssociationDirty = true;
+
+ // area needs update (shape is removed from normal
+ // slide, and now rendered as an autonomous
+ // sprite). store in update set
+ if( rShape->isVisible() )
+ addUpdateArea( rShape );
+ }
+
+ // TODO(P1): this can lead to potential wasted effort, if
+ // a shape gets toggled animated/unanimated a few times
+ // between two frames, returning to the original state.
+ }
+
+ void LayerManager::leaveAnimationMode( const AnimatableShapeSharedPtr& rShape )
+ {
+ ENSURE_OR_THROW( !maLayers.empty(), "LayerManager::leaveAnimationMode(): no layers" );
+ ENSURE_OR_THROW( rShape, "LayerManager::leaveAnimationMode(): invalid Shape" );
+
+ const bool bPrevAnimState( rShape->isBackgroundDetached() );
+
+ rShape->leaveAnimationMode();
+
+ // if this call _really_ ended the animation mode at
+ // rShape, insert it to our leave animation queue, to
+ // perform the necessary layer reorg lazily on
+ // LayerManager::update()/render().
+ if( bPrevAnimState != rShape->isBackgroundDetached() )
+ {
+ --mnActiveSprites;
+ mbLayerAssociationDirty = true;
+
+ // shape needs update, no previous rendering, fast
+ // update possible.
+ if( rShape->isVisible() )
+ notifyShapeUpdate( rShape );
+ }
+
+ // TODO(P1): this can lead to potential wasted effort, if
+ // a shape gets toggled animated/unanimated a few times
+ // between two frames, returning to the original state.
+ }
+
+ void LayerManager::notifyShapeUpdate( const ShapeSharedPtr& rShape )
+ {
+ if( !mbActive || mrViews.empty() )
+ return;
+
+ // hidden sprite-shape needs render() call still, to hide sprite
+ if( rShape->isVisible() || rShape->isBackgroundDetached() )
+ maUpdateShapes.insert( rShape );
+ else
+ addUpdateArea( rShape );
+ }
+
+ bool LayerManager::isUpdatePending() const
+ {
+ if( !mbActive )
+ return false;
+
+ if( mbLayerAssociationDirty || !maUpdateShapes.empty() )
+ return true;
+
+ const LayerVector::const_iterator aEnd( maLayers.end() );
+ if( std::find_if( maLayers.begin(),
+ aEnd,
+ boost::mem_fn(&Layer::isUpdatePending)) != aEnd )
+ return true;
+
+ return false;
+ }
+
+ bool LayerManager::updateSprites()
+ {
+ bool bRet(true);
+
+ // send update() calls to every shape in the
+ // maUpdateShapes set, which is _animated_ (i.e. a
+ // sprite).
+ const ShapeUpdateSet::const_iterator aEnd=maUpdateShapes.end();
+ ShapeUpdateSet::const_iterator aCurrShape=maUpdateShapes.begin();
+ while( aCurrShape != aEnd )
+ {
+ if( (*aCurrShape)->isBackgroundDetached() )
+ {
+ // can update shape directly, without
+ // affecting layer content (shape is
+ // currently displayed in a sprite)
+ if( !(*aCurrShape)->update() )
+ bRet = false; // delay error exit
+ }
+ else
+ {
+ // TODO(P2): addUpdateArea() involves log(n)
+ // search for shape layer. Have a frequent
+ // shape/layer association cache, or ptr back to
+ // layer at the shape?
+
+ // cannot update shape directly, it's not
+ // animated and update() calls will prolly
+ // overwrite other page content.
+ addUpdateArea( *aCurrShape );
+ }
+
+ ++aCurrShape;
+ }
+
+ maUpdateShapes.clear();
+
+ return bRet;
+ }
+
+ bool LayerManager::update()
+ {
+ bool bRet = true;
+
+ if( !mbActive )
+ return bRet;
+
+ // going to render - better flush any pending layer reorg
+ // now
+ updateShapeLayers(false);
+
+ // all sprites
+ bRet = updateSprites();
+
+ // any non-sprite update areas left?
+ if( std::find_if( maLayers.begin(),
+ maLayers.end(),
+ boost::mem_fn( &Layer::isUpdatePending )) == maLayers.end() )
+ return bRet; // nope, done.
+
+ // update each shape on each layer, that has
+ // isUpdatePending()
+ bool bIsCurrLayerUpdating(false);
+ Layer::EndUpdater aEndUpdater;
+ LayerSharedPtr pCurrLayer;
+ LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
+ const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
+ while( aIter != aEnd )
+ {
+ LayerSharedPtr pLayer = aIter->second.lock();
+ if( pLayer != pCurrLayer )
+ {
+ pCurrLayer = pLayer;
+ bIsCurrLayerUpdating = pCurrLayer->isUpdatePending();
+
+ if( bIsCurrLayerUpdating )
+ aEndUpdater = pCurrLayer->beginUpdate();
+ }
+
+ if( bIsCurrLayerUpdating &&
+ !aIter->first->isBackgroundDetached() &&
+ pCurrLayer->isInsideUpdateArea(aIter->first) )
+ {
+ if( !aIter->first->render() )
+ bRet = false;
+ }
+
+ ++aIter;
+ }
+
+ return bRet;
+ }
+
+ namespace
+ {
+ /** Little wrapper around a Canvas, to render one-shot
+ into a canvas
+ */
+ class DummyLayer : public ViewLayer
+ {
+ public:
+ explicit DummyLayer( const ::cppcanvas::CanvasSharedPtr& rCanvas ) :
+ mpCanvas( rCanvas )
+ {
+ }
+
+ virtual bool isOnView(boost::shared_ptr<View> const& /*rView*/) const
+ {
+ return true; // visible on all views
+ }
+
+ virtual ::cppcanvas::CanvasSharedPtr getCanvas() const
+ {
+ return mpCanvas;
+ }
+
+ virtual void clear() const
+ {
+ // NOOP
+ }
+
+ virtual void clearAll() const
+ {
+ // NOOP
+ }
+
+ virtual ::cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& /*rSpriteSizePixel*/,
+ double /*nSpritePrio*/ ) const
+ {
+ ENSURE_OR_THROW( false,
+ "DummyLayer::createSprite(): This method is not supposed to be called!" );
+ return ::cppcanvas::CustomSpriteSharedPtr();
+ }
+
+ virtual void setPriority( const basegfx::B1DRange& /*rRange*/ )
+ {
+ OSL_ENSURE( false,
+ "BitmapView::setPriority(): This method is not supposed to be called!" );
+ }
+
+ virtual ::basegfx::B2DHomMatrix getTransformation() const
+ {
+ return mpCanvas->getTransformation();
+ }
+
+ virtual ::basegfx::B2DHomMatrix getSpriteTransformation() const
+ {
+ OSL_ENSURE( false,
+ "BitmapView::getSpriteTransformation(): This method is not supposed to be called!" );
+ return ::basegfx::B2DHomMatrix();
+ }
+
+ virtual void setClip( const ::basegfx::B2DPolyPolygon& /*rClip*/ )
+ {
+ OSL_ENSURE( false,
+ "BitmapView::setClip(): This method is not supposed to be called!" );
+ }
+
+ virtual bool resize( const ::basegfx::B2DRange& /*rArea*/ )
+ {
+ OSL_ENSURE( false,
+ "BitmapView::resize(): This method is not supposed to be called!" );
+ return false;
+ }
+
+ private:
+ ::cppcanvas::CanvasSharedPtr mpCanvas;
+ };
+ }
+
+ bool LayerManager::renderTo( const ::cppcanvas::CanvasSharedPtr& rTargetCanvas ) const
+ {
+ bool bRet( true );
+ ViewLayerSharedPtr pTmpLayer( new DummyLayer( rTargetCanvas ) );
+
+ LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
+ const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
+ while( aIter != aEnd )
+ {
+ try
+ {
+ // forward to all shape's addViewLayer method (which
+ // we request to render the Shape on the new
+ // ViewLayer. Since we add the shapes in the
+ // maShapeSet order (which is also the render order),
+ // this is equivalent to a subsequent render() call)
+ aIter->first->addViewLayer( pTmpLayer,
+ true );
+
+ // and remove again, this is only temporary
+ aIter->first->removeViewLayer( pTmpLayer );
+ }
+ catch( uno::Exception& )
+ {
+ // TODO(E1): Might be superfluous. Nowadays,
+ // addViewLayer swallows all errors, anyway.
+ OSL_ENSURE( false,
+ rtl::OUStringToOString(
+ comphelper::anyToString( cppu::getCaughtException() ),
+ RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ // at least one shape could not be rendered
+ bRet = false;
+ }
+
+ ++aIter;
+ }
+
+ return bRet;
+ }
+
+ void LayerManager::addUpdateArea( ShapeSharedPtr const& rShape )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+ ENSURE_OR_THROW( rShape, "LayerManager::addUpdateArea(): invalid Shape" );
+
+ const LayerShapeMap::const_iterator aShapeEntry( maAllShapes.find(rShape) );
+
+ if( aShapeEntry == maAllShapes.end() )
+ return;
+
+ LayerSharedPtr pLayer = aShapeEntry->second.lock();
+ if( pLayer )
+ pLayer->addUpdateRange( rShape->getUpdateArea() );
+ }
+
+ void LayerManager::commitLayerChanges( std::size_t nCurrLayerIndex,
+ LayerShapeMap::const_iterator aFirstLayerShape,
+ LayerShapeMap::const_iterator aEndLayerShapes )
+ {
+ const bool bLayerExists( maLayers.size() > nCurrLayerIndex );
+ if( bLayerExists )
+ {
+ const LayerSharedPtr& rLayer( maLayers.at(nCurrLayerIndex) );
+ const bool bLayerResized( rLayer->commitBounds() );
+ rLayer->setPriority( basegfx::B1DRange(nCurrLayerIndex,
+ nCurrLayerIndex+1) );
+
+ if( bLayerResized )
+ {
+ // need to re-render whole layer - start from
+ // clean state
+ rLayer->clearContent();
+
+ // render and remove from update set
+ while( aFirstLayerShape != aEndLayerShapes )
+ {
+ maUpdateShapes.erase(aFirstLayerShape->first);
+ aFirstLayerShape->first->render();
+ ++aFirstLayerShape;
+ }
+ }
+ }
+ }
+
+ LayerSharedPtr LayerManager::createForegroundLayer() const
+ {
+ OSL_ASSERT( mbActive );
+
+ LayerSharedPtr pLayer( Layer::createLayer(
+ maPageBounds ));
+
+ // create ViewLayers for all registered views, and add to
+ // newly created layer.
+ ::std::for_each( mrViews.begin(),
+ mrViews.end(),
+ boost::bind( &Layer::addView,
+ boost::cref(pLayer),
+ _1 ));
+
+ return pLayer;
+ }
+
+ void LayerManager::updateShapeLayers( bool bBackgroundLayerPainted )
+ {
+ OSL_ASSERT( !maLayers.empty() ); // always at least background layer
+ OSL_ASSERT( mbActive );
+
+ // do we need to process shapes?
+ if( !mbLayerAssociationDirty )
+ return;
+
+ if( mbDisableAnimationZOrder )
+ {
+ // layer setup happened elsewhere, is only bg layer
+ // anyway.
+ mbLayerAssociationDirty = false;
+ return;
+ }
+
+ // scan through maAllShapes, and determine shape animation
+ // discontinuities: when a shape that has
+ // isBackgroundDetached() return false follows a shape
+ // with isBackgroundDetached() true, the former and all
+ // following ones must be moved into an own layer.
+
+ // to avoid tons of temporaries, create weak_ptr to Layers
+ // beforehand
+ std::vector< LayerWeakPtr > aWeakLayers(maLayers.size());
+ std::copy(maLayers.begin(),maLayers.end(),aWeakLayers.begin());
+
+ std::size_t nCurrLayerIndex(0);
+ bool bIsBackgroundLayer(true);
+ bool bLastWasBackgroundDetached(false); // last shape sprite state
+ LayerShapeMap::iterator aCurrShapeEntry( maAllShapes.begin() );
+ LayerShapeMap::iterator aCurrLayerFirstShapeEntry( maAllShapes.begin() );
+ const LayerShapeMap::iterator aEndShapeEntry ( maAllShapes.end() );
+ ShapeUpdateSet aUpdatedShapes; // shapes that need update
+ while( aCurrShapeEntry != aEndShapeEntry )
+ {
+ const ShapeSharedPtr pCurrShape( aCurrShapeEntry->first );
+ const bool bThisIsBackgroundDetached(
+ pCurrShape->isBackgroundDetached() );
+
+ if( bLastWasBackgroundDetached == true &&
+ bThisIsBackgroundDetached == false )
+ {
+ // discontinuity found - current shape needs to
+ // get into a new layer
+ // --------------------------------------------
+
+ // commit changes to previous layer
+ commitLayerChanges(nCurrLayerIndex,
+ aCurrLayerFirstShapeEntry,
+ aCurrShapeEntry);
+ aCurrLayerFirstShapeEntry=aCurrShapeEntry;
+ ++nCurrLayerIndex;
+ bIsBackgroundLayer = false;
+
+ if( aWeakLayers.size() <= nCurrLayerIndex ||
+ aWeakLayers.at(nCurrLayerIndex) != aCurrShapeEntry->second )
+ {
+ // no more layers left, or shape was not
+ // member of this layer - create a new one
+ maLayers.insert( maLayers.begin()+nCurrLayerIndex,
+ createForegroundLayer() );
+ aWeakLayers.insert( aWeakLayers.begin()+nCurrLayerIndex,
+ maLayers[nCurrLayerIndex] );
+ }
+ }
+
+ OSL_ASSERT( maLayers.size() == aWeakLayers.size() );
+
+ // note: using indices here, since vector::insert
+ // above invalidates iterators
+ LayerSharedPtr& rCurrLayer( maLayers.at(nCurrLayerIndex) );
+ LayerWeakPtr& rCurrWeakLayer( aWeakLayers.at(nCurrLayerIndex) );
+ if( rCurrWeakLayer != aCurrShapeEntry->second )
+ {
+ // mismatch: shape is not contained in current
+ // layer - move shape to that layer, then.
+ maLayers.at(nCurrLayerIndex)->setShapeViews(
+ pCurrShape );
+
+ // layer got new shape(s), need full repaint, if
+ // non-sprite shape
+ if( !bThisIsBackgroundDetached && pCurrShape->isVisible() )
+ {
+ LayerSharedPtr pOldLayer( aCurrShapeEntry->second.lock() );
+ if( pOldLayer )
+ {
+ // old layer still valid? then we need to
+ // repaint former shape area
+ pOldLayer->addUpdateRange(
+ pCurrShape->getUpdateArea() );
+ }
+
+ // render on new layer (only if not
+ // explicitely disabled)
+ if( !(bBackgroundLayerPainted && bIsBackgroundLayer) )
+ maUpdateShapes.insert( pCurrShape );
+ }
+
+ aCurrShapeEntry->second = rCurrWeakLayer;
+ }
+
+ // update layerbounds regardless of the fact that the
+ // shape might be contained in said layer
+ // already. updateBounds() is dumb and needs to
+ // collect all shape bounds.
+ // of course, no need to expand layer bounds for
+ // shapes that reside in sprites themselves.
+ if( !bThisIsBackgroundDetached && !bIsBackgroundLayer )
+ rCurrLayer->updateBounds( pCurrShape );
+
+ bLastWasBackgroundDetached = bThisIsBackgroundDetached;
+ ++aCurrShapeEntry;
+ }
+
+ // commit very last layer data
+ commitLayerChanges(nCurrLayerIndex,
+ aCurrLayerFirstShapeEntry,
+ aCurrShapeEntry);
+
+ // any layers left? Bin them!
+ if( maLayers.size() > nCurrLayerIndex+1 )
+ maLayers.erase(maLayers.begin()+nCurrLayerIndex+1,
+ maLayers.end());
+
+ mbLayerAssociationDirty = false;
+ }
+ }
+}