bump product version to 5.0.4.1
[LibreOffice.git] / slideshow / source / engine / slide / layermanager.cxx
blob7e0279920b5dc370f3d42e0f74e0180db8d74d01
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 <canvas/debug.hxx>
22 #include <tools/diagnose_ex.h>
23 #include <basegfx/range/b1drange.hxx>
24 #include <basegfx/matrix/b2dhommatrix.hxx>
26 #include <comphelper/anytostring.hxx>
27 #include <cppuhelper/exc_hlp.hxx>
29 #include <boost/bind.hpp>
30 #include <algorithm>
32 #include <o3tl/compat_functional.hxx>
34 #include "layermanager.hxx"
36 using namespace ::com::sun::star;
38 namespace boost
40 // add operator!= for weak_ptr
41 inline bool operator!=( slideshow::internal::LayerWeakPtr const& rLHS,
42 slideshow::internal::LayerWeakPtr const& rRHS )
44 return (rLHS<rRHS) || (rRHS<rLHS);
48 namespace slideshow
50 namespace internal
52 template<typename LayerFunc,
53 typename ShapeFunc> void LayerManager::manageViews(
54 LayerFunc layerFunc,
55 ShapeFunc shapeFunc )
57 LayerSharedPtr pCurrLayer;
58 ViewLayerSharedPtr pCurrViewLayer;
59 LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
60 const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
61 while( aIter != aEnd )
63 LayerSharedPtr pLayer = aIter->second.lock();
64 if( pLayer && pLayer != pCurrLayer )
66 pCurrLayer = pLayer;
67 pCurrViewLayer = layerFunc(pCurrLayer);
70 if( pCurrViewLayer )
71 shapeFunc(aIter->first,pCurrViewLayer);
73 ++aIter;
77 LayerManager::LayerManager( const UnoViewContainer& rViews,
78 const ::basegfx::B2DRange& rPageBounds,
79 bool bDisableAnimationZOrder ) :
80 mrViews(rViews),
81 maLayers(),
82 maXShapeHash( 101 ),
83 maAllShapes(),
84 maUpdateShapes(),
85 maPageBounds( rPageBounds ),
86 mnActiveSprites(0),
87 mbLayerAssociationDirty(false),
88 mbActive(false),
89 mbDisableAnimationZOrder(bDisableAnimationZOrder)
91 // prevent frequent resizes (won't have more than 4 layers
92 // for 99.9% of the cases)
93 maLayers.reserve(4);
95 // create initial background layer
96 maLayers.push_back(
97 Layer::createBackgroundLayer(
98 maPageBounds ));
100 // init views
101 std::for_each( mrViews.begin(),
102 mrViews.end(),
103 ::boost::bind(&LayerManager::viewAdded,
104 this,
105 _1) );
108 void LayerManager::activate( bool bSlideBackgoundPainted )
110 mbActive = true;
111 maUpdateShapes.clear(); // update gets forced via area, or
112 // has happened outside already
114 if( !bSlideBackgoundPainted )
116 std::for_each(mrViews.begin(),
117 mrViews.end(),
118 boost::mem_fn(&View::clearAll));
120 // force update of whole slide area
121 std::for_each( maLayers.begin(),
122 maLayers.end(),
123 boost::bind( &Layer::addUpdateRange,
125 boost::cref(maPageBounds) ));
127 else
129 // clear all possibly pending update areas - content
130 // is there, already
131 std::for_each( maLayers.begin(),
132 maLayers.end(),
133 boost::mem_fn( &Layer::clearUpdateRanges ));
136 updateShapeLayers( bSlideBackgoundPainted );
139 void LayerManager::deactivate()
141 // TODO(F3): This is mostly a hack. Problem is, there's
142 // currently no smart way of telling shapes "remove your
143 // sprites". Others, like MediaShapes, listen to
144 // start/stop animation events, which is too much overhead
145 // for all shapes, though.
147 const bool bMoreThanOneLayer(maLayers.size() > 1);
148 if( mnActiveSprites || bMoreThanOneLayer )
150 // clear all viewlayers, dump everything but the
151 // background layer - this will also remove all shape
152 // sprites
153 std::for_each(maAllShapes.begin(),
154 maAllShapes.end(),
155 boost::bind( &Shape::clearAllViewLayers,
156 boost::bind( o3tl::select1st<LayerShapeMap::value_type>(),
157 _1 )));
159 for (LayerShapeMap::iterator
160 iShape (maAllShapes.begin()),
161 iEnd (maAllShapes.end());
162 iShape!=iEnd;
163 ++iShape)
165 iShape->second.reset();
168 if( bMoreThanOneLayer )
169 maLayers.erase(maLayers.begin()+1,
170 maLayers.end());
172 mbLayerAssociationDirty = true;
175 mbActive = false;
177 // only background layer left
178 OSL_ASSERT( maLayers.size() == 1 && maLayers.front()->isBackgroundLayer() );
181 void LayerManager::viewAdded( 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 // init view content
189 if( mbActive )
190 rView->clearAll();
192 // add View to all registered shapes
193 manageViews(
194 boost::bind(&Layer::addView,
196 boost::cref(rView)),
197 // repaint on view add
198 boost::bind(&Shape::addViewLayer,
201 true) );
203 // in case we haven't reached all layers from the
204 // maAllShapes, issue addView again for good measure
205 std::for_each( maLayers.begin(),
206 maLayers.end(),
207 boost::bind( &Layer::addView,
209 boost::cref(rView) ));
212 void LayerManager::viewRemoved( const UnoViewSharedPtr& rView )
214 // view must not be member of mrViews container anymore
215 OSL_ASSERT( std::find(mrViews.begin(),
216 mrViews.end(),
217 rView) == mrViews.end() );
219 // remove View from all registered shapes
220 manageViews(
221 boost::bind(&Layer::removeView,
223 boost::cref(rView)),
224 boost::bind(&Shape::removeViewLayer,
226 _2) );
228 // in case we haven't reached all layers from the
229 // maAllShapes, issue removeView again for good measure
230 std::for_each( maLayers.begin(),
231 maLayers.end(),
232 boost::bind( &Layer::removeView,
234 boost::cref(rView) ));
237 void LayerManager::viewChanged( const UnoViewSharedPtr& rView )
239 (void)rView;
241 // view must be member of mrViews container
242 OSL_ASSERT( std::find(mrViews.begin(),
243 mrViews.end(),
244 rView) != mrViews.end() );
246 // TODO(P2): selectively update only changed view
247 viewsChanged();
250 void LayerManager::viewsChanged()
252 if( !mbActive )
253 return;
255 // clear view area
256 ::std::for_each( mrViews.begin(),
257 mrViews.end(),
258 ::boost::mem_fn(&View::clearAll) );
260 // TODO(F3): resize and repaint all layers
262 // render all shapes
263 std::for_each( maAllShapes.begin(),
264 maAllShapes.end(),
265 boost::bind(&Shape::render,
266 boost::bind( ::o3tl::select1st<LayerShapeMap::value_type>(), _1)) );
269 void LayerManager::addShape( const ShapeSharedPtr& rShape )
271 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
272 ENSURE_OR_THROW( rShape, "LayerManager::addShape(): invalid Shape" );
274 // add shape to XShape hash map
275 if( !maXShapeHash.insert(
276 XShapeHash::value_type( rShape->getXShape(),
277 rShape) ).second )
279 // entry already present, nothing to do
280 return;
283 // add shape to appropriate layer
284 implAddShape( rShape );
287 void LayerManager::putShape2BackgroundLayer( LayerShapeMap::value_type& rShapeEntry )
289 LayerSharedPtr& rBgLayer( maLayers.front() );
290 rBgLayer->setShapeViews(rShapeEntry.first);
291 rShapeEntry.second = rBgLayer;
294 void LayerManager::implAddShape( const ShapeSharedPtr& rShape )
296 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
297 ENSURE_OR_THROW( rShape, "LayerManager::implAddShape(): invalid Shape" );
299 LayerShapeMap::value_type aValue (rShape, LayerWeakPtr());
301 OSL_ASSERT( maAllShapes.find(rShape) == maAllShapes.end() ); // shape must not be added already
302 mbLayerAssociationDirty = true;
304 if( mbDisableAnimationZOrder )
305 putShape2BackgroundLayer(
306 *maAllShapes.insert(aValue).first );
307 else
308 maAllShapes.insert(aValue);
310 // update shape, it's just added and not yet painted
311 if( rShape->isVisible() )
312 notifyShapeUpdate( rShape );
315 void LayerManager::implRemoveShape( const ShapeSharedPtr& rShape )
317 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
318 ENSURE_OR_THROW( rShape, "LayerManager::implRemoveShape(): invalid Shape" );
320 const LayerShapeMap::iterator aShapeEntry( maAllShapes.find(rShape) );
322 if( aShapeEntry == maAllShapes.end() )
323 return;
325 const bool bShapeUpdateNotified = maUpdateShapes.erase( rShape ) != 0;
327 // Enter shape area to the update area, but only if shape
328 // is visible and not in sprite mode (otherwise, updating
329 // the area doesn't do actual harm, but costs time)
330 // Actually, also add it if it was listed in
331 // maUpdateShapes (might have just gone invisible).
332 if( bShapeUpdateNotified ||
333 (rShape->isVisible() &&
334 !rShape->isBackgroundDetached()) )
336 LayerSharedPtr pLayer = aShapeEntry->second.lock();
337 if( pLayer )
339 // store area early, once the shape is removed from
340 // the layers, it no longer has any view references
341 pLayer->addUpdateRange( rShape->getUpdateArea() );
345 rShape->clearAllViewLayers();
346 maAllShapes.erase( aShapeEntry );
348 mbLayerAssociationDirty = true;
351 ShapeSharedPtr LayerManager::lookupShape( const uno::Reference< drawing::XShape >& xShape ) const
353 ENSURE_OR_THROW( xShape.is(), "LayerManager::lookupShape(): invalid Shape" );
355 const XShapeHash::const_iterator aIter( maXShapeHash.find( xShape ));
356 if( aIter == maXShapeHash.end() )
357 return ShapeSharedPtr(); // not found
359 // found, return data part of entry pair.
360 return aIter->second;
363 AttributableShapeSharedPtr LayerManager::getSubsetShape( const AttributableShapeSharedPtr& rOrigShape,
364 const DocTreeNode& rTreeNode )
366 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
368 AttributableShapeSharedPtr pSubset;
370 // shape already added?
371 if( rOrigShape->createSubset( pSubset,
372 rTreeNode ) )
374 OSL_ENSURE( pSubset, "LayerManager::getSubsetShape(): failed to create subset" );
376 // don't add to shape hash, we're dupes to the
377 // original XShape anyway - all subset shapes return
378 // the same XShape as the original one.
380 // add shape to corresponding layer
381 implAddShape( pSubset );
383 // update original shape, it now shows less content
384 // (the subset is removed from its displayed
385 // output). Subset shape is updated within
386 // implAddShape().
387 if( rOrigShape->isVisible() )
388 notifyShapeUpdate( rOrigShape );
391 return pSubset;
394 void LayerManager::revokeSubset( const AttributableShapeSharedPtr& rOrigShape,
395 const AttributableShapeSharedPtr& rSubsetShape )
397 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
399 if( rOrigShape->revokeSubset( rSubsetShape ) )
401 OSL_ASSERT( maAllShapes.find(rSubsetShape) != maAllShapes.end() );
403 implRemoveShape( rSubsetShape );
405 // update original shape, it now shows more content
406 // (the subset is added back to its displayed output)
407 if( rOrigShape->isVisible() )
408 notifyShapeUpdate( rOrigShape );
412 void LayerManager::enterAnimationMode( const AnimatableShapeSharedPtr& rShape )
414 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
415 ENSURE_OR_THROW( rShape, "LayerManager::enterAnimationMode(): invalid Shape" );
417 const bool bPrevAnimState( rShape->isBackgroundDetached() );
419 rShape->enterAnimationMode();
421 // if this call _really_ enabled the animation mode at
422 // rShape, insert it to our enter animation queue, to
423 // perform the necessary layer reorg lazily on
424 // LayerManager::update()/render().
425 if( bPrevAnimState != rShape->isBackgroundDetached() )
427 ++mnActiveSprites;
428 mbLayerAssociationDirty = true;
430 // area needs update (shape is removed from normal
431 // slide, and now rendered as an autonomous
432 // sprite). store in update set
433 if( rShape->isVisible() )
434 addUpdateArea( rShape );
437 // TODO(P1): this can lead to potential wasted effort, if
438 // a shape gets toggled animated/unanimated a few times
439 // between two frames, returning to the original state.
442 void LayerManager::leaveAnimationMode( const AnimatableShapeSharedPtr& rShape )
444 ENSURE_OR_THROW( !maLayers.empty(), "LayerManager::leaveAnimationMode(): no layers" );
445 ENSURE_OR_THROW( rShape, "LayerManager::leaveAnimationMode(): invalid Shape" );
447 const bool bPrevAnimState( rShape->isBackgroundDetached() );
449 rShape->leaveAnimationMode();
451 // if this call _really_ ended the animation mode at
452 // rShape, insert it to our leave animation queue, to
453 // perform the necessary layer reorg lazily on
454 // LayerManager::update()/render().
455 if( bPrevAnimState != rShape->isBackgroundDetached() )
457 --mnActiveSprites;
458 mbLayerAssociationDirty = true;
460 // shape needs update, no previous rendering, fast
461 // update possible.
462 if( rShape->isVisible() )
463 notifyShapeUpdate( rShape );
466 // TODO(P1): this can lead to potential wasted effort, if
467 // a shape gets toggled animated/unanimated a few times
468 // between two frames, returning to the original state.
471 void LayerManager::notifyShapeUpdate( const ShapeSharedPtr& rShape )
473 if( !mbActive || mrViews.empty() )
474 return;
476 // hidden sprite-shape needs render() call still, to hide sprite
477 if( rShape->isVisible() || rShape->isBackgroundDetached() )
478 maUpdateShapes.insert( rShape );
479 else
480 addUpdateArea( rShape );
483 bool LayerManager::isUpdatePending() const
485 if( !mbActive )
486 return false;
488 if( mbLayerAssociationDirty || !maUpdateShapes.empty() )
489 return true;
491 return std::any_of( maLayers.begin(),
492 maLayers.end(),
493 boost::mem_fn(&Layer::isUpdatePending) );
496 bool LayerManager::updateSprites()
498 bool bRet(true);
500 // send update() calls to every shape in the
501 // maUpdateShapes set, which is _animated_ (i.e. a
502 // sprite).
503 const ShapeUpdateSet::const_iterator aEnd=maUpdateShapes.end();
504 ShapeUpdateSet::const_iterator aCurrShape=maUpdateShapes.begin();
505 while( aCurrShape != aEnd )
507 if( (*aCurrShape)->isBackgroundDetached() )
509 // can update shape directly, without
510 // affecting layer content (shape is
511 // currently displayed in a sprite)
512 if( !(*aCurrShape)->update() )
513 bRet = false; // delay error exit
515 else
517 // TODO(P2): addUpdateArea() involves log(n)
518 // search for shape layer. Have a frequent
519 // shape/layer association cache, or ptr back to
520 // layer at the shape?
522 // cannot update shape directly, it's not
523 // animated and update() calls will prolly
524 // overwrite other page content.
525 addUpdateArea( *aCurrShape );
528 ++aCurrShape;
531 maUpdateShapes.clear();
533 return bRet;
536 bool LayerManager::update()
538 bool bRet = true;
540 if( !mbActive )
541 return bRet;
543 // going to render - better flush any pending layer reorg
544 // now
545 updateShapeLayers(false);
547 // all sprites
548 bRet = updateSprites();
550 // any non-sprite update areas left?
551 if( std::none_of( maLayers.begin(),
552 maLayers.end(),
553 boost::mem_fn( &Layer::isUpdatePending ) ) )
554 return bRet; // nope, done.
556 // update each shape on each layer, that has
557 // isUpdatePending()
558 bool bIsCurrLayerUpdating(false);
559 Layer::EndUpdater aEndUpdater;
560 LayerSharedPtr pCurrLayer;
561 LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
562 const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
563 while( aIter != aEnd )
565 LayerSharedPtr pLayer = aIter->second.lock();
566 if( pLayer != pCurrLayer )
568 pCurrLayer = pLayer;
569 bIsCurrLayerUpdating = pCurrLayer->isUpdatePending();
571 if( bIsCurrLayerUpdating )
572 aEndUpdater = pCurrLayer->beginUpdate();
575 if( bIsCurrLayerUpdating &&
576 !aIter->first->isBackgroundDetached() &&
577 pCurrLayer->isInsideUpdateArea(aIter->first) )
579 if( !aIter->first->render() )
580 bRet = false;
583 ++aIter;
586 return bRet;
589 namespace
591 /** Little wrapper around a Canvas, to render one-shot
592 into a canvas
594 class DummyLayer : public ViewLayer
596 public:
597 explicit DummyLayer( const ::cppcanvas::CanvasSharedPtr& rCanvas ) :
598 mpCanvas( rCanvas )
602 virtual bool isOnView(boost::shared_ptr<View> const& /*rView*/) const SAL_OVERRIDE
604 return true; // visible on all views
607 virtual ::cppcanvas::CanvasSharedPtr getCanvas() const SAL_OVERRIDE
609 return mpCanvas;
612 virtual void clear() const SAL_OVERRIDE
614 // NOOP
617 virtual void clearAll() const SAL_OVERRIDE
619 // NOOP
622 virtual ::cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& /*rSpriteSizePixel*/,
623 double /*nSpritePrio*/ ) const SAL_OVERRIDE
625 ENSURE_OR_THROW( false,
626 "DummyLayer::createSprite(): This method is not supposed to be called!" );
627 return ::cppcanvas::CustomSpriteSharedPtr();
630 virtual void setPriority( const basegfx::B1DRange& /*rRange*/ ) SAL_OVERRIDE
632 OSL_FAIL( "BitmapView::setPriority(): This method is not supposed to be called!" );
635 virtual ::com::sun::star::geometry::IntegerSize2D getTranslationOffset() const SAL_OVERRIDE
637 return geometry::IntegerSize2D(0,0);
640 virtual ::basegfx::B2DHomMatrix getTransformation() const SAL_OVERRIDE
642 return mpCanvas->getTransformation();
645 virtual ::basegfx::B2DHomMatrix getSpriteTransformation() const SAL_OVERRIDE
647 OSL_FAIL( "BitmapView::getSpriteTransformation(): This method is not supposed to be called!" );
648 return ::basegfx::B2DHomMatrix();
651 virtual void setClip( const ::basegfx::B2DPolyPolygon& /*rClip*/ ) SAL_OVERRIDE
653 OSL_FAIL( "BitmapView::setClip(): This method is not supposed to be called!" );
656 virtual bool resize( const ::basegfx::B2DRange& /*rArea*/ ) SAL_OVERRIDE
658 OSL_FAIL( "BitmapView::resize(): This method is not supposed to be called!" );
659 return false;
662 private:
663 ::cppcanvas::CanvasSharedPtr mpCanvas;
667 bool LayerManager::renderTo( const ::cppcanvas::CanvasSharedPtr& rTargetCanvas ) const
669 bool bRet( true );
670 ViewLayerSharedPtr pTmpLayer( new DummyLayer( rTargetCanvas ) );
672 LayerShapeMap::const_iterator aIter( maAllShapes.begin() );
673 const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
674 while( aIter != aEnd )
678 // forward to all shape's addViewLayer method (which
679 // we request to render the Shape on the new
680 // ViewLayer. Since we add the shapes in the
681 // maShapeSet order (which is also the render order),
682 // this is equivalent to a subsequent render() call)
683 aIter->first->addViewLayer( pTmpLayer,
684 true );
686 // and remove again, this is only temporary
687 aIter->first->removeViewLayer( pTmpLayer );
689 catch( uno::Exception& )
691 // TODO(E1): Might be superfluous. Nowadays,
692 // addViewLayer swallows all errors, anyway.
693 OSL_FAIL( OUStringToOString(
694 comphelper::anyToString( cppu::getCaughtException() ),
695 RTL_TEXTENCODING_UTF8 ).getStr() );
697 // at least one shape could not be rendered
698 bRet = false;
701 ++aIter;
704 return bRet;
707 void LayerManager::addUpdateArea( ShapeSharedPtr const& rShape )
709 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
710 ENSURE_OR_THROW( rShape, "LayerManager::addUpdateArea(): invalid Shape" );
712 const LayerShapeMap::const_iterator aShapeEntry( maAllShapes.find(rShape) );
714 if( aShapeEntry == maAllShapes.end() )
715 return;
717 LayerSharedPtr pLayer = aShapeEntry->second.lock();
718 if( pLayer )
719 pLayer->addUpdateRange( rShape->getUpdateArea() );
722 void LayerManager::commitLayerChanges( std::size_t nCurrLayerIndex,
723 LayerShapeMap::const_iterator aFirstLayerShape,
724 LayerShapeMap::const_iterator aEndLayerShapes )
726 const bool bLayerExists( maLayers.size() > nCurrLayerIndex );
727 if( bLayerExists )
729 const LayerSharedPtr& rLayer( maLayers.at(nCurrLayerIndex) );
730 const bool bLayerResized( rLayer->commitBounds() );
731 rLayer->setPriority( basegfx::B1DRange(nCurrLayerIndex,
732 nCurrLayerIndex+1) );
734 if( bLayerResized )
736 // need to re-render whole layer - start from
737 // clean state
738 rLayer->clearContent();
740 // render and remove from update set
741 while( aFirstLayerShape != aEndLayerShapes )
743 maUpdateShapes.erase(aFirstLayerShape->first);
744 aFirstLayerShape->first->render();
745 ++aFirstLayerShape;
751 LayerSharedPtr LayerManager::createForegroundLayer() const
753 OSL_ASSERT( mbActive );
755 LayerSharedPtr pLayer( Layer::createLayer(
756 maPageBounds ));
758 // create ViewLayers for all registered views, and add to
759 // newly created layer.
760 ::std::for_each( mrViews.begin(),
761 mrViews.end(),
762 boost::bind( &Layer::addView,
763 boost::cref(pLayer),
764 _1 ));
766 return pLayer;
769 void LayerManager::updateShapeLayers( bool bBackgroundLayerPainted )
771 OSL_ASSERT( !maLayers.empty() ); // always at least background layer
772 OSL_ASSERT( mbActive );
774 // do we need to process shapes?
775 if( !mbLayerAssociationDirty )
776 return;
778 if( mbDisableAnimationZOrder )
780 // layer setup happened elsewhere, is only bg layer
781 // anyway.
782 mbLayerAssociationDirty = false;
783 return;
786 // scan through maAllShapes, and determine shape animation
787 // discontinuities: when a shape that has
788 // isBackgroundDetached() return false follows a shape
789 // with isBackgroundDetached() true, the former and all
790 // following ones must be moved into an own layer.
792 // to avoid tons of temporaries, create weak_ptr to Layers
793 // beforehand
794 std::vector< LayerWeakPtr > aWeakLayers(maLayers.size());
795 std::copy(maLayers.begin(),maLayers.end(),aWeakLayers.begin());
797 std::size_t nCurrLayerIndex(0);
798 bool bIsBackgroundLayer(true);
799 bool bLastWasBackgroundDetached(false); // last shape sprite state
800 LayerShapeMap::iterator aCurrShapeEntry( maAllShapes.begin() );
801 LayerShapeMap::iterator aCurrLayerFirstShapeEntry( maAllShapes.begin() );
802 const LayerShapeMap::iterator aEndShapeEntry ( maAllShapes.end() );
803 ShapeUpdateSet aUpdatedShapes; // shapes that need update
804 while( aCurrShapeEntry != aEndShapeEntry )
806 const ShapeSharedPtr pCurrShape( aCurrShapeEntry->first );
807 const bool bThisIsBackgroundDetached(
808 pCurrShape->isBackgroundDetached() );
810 if( bLastWasBackgroundDetached &&
811 !bThisIsBackgroundDetached )
813 // discontinuity found - current shape needs to
814 // get into a new layer
817 // commit changes to previous layer
818 commitLayerChanges(nCurrLayerIndex,
819 aCurrLayerFirstShapeEntry,
820 aCurrShapeEntry);
821 aCurrLayerFirstShapeEntry=aCurrShapeEntry;
822 ++nCurrLayerIndex;
823 bIsBackgroundLayer = false;
825 if( aWeakLayers.size() <= nCurrLayerIndex ||
826 aWeakLayers.at(nCurrLayerIndex) != aCurrShapeEntry->second )
828 // no more layers left, or shape was not
829 // member of this layer - create a new one
830 maLayers.insert( maLayers.begin()+nCurrLayerIndex,
831 createForegroundLayer() );
832 aWeakLayers.insert( aWeakLayers.begin()+nCurrLayerIndex,
833 maLayers[nCurrLayerIndex] );
837 OSL_ASSERT( maLayers.size() == aWeakLayers.size() );
839 // note: using indices here, since vector::insert
840 // above invalidates iterators
841 LayerSharedPtr& rCurrLayer( maLayers.at(nCurrLayerIndex) );
842 LayerWeakPtr& rCurrWeakLayer( aWeakLayers.at(nCurrLayerIndex) );
843 if( rCurrWeakLayer != aCurrShapeEntry->second )
845 // mismatch: shape is not contained in current
846 // layer - move shape to that layer, then.
847 maLayers.at(nCurrLayerIndex)->setShapeViews(
848 pCurrShape );
850 // layer got new shape(s), need full repaint, if
851 // non-sprite shape
852 if( !bThisIsBackgroundDetached && pCurrShape->isVisible() )
854 LayerSharedPtr pOldLayer( aCurrShapeEntry->second.lock() );
855 if( pOldLayer )
857 // old layer still valid? then we need to
858 // repaint former shape area
859 pOldLayer->addUpdateRange(
860 pCurrShape->getUpdateArea() );
863 // render on new layer (only if not
864 // explicitly disabled)
865 if( !(bBackgroundLayerPainted && bIsBackgroundLayer) )
866 maUpdateShapes.insert( pCurrShape );
869 aCurrShapeEntry->second = rCurrWeakLayer;
872 // update layerbounds regardless of the fact that the
873 // shape might be contained in said layer
874 // already. updateBounds() is dumb and needs to
875 // collect all shape bounds.
876 // of course, no need to expand layer bounds for
877 // shapes that reside in sprites themselves.
878 if( !bThisIsBackgroundDetached && !bIsBackgroundLayer )
879 rCurrLayer->updateBounds( pCurrShape );
881 bLastWasBackgroundDetached = bThisIsBackgroundDetached;
882 ++aCurrShapeEntry;
885 // commit very last layer data
886 commitLayerChanges(nCurrLayerIndex,
887 aCurrLayerFirstShapeEntry,
888 aCurrShapeEntry);
890 // any layers left? Bin them!
891 if( maLayers.size() > nCurrLayerIndex+1 )
892 maLayers.erase(maLayers.begin()+nCurrLayerIndex+1,
893 maLayers.end());
895 mbLayerAssociationDirty = false;
900 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */