Update ooo320-m1
[ooovba.git] / slideshow / source / engine / slide / layermanager.cxx
blobf55bef6ba07245195a1d6e782e1e67087e6b6708
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: layermanager.cxx,v $
10 * $Revision: 1.6 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_slideshow.hxx"
34 #include <canvas/debug.hxx>
35 #include <tools/diagnose_ex.h>
36 #include <basegfx/range/b1drange.hxx>
37 #include <basegfx/matrix/b2dhommatrix.hxx>
39 #include <comphelper/anytostring.hxx>
40 #include <cppuhelper/exc_hlp.hxx>
42 #include <boost/bind.hpp>
43 #include <algorithm>
45 #include "layermanager.hxx"
47 using namespace ::com::sun::star;
49 namespace boost
51 // add operator!= for weak_ptr
52 inline bool operator!=( slideshow::internal::LayerWeakPtr const& rLHS,
53 slideshow::internal::LayerWeakPtr const& rRHS )
55 return (rLHS<rRHS) || (rRHS<rLHS);
59 namespace slideshow
61 namespace internal
63 template<typename LayerFunc,
64 typename ShapeFunc> void LayerManager::manageViews(
65 LayerFunc layerFunc,
66 ShapeFunc shapeFunc )
68 LayerSharedPtr pCurrLayer;
69 ViewLayerSharedPtr pCurrViewLayer;
70 LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
71 const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
72 while( aIter != aEnd )
74 LayerSharedPtr pLayer = aIter->second.lock();
75 if( pLayer && pLayer != pCurrLayer )
77 pCurrLayer = pLayer;
78 pCurrViewLayer = layerFunc(pCurrLayer);
81 if( pCurrViewLayer )
82 shapeFunc(aIter->first,pCurrViewLayer);
84 ++aIter;
88 LayerManager::LayerManager( const UnoViewContainer& rViews,
89 const ::basegfx::B2DRange& rPageBounds,
90 bool bDisableAnimationZOrder ) :
91 mrViews(rViews),
92 maLayers(),
93 maXShapeHash( 101 ),
94 maAllShapes(),
95 maUpdateShapes(),
96 maPageBounds( rPageBounds ),
97 mnActiveSprites(0),
98 mbLayerAssociationDirty(false),
99 mbActive(false),
100 mbDisableAnimationZOrder(bDisableAnimationZOrder)
102 // prevent frequent resizes (won't have more than 4 layers
103 // for 99.9% of the cases)
104 maLayers.reserve(4);
106 // create initial background layer
107 maLayers.push_back(
108 Layer::createBackgroundLayer(
109 maPageBounds ));
111 // init views
112 std::for_each( mrViews.begin(),
113 mrViews.end(),
114 ::boost::bind(&LayerManager::viewAdded,
115 this,
116 _1) );
119 void LayerManager::activate( bool bSlideBackgoundPainted )
121 mbActive = true;
122 maUpdateShapes.clear(); // update gets forced via area, or
123 // has happend outside already
125 if( !bSlideBackgoundPainted )
127 std::for_each(mrViews.begin(),
128 mrViews.end(),
129 boost::mem_fn(&View::clearAll));
131 // force update of whole slide area
132 std::for_each( maLayers.begin(),
133 maLayers.end(),
134 boost::bind( &Layer::addUpdateRange,
136 boost::cref(maPageBounds) ));
138 else
140 // clear all possibly pending update areas - content
141 // is there, already
142 std::for_each( maLayers.begin(),
143 maLayers.end(),
144 boost::mem_fn( &Layer::clearUpdateRanges ));
147 updateShapeLayers( bSlideBackgoundPainted );
150 void LayerManager::deactivate()
152 // TODO(F3): This is mostly a hack. Problem is, there's
153 // currently no smart way of telling shapes "remove your
154 // sprites". Others, like MediaShapes, listen to
155 // start/stop animation events, which is too much overhead
156 // for all shapes, though.
158 const bool bMoreThanOneLayer(maLayers.size() > 1);
159 if( mnActiveSprites || bMoreThanOneLayer )
161 // clear all viewlayers, dump everything but the
162 // background layer - this will also remove all shape
163 // sprites
164 std::for_each(maAllShapes.begin(),
165 maAllShapes.end(),
166 boost::bind( &Shape::clearAllViewLayers,
167 boost::bind( std::select1st<LayerShapeMap::value_type>(),
168 _1 )));
170 for (LayerShapeMap::iterator
171 iShape (maAllShapes.begin()),
172 iEnd (maAllShapes.end());
173 iShape!=iEnd;
174 ++iShape)
176 iShape->second.reset();
179 if( bMoreThanOneLayer )
180 maLayers.erase(maLayers.begin()+1,
181 maLayers.end());
183 mbLayerAssociationDirty = true;
186 mbActive = false;
188 // only background layer left
189 OSL_ASSERT( maLayers.size() == 1 && maLayers.front()->isBackgroundLayer() );
192 void LayerManager::viewAdded( const UnoViewSharedPtr& rView )
194 // view must be member of mrViews container
195 OSL_ASSERT( std::find(mrViews.begin(),
196 mrViews.end(),
197 rView) != mrViews.end() );
199 // init view content
200 if( mbActive )
201 rView->clearAll();
203 // add View to all registered shapes
204 manageViews(
205 boost::bind(&Layer::addView,
207 boost::cref(rView)),
208 // repaint on view add
209 boost::bind(&Shape::addViewLayer,
210 _1,
212 true) );
214 // in case we haven't reached all layers from the
215 // maAllShapes, issue addView again for good measure
216 std::for_each( maLayers.begin(),
217 maLayers.end(),
218 boost::bind( &Layer::addView,
220 boost::cref(rView) ));
223 void LayerManager::viewRemoved( const UnoViewSharedPtr& rView )
225 // view must not be member of mrViews container anymore
226 OSL_ASSERT( std::find(mrViews.begin(),
227 mrViews.end(),
228 rView) == mrViews.end() );
230 // remove View from all registered shapes
231 manageViews(
232 boost::bind(&Layer::removeView,
234 boost::cref(rView)),
235 boost::bind(&Shape::removeViewLayer,
237 _2) );
239 // in case we haven't reached all layers from the
240 // maAllShapes, issue removeView again for good measure
241 std::for_each( maLayers.begin(),
242 maLayers.end(),
243 boost::bind( &Layer::removeView,
245 boost::cref(rView) ));
248 void LayerManager::viewChanged( const UnoViewSharedPtr& rView )
250 (void)rView;
252 // view must be member of mrViews container
253 OSL_ASSERT( std::find(mrViews.begin(),
254 mrViews.end(),
255 rView) != mrViews.end() );
257 // TODO(P2): selectively update only changed view
258 viewsChanged();
261 void LayerManager::viewsChanged()
263 if( !mbActive )
264 return;
266 // clear view area
267 ::std::for_each( mrViews.begin(),
268 mrViews.end(),
269 ::boost::mem_fn(&View::clearAll) );
271 // TODO(F3): resize and repaint all layers
273 // render all shapes
274 std::for_each( maAllShapes.begin(),
275 maAllShapes.end(),
276 boost::bind(&Shape::render,
277 boost::bind( ::std::select1st<LayerShapeMap::value_type>(), _1)) );
280 void LayerManager::addShape( const ShapeSharedPtr& rShape )
282 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
283 ENSURE_OR_THROW( rShape, "LayerManager::addShape(): invalid Shape" );
285 // add shape to XShape hash map
286 if( !maXShapeHash.insert(
287 XShapeHash::value_type( rShape->getXShape(),
288 rShape) ).second )
290 // entry already present, nothing to do
291 return;
294 // add shape to appropriate layer
295 implAddShape( rShape );
298 void LayerManager::putShape2BackgroundLayer( LayerShapeMap::value_type& rShapeEntry )
300 LayerSharedPtr& rBgLayer( maLayers.front() );
301 rBgLayer->setShapeViews(rShapeEntry.first);
302 rShapeEntry.second = rBgLayer;
305 void LayerManager::implAddShape( const ShapeSharedPtr& rShape )
307 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
308 ENSURE_OR_THROW( rShape, "LayerManager::implAddShape(): invalid Shape" );
310 LayerShapeMap::value_type aValue (rShape, LayerWeakPtr());
312 OSL_ASSERT( maAllShapes.find(rShape) == maAllShapes.end() ); // shape must not be added already
313 mbLayerAssociationDirty = true;
315 if( mbDisableAnimationZOrder )
316 putShape2BackgroundLayer(
317 *maAllShapes.insert(aValue).first );
318 else
319 maAllShapes.insert(aValue);
321 // update shape, it's just added and not yet painted
322 if( rShape->isVisible() )
323 notifyShapeUpdate( rShape );
326 bool LayerManager::removeShape( const ShapeSharedPtr& rShape )
328 // remove shape from XShape hash map
329 if( maXShapeHash.erase( rShape->getXShape() ) == 0 )
330 return false; // shape not in map
332 OSL_ASSERT( maAllShapes.find(rShape) != maAllShapes.end() );
334 implRemoveShape( rShape );
336 return true;
339 void LayerManager::implRemoveShape( const ShapeSharedPtr& rShape )
341 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
342 ENSURE_OR_THROW( rShape, "LayerManager::implRemoveShape(): invalid Shape" );
344 const LayerShapeMap::iterator aShapeEntry( maAllShapes.find(rShape) );
346 if( aShapeEntry == maAllShapes.end() )
347 return;
349 const bool bShapeUpdateNotified = maUpdateShapes.erase( rShape ) != 0;
351 // Enter shape area to the update area, but only if shape
352 // is visible and not in sprite mode (otherwise, updating
353 // the area doesn't do actual harm, but costs time)
354 // Actually, also add it if it was listed in
355 // maUpdateShapes (might have just gone invisible).
356 if( bShapeUpdateNotified ||
357 (rShape->isVisible() &&
358 !rShape->isBackgroundDetached()) )
360 LayerSharedPtr pLayer = aShapeEntry->second.lock();
361 if( pLayer )
363 // store area early, once the shape is removed from
364 // the layers, it no longer has any view references
365 pLayer->addUpdateRange( rShape->getUpdateArea() );
369 rShape->clearAllViewLayers();
370 maAllShapes.erase( aShapeEntry );
372 mbLayerAssociationDirty = true;
375 ShapeSharedPtr LayerManager::lookupShape( const uno::Reference< drawing::XShape >& xShape ) const
377 ENSURE_OR_THROW( xShape.is(), "LayerManager::lookupShape(): invalid Shape" );
379 const XShapeHash::const_iterator aIter( maXShapeHash.find( xShape ));
380 if( aIter == maXShapeHash.end() )
381 return ShapeSharedPtr(); // not found
383 // found, return data part of entry pair.
384 return aIter->second;
387 AttributableShapeSharedPtr LayerManager::getSubsetShape( const AttributableShapeSharedPtr& rOrigShape,
388 const DocTreeNode& rTreeNode )
390 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
392 AttributableShapeSharedPtr pSubset;
394 // shape already added?
395 if( rOrigShape->createSubset( pSubset,
396 rTreeNode ) )
398 OSL_ENSURE( pSubset, "LayerManager::getSubsetShape(): failed to create subset" );
400 // don't add to shape hash, we're dupes to the
401 // original XShape anyway - all subset shapes return
402 // the same XShape as the original one.
404 // add shape to corresponding layer
405 implAddShape( pSubset );
407 // update original shape, it now shows less content
408 // (the subset is removed from its displayed
409 // output). Subset shape is updated within
410 // implAddShape().
411 if( rOrigShape->isVisible() )
412 notifyShapeUpdate( rOrigShape );
415 return pSubset;
418 void LayerManager::revokeSubset( const AttributableShapeSharedPtr& rOrigShape,
419 const AttributableShapeSharedPtr& rSubsetShape )
421 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
423 if( rOrigShape->revokeSubset( rSubsetShape ) )
425 OSL_ASSERT( maAllShapes.find(rSubsetShape) != maAllShapes.end() );
427 implRemoveShape( rSubsetShape );
429 // update original shape, it now shows more content
430 // (the subset is added back to its displayed output)
431 if( rOrigShape->isVisible() )
432 notifyShapeUpdate( rOrigShape );
436 void LayerManager::enterAnimationMode( const AnimatableShapeSharedPtr& rShape )
438 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
439 ENSURE_OR_THROW( rShape, "LayerManager::enterAnimationMode(): invalid Shape" );
441 const bool bPrevAnimState( rShape->isBackgroundDetached() );
443 rShape->enterAnimationMode();
445 // if this call _really_ enabled the animation mode at
446 // rShape, insert it to our enter animation queue, to
447 // perform the necessary layer reorg lazily on
448 // LayerManager::update()/render().
449 if( bPrevAnimState != rShape->isBackgroundDetached() )
451 ++mnActiveSprites;
452 mbLayerAssociationDirty = true;
454 // area needs update (shape is removed from normal
455 // slide, and now rendered as an autonomous
456 // sprite). store in update set
457 if( rShape->isVisible() )
458 addUpdateArea( rShape );
461 // TODO(P1): this can lead to potential wasted effort, if
462 // a shape gets toggled animated/unanimated a few times
463 // between two frames, returning to the original state.
466 void LayerManager::leaveAnimationMode( const AnimatableShapeSharedPtr& rShape )
468 ENSURE_OR_THROW( !maLayers.empty(), "LayerManager::leaveAnimationMode(): no layers" );
469 ENSURE_OR_THROW( rShape, "LayerManager::leaveAnimationMode(): invalid Shape" );
471 const bool bPrevAnimState( rShape->isBackgroundDetached() );
473 rShape->leaveAnimationMode();
475 // if this call _really_ ended the animation mode at
476 // rShape, insert it to our leave animation queue, to
477 // perform the necessary layer reorg lazily on
478 // LayerManager::update()/render().
479 if( bPrevAnimState != rShape->isBackgroundDetached() )
481 --mnActiveSprites;
482 mbLayerAssociationDirty = true;
484 // shape needs update, no previous rendering, fast
485 // update possible.
486 if( rShape->isVisible() )
487 notifyShapeUpdate( rShape );
490 // TODO(P1): this can lead to potential wasted effort, if
491 // a shape gets toggled animated/unanimated a few times
492 // between two frames, returning to the original state.
495 void LayerManager::notifyShapeUpdate( const ShapeSharedPtr& rShape )
497 if( !mbActive || mrViews.empty() )
498 return;
500 // hidden sprite-shape needs render() call still, to hide sprite
501 if( rShape->isVisible() || rShape->isBackgroundDetached() )
502 maUpdateShapes.insert( rShape );
503 else
504 addUpdateArea( rShape );
507 bool LayerManager::isUpdatePending() const
509 if( !mbActive )
510 return false;
512 if( mbLayerAssociationDirty || !maUpdateShapes.empty() )
513 return true;
515 const LayerVector::const_iterator aEnd( maLayers.end() );
516 if( std::find_if( maLayers.begin(),
517 aEnd,
518 boost::mem_fn(&Layer::isUpdatePending)) != aEnd )
519 return true;
521 return false;
524 bool LayerManager::updateSprites()
526 bool bRet(true);
528 // send update() calls to every shape in the
529 // maUpdateShapes set, which is _animated_ (i.e. a
530 // sprite).
531 const ShapeUpdateSet::const_iterator aEnd=maUpdateShapes.end();
532 ShapeUpdateSet::const_iterator aCurrShape=maUpdateShapes.begin();
533 while( aCurrShape != aEnd )
535 if( (*aCurrShape)->isBackgroundDetached() )
537 // can update shape directly, without
538 // affecting layer content (shape is
539 // currently displayed in a sprite)
540 if( !(*aCurrShape)->update() )
541 bRet = false; // delay error exit
543 else
545 // TODO(P2): addUpdateArea() involves log(n)
546 // search for shape layer. Have a frequent
547 // shape/layer association cache, or ptr back to
548 // layer at the shape?
550 // cannot update shape directly, it's not
551 // animated and update() calls will prolly
552 // overwrite other page content.
553 addUpdateArea( *aCurrShape );
556 ++aCurrShape;
559 maUpdateShapes.clear();
561 return bRet;
564 bool LayerManager::update()
566 bool bRet = true;
568 if( !mbActive )
569 return bRet;
571 // going to render - better flush any pending layer reorg
572 // now
573 updateShapeLayers(false);
575 // all sprites
576 bRet = updateSprites();
578 // any non-sprite update areas left?
579 if( std::find_if( maLayers.begin(),
580 maLayers.end(),
581 boost::mem_fn( &Layer::isUpdatePending )) == maLayers.end() )
582 return bRet; // nope, done.
584 // update each shape on each layer, that has
585 // isUpdatePending()
586 bool bIsCurrLayerUpdating(false);
587 Layer::EndUpdater aEndUpdater;
588 LayerSharedPtr pCurrLayer;
589 LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
590 const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
591 while( aIter != aEnd )
593 LayerSharedPtr pLayer = aIter->second.lock();
594 if( pLayer != pCurrLayer )
596 pCurrLayer = pLayer;
597 bIsCurrLayerUpdating = pCurrLayer->isUpdatePending();
599 if( bIsCurrLayerUpdating )
600 aEndUpdater = pCurrLayer->beginUpdate();
603 if( bIsCurrLayerUpdating &&
604 !aIter->first->isBackgroundDetached() &&
605 pCurrLayer->isInsideUpdateArea(aIter->first) )
607 if( !aIter->first->render() )
608 bRet = false;
611 ++aIter;
614 return bRet;
617 namespace
619 /** Little wrapper around a Canvas, to render one-shot
620 into a canvas
622 class DummyLayer : public ViewLayer
624 public:
625 explicit DummyLayer( const ::cppcanvas::CanvasSharedPtr& rCanvas ) :
626 mpCanvas( rCanvas )
630 virtual bool isOnView(boost::shared_ptr<View> const& /*rView*/) const
632 return true; // visible on all views
635 virtual ::cppcanvas::CanvasSharedPtr getCanvas() const
637 return mpCanvas;
640 virtual void clear() const
642 // NOOP
645 virtual void clearAll() const
647 // NOOP
650 virtual ::cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& /*rSpriteSizePixel*/,
651 double /*nSpritePrio*/ ) const
653 ENSURE_OR_THROW( false,
654 "DummyLayer::createSprite(): This method is not supposed to be called!" );
655 return ::cppcanvas::CustomSpriteSharedPtr();
658 virtual void setPriority( const basegfx::B1DRange& /*rRange*/ )
660 OSL_ENSURE( false,
661 "BitmapView::setPriority(): This method is not supposed to be called!" );
664 virtual ::basegfx::B2DHomMatrix getTransformation() const
666 return mpCanvas->getTransformation();
669 virtual ::basegfx::B2DHomMatrix getSpriteTransformation() const
671 OSL_ENSURE( false,
672 "BitmapView::getSpriteTransformation(): This method is not supposed to be called!" );
673 return ::basegfx::B2DHomMatrix();
676 virtual void setClip( const ::basegfx::B2DPolyPolygon& /*rClip*/ )
678 OSL_ENSURE( false,
679 "BitmapView::setClip(): This method is not supposed to be called!" );
682 virtual bool resize( const ::basegfx::B2DRange& /*rArea*/ )
684 OSL_ENSURE( false,
685 "BitmapView::resize(): This method is not supposed to be called!" );
686 return false;
689 private:
690 ::cppcanvas::CanvasSharedPtr mpCanvas;
694 bool LayerManager::renderTo( const ::cppcanvas::CanvasSharedPtr& rTargetCanvas ) const
696 bool bRet( true );
697 ViewLayerSharedPtr pTmpLayer( new DummyLayer( rTargetCanvas ) );
699 LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
700 const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
701 while( aIter != aEnd )
705 // forward to all shape's addViewLayer method (which
706 // we request to render the Shape on the new
707 // ViewLayer. Since we add the shapes in the
708 // maShapeSet order (which is also the render order),
709 // this is equivalent to a subsequent render() call)
710 aIter->first->addViewLayer( pTmpLayer,
711 true );
713 // and remove again, this is only temporary
714 aIter->first->removeViewLayer( pTmpLayer );
716 catch( uno::Exception& )
718 // TODO(E1): Might be superfluous. Nowadays,
719 // addViewLayer swallows all errors, anyway.
720 OSL_ENSURE( false,
721 rtl::OUStringToOString(
722 comphelper::anyToString( cppu::getCaughtException() ),
723 RTL_TEXTENCODING_UTF8 ).getStr() );
725 // at least one shape could not be rendered
726 bRet = false;
729 ++aIter;
732 return bRet;
735 void LayerManager::addUpdateArea( ShapeSharedPtr const& rShape )
737 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
738 ENSURE_OR_THROW( rShape, "LayerManager::addUpdateArea(): invalid Shape" );
740 const LayerShapeMap::const_iterator aShapeEntry( maAllShapes.find(rShape) );
742 if( aShapeEntry == maAllShapes.end() )
743 return;
745 LayerSharedPtr pLayer = aShapeEntry->second.lock();
746 if( pLayer )
747 pLayer->addUpdateRange( rShape->getUpdateArea() );
750 void LayerManager::commitLayerChanges( std::size_t nCurrLayerIndex,
751 LayerShapeMap::const_iterator aFirstLayerShape,
752 LayerShapeMap::const_iterator aEndLayerShapes )
754 const bool bLayerExists( maLayers.size() > nCurrLayerIndex );
755 if( bLayerExists )
757 const LayerSharedPtr& rLayer( maLayers.at(nCurrLayerIndex) );
758 const bool bLayerResized( rLayer->commitBounds() );
759 rLayer->setPriority( basegfx::B1DRange(nCurrLayerIndex,
760 nCurrLayerIndex+1) );
762 if( bLayerResized )
764 // need to re-render whole layer - start from
765 // clean state
766 rLayer->clearContent();
768 // render and remove from update set
769 while( aFirstLayerShape != aEndLayerShapes )
771 maUpdateShapes.erase(aFirstLayerShape->first);
772 aFirstLayerShape->first->render();
773 ++aFirstLayerShape;
779 LayerSharedPtr LayerManager::createForegroundLayer() const
781 OSL_ASSERT( mbActive );
783 LayerSharedPtr pLayer( Layer::createLayer(
784 maPageBounds ));
786 // create ViewLayers for all registered views, and add to
787 // newly created layer.
788 ::std::for_each( mrViews.begin(),
789 mrViews.end(),
790 boost::bind( &Layer::addView,
791 boost::cref(pLayer),
792 _1 ));
794 return pLayer;
797 void LayerManager::updateShapeLayers( bool bBackgroundLayerPainted )
799 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
800 OSL_ASSERT( mbActive );
802 // do we need to process shapes?
803 if( !mbLayerAssociationDirty )
804 return;
806 if( mbDisableAnimationZOrder )
808 // layer setup happened elsewhere, is only bg layer
809 // anyway.
810 mbLayerAssociationDirty = false;
811 return;
814 // scan through maAllShapes, and determine shape animation
815 // discontinuities: when a shape that has
816 // isBackgroundDetached() return false follows a shape
817 // with isBackgroundDetached() true, the former and all
818 // following ones must be moved into an own layer.
820 // to avoid tons of temporaries, create weak_ptr to Layers
821 // beforehand
822 std::vector< LayerWeakPtr > aWeakLayers(maLayers.size());
823 std::copy(maLayers.begin(),maLayers.end(),aWeakLayers.begin());
825 std::size_t nCurrLayerIndex(0);
826 bool bIsBackgroundLayer(true);
827 bool bLastWasBackgroundDetached(false); // last shape sprite state
828 LayerShapeMap::iterator aCurrShapeEntry( maAllShapes.begin() );
829 LayerShapeMap::iterator aCurrLayerFirstShapeEntry( maAllShapes.begin() );
830 const LayerShapeMap::iterator aEndShapeEntry ( maAllShapes.end() );
831 ShapeUpdateSet aUpdatedShapes; // shapes that need update
832 while( aCurrShapeEntry != aEndShapeEntry )
834 const ShapeSharedPtr pCurrShape( aCurrShapeEntry->first );
835 const bool bThisIsBackgroundDetached(
836 pCurrShape->isBackgroundDetached() );
838 if( bLastWasBackgroundDetached == true &&
839 bThisIsBackgroundDetached == false )
841 // discontinuity found - current shape needs to
842 // get into a new layer
843 // --------------------------------------------
845 // commit changes to previous layer
846 commitLayerChanges(nCurrLayerIndex,
847 aCurrLayerFirstShapeEntry,
848 aCurrShapeEntry);
849 aCurrLayerFirstShapeEntry=aCurrShapeEntry;
850 ++nCurrLayerIndex;
851 bIsBackgroundLayer = false;
853 if( aWeakLayers.size() <= nCurrLayerIndex ||
854 aWeakLayers.at(nCurrLayerIndex) != aCurrShapeEntry->second )
856 // no more layers left, or shape was not
857 // member of this layer - create a new one
858 maLayers.insert( maLayers.begin()+nCurrLayerIndex,
859 createForegroundLayer() );
860 aWeakLayers.insert( aWeakLayers.begin()+nCurrLayerIndex,
861 maLayers[nCurrLayerIndex] );
865 OSL_ASSERT( maLayers.size() == aWeakLayers.size() );
867 // note: using indices here, since vector::insert
868 // above invalidates iterators
869 LayerSharedPtr& rCurrLayer( maLayers.at(nCurrLayerIndex) );
870 LayerWeakPtr& rCurrWeakLayer( aWeakLayers.at(nCurrLayerIndex) );
871 if( rCurrWeakLayer != aCurrShapeEntry->second )
873 // mismatch: shape is not contained in current
874 // layer - move shape to that layer, then.
875 maLayers.at(nCurrLayerIndex)->setShapeViews(
876 pCurrShape );
878 // layer got new shape(s), need full repaint, if
879 // non-sprite shape
880 if( !bThisIsBackgroundDetached && pCurrShape->isVisible() )
882 LayerSharedPtr pOldLayer( aCurrShapeEntry->second.lock() );
883 if( pOldLayer )
885 // old layer still valid? then we need to
886 // repaint former shape area
887 pOldLayer->addUpdateRange(
888 pCurrShape->getUpdateArea() );
891 // render on new layer (only if not
892 // explicitely disabled)
893 if( !(bBackgroundLayerPainted && bIsBackgroundLayer) )
894 maUpdateShapes.insert( pCurrShape );
897 aCurrShapeEntry->second = rCurrWeakLayer;
900 // update layerbounds regardless of the fact that the
901 // shape might be contained in said layer
902 // already. updateBounds() is dumb and needs to
903 // collect all shape bounds.
904 // of course, no need to expand layer bounds for
905 // shapes that reside in sprites themselves.
906 if( !bThisIsBackgroundDetached && !bIsBackgroundLayer )
907 rCurrLayer->updateBounds( pCurrShape );
909 bLastWasBackgroundDetached = bThisIsBackgroundDetached;
910 ++aCurrShapeEntry;
913 // commit very last layer data
914 commitLayerChanges(nCurrLayerIndex,
915 aCurrLayerFirstShapeEntry,
916 aCurrShapeEntry);
918 // any layers left? Bin them!
919 if( maLayers.size() > nCurrLayerIndex+1 )
920 maLayers.erase(maLayers.begin()+nCurrLayerIndex+1,
921 maLayers.end());
923 mbLayerAssociationDirty = false;