android: Update app-specific/MIME type icons
[LibreOffice.git] / slideshow / source / engine / slide / layermanager.cxx
blob28d64481781740f54b1c50c90a22eb233871c1e8
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 <comphelper/diagnose_ex.hxx>
22 #include <basegfx/range/b1drange.hxx>
23 #include <basegfx/matrix/b2dhommatrix.hxx>
24 #include <cppcanvas/canvas.hxx>
26 #include <functional>
27 #include <algorithm>
28 #include <utility>
30 #include "layermanager.hxx"
32 using namespace ::com::sun::star;
34 namespace
36 // add operator!= for weak_ptr
37 bool notEqual( slideshow::internal::LayerWeakPtr const& rLHS,
38 slideshow::internal::LayerWeakPtr const& rRHS )
40 return rLHS.lock().get() != rRHS.lock().get();
44 namespace slideshow::internal
46 template<typename LayerFunc,
47 typename ShapeFunc> void LayerManager::manageViews(
48 LayerFunc layerFunc,
49 ShapeFunc shapeFunc )
51 LayerSharedPtr pCurrLayer;
52 ViewLayerSharedPtr pCurrViewLayer;
53 for( const auto& rShape : maAllShapes )
55 LayerSharedPtr pLayer = rShape.second.lock();
56 if( pLayer && pLayer != pCurrLayer )
58 pCurrLayer = pLayer;
59 pCurrViewLayer = layerFunc(pCurrLayer);
62 if( pCurrViewLayer )
63 shapeFunc(rShape.first,pCurrViewLayer);
67 LayerManager::LayerManager( const UnoViewContainer& rViews,
68 bool bDisableAnimationZOrder ) :
69 mrViews(rViews),
70 maLayers(),
71 maXShapeHash( 101 ),
72 maAllShapes(),
73 maUpdateShapes(),
74 mnActiveSprites(0),
75 mbLayerAssociationDirty(false),
76 mbActive(false),
77 mbDisableAnimationZOrder(bDisableAnimationZOrder)
79 // prevent frequent resizes (won't have more than 4 layers
80 // for 99.9% of the cases)
81 maLayers.reserve(4);
83 // create initial background layer
84 maLayers.push_back( Layer::createBackgroundLayer() );
86 // init views
87 for( const auto& rView : mrViews )
88 viewAdded( rView );
91 void LayerManager::activate()
93 mbActive = true;
94 maUpdateShapes.clear(); // update gets forced via area, or
95 // has happened outside already
97 // clear all possibly pending update areas - content
98 // is there, already
99 for( const auto& pLayer : maLayers )
100 pLayer->clearUpdateRanges();
102 updateShapeLayers( true/*bSlideBackgroundPainted*/ );
105 void LayerManager::deactivate()
107 // TODO(F3): This is mostly a hack. Problem is, there's
108 // currently no smart way of telling shapes "remove your
109 // sprites". Others, like MediaShapes, listen to
110 // start/stop animation events, which is too much overhead
111 // for all shapes, though.
113 const bool bMoreThanOneLayer(maLayers.size() > 1);
114 if (mnActiveSprites || bMoreThanOneLayer)
116 // clear all viewlayers, dump everything but the
117 // background layer - this will also remove all shape
118 // sprites
119 for (auto& rShape : maAllShapes)
120 rShape.first->clearAllViewLayers();
122 for (auto& rShape : maAllShapes)
123 rShape.second.reset();
125 if (bMoreThanOneLayer)
126 maLayers.erase(maLayers.begin() + 1, maLayers.end());
128 mbLayerAssociationDirty = true;
131 mbActive = false;
133 // only background layer left
134 OSL_ASSERT( maLayers.size() == 1 && maLayers.front()->isBackgroundLayer() );
137 void LayerManager::viewAdded( const UnoViewSharedPtr& rView )
139 // view must be member of mrViews container
140 OSL_ASSERT( std::find(mrViews.begin(),
141 mrViews.end(),
142 rView) != mrViews.end() );
144 // init view content
145 if( mbActive )
146 rView->clearAll();
148 // add View to all registered shapes
149 manageViews(
150 [&rView]( const LayerSharedPtr& pLayer )
151 { return pLayer->addView( rView ); },
152 []( const ShapeSharedPtr& pShape, const ViewLayerSharedPtr& pLayer )
153 { return pShape->addViewLayer( pLayer, true ); } );
155 // in case we haven't reached all layers from the
156 // maAllShapes, issue addView again for good measure
157 for( const auto& pLayer : maLayers )
158 pLayer->addView( rView );
161 void LayerManager::viewRemoved( const UnoViewSharedPtr& rView )
163 // view must not be member of mrViews container anymore
164 OSL_ASSERT( std::find(mrViews.begin(),
165 mrViews.end(),
166 rView) == mrViews.end() );
168 // remove View from all registered shapes
169 manageViews(
170 [&rView]( const LayerSharedPtr& pLayer )
171 { return pLayer->removeView( rView ); },
172 []( const ShapeSharedPtr& pShape, const ViewLayerSharedPtr& pLayer )
173 { return pShape->removeViewLayer( pLayer ); } );
175 // in case we haven't reached all layers from the
176 // maAllShapes, issue removeView again for good measure
177 for( const auto& pLayer : maLayers )
178 pLayer->removeView( rView );
181 void LayerManager::viewChanged( const UnoViewSharedPtr& rView )
183 // view must be member of mrViews container
184 OSL_ASSERT( std::find(mrViews.begin(),
185 mrViews.end(),
186 rView) != mrViews.end() );
188 // TODO(P2): selectively update only changed view
189 viewsChanged();
192 void LayerManager::viewsChanged()
194 if( !mbActive )
195 return;
197 // clear view area
198 for( const auto& pView : mrViews )
199 pView->clearAll();
201 // TODO(F3): resize and repaint all layers
203 // render all shapes
204 for( const auto& rShape : maAllShapes )
205 rShape.first->render();
208 void LayerManager::addShape( const ShapeSharedPtr& rShape )
210 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
211 ENSURE_OR_THROW( rShape, "LayerManager::addShape(): invalid Shape" );
213 // add shape to XShape hash map
214 if( !maXShapeHash.emplace(rShape->getXShape(),
215 rShape).second )
217 // entry already present, nothing to do
218 return;
221 // add shape to appropriate layer
222 implAddShape( rShape );
225 void LayerManager::putShape2BackgroundLayer( LayerShapeMap::value_type& rShapeEntry )
227 LayerSharedPtr& rBgLayer( maLayers.front() );
228 rBgLayer->setShapeViews(rShapeEntry.first);
229 rShapeEntry.second = rBgLayer;
232 void LayerManager::implAddShape( const ShapeSharedPtr& rShape )
234 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
235 ENSURE_OR_THROW( rShape, "LayerManager::implAddShape(): invalid Shape" );
237 LayerShapeMap::value_type aValue (rShape, LayerWeakPtr());
239 OSL_ASSERT( maAllShapes.find(rShape) == maAllShapes.end() ); // shape must not be added already
240 mbLayerAssociationDirty = true;
242 if( mbDisableAnimationZOrder )
243 putShape2BackgroundLayer(
244 *maAllShapes.insert(aValue).first );
245 else
246 maAllShapes.insert(aValue);
248 // update shape, it's just added and not yet painted
249 if( rShape->isVisible() )
250 notifyShapeUpdate( rShape );
253 bool LayerManager::removeShape( const ShapeSharedPtr& rShape )
255 // remove shape from XShape hash map
256 if( maXShapeHash.erase( rShape->getXShape() ) == 0 )
257 return false; // shape not in map
259 OSL_ASSERT( maAllShapes.find(rShape) != maAllShapes.end() );
261 implRemoveShape( rShape );
263 return true;
266 void LayerManager::implRemoveShape( const ShapeSharedPtr& rShape )
268 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
269 ENSURE_OR_THROW( rShape, "LayerManager::implRemoveShape(): invalid Shape" );
271 const LayerShapeMap::iterator aShapeEntry( maAllShapes.find(rShape) );
273 if( aShapeEntry == maAllShapes.end() )
274 return;
276 const bool bShapeUpdateNotified = maUpdateShapes.erase( rShape ) != 0;
278 // Enter shape area to the update area, but only if shape
279 // is visible and not in sprite mode (otherwise, updating
280 // the area doesn't do actual harm, but costs time)
281 // Actually, also add it if it was listed in
282 // maUpdateShapes (might have just gone invisible).
283 if( bShapeUpdateNotified ||
284 (rShape->isVisible() &&
285 !rShape->isBackgroundDetached()) )
287 LayerSharedPtr pLayer = aShapeEntry->second.lock();
288 if( pLayer )
290 // store area early, once the shape is removed from
291 // the layers, it no longer has any view references
292 pLayer->addUpdateRange( rShape->getUpdateArea() );
296 rShape->clearAllViewLayers();
297 maAllShapes.erase( aShapeEntry );
299 mbLayerAssociationDirty = true;
302 ShapeSharedPtr LayerManager::lookupShape( const uno::Reference< drawing::XShape >& xShape ) const
304 ENSURE_OR_THROW( xShape.is(), "LayerManager::lookupShape(): invalid Shape" );
306 const XShapeToShapeMap::const_iterator aIter( maXShapeHash.find( xShape ));
307 if( aIter == maXShapeHash.end() )
308 return ShapeSharedPtr(); // not found
310 // found, return data part of entry pair.
311 return aIter->second;
314 AttributableShapeSharedPtr LayerManager::getSubsetShape( const AttributableShapeSharedPtr& rOrigShape,
315 const DocTreeNode& rTreeNode )
317 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
319 AttributableShapeSharedPtr pSubset;
321 // shape already added?
322 if( rOrigShape->createSubset( pSubset,
323 rTreeNode ) )
325 OSL_ENSURE( pSubset, "LayerManager::getSubsetShape(): failed to create subset" );
327 // don't add to shape hash, we're dupes to the
328 // original XShape anyway - all subset shapes return
329 // the same XShape as the original one.
331 // add shape to corresponding layer
332 implAddShape( pSubset );
334 // update original shape, it now shows less content
335 // (the subset is removed from its displayed
336 // output). Subset shape is updated within
337 // implAddShape().
338 if( rOrigShape->isVisible() )
339 notifyShapeUpdate( rOrigShape );
342 return pSubset;
345 const XShapeToShapeMap& LayerManager::getXShapeToShapeMap() const
347 return maXShapeHash;
350 void LayerManager::revokeSubset( const AttributableShapeSharedPtr& rOrigShape,
351 const AttributableShapeSharedPtr& rSubsetShape )
353 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
355 if( rOrigShape->revokeSubset( rSubsetShape ) )
357 OSL_ASSERT( maAllShapes.find(rSubsetShape) != maAllShapes.end() );
359 implRemoveShape( rSubsetShape );
361 // update original shape, it now shows more content
362 // (the subset is added back to its displayed output)
363 if( rOrigShape->isVisible() )
364 notifyShapeUpdate( rOrigShape );
368 void LayerManager::enterAnimationMode( const AnimatableShapeSharedPtr& rShape )
370 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
371 ENSURE_OR_THROW( rShape, "LayerManager::enterAnimationMode(): invalid Shape" );
373 const bool bPrevAnimState( rShape->isBackgroundDetached() );
375 rShape->enterAnimationMode();
377 // if this call _really_ enabled the animation mode at
378 // rShape, insert it to our enter animation queue, to
379 // perform the necessary layer reorg lazily on
380 // LayerManager::update()/render().
381 if( bPrevAnimState != rShape->isBackgroundDetached() )
383 ++mnActiveSprites;
384 mbLayerAssociationDirty = true;
386 // area needs update (shape is removed from normal
387 // slide, and now rendered as an autonomous
388 // sprite). store in update set
389 if( rShape->isVisible() )
390 addUpdateArea( rShape );
393 // TODO(P1): this can lead to potential wasted effort, if
394 // a shape gets toggled animated/unanimated a few times
395 // between two frames, returning to the original state.
398 void LayerManager::leaveAnimationMode( const AnimatableShapeSharedPtr& rShape )
400 ENSURE_OR_THROW( !maLayers.empty(), "LayerManager::leaveAnimationMode(): no layers" );
401 ENSURE_OR_THROW( rShape, "LayerManager::leaveAnimationMode(): invalid Shape" );
403 const bool bPrevAnimState( rShape->isBackgroundDetached() );
405 rShape->leaveAnimationMode();
407 // if this call _really_ ended the animation mode at
408 // rShape, insert it to our leave animation queue, to
409 // perform the necessary layer reorg lazily on
410 // LayerManager::update()/render().
411 if( bPrevAnimState != rShape->isBackgroundDetached() )
413 --mnActiveSprites;
414 mbLayerAssociationDirty = true;
416 // shape needs update, no previous rendering, fast
417 // update possible.
418 if( rShape->isVisible() )
419 notifyShapeUpdate( rShape );
422 // TODO(P1): this can lead to potential wasted effort, if
423 // a shape gets toggled animated/unanimated a few times
424 // between two frames, returning to the original state.
427 void LayerManager::notifyShapeUpdate( const ShapeSharedPtr& rShape )
429 if( !mbActive || mrViews.empty() )
430 return;
432 // hidden sprite-shape needs render() call still, to hide sprite
433 if( rShape->isVisible() || rShape->isBackgroundDetached() )
434 maUpdateShapes.insert( rShape );
435 else
436 addUpdateArea( rShape );
439 bool LayerManager::isUpdatePending() const
441 if( !mbActive )
442 return false;
444 if( mbLayerAssociationDirty || !maUpdateShapes.empty() )
445 return true;
447 return std::any_of( maLayers.begin(),
448 maLayers.end(),
449 std::mem_fn(&Layer::isUpdatePending) );
452 bool LayerManager::updateSprites()
454 bool bRet(true);
456 // send update() calls to every shape in the
457 // maUpdateShapes set, which is _animated_ (i.e. a
458 // sprite).
459 for( const auto& pShape : maUpdateShapes )
461 if( pShape->isBackgroundDetached() )
463 // can update shape directly, without
464 // affecting layer content (shape is
465 // currently displayed in a sprite)
466 if( !pShape->update() )
467 bRet = false; // delay error exit
469 else
471 // TODO(P2): addUpdateArea() involves log(n)
472 // search for shape layer. Have a frequent
473 // shape/layer association cache, or ptr back to
474 // layer at the shape?
476 // cannot update shape directly, it's not
477 // animated and update() calls will prolly
478 // overwrite other page content.
479 addUpdateArea( pShape );
483 maUpdateShapes.clear();
485 return bRet;
488 bool LayerManager::update()
490 bool bRet = true;
492 if( !mbActive )
493 return bRet;
495 // going to render - better flush any pending layer reorg
496 // now
497 updateShapeLayers(false);
499 // all sprites
500 bRet = updateSprites();
502 // any non-sprite update areas left?
503 if( std::none_of( maLayers.begin(),
504 maLayers.end(),
505 std::mem_fn( &Layer::isUpdatePending ) ) )
506 return bRet; // nope, done.
508 // update each shape on each layer, that has
509 // isUpdatePending()
510 bool bIsCurrLayerUpdating(false);
511 Layer::EndUpdater aEndUpdater;
512 LayerSharedPtr pCurrLayer;
513 for( const auto& rShape : maAllShapes )
515 LayerSharedPtr pLayer = rShape.second.lock();
516 if( pLayer != pCurrLayer )
518 pCurrLayer = pLayer;
519 bIsCurrLayerUpdating = pCurrLayer->isUpdatePending();
521 if( bIsCurrLayerUpdating )
522 aEndUpdater = pCurrLayer->beginUpdate();
525 if( bIsCurrLayerUpdating &&
526 !rShape.first->isBackgroundDetached() &&
527 pCurrLayer->isInsideUpdateArea(rShape.first) )
529 if( !rShape.first->render() )
530 bRet = false;
534 return bRet;
537 namespace
539 /** Little wrapper around a Canvas, to render one-shot
540 into a canvas
542 class DummyLayer : public ViewLayer
544 public:
545 explicit DummyLayer( ::cppcanvas::CanvasSharedPtr xCanvas ) :
546 mpCanvas(std::move( xCanvas ))
550 virtual bool isOnView(ViewSharedPtr const& /*rView*/) const override
552 return true; // visible on all views
555 virtual ::cppcanvas::CanvasSharedPtr getCanvas() const override
557 return mpCanvas;
560 virtual void clear() const override
562 // NOOP
565 virtual void clearAll() const override
567 // NOOP
570 virtual ::cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& /*rSpriteSizePixel*/,
571 double /*nSpritePrio*/ ) const override
573 ENSURE_OR_THROW( false,
574 "DummyLayer::createSprite(): This method is not supposed to be called!" );
575 return ::cppcanvas::CustomSpriteSharedPtr();
578 virtual void setPriority( const basegfx::B1DRange& /*rRange*/ ) override
580 OSL_FAIL( "BitmapView::setPriority(): This method is not supposed to be called!" );
583 virtual css::geometry::IntegerSize2D getTranslationOffset() const override
585 return geometry::IntegerSize2D(0,0);
588 virtual ::basegfx::B2DHomMatrix getTransformation() const override
590 return mpCanvas->getTransformation();
593 virtual ::basegfx::B2DHomMatrix getSpriteTransformation() const override
595 OSL_FAIL( "BitmapView::getSpriteTransformation(): This method is not supposed to be called!" );
596 return ::basegfx::B2DHomMatrix();
599 virtual void setClip( const ::basegfx::B2DPolyPolygon& /*rClip*/ ) override
601 OSL_FAIL( "BitmapView::setClip(): This method is not supposed to be called!" );
604 virtual bool resize( const ::basegfx::B2DRange& /*rArea*/ ) override
606 OSL_FAIL( "BitmapView::resize(): This method is not supposed to be called!" );
607 return false;
610 private:
611 ::cppcanvas::CanvasSharedPtr mpCanvas;
615 bool LayerManager::renderTo( const ::cppcanvas::CanvasSharedPtr& rTargetCanvas ) const
617 bool bRet( true );
618 ViewLayerSharedPtr pTmpLayer = std::make_shared<DummyLayer>( rTargetCanvas );
620 for( const auto& rShape : maAllShapes )
624 // forward to all shape's addViewLayer method (which
625 // we request to render the Shape on the new
626 // ViewLayer. Since we add the shapes in the
627 // maShapeSet order (which is also the render order),
628 // this is equivalent to a subsequent render() call)
629 rShape.first->addViewLayer( pTmpLayer,
630 true );
632 // and remove again, this is only temporary
633 rShape.first->removeViewLayer( pTmpLayer );
635 catch( uno::Exception& )
637 // TODO(E1): Might be superfluous. Nowadays,
638 // addViewLayer swallows all errors, anyway.
639 TOOLS_WARN_EXCEPTION( "slideshow", "" );
640 // at least one shape could not be rendered
641 bRet = false;
645 return bRet;
648 void LayerManager::addUpdateArea( ShapeSharedPtr const& rShape )
650 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
651 ENSURE_OR_THROW( rShape, "LayerManager::addUpdateArea(): invalid Shape" );
653 const LayerShapeMap::const_iterator aShapeEntry( maAllShapes.find(rShape) );
655 if( aShapeEntry == maAllShapes.end() )
656 return;
658 LayerSharedPtr pLayer = aShapeEntry->second.lock();
659 if( pLayer )
660 pLayer->addUpdateRange( rShape->getUpdateArea() );
663 void LayerManager::commitLayerChanges( std::size_t nCurrLayerIndex,
664 LayerShapeMap::const_iterator aFirstLayerShape,
665 const LayerShapeMap::const_iterator& aEndLayerShapes )
667 const bool bLayerExists( maLayers.size() > nCurrLayerIndex );
668 if( !bLayerExists )
669 return;
671 const LayerSharedPtr& rLayer( maLayers.at(nCurrLayerIndex) );
672 const bool bLayerResized( rLayer->commitBounds() );
673 rLayer->setPriority( basegfx::B1DRange(nCurrLayerIndex,
674 nCurrLayerIndex+1) );
676 if( !bLayerResized )
677 return;
679 // need to re-render whole layer - start from
680 // clean state
681 rLayer->clearContent();
683 // render and remove from update set
684 while( aFirstLayerShape != aEndLayerShapes )
686 maUpdateShapes.erase(aFirstLayerShape->first);
687 aFirstLayerShape->first->render();
688 ++aFirstLayerShape;
692 LayerSharedPtr LayerManager::createForegroundLayer() const
694 OSL_ASSERT( mbActive );
696 LayerSharedPtr pLayer( Layer::createLayer() );
698 // create ViewLayers for all registered views, and add to
699 // newly created layer.
700 for( const auto& rView : mrViews )
701 pLayer->addView( rView );
703 return pLayer;
706 void LayerManager::updateShapeLayers( bool bBackgroundLayerPainted )
708 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
709 OSL_ASSERT( mbActive );
711 // do we need to process shapes?
712 if( !mbLayerAssociationDirty )
713 return;
715 if( mbDisableAnimationZOrder )
717 // layer setup happened elsewhere, is only bg layer
718 // anyway.
719 mbLayerAssociationDirty = false;
720 return;
723 // scan through maAllShapes, and determine shape animation
724 // discontinuities: when a shape that has
725 // isBackgroundDetached() return false follows a shape
726 // with isBackgroundDetached() true, the former and all
727 // following ones must be moved into an own layer.
729 // to avoid tons of temporaries, create weak_ptr to Layers
730 // beforehand
731 std::vector< LayerWeakPtr > aWeakLayers(maLayers.begin(),maLayers.end());
733 std::size_t nCurrLayerIndex(0);
734 bool bIsBackgroundLayer(true);
735 bool bLastWasBackgroundDetached(false); // last shape sprite state
736 LayerShapeMap::iterator aCurrShapeEntry( maAllShapes.begin() );
737 LayerShapeMap::iterator aCurrLayerFirstShapeEntry( maAllShapes.begin() );
738 const LayerShapeMap::iterator aEndShapeEntry ( maAllShapes.end() );
739 while( aCurrShapeEntry != aEndShapeEntry )
741 const ShapeSharedPtr pCurrShape( aCurrShapeEntry->first );
742 const bool bThisIsBackgroundDetached(
743 pCurrShape->isBackgroundDetached() );
745 if( bLastWasBackgroundDetached &&
746 !bThisIsBackgroundDetached )
748 // discontinuity found - current shape needs to
749 // get into a new layer
752 // commit changes to previous layer
753 commitLayerChanges(nCurrLayerIndex,
754 aCurrLayerFirstShapeEntry,
755 aCurrShapeEntry);
756 aCurrLayerFirstShapeEntry=aCurrShapeEntry;
757 ++nCurrLayerIndex;
758 bIsBackgroundLayer = false;
760 if( aWeakLayers.size() <= nCurrLayerIndex ||
761 notEqual(aWeakLayers.at(nCurrLayerIndex), aCurrShapeEntry->second) )
763 // no more layers left, or shape was not
764 // member of this layer - create a new one
765 maLayers.insert( maLayers.begin()+nCurrLayerIndex,
766 createForegroundLayer() );
767 aWeakLayers.insert( aWeakLayers.begin()+nCurrLayerIndex,
768 maLayers[nCurrLayerIndex] );
772 OSL_ASSERT( maLayers.size() == aWeakLayers.size() );
774 // note: using indices here, since vector::insert
775 // above invalidates iterators
776 LayerSharedPtr& rCurrLayer( maLayers.at(nCurrLayerIndex) );
777 LayerWeakPtr& rCurrWeakLayer( aWeakLayers.at(nCurrLayerIndex) );
778 if( notEqual(rCurrWeakLayer, aCurrShapeEntry->second) )
780 // mismatch: shape is not contained in current
781 // layer - move shape to that layer, then.
782 maLayers.at(nCurrLayerIndex)->setShapeViews(
783 pCurrShape );
785 // layer got new shape(s), need full repaint, if
786 // non-sprite shape
787 if( !bThisIsBackgroundDetached && pCurrShape->isVisible() )
789 LayerSharedPtr pOldLayer( aCurrShapeEntry->second.lock() );
790 if( pOldLayer )
792 // old layer still valid? then we need to
793 // repaint former shape area
794 pOldLayer->addUpdateRange(
795 pCurrShape->getUpdateArea() );
798 // render on new layer (only if not
799 // explicitly disabled)
800 if( !(bBackgroundLayerPainted && bIsBackgroundLayer) )
801 maUpdateShapes.insert( pCurrShape );
804 aCurrShapeEntry->second = rCurrWeakLayer;
807 // update layerbounds regardless of the fact that the
808 // shape might be contained in said layer
809 // already. updateBounds() is dumb and needs to
810 // collect all shape bounds.
811 // of course, no need to expand layer bounds for
812 // shapes that reside in sprites themselves.
813 if( !bThisIsBackgroundDetached && !bIsBackgroundLayer )
814 rCurrLayer->updateBounds( pCurrShape );
816 bLastWasBackgroundDetached = bThisIsBackgroundDetached;
817 ++aCurrShapeEntry;
820 // commit very last layer data
821 commitLayerChanges(nCurrLayerIndex,
822 aCurrLayerFirstShapeEntry,
823 aCurrShapeEntry);
825 // any layers left? Bin them!
826 if( maLayers.size() > nCurrLayerIndex+1 )
827 maLayers.erase(maLayers.begin()+nCurrLayerIndex+1,
828 maLayers.end());
830 mbLayerAssociationDirty = false;
834 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */