Bump version to 6.0-36
[LibreOffice.git] / slideshow / source / engine / slide / layermanager.cxx
blob09c80f2208c1219d428de00a875868d104951881
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <tools/diagnose_ex.h>
22 #include <basegfx/range/b1drange.hxx>
23 #include <basegfx/matrix/b2dhommatrix.hxx>
25 #include <comphelper/anytostring.hxx>
26 #include <cppuhelper/exc_hlp.hxx>
28 #include <functional>
29 #include <algorithm>
31 #include "layermanager.hxx"
33 using namespace ::com::sun::star;
35 namespace std
37 // add operator!= for weak_ptr
38 inline bool operator!=( slideshow::internal::LayerWeakPtr const& rLHS,
39 slideshow::internal::LayerWeakPtr const& rRHS )
41 return rLHS.lock().get() != rRHS.lock().get();
45 namespace slideshow
47 namespace internal
49 template<typename LayerFunc,
50 typename ShapeFunc> void LayerManager::manageViews(
51 LayerFunc layerFunc,
52 ShapeFunc shapeFunc )
54 LayerSharedPtr pCurrLayer;
55 ViewLayerSharedPtr pCurrViewLayer;
56 for( const auto& rShape : maAllShapes )
58 LayerSharedPtr pLayer = rShape.second.lock();
59 if( pLayer && pLayer != pCurrLayer )
61 pCurrLayer = pLayer;
62 pCurrViewLayer = layerFunc(pCurrLayer);
65 if( pCurrViewLayer )
66 shapeFunc(rShape.first,pCurrViewLayer);
70 LayerManager::LayerManager( const UnoViewContainer& rViews,
71 bool bDisableAnimationZOrder ) :
72 mrViews(rViews),
73 maLayers(),
74 maXShapeHash( 101 ),
75 maAllShapes(),
76 maUpdateShapes(),
77 mnActiveSprites(0),
78 mbLayerAssociationDirty(false),
79 mbActive(false),
80 mbDisableAnimationZOrder(bDisableAnimationZOrder)
82 // prevent frequent resizes (won't have more than 4 layers
83 // for 99.9% of the cases)
84 maLayers.reserve(4);
86 // create initial background layer
87 maLayers.push_back( Layer::createBackgroundLayer() );
89 // init views
90 for( const auto& rView : mrViews )
91 viewAdded( rView );
94 void LayerManager::activate()
96 mbActive = true;
97 maUpdateShapes.clear(); // update gets forced via area, or
98 // has happened outside already
100 // clear all possibly pending update areas - content
101 // is there, already
102 for( const auto& pLayer : maLayers )
103 pLayer->clearUpdateRanges();
105 updateShapeLayers( true/*bSlideBackgoundPainted*/ );
108 void LayerManager::deactivate()
110 // TODO(F3): This is mostly a hack. Problem is, there's
111 // currently no smart way of telling shapes "remove your
112 // sprites". Others, like MediaShapes, listen to
113 // start/stop animation events, which is too much overhead
114 // for all shapes, though.
116 const bool bMoreThanOneLayer(maLayers.size() > 1);
117 if (mnActiveSprites || bMoreThanOneLayer)
119 // clear all viewlayers, dump everything but the
120 // background layer - this will also remove all shape
121 // sprites
122 for (auto& rShape : maAllShapes)
123 rShape.first->clearAllViewLayers();
125 for (auto& rShape : maAllShapes)
126 rShape.second.reset();
128 if (bMoreThanOneLayer)
129 maLayers.erase(maLayers.begin() + 1, maLayers.end());
131 mbLayerAssociationDirty = true;
134 mbActive = false;
136 // only background layer left
137 OSL_ASSERT( maLayers.size() == 1 && maLayers.front()->isBackgroundLayer() );
140 void LayerManager::viewAdded( const UnoViewSharedPtr& rView )
142 // view must be member of mrViews container
143 OSL_ASSERT( std::find(mrViews.begin(),
144 mrViews.end(),
145 rView) != mrViews.end() );
147 // init view content
148 if( mbActive )
149 rView->clearAll();
151 // add View to all registered shapes
152 manageViews(
153 [&rView]( const LayerSharedPtr& pLayer )
154 { return pLayer->addView( rView ); },
155 []( const ShapeSharedPtr& pShape, const ViewLayerSharedPtr& pLayer )
156 { return pShape->addViewLayer( pLayer, true ); } );
158 // in case we haven't reached all layers from the
159 // maAllShapes, issue addView again for good measure
160 for( const auto& pLayer : maLayers )
161 pLayer->addView( rView );
164 void LayerManager::viewRemoved( const UnoViewSharedPtr& rView )
166 // view must not be member of mrViews container anymore
167 OSL_ASSERT( std::find(mrViews.begin(),
168 mrViews.end(),
169 rView) == mrViews.end() );
171 // remove View from all registered shapes
172 manageViews(
173 [&rView]( const LayerSharedPtr& pLayer )
174 { return pLayer->removeView( rView ); },
175 []( const ShapeSharedPtr& pShape, const ViewLayerSharedPtr& pLayer )
176 { return pShape->removeViewLayer( pLayer ); } );
178 // in case we haven't reached all layers from the
179 // maAllShapes, issue removeView again for good measure
180 for( const auto& pLayer : maLayers )
181 pLayer->removeView( rView );
184 void LayerManager::viewChanged( const UnoViewSharedPtr& rView )
186 // view must be member of mrViews container
187 OSL_ASSERT( std::find(mrViews.begin(),
188 mrViews.end(),
189 rView) != mrViews.end() );
191 // TODO(P2): selectively update only changed view
192 viewsChanged();
195 void LayerManager::viewsChanged()
197 if( !mbActive )
198 return;
200 // clear view area
201 for( const auto& pView : mrViews )
202 pView->clearAll();
204 // TODO(F3): resize and repaint all layers
206 // render all shapes
207 for( const auto& rShape : maAllShapes )
208 rShape.first->render();
211 void LayerManager::addShape( const ShapeSharedPtr& rShape )
213 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
214 ENSURE_OR_THROW( rShape, "LayerManager::addShape(): invalid Shape" );
216 // add shape to XShape hash map
217 if( !maXShapeHash.emplace(rShape->getXShape(),
218 rShape).second )
220 // entry already present, nothing to do
221 return;
224 // add shape to appropriate layer
225 implAddShape( rShape );
228 void LayerManager::putShape2BackgroundLayer( LayerShapeMap::value_type& rShapeEntry )
230 LayerSharedPtr& rBgLayer( maLayers.front() );
231 rBgLayer->setShapeViews(rShapeEntry.first);
232 rShapeEntry.second = rBgLayer;
235 void LayerManager::implAddShape( const ShapeSharedPtr& rShape )
237 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
238 ENSURE_OR_THROW( rShape, "LayerManager::implAddShape(): invalid Shape" );
240 LayerShapeMap::value_type aValue (rShape, LayerWeakPtr());
242 OSL_ASSERT( maAllShapes.find(rShape) == maAllShapes.end() ); // shape must not be added already
243 mbLayerAssociationDirty = true;
245 if( mbDisableAnimationZOrder )
246 putShape2BackgroundLayer(
247 *maAllShapes.insert(aValue).first );
248 else
249 maAllShapes.insert(aValue);
251 // update shape, it's just added and not yet painted
252 if( rShape->isVisible() )
253 notifyShapeUpdate( rShape );
256 void LayerManager::implRemoveShape( const ShapeSharedPtr& rShape )
258 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
259 ENSURE_OR_THROW( rShape, "LayerManager::implRemoveShape(): invalid Shape" );
261 const LayerShapeMap::iterator aShapeEntry( maAllShapes.find(rShape) );
263 if( aShapeEntry == maAllShapes.end() )
264 return;
266 const bool bShapeUpdateNotified = maUpdateShapes.erase( rShape ) != 0;
268 // Enter shape area to the update area, but only if shape
269 // is visible and not in sprite mode (otherwise, updating
270 // the area doesn't do actual harm, but costs time)
271 // Actually, also add it if it was listed in
272 // maUpdateShapes (might have just gone invisible).
273 if( bShapeUpdateNotified ||
274 (rShape->isVisible() &&
275 !rShape->isBackgroundDetached()) )
277 LayerSharedPtr pLayer = aShapeEntry->second.lock();
278 if( pLayer )
280 // store area early, once the shape is removed from
281 // the layers, it no longer has any view references
282 pLayer->addUpdateRange( rShape->getUpdateArea() );
286 rShape->clearAllViewLayers();
287 maAllShapes.erase( aShapeEntry );
289 mbLayerAssociationDirty = true;
292 ShapeSharedPtr LayerManager::lookupShape( const uno::Reference< drawing::XShape >& xShape ) const
294 ENSURE_OR_THROW( xShape.is(), "LayerManager::lookupShape(): invalid Shape" );
296 const XShapeHash::const_iterator aIter( maXShapeHash.find( xShape ));
297 if( aIter == maXShapeHash.end() )
298 return ShapeSharedPtr(); // not found
300 // found, return data part of entry pair.
301 return aIter->second;
304 AttributableShapeSharedPtr LayerManager::getSubsetShape( const AttributableShapeSharedPtr& rOrigShape,
305 const DocTreeNode& rTreeNode )
307 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
309 AttributableShapeSharedPtr pSubset;
311 // shape already added?
312 if( rOrigShape->createSubset( pSubset,
313 rTreeNode ) )
315 OSL_ENSURE( pSubset, "LayerManager::getSubsetShape(): failed to create subset" );
317 // don't add to shape hash, we're dupes to the
318 // original XShape anyway - all subset shapes return
319 // the same XShape as the original one.
321 // add shape to corresponding layer
322 implAddShape( pSubset );
324 // update original shape, it now shows less content
325 // (the subset is removed from its displayed
326 // output). Subset shape is updated within
327 // implAddShape().
328 if( rOrigShape->isVisible() )
329 notifyShapeUpdate( rOrigShape );
332 return pSubset;
335 void LayerManager::revokeSubset( const AttributableShapeSharedPtr& rOrigShape,
336 const AttributableShapeSharedPtr& rSubsetShape )
338 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
340 if( rOrigShape->revokeSubset( rSubsetShape ) )
342 OSL_ASSERT( maAllShapes.find(rSubsetShape) != maAllShapes.end() );
344 implRemoveShape( rSubsetShape );
346 // update original shape, it now shows more content
347 // (the subset is added back to its displayed output)
348 if( rOrigShape->isVisible() )
349 notifyShapeUpdate( rOrigShape );
353 void LayerManager::enterAnimationMode( const AnimatableShapeSharedPtr& rShape )
355 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
356 ENSURE_OR_THROW( rShape, "LayerManager::enterAnimationMode(): invalid Shape" );
358 const bool bPrevAnimState( rShape->isBackgroundDetached() );
360 rShape->enterAnimationMode();
362 // if this call _really_ enabled the animation mode at
363 // rShape, insert it to our enter animation queue, to
364 // perform the necessary layer reorg lazily on
365 // LayerManager::update()/render().
366 if( bPrevAnimState != rShape->isBackgroundDetached() )
368 ++mnActiveSprites;
369 mbLayerAssociationDirty = true;
371 // area needs update (shape is removed from normal
372 // slide, and now rendered as an autonomous
373 // sprite). store in update set
374 if( rShape->isVisible() )
375 addUpdateArea( rShape );
378 // TODO(P1): this can lead to potential wasted effort, if
379 // a shape gets toggled animated/unanimated a few times
380 // between two frames, returning to the original state.
383 void LayerManager::leaveAnimationMode( const AnimatableShapeSharedPtr& rShape )
385 ENSURE_OR_THROW( !maLayers.empty(), "LayerManager::leaveAnimationMode(): no layers" );
386 ENSURE_OR_THROW( rShape, "LayerManager::leaveAnimationMode(): invalid Shape" );
388 const bool bPrevAnimState( rShape->isBackgroundDetached() );
390 rShape->leaveAnimationMode();
392 // if this call _really_ ended the animation mode at
393 // rShape, insert it to our leave animation queue, to
394 // perform the necessary layer reorg lazily on
395 // LayerManager::update()/render().
396 if( bPrevAnimState != rShape->isBackgroundDetached() )
398 --mnActiveSprites;
399 mbLayerAssociationDirty = true;
401 // shape needs update, no previous rendering, fast
402 // update possible.
403 if( rShape->isVisible() )
404 notifyShapeUpdate( rShape );
407 // TODO(P1): this can lead to potential wasted effort, if
408 // a shape gets toggled animated/unanimated a few times
409 // between two frames, returning to the original state.
412 void LayerManager::notifyShapeUpdate( const ShapeSharedPtr& rShape )
414 if( !mbActive || mrViews.empty() )
415 return;
417 // hidden sprite-shape needs render() call still, to hide sprite
418 if( rShape->isVisible() || rShape->isBackgroundDetached() )
419 maUpdateShapes.insert( rShape );
420 else
421 addUpdateArea( rShape );
424 bool LayerManager::isUpdatePending() const
426 if( !mbActive )
427 return false;
429 if( mbLayerAssociationDirty || !maUpdateShapes.empty() )
430 return true;
432 return std::any_of( maLayers.begin(),
433 maLayers.end(),
434 std::mem_fn(&Layer::isUpdatePending) );
437 bool LayerManager::updateSprites()
439 bool bRet(true);
441 // send update() calls to every shape in the
442 // maUpdateShapes set, which is _animated_ (i.e. a
443 // sprite).
444 for( const auto& pShape : maUpdateShapes )
446 if( pShape->isBackgroundDetached() )
448 // can update shape directly, without
449 // affecting layer content (shape is
450 // currently displayed in a sprite)
451 if( !pShape->update() )
452 bRet = false; // delay error exit
454 else
456 // TODO(P2): addUpdateArea() involves log(n)
457 // search for shape layer. Have a frequent
458 // shape/layer association cache, or ptr back to
459 // layer at the shape?
461 // cannot update shape directly, it's not
462 // animated and update() calls will prolly
463 // overwrite other page content.
464 addUpdateArea( pShape );
468 maUpdateShapes.clear();
470 return bRet;
473 bool LayerManager::update()
475 bool bRet = true;
477 if( !mbActive )
478 return bRet;
480 // going to render - better flush any pending layer reorg
481 // now
482 updateShapeLayers(false);
484 // all sprites
485 bRet = updateSprites();
487 // any non-sprite update areas left?
488 if( std::none_of( maLayers.begin(),
489 maLayers.end(),
490 std::mem_fn( &Layer::isUpdatePending ) ) )
491 return bRet; // nope, done.
493 // update each shape on each layer, that has
494 // isUpdatePending()
495 bool bIsCurrLayerUpdating(false);
496 Layer::EndUpdater aEndUpdater;
497 LayerSharedPtr pCurrLayer;
498 for( const auto& rShape : maAllShapes )
500 LayerSharedPtr pLayer = rShape.second.lock();
501 if( pLayer != pCurrLayer )
503 pCurrLayer = pLayer;
504 bIsCurrLayerUpdating = pCurrLayer->isUpdatePending();
506 if( bIsCurrLayerUpdating )
507 aEndUpdater = pCurrLayer->beginUpdate();
510 if( bIsCurrLayerUpdating &&
511 !rShape.first->isBackgroundDetached() &&
512 pCurrLayer->isInsideUpdateArea(rShape.first) )
514 if( !rShape.first->render() )
515 bRet = false;
519 return bRet;
522 namespace
524 /** Little wrapper around a Canvas, to render one-shot
525 into a canvas
527 class DummyLayer : public ViewLayer
529 public:
530 explicit DummyLayer( const ::cppcanvas::CanvasSharedPtr& rCanvas ) :
531 mpCanvas( rCanvas )
535 virtual bool isOnView(std::shared_ptr<View> const& /*rView*/) const override
537 return true; // visible on all views
540 virtual ::cppcanvas::CanvasSharedPtr getCanvas() const override
542 return mpCanvas;
545 virtual void clear() const override
547 // NOOP
550 virtual void clearAll() const override
552 // NOOP
555 virtual ::cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& /*rSpriteSizePixel*/,
556 double /*nSpritePrio*/ ) const override
558 ENSURE_OR_THROW( false,
559 "DummyLayer::createSprite(): This method is not supposed to be called!" );
560 return ::cppcanvas::CustomSpriteSharedPtr();
563 virtual void setPriority( const basegfx::B1DRange& /*rRange*/ ) override
565 OSL_FAIL( "BitmapView::setPriority(): This method is not supposed to be called!" );
568 virtual css::geometry::IntegerSize2D getTranslationOffset() const override
570 return geometry::IntegerSize2D(0,0);
573 virtual ::basegfx::B2DHomMatrix getTransformation() const override
575 return mpCanvas->getTransformation();
578 virtual ::basegfx::B2DHomMatrix getSpriteTransformation() const override
580 OSL_FAIL( "BitmapView::getSpriteTransformation(): This method is not supposed to be called!" );
581 return ::basegfx::B2DHomMatrix();
584 virtual void setClip( const ::basegfx::B2DPolyPolygon& /*rClip*/ ) override
586 OSL_FAIL( "BitmapView::setClip(): This method is not supposed to be called!" );
589 virtual bool resize( const ::basegfx::B2DRange& /*rArea*/ ) override
591 OSL_FAIL( "BitmapView::resize(): This method is not supposed to be called!" );
592 return false;
595 private:
596 ::cppcanvas::CanvasSharedPtr mpCanvas;
600 bool LayerManager::renderTo( const ::cppcanvas::CanvasSharedPtr& rTargetCanvas ) const
602 bool bRet( true );
603 ViewLayerSharedPtr pTmpLayer( new DummyLayer( rTargetCanvas ) );
605 for( const auto& rShape : maAllShapes )
609 // forward to all shape's addViewLayer method (which
610 // we request to render the Shape on the new
611 // ViewLayer. Since we add the shapes in the
612 // maShapeSet order (which is also the render order),
613 // this is equivalent to a subsequent render() call)
614 rShape.first->addViewLayer( pTmpLayer,
615 true );
617 // and remove again, this is only temporary
618 rShape.first->removeViewLayer( pTmpLayer );
620 catch( uno::Exception& )
622 // TODO(E1): Might be superfluous. Nowadays,
623 // addViewLayer swallows all errors, anyway.
624 SAL_WARN( "slideshow", comphelper::anyToString( cppu::getCaughtException() ) );
625 // at least one shape could not be rendered
626 bRet = false;
630 return bRet;
633 void LayerManager::addUpdateArea( ShapeSharedPtr const& rShape )
635 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
636 ENSURE_OR_THROW( rShape, "LayerManager::addUpdateArea(): invalid Shape" );
638 const LayerShapeMap::const_iterator aShapeEntry( maAllShapes.find(rShape) );
640 if( aShapeEntry == maAllShapes.end() )
641 return;
643 LayerSharedPtr pLayer = aShapeEntry->second.lock();
644 if( pLayer )
645 pLayer->addUpdateRange( rShape->getUpdateArea() );
648 void LayerManager::commitLayerChanges( std::size_t nCurrLayerIndex,
649 LayerShapeMap::const_iterator aFirstLayerShape,
650 const LayerShapeMap::const_iterator& aEndLayerShapes )
652 const bool bLayerExists( maLayers.size() > nCurrLayerIndex );
653 if( bLayerExists )
655 const LayerSharedPtr& rLayer( maLayers.at(nCurrLayerIndex) );
656 const bool bLayerResized( rLayer->commitBounds() );
657 rLayer->setPriority( basegfx::B1DRange(nCurrLayerIndex,
658 nCurrLayerIndex+1) );
660 if( bLayerResized )
662 // need to re-render whole layer - start from
663 // clean state
664 rLayer->clearContent();
666 // render and remove from update set
667 while( aFirstLayerShape != aEndLayerShapes )
669 maUpdateShapes.erase(aFirstLayerShape->first);
670 aFirstLayerShape->first->render();
671 ++aFirstLayerShape;
677 LayerSharedPtr LayerManager::createForegroundLayer() const
679 OSL_ASSERT( mbActive );
681 LayerSharedPtr pLayer( Layer::createLayer() );
683 // create ViewLayers for all registered views, and add to
684 // newly created layer.
685 for( const auto& rView : mrViews )
686 pLayer->addView( rView );
688 return pLayer;
691 void LayerManager::updateShapeLayers( bool bBackgroundLayerPainted )
693 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
694 OSL_ASSERT( mbActive );
696 // do we need to process shapes?
697 if( !mbLayerAssociationDirty )
698 return;
700 if( mbDisableAnimationZOrder )
702 // layer setup happened elsewhere, is only bg layer
703 // anyway.
704 mbLayerAssociationDirty = false;
705 return;
708 // scan through maAllShapes, and determine shape animation
709 // discontinuities: when a shape that has
710 // isBackgroundDetached() return false follows a shape
711 // with isBackgroundDetached() true, the former and all
712 // following ones must be moved into an own layer.
714 // to avoid tons of temporaries, create weak_ptr to Layers
715 // beforehand
716 std::vector< LayerWeakPtr > aWeakLayers(maLayers.size());
717 std::copy(maLayers.begin(),maLayers.end(),aWeakLayers.begin());
719 std::size_t nCurrLayerIndex(0);
720 bool bIsBackgroundLayer(true);
721 bool bLastWasBackgroundDetached(false); // last shape sprite state
722 LayerShapeMap::iterator aCurrShapeEntry( maAllShapes.begin() );
723 LayerShapeMap::iterator aCurrLayerFirstShapeEntry( maAllShapes.begin() );
724 const LayerShapeMap::iterator aEndShapeEntry ( maAllShapes.end() );
725 while( aCurrShapeEntry != aEndShapeEntry )
727 const ShapeSharedPtr pCurrShape( aCurrShapeEntry->first );
728 const bool bThisIsBackgroundDetached(
729 pCurrShape->isBackgroundDetached() );
731 if( bLastWasBackgroundDetached &&
732 !bThisIsBackgroundDetached )
734 // discontinuity found - current shape needs to
735 // get into a new layer
738 // commit changes to previous layer
739 commitLayerChanges(nCurrLayerIndex,
740 aCurrLayerFirstShapeEntry,
741 aCurrShapeEntry);
742 aCurrLayerFirstShapeEntry=aCurrShapeEntry;
743 ++nCurrLayerIndex;
744 bIsBackgroundLayer = false;
746 if( aWeakLayers.size() <= nCurrLayerIndex ||
747 aWeakLayers.at(nCurrLayerIndex) != aCurrShapeEntry->second )
749 // no more layers left, or shape was not
750 // member of this layer - create a new one
751 maLayers.insert( maLayers.begin()+nCurrLayerIndex,
752 createForegroundLayer() );
753 aWeakLayers.insert( aWeakLayers.begin()+nCurrLayerIndex,
754 maLayers[nCurrLayerIndex] );
758 OSL_ASSERT( maLayers.size() == aWeakLayers.size() );
760 // note: using indices here, since vector::insert
761 // above invalidates iterators
762 LayerSharedPtr& rCurrLayer( maLayers.at(nCurrLayerIndex) );
763 LayerWeakPtr& rCurrWeakLayer( aWeakLayers.at(nCurrLayerIndex) );
764 if( rCurrWeakLayer != aCurrShapeEntry->second )
766 // mismatch: shape is not contained in current
767 // layer - move shape to that layer, then.
768 maLayers.at(nCurrLayerIndex)->setShapeViews(
769 pCurrShape );
771 // layer got new shape(s), need full repaint, if
772 // non-sprite shape
773 if( !bThisIsBackgroundDetached && pCurrShape->isVisible() )
775 LayerSharedPtr pOldLayer( aCurrShapeEntry->second.lock() );
776 if( pOldLayer )
778 // old layer still valid? then we need to
779 // repaint former shape area
780 pOldLayer->addUpdateRange(
781 pCurrShape->getUpdateArea() );
784 // render on new layer (only if not
785 // explicitly disabled)
786 if( !(bBackgroundLayerPainted && bIsBackgroundLayer) )
787 maUpdateShapes.insert( pCurrShape );
790 aCurrShapeEntry->second = rCurrWeakLayer;
793 // update layerbounds regardless of the fact that the
794 // shape might be contained in said layer
795 // already. updateBounds() is dumb and needs to
796 // collect all shape bounds.
797 // of course, no need to expand layer bounds for
798 // shapes that reside in sprites themselves.
799 if( !bThisIsBackgroundDetached && !bIsBackgroundLayer )
800 rCurrLayer->updateBounds( pCurrShape );
802 bLastWasBackgroundDetached = bThisIsBackgroundDetached;
803 ++aCurrShapeEntry;
806 // commit very last layer data
807 commitLayerChanges(nCurrLayerIndex,
808 aCurrLayerFirstShapeEntry,
809 aCurrShapeEntry);
811 // any layers left? Bin them!
812 if( maLayers.size() > nCurrLayerIndex+1 )
813 maLayers.erase(maLayers.begin()+nCurrLayerIndex+1,
814 maLayers.end());
816 mbLayerAssociationDirty = false;
821 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */