blob: fd8a79b6c2641783b825b15bc8e0c0b783342a28 [file] [log] [blame]
/**************************************************************
*
* 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.
*
*************************************************************/
// 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;
}
}
}