| /************************************************************** |
| * |
| * 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 happened 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 |
| // explicitly 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; |
| } |
| } |
| } |