LCOV - code coverage report
Current view: top level - slideshow/source/engine/slide - layermanager.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1 312 0.3 %
Date: 2015-06-13 12:38:46 Functions: 2 44 4.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : 
      21             : #include <canvas/debug.hxx>
      22             : #include <tools/diagnose_ex.h>
      23             : #include <basegfx/range/b1drange.hxx>
      24             : #include <basegfx/matrix/b2dhommatrix.hxx>
      25             : 
      26             : #include <comphelper/anytostring.hxx>
      27             : #include <cppuhelper/exc_hlp.hxx>
      28             : 
      29             : #include <boost/bind.hpp>
      30             : #include <algorithm>
      31             : 
      32             : #include <o3tl/compat_functional.hxx>
      33             : 
      34             : #include "layermanager.hxx"
      35             : 
      36             : using namespace ::com::sun::star;
      37             : 
      38             : namespace boost
      39             : {
      40             :     // add operator!= for weak_ptr
      41           0 :     inline bool operator!=( slideshow::internal::LayerWeakPtr const& rLHS,
      42             :                             slideshow::internal::LayerWeakPtr const& rRHS )
      43             :     {
      44           0 :         return (rLHS<rRHS) || (rRHS<rLHS);
      45             :     }
      46             : }
      47             : 
      48             : namespace slideshow
      49             : {
      50             :     namespace internal
      51             :     {
      52             :         template<typename LayerFunc,
      53           0 :                  typename ShapeFunc> void LayerManager::manageViews(
      54             :                      LayerFunc layerFunc,
      55             :                      ShapeFunc shapeFunc )
      56             :         {
      57           0 :             LayerSharedPtr                      pCurrLayer;
      58           0 :             ViewLayerSharedPtr                  pCurrViewLayer;
      59           0 :             LayerShapeMap::const_iterator       aIter( maAllShapes.begin() );
      60           0 :             const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
      61           0 :             while( aIter != aEnd )
      62             :             {
      63           0 :                 LayerSharedPtr pLayer = aIter->second.lock();
      64           0 :                 if( pLayer && pLayer != pCurrLayer )
      65             :                 {
      66           0 :                     pCurrLayer = pLayer;
      67           0 :                     pCurrViewLayer = layerFunc(pCurrLayer);
      68             :                 }
      69             : 
      70           0 :                 if( pCurrViewLayer )
      71           0 :                     shapeFunc(aIter->first,pCurrViewLayer);
      72             : 
      73           0 :                 ++aIter;
      74           0 :             }
      75           0 :         }
      76             : 
      77           0 :         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           0 :             mbDisableAnimationZOrder(bDisableAnimationZOrder)
      90             :         {
      91             :             // prevent frequent resizes (won't have more than 4 layers
      92             :             // for 99.9% of the cases)
      93           0 :             maLayers.reserve(4);
      94             : 
      95             :             // create initial background layer
      96             :             maLayers.push_back(
      97             :                     Layer::createBackgroundLayer(
      98           0 :                         maPageBounds ));
      99             : 
     100             :             // init views
     101             :             std::for_each( mrViews.begin(),
     102             :                            mrViews.end(),
     103             :                            ::boost::bind(&LayerManager::viewAdded,
     104             :                                          this,
     105           0 :                                          _1) );
     106           0 :         }
     107             : 
     108           0 :         void LayerManager::activate( bool bSlideBackgoundPainted )
     109             :         {
     110           0 :             mbActive = true;
     111           0 :             maUpdateShapes.clear(); // update gets forced via area, or
     112             :                                     // has happened outside already
     113             : 
     114           0 :             if( !bSlideBackgoundPainted )
     115             :             {
     116             :                 std::for_each(mrViews.begin(),
     117             :                               mrViews.end(),
     118           0 :                               boost::mem_fn(&View::clearAll));
     119             : 
     120             :                 // force update of whole slide area
     121             :                 std::for_each( maLayers.begin(),
     122             :                                maLayers.end(),
     123             :                                boost::bind( &Layer::addUpdateRange,
     124             :                                             _1,
     125           0 :                                             boost::cref(maPageBounds) ));
     126             :             }
     127             :             else
     128             :             {
     129             :                 // clear all possibly pending update areas - content
     130             :                 // is there, already
     131             :                 std::for_each( maLayers.begin(),
     132             :                                maLayers.end(),
     133           0 :                                boost::mem_fn( &Layer::clearUpdateRanges ));
     134             :             }
     135             : 
     136           0 :             updateShapeLayers( bSlideBackgoundPainted );
     137           0 :         }
     138             : 
     139           0 :         void LayerManager::deactivate()
     140             :         {
     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.
     146             : 
     147           0 :             const bool bMoreThanOneLayer(maLayers.size() > 1);
     148           0 :             if( mnActiveSprites || bMoreThanOneLayer )
     149             :             {
     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           0 :                                                         _1 )));
     158             : 
     159           0 :                 for (LayerShapeMap::iterator
     160           0 :                          iShape (maAllShapes.begin()),
     161           0 :                          iEnd (maAllShapes.end());
     162             :                      iShape!=iEnd;
     163             :                      ++iShape)
     164             :                 {
     165           0 :                     iShape->second.reset();
     166             :                 }
     167             : 
     168           0 :                 if( bMoreThanOneLayer )
     169           0 :                     maLayers.erase(maLayers.begin()+1,
     170           0 :                                    maLayers.end());
     171             : 
     172           0 :                 mbLayerAssociationDirty = true;
     173             :             }
     174             : 
     175           0 :             mbActive = false;
     176             : 
     177             :             // only background layer left
     178             :             OSL_ASSERT( maLayers.size() == 1 && maLayers.front()->isBackgroundLayer() );
     179           0 :         }
     180             : 
     181           0 :         void LayerManager::viewAdded( const UnoViewSharedPtr& rView )
     182             :         {
     183             :             // view must be member of mrViews container
     184             :             OSL_ASSERT( std::find(mrViews.begin(),
     185             :                                   mrViews.end(),
     186             :                                   rView) != mrViews.end() );
     187             : 
     188             :             // init view content
     189           0 :             if( mbActive )
     190           0 :                 rView->clearAll();
     191             : 
     192             :             // add View to all registered shapes
     193             :             manageViews(
     194             :                 boost::bind(&Layer::addView,
     195             :                             _1,
     196             :                             boost::cref(rView)),
     197             :                 // repaint on view add
     198             :                 boost::bind(&Shape::addViewLayer,
     199             :                             _1,
     200             :                             _2,
     201           0 :                             true) );
     202             : 
     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,
     208             :                                         _1,
     209           0 :                                         boost::cref(rView) ));
     210           0 :         }
     211             : 
     212           0 :         void LayerManager::viewRemoved( const UnoViewSharedPtr& rView )
     213             :         {
     214             :             // view must not be member of mrViews container anymore
     215             :             OSL_ASSERT( std::find(mrViews.begin(),
     216             :                                   mrViews.end(),
     217             :                                   rView) == mrViews.end() );
     218             : 
     219             :             // remove View from all registered shapes
     220             :             manageViews(
     221             :                 boost::bind(&Layer::removeView,
     222             :                             _1,
     223             :                             boost::cref(rView)),
     224             :                 boost::bind(&Shape::removeViewLayer,
     225             :                             _1,
     226           0 :                             _2) );
     227             : 
     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,
     233             :                                         _1,
     234           0 :                                         boost::cref(rView) ));
     235           0 :         }
     236             : 
     237           0 :         void LayerManager::viewChanged( const UnoViewSharedPtr& rView )
     238             :         {
     239             :             (void)rView;
     240             : 
     241             :             // view must be member of mrViews container
     242             :             OSL_ASSERT( std::find(mrViews.begin(),
     243             :                                   mrViews.end(),
     244             :                                   rView) != mrViews.end() );
     245             : 
     246             :             // TODO(P2): selectively update only changed view
     247           0 :             viewsChanged();
     248           0 :         }
     249             : 
     250           0 :         void LayerManager::viewsChanged()
     251             :         {
     252           0 :             if( !mbActive )
     253           0 :                 return;
     254             : 
     255             :             // clear view area
     256             :             ::std::for_each( mrViews.begin(),
     257             :                              mrViews.end(),
     258           0 :                              ::boost::mem_fn(&View::clearAll) );
     259             : 
     260             :             // TODO(F3): resize and repaint all layers
     261             : 
     262             :             // render all shapes
     263             :             std::for_each( maAllShapes.begin(),
     264             :                            maAllShapes.end(),
     265             :                            boost::bind(&Shape::render,
     266           0 :                                boost::bind( ::o3tl::select1st<LayerShapeMap::value_type>(), _1)) );
     267             :         }
     268             : 
     269           0 :         void LayerManager::addShape( const ShapeSharedPtr& rShape )
     270             :         {
     271             :             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
     272           0 :             ENSURE_OR_THROW( rShape, "LayerManager::addShape(): invalid Shape" );
     273             : 
     274             :             // add shape to XShape hash map
     275           0 :             if( !maXShapeHash.insert(
     276           0 :                     XShapeHash::value_type( rShape->getXShape(),
     277           0 :                                             rShape) ).second )
     278             :             {
     279             :                 // entry already present, nothing to do
     280           0 :                 return;
     281             :             }
     282             : 
     283             :             // add shape to appropriate layer
     284           0 :             implAddShape( rShape );
     285             :         }
     286             : 
     287           0 :         void LayerManager::putShape2BackgroundLayer( LayerShapeMap::value_type& rShapeEntry )
     288             :         {
     289           0 :             LayerSharedPtr& rBgLayer( maLayers.front() );
     290           0 :             rBgLayer->setShapeViews(rShapeEntry.first);
     291           0 :             rShapeEntry.second = rBgLayer;
     292           0 :         }
     293             : 
     294           0 :         void LayerManager::implAddShape( const ShapeSharedPtr& rShape )
     295             :         {
     296             :             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
     297           0 :             ENSURE_OR_THROW( rShape, "LayerManager::implAddShape(): invalid Shape" );
     298             : 
     299           0 :             LayerShapeMap::value_type aValue (rShape, LayerWeakPtr());
     300             : 
     301             :             OSL_ASSERT( maAllShapes.find(rShape) == maAllShapes.end() ); // shape must not be added already
     302           0 :             mbLayerAssociationDirty = true;
     303             : 
     304           0 :             if( mbDisableAnimationZOrder )
     305             :                 putShape2BackgroundLayer(
     306           0 :                     *maAllShapes.insert(aValue).first );
     307             :             else
     308           0 :                 maAllShapes.insert(aValue);
     309             : 
     310             :             // update shape, it's just added and not yet painted
     311           0 :             if( rShape->isVisible() )
     312           0 :                 notifyShapeUpdate( rShape );
     313           0 :         }
     314             : 
     315           0 :         void LayerManager::implRemoveShape( const ShapeSharedPtr& rShape )
     316             :         {
     317             :             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
     318           0 :             ENSURE_OR_THROW( rShape, "LayerManager::implRemoveShape(): invalid Shape" );
     319             : 
     320           0 :             const LayerShapeMap::iterator aShapeEntry( maAllShapes.find(rShape) );
     321             : 
     322           0 :             if( aShapeEntry == maAllShapes.end() )
     323           0 :                 return;
     324             : 
     325           0 :             const bool bShapeUpdateNotified = maUpdateShapes.erase( rShape ) != 0;
     326             : 
     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           0 :             if( bShapeUpdateNotified ||
     333           0 :                 (rShape->isVisible() &&
     334           0 :                  !rShape->isBackgroundDetached()) )
     335             :             {
     336           0 :                 LayerSharedPtr pLayer = aShapeEntry->second.lock();
     337           0 :                 if( pLayer )
     338             :                 {
     339             :                     // store area early, once the shape is removed from
     340             :                     // the layers, it no longer has any view references
     341           0 :                     pLayer->addUpdateRange( rShape->getUpdateArea() );
     342           0 :                 }
     343             :             }
     344             : 
     345           0 :             rShape->clearAllViewLayers();
     346           0 :             maAllShapes.erase( aShapeEntry );
     347             : 
     348           0 :             mbLayerAssociationDirty = true;
     349             :         }
     350             : 
     351           0 :         ShapeSharedPtr LayerManager::lookupShape( const uno::Reference< drawing::XShape >& xShape ) const
     352             :         {
     353           0 :             ENSURE_OR_THROW( xShape.is(), "LayerManager::lookupShape(): invalid Shape" );
     354             : 
     355           0 :             const XShapeHash::const_iterator aIter( maXShapeHash.find( xShape ));
     356           0 :             if( aIter == maXShapeHash.end() )
     357           0 :                 return ShapeSharedPtr(); // not found
     358             : 
     359             :             // found, return data part of entry pair.
     360           0 :             return aIter->second;
     361             :         }
     362             : 
     363           0 :         AttributableShapeSharedPtr LayerManager::getSubsetShape( const AttributableShapeSharedPtr&  rOrigShape,
     364             :                                                                  const DocTreeNode&                 rTreeNode )
     365             :         {
     366             :             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
     367             : 
     368           0 :             AttributableShapeSharedPtr pSubset;
     369             : 
     370             :             // shape already added?
     371           0 :             if( rOrigShape->createSubset( pSubset,
     372           0 :                                           rTreeNode ) )
     373             :             {
     374             :                 OSL_ENSURE( pSubset, "LayerManager::getSubsetShape(): failed to create subset" );
     375             : 
     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.
     379             : 
     380             :                 // add shape to corresponding layer
     381           0 :                 implAddShape( pSubset );
     382             : 
     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           0 :                 if( rOrigShape->isVisible() )
     388           0 :                     notifyShapeUpdate( rOrigShape );
     389             :             }
     390             : 
     391           0 :             return pSubset;
     392             :         }
     393             : 
     394           0 :         void LayerManager::revokeSubset( const AttributableShapeSharedPtr& rOrigShape,
     395             :                                          const AttributableShapeSharedPtr& rSubsetShape )
     396             :         {
     397             :             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
     398             : 
     399           0 :             if( rOrigShape->revokeSubset( rSubsetShape ) )
     400             :             {
     401             :                 OSL_ASSERT( maAllShapes.find(rSubsetShape) != maAllShapes.end() );
     402             : 
     403           0 :                 implRemoveShape( rSubsetShape );
     404             : 
     405             :                 // update original shape, it now shows more content
     406             :                 // (the subset is added back to its displayed output)
     407           0 :                 if( rOrigShape->isVisible() )
     408           0 :                     notifyShapeUpdate( rOrigShape );
     409             :             }
     410           0 :         }
     411             : 
     412           0 :         void LayerManager::enterAnimationMode( const AnimatableShapeSharedPtr& rShape )
     413             :         {
     414             :             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
     415           0 :             ENSURE_OR_THROW( rShape, "LayerManager::enterAnimationMode(): invalid Shape" );
     416             : 
     417           0 :             const bool bPrevAnimState( rShape->isBackgroundDetached() );
     418             : 
     419           0 :             rShape->enterAnimationMode();
     420             : 
     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           0 :             if( bPrevAnimState != rShape->isBackgroundDetached() )
     426             :             {
     427           0 :                 ++mnActiveSprites;
     428           0 :                 mbLayerAssociationDirty = true;
     429             : 
     430             :                 // area needs update (shape is removed from normal
     431             :                 // slide, and now rendered as an autonomous
     432             :                 // sprite). store in update set
     433           0 :                 if( rShape->isVisible() )
     434           0 :                     addUpdateArea( rShape );
     435             :             }
     436             : 
     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.
     440           0 :         }
     441             : 
     442           0 :         void LayerManager::leaveAnimationMode( const AnimatableShapeSharedPtr& rShape )
     443             :         {
     444           0 :             ENSURE_OR_THROW( !maLayers.empty(), "LayerManager::leaveAnimationMode(): no layers" );
     445           0 :             ENSURE_OR_THROW( rShape, "LayerManager::leaveAnimationMode(): invalid Shape" );
     446             : 
     447           0 :             const bool bPrevAnimState( rShape->isBackgroundDetached() );
     448             : 
     449           0 :             rShape->leaveAnimationMode();
     450             : 
     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           0 :             if( bPrevAnimState != rShape->isBackgroundDetached() )
     456             :             {
     457           0 :                 --mnActiveSprites;
     458           0 :                 mbLayerAssociationDirty = true;
     459             : 
     460             :                 // shape needs update, no previous rendering, fast
     461             :                 // update possible.
     462           0 :                 if( rShape->isVisible() )
     463           0 :                     notifyShapeUpdate( rShape );
     464             :             }
     465             : 
     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.
     469           0 :         }
     470             : 
     471           0 :         void LayerManager::notifyShapeUpdate( const ShapeSharedPtr& rShape )
     472             :         {
     473           0 :             if( !mbActive || mrViews.empty() )
     474           0 :                 return;
     475             : 
     476             :             // hidden sprite-shape needs render() call still, to hide sprite
     477           0 :             if( rShape->isVisible() || rShape->isBackgroundDetached() )
     478           0 :                 maUpdateShapes.insert( rShape );
     479             :             else
     480           0 :                 addUpdateArea( rShape );
     481             :         }
     482             : 
     483           0 :         bool LayerManager::isUpdatePending() const
     484             :         {
     485           0 :             if( !mbActive )
     486           0 :                 return false;
     487             : 
     488           0 :             if( mbLayerAssociationDirty || !maUpdateShapes.empty() )
     489           0 :                 return true;
     490             : 
     491             :             return std::any_of( maLayers.begin(),
     492             :                                 maLayers.end(),
     493           0 :                                 boost::mem_fn(&Layer::isUpdatePending) );
     494             :         }
     495             : 
     496           0 :         bool LayerManager::updateSprites()
     497             :         {
     498           0 :             bool bRet(true);
     499             : 
     500             :             // send update() calls to every shape in the
     501             :             // maUpdateShapes set, which is _animated_ (i.e. a
     502             :             // sprite).
     503           0 :             const ShapeUpdateSet::const_iterator aEnd=maUpdateShapes.end();
     504           0 :             ShapeUpdateSet::const_iterator       aCurrShape=maUpdateShapes.begin();
     505           0 :             while( aCurrShape != aEnd )
     506             :             {
     507           0 :                 if( (*aCurrShape)->isBackgroundDetached() )
     508             :                 {
     509             :                     // can update shape directly, without
     510             :                     // affecting layer content (shape is
     511             :                     // currently displayed in a sprite)
     512           0 :                     if( !(*aCurrShape)->update() )
     513           0 :                         bRet = false; // delay error exit
     514             :                 }
     515             :                 else
     516             :                 {
     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?
     521             : 
     522             :                     // cannot update shape directly, it's not
     523             :                     // animated and update() calls will prolly
     524             :                     // overwrite other page content.
     525           0 :                     addUpdateArea( *aCurrShape );
     526             :                 }
     527             : 
     528           0 :                 ++aCurrShape;
     529             :             }
     530             : 
     531           0 :             maUpdateShapes.clear();
     532             : 
     533           0 :             return bRet;
     534             :         }
     535             : 
     536           0 :         bool LayerManager::update()
     537             :         {
     538           0 :             bool bRet = true;
     539             : 
     540           0 :             if( !mbActive )
     541           0 :                 return bRet;
     542             : 
     543             :             // going to render - better flush any pending layer reorg
     544             :             // now
     545           0 :             updateShapeLayers(false);
     546             : 
     547             :             // all sprites
     548           0 :             bRet = updateSprites();
     549             : 
     550             :             // any non-sprite update areas left?
     551           0 :             if( std::none_of( maLayers.begin(),
     552             :                               maLayers.end(),
     553           0 :                               boost::mem_fn( &Layer::isUpdatePending ) ) )
     554           0 :                 return bRet; // nope, done.
     555             : 
     556             :             // update each shape on each layer, that has
     557             :             // isUpdatePending()
     558           0 :             bool                                bIsCurrLayerUpdating(false);
     559           0 :             Layer::EndUpdater                   aEndUpdater;
     560           0 :             LayerSharedPtr                      pCurrLayer;
     561           0 :             LayerShapeMap::const_iterator       aIter( maAllShapes.begin() );
     562           0 :             const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
     563           0 :             while( aIter != aEnd )
     564             :             {
     565           0 :                 LayerSharedPtr pLayer = aIter->second.lock();
     566           0 :                 if( pLayer != pCurrLayer )
     567             :                 {
     568           0 :                     pCurrLayer = pLayer;
     569           0 :                     bIsCurrLayerUpdating = pCurrLayer->isUpdatePending();
     570             : 
     571           0 :                     if( bIsCurrLayerUpdating )
     572           0 :                         aEndUpdater = pCurrLayer->beginUpdate();
     573             :                 }
     574             : 
     575           0 :                 if( bIsCurrLayerUpdating &&
     576           0 :                     !aIter->first->isBackgroundDetached() &&
     577           0 :                     pCurrLayer->isInsideUpdateArea(aIter->first) )
     578             :                 {
     579           0 :                     if( !aIter->first->render() )
     580           0 :                         bRet = false;
     581             :                 }
     582             : 
     583           0 :                 ++aIter;
     584           0 :             }
     585             : 
     586           0 :             return bRet;
     587             :         }
     588             : 
     589             :         namespace
     590             :         {
     591             :             /** Little wrapper around a Canvas, to render one-shot
     592             :                 into a canvas
     593             :              */
     594           0 :             class DummyLayer : public ViewLayer
     595             :             {
     596             :             public:
     597           0 :                 explicit DummyLayer( const ::cppcanvas::CanvasSharedPtr& rCanvas ) :
     598           0 :                     mpCanvas( rCanvas )
     599             :                 {
     600           0 :                 }
     601             : 
     602           0 :                 virtual bool isOnView(boost::shared_ptr<View> const& /*rView*/) const SAL_OVERRIDE
     603             :                 {
     604           0 :                     return true; // visible on all views
     605             :                 }
     606             : 
     607           0 :                 virtual ::cppcanvas::CanvasSharedPtr getCanvas() const SAL_OVERRIDE
     608             :                 {
     609           0 :                     return mpCanvas;
     610             :                 }
     611             : 
     612           0 :                 virtual void clear() const SAL_OVERRIDE
     613             :                 {
     614             :                     // NOOP
     615           0 :                 }
     616             : 
     617           0 :                 virtual void clearAll() const SAL_OVERRIDE
     618             :                 {
     619             :                     // NOOP
     620           0 :                 }
     621             : 
     622           0 :                 virtual ::cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& /*rSpriteSizePixel*/,
     623             :                                                                          double                    /*nSpritePrio*/ ) const SAL_OVERRIDE
     624             :                 {
     625           0 :                     ENSURE_OR_THROW( false,
     626             :                                       "DummyLayer::createSprite(): This method is not supposed to be called!" );
     627             :                     return ::cppcanvas::CustomSpriteSharedPtr();
     628             :                 }
     629             : 
     630           0 :                 virtual void setPriority( const basegfx::B1DRange& /*rRange*/ ) SAL_OVERRIDE
     631             :                 {
     632             :                     OSL_FAIL( "BitmapView::setPriority(): This method is not supposed to be called!" );
     633           0 :                 }
     634             : 
     635           0 :                 virtual ::com::sun::star::geometry::IntegerSize2D getTranslationOffset() const SAL_OVERRIDE
     636             :                 {
     637           0 :                     return geometry::IntegerSize2D(0,0);
     638             :                 }
     639             : 
     640           0 :                 virtual ::basegfx::B2DHomMatrix getTransformation() const SAL_OVERRIDE
     641             :                 {
     642           0 :                     return mpCanvas->getTransformation();
     643             :                 }
     644             : 
     645           0 :                 virtual ::basegfx::B2DHomMatrix getSpriteTransformation() const SAL_OVERRIDE
     646             :                 {
     647             :                     OSL_FAIL( "BitmapView::getSpriteTransformation(): This method is not supposed to be called!" );
     648           0 :                     return ::basegfx::B2DHomMatrix();
     649             :                 }
     650             : 
     651           0 :                 virtual void setClip( const ::basegfx::B2DPolyPolygon& /*rClip*/ ) SAL_OVERRIDE
     652             :                 {
     653             :                     OSL_FAIL( "BitmapView::setClip(): This method is not supposed to be called!" );
     654           0 :                 }
     655             : 
     656           0 :                 virtual bool resize( const ::basegfx::B2DRange& /*rArea*/ ) SAL_OVERRIDE
     657             :                 {
     658             :                     OSL_FAIL( "BitmapView::resize(): This method is not supposed to be called!" );
     659           0 :                     return false;
     660             :                 }
     661             : 
     662             :             private:
     663             :                 ::cppcanvas::CanvasSharedPtr mpCanvas;
     664             :             };
     665             :         }
     666             : 
     667           0 :         bool LayerManager::renderTo( const ::cppcanvas::CanvasSharedPtr& rTargetCanvas ) const
     668             :         {
     669           0 :             bool bRet( true );
     670           0 :             ViewLayerSharedPtr pTmpLayer( new DummyLayer( rTargetCanvas ) );
     671             : 
     672           0 :             LayerShapeMap::const_iterator       aIter( maAllShapes.begin() );
     673           0 :             const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
     674           0 :             while( aIter != aEnd )
     675             :             {
     676             :                 try
     677             :                 {
     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           0 :                     aIter->first->addViewLayer( pTmpLayer,
     684           0 :                                                 true );
     685             : 
     686             :                     // and remove again, this is only temporary
     687           0 :                     aIter->first->removeViewLayer( pTmpLayer );
     688             :                 }
     689           0 :                 catch( uno::Exception& )
     690             :                 {
     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() );
     696             : 
     697             :                     // at least one shape could not be rendered
     698           0 :                     bRet = false;
     699             :                 }
     700             : 
     701           0 :                 ++aIter;
     702             :             }
     703             : 
     704           0 :             return bRet;
     705             :         }
     706             : 
     707           0 :         void LayerManager::addUpdateArea( ShapeSharedPtr const& rShape )
     708             :         {
     709             :             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
     710           0 :             ENSURE_OR_THROW( rShape, "LayerManager::addUpdateArea(): invalid Shape" );
     711             : 
     712           0 :             const LayerShapeMap::const_iterator aShapeEntry( maAllShapes.find(rShape) );
     713             : 
     714           0 :             if( aShapeEntry == maAllShapes.end() )
     715           0 :                 return;
     716             : 
     717           0 :             LayerSharedPtr pLayer = aShapeEntry->second.lock();
     718           0 :             if( pLayer )
     719           0 :                 pLayer->addUpdateRange( rShape->getUpdateArea() );
     720             :         }
     721             : 
     722           0 :         void LayerManager::commitLayerChanges( std::size_t              nCurrLayerIndex,
     723             :                                                LayerShapeMap::const_iterator  aFirstLayerShape,
     724             :                                                LayerShapeMap::const_iterator  aEndLayerShapes )
     725             :         {
     726           0 :             const bool bLayerExists( maLayers.size() > nCurrLayerIndex );
     727           0 :             if( bLayerExists )
     728             :             {
     729           0 :                 const LayerSharedPtr& rLayer( maLayers.at(nCurrLayerIndex) );
     730           0 :                 const bool bLayerResized( rLayer->commitBounds() );
     731             :                 rLayer->setPriority( basegfx::B1DRange(nCurrLayerIndex,
     732           0 :                                                        nCurrLayerIndex+1) );
     733             : 
     734           0 :                 if( bLayerResized )
     735             :                 {
     736             :                     // need to re-render whole layer - start from
     737             :                     // clean state
     738           0 :                     rLayer->clearContent();
     739             : 
     740             :                     // render and remove from update set
     741           0 :                     while( aFirstLayerShape != aEndLayerShapes )
     742             :                     {
     743           0 :                         maUpdateShapes.erase(aFirstLayerShape->first);
     744           0 :                         aFirstLayerShape->first->render();
     745           0 :                         ++aFirstLayerShape;
     746             :                     }
     747             :                 }
     748             :             }
     749           0 :         }
     750             : 
     751           0 :         LayerSharedPtr LayerManager::createForegroundLayer() const
     752             :         {
     753             :             OSL_ASSERT( mbActive );
     754             : 
     755             :             LayerSharedPtr pLayer( Layer::createLayer(
     756           0 :                                        maPageBounds ));
     757             : 
     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           0 :                                           _1 ));
     765             : 
     766           0 :             return pLayer;
     767             :         }
     768             : 
     769           0 :         void LayerManager::updateShapeLayers( bool bBackgroundLayerPainted )
     770             :         {
     771             :             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
     772             :             OSL_ASSERT( mbActive );
     773             : 
     774             :             // do we need to process shapes?
     775           0 :             if( !mbLayerAssociationDirty )
     776           0 :                 return;
     777             : 
     778           0 :             if( mbDisableAnimationZOrder )
     779             :             {
     780             :                 // layer setup happened elsewhere, is only bg layer
     781             :                 // anyway.
     782           0 :                 mbLayerAssociationDirty = false;
     783           0 :                 return;
     784             :             }
     785             : 
     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.
     791             : 
     792             :             // to avoid tons of temporaries, create weak_ptr to Layers
     793             :             // beforehand
     794           0 :             std::vector< LayerWeakPtr > aWeakLayers(maLayers.size());
     795           0 :             std::copy(maLayers.begin(),maLayers.end(),aWeakLayers.begin());
     796             : 
     797           0 :             std::size_t                   nCurrLayerIndex(0);
     798           0 :             bool                          bIsBackgroundLayer(true);
     799           0 :             bool                          bLastWasBackgroundDetached(false); // last shape sprite state
     800           0 :             LayerShapeMap::iterator       aCurrShapeEntry( maAllShapes.begin() );
     801           0 :             LayerShapeMap::iterator       aCurrLayerFirstShapeEntry( maAllShapes.begin() );
     802           0 :             const LayerShapeMap::iterator aEndShapeEntry ( maAllShapes.end() );
     803           0 :             ShapeUpdateSet                aUpdatedShapes; // shapes that need update
     804           0 :             while( aCurrShapeEntry != aEndShapeEntry )
     805             :             {
     806           0 :                 const ShapeSharedPtr pCurrShape( aCurrShapeEntry->first );
     807             :                 const bool bThisIsBackgroundDetached(
     808           0 :                     pCurrShape->isBackgroundDetached() );
     809             : 
     810           0 :                 if( bLastWasBackgroundDetached &&
     811           0 :                     !bThisIsBackgroundDetached )
     812             :                 {
     813             :                     // discontinuity found - current shape needs to
     814             :                     // get into a new layer
     815             : 
     816             : 
     817             :                     // commit changes to previous layer
     818             :                     commitLayerChanges(nCurrLayerIndex,
     819             :                                        aCurrLayerFirstShapeEntry,
     820           0 :                                        aCurrShapeEntry);
     821           0 :                     aCurrLayerFirstShapeEntry=aCurrShapeEntry;
     822           0 :                     ++nCurrLayerIndex;
     823           0 :                     bIsBackgroundLayer = false;
     824             : 
     825           0 :                     if( aWeakLayers.size() <= nCurrLayerIndex ||
     826           0 :                         aWeakLayers.at(nCurrLayerIndex) != aCurrShapeEntry->second )
     827             :                     {
     828             :                         // no more layers left, or shape was not
     829             :                         // member of this layer - create a new one
     830           0 :                         maLayers.insert( maLayers.begin()+nCurrLayerIndex,
     831           0 :                                          createForegroundLayer() );
     832             :                         aWeakLayers.insert( aWeakLayers.begin()+nCurrLayerIndex,
     833           0 :                                             maLayers[nCurrLayerIndex] );
     834             :                     }
     835             :                 }
     836             : 
     837             :                 OSL_ASSERT( maLayers.size() == aWeakLayers.size() );
     838             : 
     839             :                 // note: using indices here, since vector::insert
     840             :                 // above invalidates iterators
     841           0 :                 LayerSharedPtr& rCurrLayer( maLayers.at(nCurrLayerIndex) );
     842           0 :                 LayerWeakPtr& rCurrWeakLayer( aWeakLayers.at(nCurrLayerIndex) );
     843           0 :                 if( rCurrWeakLayer != aCurrShapeEntry->second )
     844             :                 {
     845             :                     // mismatch: shape is not contained in current
     846             :                     // layer - move shape to that layer, then.
     847           0 :                     maLayers.at(nCurrLayerIndex)->setShapeViews(
     848           0 :                         pCurrShape );
     849             : 
     850             :                     // layer got new shape(s), need full repaint, if
     851             :                     // non-sprite shape
     852           0 :                     if( !bThisIsBackgroundDetached && pCurrShape->isVisible() )
     853             :                     {
     854           0 :                         LayerSharedPtr pOldLayer( aCurrShapeEntry->second.lock() );
     855           0 :                         if( pOldLayer )
     856             :                         {
     857             :                             // old layer still valid? then we need to
     858             :                             // repaint former shape area
     859             :                             pOldLayer->addUpdateRange(
     860           0 :                                 pCurrShape->getUpdateArea() );
     861             :                         }
     862             : 
     863             :                         // render on new layer (only if not
     864             :                         // explicitly disabled)
     865           0 :                         if( !(bBackgroundLayerPainted && bIsBackgroundLayer) )
     866           0 :                             maUpdateShapes.insert( pCurrShape );
     867             :                     }
     868             : 
     869           0 :                     aCurrShapeEntry->second = rCurrWeakLayer;
     870             :                 }
     871             : 
     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           0 :                 if( !bThisIsBackgroundDetached && !bIsBackgroundLayer )
     879           0 :                     rCurrLayer->updateBounds( pCurrShape );
     880             : 
     881           0 :                 bLastWasBackgroundDetached = bThisIsBackgroundDetached;
     882           0 :                 ++aCurrShapeEntry;
     883           0 :             }
     884             : 
     885             :             // commit very last layer data
     886             :             commitLayerChanges(nCurrLayerIndex,
     887             :                                aCurrLayerFirstShapeEntry,
     888           0 :                                aCurrShapeEntry);
     889             : 
     890             :             // any layers left? Bin them!
     891           0 :             if( maLayers.size() > nCurrLayerIndex+1 )
     892           0 :                 maLayers.erase(maLayers.begin()+nCurrLayerIndex+1,
     893           0 :                                maLayers.end());
     894             : 
     895           0 :             mbLayerAssociationDirty = false;
     896             :         }
     897             :     }
     898           3 : }
     899             : 
     900             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11