1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_slideshow.hxx"
26 
27 #include <canvas/debug.hxx>
28 #include <tools/diagnose_ex.h>
29 #include <basegfx/range/b1drange.hxx>
30 #include <basegfx/matrix/b2dhommatrix.hxx>
31 
32 #include <comphelper/anytostring.hxx>
33 #include <cppuhelper/exc_hlp.hxx>
34 
35 #include <boost/bind.hpp>
36 #include <algorithm>
37 
38 #include "layermanager.hxx"
39 
40 using namespace ::com::sun::star;
41 
42 namespace boost
43 {
44     // add operator!= for weak_ptr
45     inline bool operator!=( slideshow::internal::LayerWeakPtr const& rLHS,
46                             slideshow::internal::LayerWeakPtr const& rRHS )
47     {
48         return (rLHS<rRHS) || (rRHS<rLHS);
49     }
50 }
51 
52 namespace slideshow
53 {
54     namespace internal
55     {
56         template<typename LayerFunc,
57                  typename ShapeFunc> void LayerManager::manageViews(
58                      LayerFunc layerFunc,
59                      ShapeFunc shapeFunc )
60         {
61             LayerSharedPtr                      pCurrLayer;
62             ViewLayerSharedPtr                  pCurrViewLayer;
63             LayerShapeMap::const_iterator       aIter( maAllShapes.begin() );
64             const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
65             while( aIter != aEnd )
66             {
67                 LayerSharedPtr pLayer = aIter->second.lock();
68                 if( pLayer && pLayer != pCurrLayer )
69                 {
70                     pCurrLayer = pLayer;
71                     pCurrViewLayer = layerFunc(pCurrLayer);
72                 }
73 
74                 if( pCurrViewLayer )
75                     shapeFunc(aIter->first,pCurrViewLayer);
76 
77                 ++aIter;
78             }
79         }
80 
81         LayerManager::LayerManager( const UnoViewContainer&    rViews,
82                                     const ::basegfx::B2DRange& rPageBounds,
83                                     bool                       bDisableAnimationZOrder ) :
84             mrViews(rViews),
85             maLayers(),
86             maXShapeHash( 101 ),
87             maAllShapes(),
88             maUpdateShapes(),
89             maPageBounds( rPageBounds ),
90             mnActiveSprites(0),
91             mbLayerAssociationDirty(false),
92             mbActive(false),
93             mbDisableAnimationZOrder(bDisableAnimationZOrder)
94         {
95             // prevent frequent resizes (won't have more than 4 layers
96             // for 99.9% of the cases)
97             maLayers.reserve(4);
98 
99             // create initial background layer
100             maLayers.push_back(
101                     Layer::createBackgroundLayer(
102                         maPageBounds ));
103 
104             // init views
105             std::for_each( mrViews.begin(),
106                            mrViews.end(),
107                            ::boost::bind(&LayerManager::viewAdded,
108                                          this,
109                                          _1) );
110         }
111 
112         void LayerManager::activate( bool bSlideBackgoundPainted )
113         {
114             mbActive = true;
115             maUpdateShapes.clear(); // update gets forced via area, or
116                                     // has happened outside already
117 
118             if( !bSlideBackgoundPainted )
119             {
120                 std::for_each(mrViews.begin(),
121                               mrViews.end(),
122                               boost::mem_fn(&View::clearAll));
123 
124                 // force update of whole slide area
125                 std::for_each( maLayers.begin(),
126                                maLayers.end(),
127                                boost::bind( &Layer::addUpdateRange,
128                                             _1,
129                                             boost::cref(maPageBounds) ));
130             }
131             else
132             {
133                 // clear all possibly pending update areas - content
134                 // is there, already
135                 std::for_each( maLayers.begin(),
136                                maLayers.end(),
137                                boost::mem_fn( &Layer::clearUpdateRanges ));
138             }
139 
140             updateShapeLayers( bSlideBackgoundPainted );
141         }
142 
143         void LayerManager::deactivate()
144         {
145             // TODO(F3): This is mostly a hack. Problem is, there's
146             // currently no smart way of telling shapes "remove your
147             // sprites". Others, like MediaShapes, listen to
148             // start/stop animation events, which is too much overhead
149             // for all shapes, though.
150 
151             const bool bMoreThanOneLayer(maLayers.size() > 1);
152             if( mnActiveSprites || bMoreThanOneLayer )
153             {
154                 // clear all viewlayers, dump everything but the
155                 // background layer - this will also remove all shape
156                 // sprites
157                 std::for_each(maAllShapes.begin(),
158                               maAllShapes.end(),
159                               boost::bind( &Shape::clearAllViewLayers,
160                                            boost::bind( std::select1st<LayerShapeMap::value_type>(),
161                                                         _1 )));
162 
163                 for (LayerShapeMap::iterator
164                          iShape (maAllShapes.begin()),
165                          iEnd (maAllShapes.end());
166                      iShape!=iEnd;
167                      ++iShape)
168                 {
169                     iShape->second.reset();
170                 }
171 
172                 if( bMoreThanOneLayer )
173                     maLayers.erase(maLayers.begin()+1,
174                                    maLayers.end());
175 
176                 mbLayerAssociationDirty = true;
177             }
178 
179             mbActive = false;
180 
181             // only background layer left
182             OSL_ASSERT( maLayers.size() == 1 && maLayers.front()->isBackgroundLayer() );
183         }
184 
185         void LayerManager::viewAdded( const UnoViewSharedPtr& rView )
186         {
187             // view must be member of mrViews container
188             OSL_ASSERT( std::find(mrViews.begin(),
189                                   mrViews.end(),
190                                   rView) != mrViews.end() );
191 
192             // init view content
193             if( mbActive )
194                 rView->clearAll();
195 
196             // add View to all registered shapes
197             manageViews(
198                 boost::bind(&Layer::addView,
199                             _1,
200                             boost::cref(rView)),
201                 // repaint on view add
202                 boost::bind(&Shape::addViewLayer,
203                             _1,
204                             _2,
205                             true) );
206 
207             // in case we haven't reached all layers from the
208             // maAllShapes, issue addView again for good measure
209             std::for_each( maLayers.begin(),
210                            maLayers.end(),
211                            boost::bind( &Layer::addView,
212                                         _1,
213                                         boost::cref(rView) ));
214         }
215 
216         void LayerManager::viewRemoved( const UnoViewSharedPtr& rView )
217         {
218             // view must not be member of mrViews container anymore
219             OSL_ASSERT( std::find(mrViews.begin(),
220                                   mrViews.end(),
221                                   rView) == mrViews.end() );
222 
223             // remove View from all registered shapes
224             manageViews(
225                 boost::bind(&Layer::removeView,
226                             _1,
227                             boost::cref(rView)),
228                 boost::bind(&Shape::removeViewLayer,
229                             _1,
230                             _2) );
231 
232             // in case we haven't reached all layers from the
233             // maAllShapes, issue removeView again for good measure
234             std::for_each( maLayers.begin(),
235                            maLayers.end(),
236                            boost::bind( &Layer::removeView,
237                                         _1,
238                                         boost::cref(rView) ));
239         }
240 
241         void LayerManager::viewChanged( const UnoViewSharedPtr& rView )
242         {
243             (void)rView;
244 
245             // view must be member of mrViews container
246             OSL_ASSERT( std::find(mrViews.begin(),
247                                   mrViews.end(),
248                                   rView) != mrViews.end() );
249 
250             // TODO(P2): selectively update only changed view
251             viewsChanged();
252         }
253 
254         void LayerManager::viewsChanged()
255         {
256             if( !mbActive )
257                 return;
258 
259             // clear view area
260             ::std::for_each( mrViews.begin(),
261                              mrViews.end(),
262                              ::boost::mem_fn(&View::clearAll) );
263 
264             // TODO(F3): resize and repaint all layers
265 
266             // render all shapes
267             std::for_each( maAllShapes.begin(),
268                            maAllShapes.end(),
269                            boost::bind(&Shape::render,
270                                boost::bind( ::std::select1st<LayerShapeMap::value_type>(), _1)) );
271         }
272 
273         void LayerManager::addShape( const ShapeSharedPtr& rShape )
274         {
275             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
276             ENSURE_OR_THROW( rShape, "LayerManager::addShape(): invalid Shape" );
277 
278             // add shape to XShape hash map
279             if( !maXShapeHash.insert(
280                     XShapeHash::value_type( rShape->getXShape(),
281                                             rShape) ).second )
282             {
283                 // entry already present, nothing to do
284                 return;
285             }
286 
287             // add shape to appropriate layer
288             implAddShape( rShape );
289         }
290 
291         void LayerManager::putShape2BackgroundLayer( LayerShapeMap::value_type& rShapeEntry )
292         {
293             LayerSharedPtr& rBgLayer( maLayers.front() );
294             rBgLayer->setShapeViews(rShapeEntry.first);
295             rShapeEntry.second = rBgLayer;
296         }
297 
298         void LayerManager::implAddShape( const ShapeSharedPtr& rShape )
299         {
300             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
301             ENSURE_OR_THROW( rShape, "LayerManager::implAddShape(): invalid Shape" );
302 
303             LayerShapeMap::value_type aValue (rShape, LayerWeakPtr());
304 
305             OSL_ASSERT( maAllShapes.find(rShape) == maAllShapes.end() ); // shape must not be added already
306             mbLayerAssociationDirty = true;
307 
308             if( mbDisableAnimationZOrder )
309                 putShape2BackgroundLayer(
310                     *maAllShapes.insert(aValue).first );
311             else
312                 maAllShapes.insert(aValue);
313 
314             // update shape, it's just added and not yet painted
315             if( rShape->isVisible() )
316                 notifyShapeUpdate( rShape );
317         }
318 
319         bool LayerManager::removeShape( const ShapeSharedPtr& rShape )
320         {
321             // remove shape from XShape hash map
322             if( maXShapeHash.erase( rShape->getXShape() ) == 0 )
323                 return false; // shape not in map
324 
325             OSL_ASSERT( maAllShapes.find(rShape) != maAllShapes.end() );
326 
327             implRemoveShape( rShape );
328 
329             return true;
330         }
331 
332         void LayerManager::implRemoveShape( const ShapeSharedPtr& rShape )
333         {
334             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
335             ENSURE_OR_THROW( rShape, "LayerManager::implRemoveShape(): invalid Shape" );
336 
337             const LayerShapeMap::iterator aShapeEntry( maAllShapes.find(rShape) );
338 
339             if( aShapeEntry == maAllShapes.end() )
340                 return;
341 
342             const bool bShapeUpdateNotified = maUpdateShapes.erase( rShape ) != 0;
343 
344             // Enter shape area to the update area, but only if shape
345             // is visible and not in sprite mode (otherwise, updating
346             // the area doesn't do actual harm, but costs time)
347             // Actually, also add it if it was listed in
348             // maUpdateShapes (might have just gone invisible).
349             if( bShapeUpdateNotified ||
350                 (rShape->isVisible() &&
351                  !rShape->isBackgroundDetached()) )
352             {
353                 LayerSharedPtr pLayer = aShapeEntry->second.lock();
354                 if( pLayer )
355                 {
356                     // store area early, once the shape is removed from
357                     // the layers, it no longer has any view references
358                     pLayer->addUpdateRange( rShape->getUpdateArea() );
359                 }
360             }
361 
362             rShape->clearAllViewLayers();
363             maAllShapes.erase( aShapeEntry );
364 
365             mbLayerAssociationDirty = true;
366         }
367 
368         ShapeSharedPtr LayerManager::lookupShape( const uno::Reference< drawing::XShape >& xShape ) const
369         {
370             ENSURE_OR_THROW( xShape.is(), "LayerManager::lookupShape(): invalid Shape" );
371 
372             const XShapeHash::const_iterator aIter( maXShapeHash.find( xShape ));
373             if( aIter == maXShapeHash.end() )
374                 return ShapeSharedPtr(); // not found
375 
376             // found, return data part of entry pair.
377             return aIter->second;
378         }
379 
380         AttributableShapeSharedPtr LayerManager::getSubsetShape( const AttributableShapeSharedPtr& 	rOrigShape,
381                                                                  const DocTreeNode&					rTreeNode )
382         {
383             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
384 
385             AttributableShapeSharedPtr pSubset;
386 
387             // shape already added?
388             if( rOrigShape->createSubset( pSubset,
389                                           rTreeNode ) )
390             {
391                 OSL_ENSURE( pSubset, "LayerManager::getSubsetShape(): failed to create subset" );
392 
393                 // don't add to shape hash, we're dupes to the
394                 // original XShape anyway - all subset shapes return
395                 // the same XShape as the original one.
396 
397                 // add shape to corresponding layer
398                 implAddShape( pSubset );
399 
400                 // update original shape, it now shows less content
401                 // (the subset is removed from its displayed
402                 // output). Subset shape is updated within
403                 // implAddShape().
404                 if( rOrigShape->isVisible() )
405                     notifyShapeUpdate( rOrigShape );
406             }
407 
408             return pSubset;
409         }
410 
411         void LayerManager::revokeSubset( const AttributableShapeSharedPtr& rOrigShape,
412                                          const AttributableShapeSharedPtr& rSubsetShape )
413         {
414             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
415 
416             if( rOrigShape->revokeSubset( rSubsetShape ) )
417             {
418                 OSL_ASSERT( maAllShapes.find(rSubsetShape) != maAllShapes.end() );
419 
420                 implRemoveShape( rSubsetShape );
421 
422                 // update original shape, it now shows more content
423                 // (the subset is added back to its displayed output)
424                 if( rOrigShape->isVisible() )
425                     notifyShapeUpdate( rOrigShape );
426             }
427         }
428 
429         void LayerManager::enterAnimationMode( const AnimatableShapeSharedPtr& rShape )
430         {
431             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
432             ENSURE_OR_THROW( rShape, "LayerManager::enterAnimationMode(): invalid Shape" );
433 
434             const bool bPrevAnimState( rShape->isBackgroundDetached() );
435 
436             rShape->enterAnimationMode();
437 
438             // if this call _really_ enabled the animation mode at
439             // rShape, insert it to our enter animation queue, to
440             // perform the necessary layer reorg lazily on
441             // LayerManager::update()/render().
442             if( bPrevAnimState != rShape->isBackgroundDetached() )
443             {
444                 ++mnActiveSprites;
445                 mbLayerAssociationDirty = true;
446 
447                 // area needs update (shape is removed from normal
448                 // slide, and now rendered as an autonomous
449                 // sprite). store in update set
450                 if( rShape->isVisible() )
451                     addUpdateArea( rShape );
452             }
453 
454             // TODO(P1): this can lead to potential wasted effort, if
455             // a shape gets toggled animated/unanimated a few times
456             // between two frames, returning to the original state.
457         }
458 
459         void LayerManager::leaveAnimationMode( const AnimatableShapeSharedPtr& rShape )
460         {
461             ENSURE_OR_THROW( !maLayers.empty(), "LayerManager::leaveAnimationMode(): no layers" );
462             ENSURE_OR_THROW( rShape, "LayerManager::leaveAnimationMode(): invalid Shape" );
463 
464             const bool bPrevAnimState( rShape->isBackgroundDetached() );
465 
466             rShape->leaveAnimationMode();
467 
468             // if this call _really_ ended the animation mode at
469             // rShape, insert it to our leave animation queue, to
470             // perform the necessary layer reorg lazily on
471             // LayerManager::update()/render().
472             if( bPrevAnimState != rShape->isBackgroundDetached() )
473             {
474                 --mnActiveSprites;
475                 mbLayerAssociationDirty = true;
476 
477                 // shape needs update, no previous rendering, fast
478                 // update possible.
479                 if( rShape->isVisible() )
480                     notifyShapeUpdate( rShape );
481             }
482 
483             // TODO(P1): this can lead to potential wasted effort, if
484             // a shape gets toggled animated/unanimated a few times
485             // between two frames, returning to the original state.
486         }
487 
488         void LayerManager::notifyShapeUpdate( const ShapeSharedPtr& rShape )
489         {
490             if( !mbActive || mrViews.empty() )
491                 return;
492 
493             // hidden sprite-shape needs render() call still, to hide sprite
494             if( rShape->isVisible() || rShape->isBackgroundDetached() )
495                 maUpdateShapes.insert( rShape );
496             else
497                 addUpdateArea( rShape );
498         }
499 
500         bool LayerManager::isUpdatePending() const
501         {
502             if( !mbActive )
503                 return false;
504 
505             if( mbLayerAssociationDirty || !maUpdateShapes.empty() )
506                 return true;
507 
508             const LayerVector::const_iterator aEnd( maLayers.end() );
509             if( std::find_if( maLayers.begin(),
510                               aEnd,
511                               boost::mem_fn(&Layer::isUpdatePending)) != aEnd )
512                 return true;
513 
514             return false;
515         }
516 
517         bool LayerManager::updateSprites()
518         {
519             bool bRet(true);
520 
521             // send update() calls to every shape in the
522             // maUpdateShapes set, which is _animated_ (i.e. a
523             // sprite).
524             const ShapeUpdateSet::const_iterator aEnd=maUpdateShapes.end();
525             ShapeUpdateSet::const_iterator 	     aCurrShape=maUpdateShapes.begin();
526             while( aCurrShape != aEnd )
527             {
528                 if( (*aCurrShape)->isBackgroundDetached() )
529                 {
530                     // can update shape directly, without
531                     // affecting layer content (shape is
532                     // currently displayed in a sprite)
533                     if( !(*aCurrShape)->update() )
534                         bRet = false; // delay error exit
535                 }
536                 else
537                 {
538                     // TODO(P2): addUpdateArea() involves log(n)
539                     // search for shape layer. Have a frequent
540                     // shape/layer association cache, or ptr back to
541                     // layer at the shape?
542 
543                     // cannot update shape directly, it's not
544                     // animated and update() calls will prolly
545                     // overwrite other page content.
546                     addUpdateArea( *aCurrShape );
547                 }
548 
549                 ++aCurrShape;
550             }
551 
552             maUpdateShapes.clear();
553 
554             return bRet;
555         }
556 
557         bool LayerManager::update()
558         {
559             bool bRet = true;
560 
561             if( !mbActive )
562                 return bRet;
563 
564             // going to render - better flush any pending layer reorg
565             // now
566             updateShapeLayers(false);
567 
568             // all sprites
569             bRet = updateSprites();
570 
571             // any non-sprite update areas left?
572             if( std::find_if( maLayers.begin(),
573                               maLayers.end(),
574                               boost::mem_fn( &Layer::isUpdatePending )) == maLayers.end() )
575                 return bRet; // nope, done.
576 
577             // update each shape on each layer, that has
578             // isUpdatePending()
579             bool                                bIsCurrLayerUpdating(false);
580             Layer::EndUpdater                   aEndUpdater;
581             LayerSharedPtr                      pCurrLayer;
582             LayerShapeMap::const_iterator       aIter( maAllShapes.begin() );
583             const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
584             while( aIter != aEnd )
585             {
586                 LayerSharedPtr pLayer = aIter->second.lock();
587                 if( pLayer != pCurrLayer )
588                 {
589                     pCurrLayer = pLayer;
590                     bIsCurrLayerUpdating = pCurrLayer->isUpdatePending();
591 
592                     if( bIsCurrLayerUpdating )
593                         aEndUpdater = pCurrLayer->beginUpdate();
594                 }
595 
596                 if( bIsCurrLayerUpdating &&
597                     !aIter->first->isBackgroundDetached() &&
598                     pCurrLayer->isInsideUpdateArea(aIter->first) )
599                 {
600                     if( !aIter->first->render() )
601                         bRet = false;
602                 }
603 
604                 ++aIter;
605             }
606 
607             return bRet;
608         }
609 
610         namespace
611         {
612             /** Little wrapper around a Canvas, to render one-shot
613                 into a canvas
614              */
615             class DummyLayer : public ViewLayer
616             {
617             public:
618                 explicit DummyLayer( const ::cppcanvas::CanvasSharedPtr& rCanvas ) :
619                     mpCanvas( rCanvas )
620                 {
621                 }
622 
623                 virtual bool isOnView(boost::shared_ptr<View> const& /*rView*/) const
624                 {
625                     return true; // visible on all views
626                 }
627 
628                 virtual ::cppcanvas::CanvasSharedPtr getCanvas() const
629                 {
630                     return mpCanvas;
631                 }
632 
633                 virtual void clear() const
634                 {
635                     // NOOP
636                 }
637 
638                 virtual void clearAll() const
639                 {
640                     // NOOP
641                 }
642 
643                 virtual ::cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& /*rSpriteSizePixel*/,
644                                                                          double                    /*nSpritePrio*/ ) const
645                 {
646                     ENSURE_OR_THROW( false,
647                                       "DummyLayer::createSprite(): This method is not supposed to be called!" );
648                     return ::cppcanvas::CustomSpriteSharedPtr();
649                 }
650 
651                 virtual void setPriority( const basegfx::B1DRange& /*rRange*/ )
652                 {
653                     OSL_ENSURE( false,
654                                 "BitmapView::setPriority(): This method is not supposed to be called!" );
655                 }
656 
657                 virtual ::basegfx::B2DHomMatrix getTransformation() const
658                 {
659                     return mpCanvas->getTransformation();
660                 }
661 
662                 virtual ::basegfx::B2DHomMatrix getSpriteTransformation() const
663                 {
664                     OSL_ENSURE( false,
665                                 "BitmapView::getSpriteTransformation(): This method is not supposed to be called!" );
666                     return ::basegfx::B2DHomMatrix();
667                 }
668 
669                 virtual void setClip( const ::basegfx::B2DPolyPolygon& /*rClip*/ )
670                 {
671                     OSL_ENSURE( false,
672                                 "BitmapView::setClip(): This method is not supposed to be called!" );
673                 }
674 
675                 virtual bool resize( const ::basegfx::B2DRange& /*rArea*/ )
676                 {
677                     OSL_ENSURE( false,
678                                 "BitmapView::resize(): This method is not supposed to be called!" );
679                     return false;
680                 }
681 
682             private:
683                 ::cppcanvas::CanvasSharedPtr mpCanvas;
684             };
685         }
686 
687         bool LayerManager::renderTo( const ::cppcanvas::CanvasSharedPtr& rTargetCanvas ) const
688         {
689             bool bRet( true );
690             ViewLayerSharedPtr pTmpLayer( new DummyLayer( rTargetCanvas ) );
691 
692             LayerShapeMap::const_iterator       aIter( maAllShapes.begin() );
693             const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
694             while( aIter != aEnd )
695             {
696                 try
697                 {
698                     // forward to all shape's addViewLayer method (which
699                     // we request to render the Shape on the new
700                     // ViewLayer. Since we add the shapes in the
701                     // maShapeSet order (which is also the render order),
702                     // this is equivalent to a subsequent render() call)
703                     aIter->first->addViewLayer( pTmpLayer,
704                                                 true );
705 
706                     // and remove again, this is only temporary
707                     aIter->first->removeViewLayer( pTmpLayer );
708                 }
709                 catch( uno::Exception& )
710                 {
711                     // TODO(E1): Might be superfluous. Nowadays,
712                     // addViewLayer swallows all errors, anyway.
713                     OSL_ENSURE( false,
714                                 rtl::OUStringToOString(
715                                     comphelper::anyToString( cppu::getCaughtException() ),
716                                     RTL_TEXTENCODING_UTF8 ).getStr() );
717 
718                     // at least one shape could not be rendered
719                     bRet = false;
720                 }
721 
722                 ++aIter;
723             }
724 
725             return bRet;
726         }
727 
728         void LayerManager::addUpdateArea( ShapeSharedPtr const& rShape )
729         {
730             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
731             ENSURE_OR_THROW( rShape, "LayerManager::addUpdateArea(): invalid Shape" );
732 
733             const LayerShapeMap::const_iterator aShapeEntry( maAllShapes.find(rShape) );
734 
735             if( aShapeEntry == maAllShapes.end() )
736                 return;
737 
738             LayerSharedPtr pLayer = aShapeEntry->second.lock();
739             if( pLayer )
740                 pLayer->addUpdateRange( rShape->getUpdateArea() );
741         }
742 
743         void LayerManager::commitLayerChanges( std::size_t              nCurrLayerIndex,
744                                                LayerShapeMap::const_iterator  aFirstLayerShape,
745                                                LayerShapeMap::const_iterator  aEndLayerShapes )
746         {
747             const bool bLayerExists( maLayers.size() > nCurrLayerIndex );
748             if( bLayerExists )
749             {
750                 const LayerSharedPtr& rLayer( maLayers.at(nCurrLayerIndex) );
751                 const bool bLayerResized( rLayer->commitBounds() );
752                 rLayer->setPriority( basegfx::B1DRange(nCurrLayerIndex,
753                                                        nCurrLayerIndex+1) );
754 
755                 if( bLayerResized )
756                 {
757                     // need to re-render whole layer - start from
758                     // clean state
759                     rLayer->clearContent();
760 
761                     // render and remove from update set
762                     while( aFirstLayerShape != aEndLayerShapes )
763                     {
764                         maUpdateShapes.erase(aFirstLayerShape->first);
765                         aFirstLayerShape->first->render();
766                         ++aFirstLayerShape;
767                     }
768                 }
769             }
770         }
771 
772         LayerSharedPtr LayerManager::createForegroundLayer() const
773         {
774             OSL_ASSERT( mbActive );
775 
776             LayerSharedPtr pLayer( Layer::createLayer(
777                                        maPageBounds ));
778 
779             // create ViewLayers for all registered views, and add to
780             // newly created layer.
781             ::std::for_each( mrViews.begin(),
782                              mrViews.end(),
783                              boost::bind( &Layer::addView,
784                                           boost::cref(pLayer),
785                                           _1 ));
786 
787             return pLayer;
788         }
789 
790         void LayerManager::updateShapeLayers( bool bBackgroundLayerPainted )
791         {
792             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
793             OSL_ASSERT( mbActive );
794 
795             // do we need to process shapes?
796             if( !mbLayerAssociationDirty )
797                 return;
798 
799             if( mbDisableAnimationZOrder )
800             {
801                 // layer setup happened elsewhere, is only bg layer
802                 // anyway.
803                 mbLayerAssociationDirty = false;
804                 return;
805             }
806 
807             // scan through maAllShapes, and determine shape animation
808             // discontinuities: when a shape that has
809             // isBackgroundDetached() return false follows a shape
810             // with isBackgroundDetached() true, the former and all
811             // following ones must be moved into an own layer.
812 
813             // to avoid tons of temporaries, create weak_ptr to Layers
814             // beforehand
815             std::vector< LayerWeakPtr > aWeakLayers(maLayers.size());
816             std::copy(maLayers.begin(),maLayers.end(),aWeakLayers.begin());
817 
818             std::size_t                   nCurrLayerIndex(0);
819             bool                          bIsBackgroundLayer(true);
820             bool                          bLastWasBackgroundDetached(false); // last shape sprite state
821             LayerShapeMap::iterator       aCurrShapeEntry( maAllShapes.begin() );
822             LayerShapeMap::iterator       aCurrLayerFirstShapeEntry( maAllShapes.begin() );
823             const LayerShapeMap::iterator aEndShapeEntry ( maAllShapes.end() );
824             ShapeUpdateSet                aUpdatedShapes; // shapes that need update
825             while( aCurrShapeEntry != aEndShapeEntry )
826             {
827                 const ShapeSharedPtr pCurrShape( aCurrShapeEntry->first );
828                 const bool bThisIsBackgroundDetached(
829                     pCurrShape->isBackgroundDetached() );
830 
831                 if( bLastWasBackgroundDetached == true &&
832                     bThisIsBackgroundDetached == false )
833                 {
834                     // discontinuity found - current shape needs to
835                     // get into a new layer
836                     // --------------------------------------------
837 
838                     // commit changes to previous layer
839                     commitLayerChanges(nCurrLayerIndex,
840                                        aCurrLayerFirstShapeEntry,
841                                        aCurrShapeEntry);
842                     aCurrLayerFirstShapeEntry=aCurrShapeEntry;
843                     ++nCurrLayerIndex;
844                     bIsBackgroundLayer = false;
845 
846                     if( aWeakLayers.size() <= nCurrLayerIndex ||
847                         aWeakLayers.at(nCurrLayerIndex) != aCurrShapeEntry->second )
848                     {
849                         // no more layers left, or shape was not
850                         // member of this layer - create a new one
851                         maLayers.insert( maLayers.begin()+nCurrLayerIndex,
852                                          createForegroundLayer() );
853                         aWeakLayers.insert( aWeakLayers.begin()+nCurrLayerIndex,
854                                             maLayers[nCurrLayerIndex] );
855                     }
856                 }
857 
858                 OSL_ASSERT( maLayers.size() == aWeakLayers.size() );
859 
860                 // note: using indices here, since vector::insert
861                 // above invalidates iterators
862                 LayerSharedPtr& rCurrLayer( maLayers.at(nCurrLayerIndex) );
863                 LayerWeakPtr& rCurrWeakLayer( aWeakLayers.at(nCurrLayerIndex) );
864                 if( rCurrWeakLayer != aCurrShapeEntry->second )
865                 {
866                     // mismatch: shape is not contained in current
867                     // layer - move shape to that layer, then.
868                     maLayers.at(nCurrLayerIndex)->setShapeViews(
869                         pCurrShape );
870 
871                     // layer got new shape(s), need full repaint, if
872                     // non-sprite shape
873                     if( !bThisIsBackgroundDetached && pCurrShape->isVisible() )
874                     {
875                         LayerSharedPtr pOldLayer( aCurrShapeEntry->second.lock() );
876                         if( pOldLayer )
877                         {
878                             // old layer still valid? then we need to
879                             // repaint former shape area
880                             pOldLayer->addUpdateRange(
881                                 pCurrShape->getUpdateArea() );
882                         }
883 
884                         // render on new layer (only if not
885                         // explicitely disabled)
886                         if( !(bBackgroundLayerPainted && bIsBackgroundLayer) )
887                             maUpdateShapes.insert( pCurrShape );
888                     }
889 
890                     aCurrShapeEntry->second = rCurrWeakLayer;
891                 }
892 
893                 // update layerbounds regardless of the fact that the
894                 // shape might be contained in said layer
895                 // already. updateBounds() is dumb and needs to
896                 // collect all shape bounds.
897                 // of course, no need to expand layer bounds for
898                 // shapes that reside in sprites themselves.
899                 if( !bThisIsBackgroundDetached && !bIsBackgroundLayer )
900                     rCurrLayer->updateBounds( pCurrShape );
901 
902                 bLastWasBackgroundDetached = bThisIsBackgroundDetached;
903                 ++aCurrShapeEntry;
904             }
905 
906             // commit very last layer data
907             commitLayerChanges(nCurrLayerIndex,
908                                aCurrLayerFirstShapeEntry,
909                                aCurrShapeEntry);
910 
911             // any layers left? Bin them!
912             if( maLayers.size() > nCurrLayerIndex+1 )
913                 maLayers.erase(maLayers.begin()+nCurrLayerIndex+1,
914                                maLayers.end());
915 
916             mbLayerAssociationDirty = false;
917         }
918     }
919 }
920