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