LCOV - code coverage report
Current view: top level - slideshow/source/engine/slide - layermanager.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 316 0.0 %
Date: 2014-04-14 Functions: 0 44 0.0 %
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           0 :             const LayerVector::const_iterator aEnd( maLayers.end() );
     492           0 :             if( std::find_if( maLayers.begin(),
     493             :                               aEnd,
     494           0 :                               boost::mem_fn(&Layer::isUpdatePending)) != aEnd )
     495           0 :                 return true;
     496             : 
     497           0 :             return false;
     498             :         }
     499             : 
     500           0 :         bool LayerManager::updateSprites()
     501             :         {
     502           0 :             bool bRet(true);
     503             : 
     504             :             // send update() calls to every shape in the
     505             :             // maUpdateShapes set, which is _animated_ (i.e. a
     506             :             // sprite).
     507           0 :             const ShapeUpdateSet::const_iterator aEnd=maUpdateShapes.end();
     508           0 :             ShapeUpdateSet::const_iterator       aCurrShape=maUpdateShapes.begin();
     509           0 :             while( aCurrShape != aEnd )
     510             :             {
     511           0 :                 if( (*aCurrShape)->isBackgroundDetached() )
     512             :                 {
     513             :                     // can update shape directly, without
     514             :                     // affecting layer content (shape is
     515             :                     // currently displayed in a sprite)
     516           0 :                     if( !(*aCurrShape)->update() )
     517           0 :                         bRet = false; // delay error exit
     518             :                 }
     519             :                 else
     520             :                 {
     521             :                     // TODO(P2): addUpdateArea() involves log(n)
     522             :                     // search for shape layer. Have a frequent
     523             :                     // shape/layer association cache, or ptr back to
     524             :                     // layer at the shape?
     525             : 
     526             :                     // cannot update shape directly, it's not
     527             :                     // animated and update() calls will prolly
     528             :                     // overwrite other page content.
     529           0 :                     addUpdateArea( *aCurrShape );
     530             :                 }
     531             : 
     532           0 :                 ++aCurrShape;
     533             :             }
     534             : 
     535           0 :             maUpdateShapes.clear();
     536             : 
     537           0 :             return bRet;
     538             :         }
     539             : 
     540           0 :         bool LayerManager::update()
     541             :         {
     542           0 :             bool bRet = true;
     543             : 
     544           0 :             if( !mbActive )
     545           0 :                 return bRet;
     546             : 
     547             :             // going to render - better flush any pending layer reorg
     548             :             // now
     549           0 :             updateShapeLayers(false);
     550             : 
     551             :             // all sprites
     552           0 :             bRet = updateSprites();
     553             : 
     554             :             // any non-sprite update areas left?
     555           0 :             if( std::find_if( maLayers.begin(),
     556             :                               maLayers.end(),
     557           0 :                               boost::mem_fn( &Layer::isUpdatePending )) == maLayers.end() )
     558           0 :                 return bRet; // nope, done.
     559             : 
     560             :             // update each shape on each layer, that has
     561             :             // isUpdatePending()
     562           0 :             bool                                bIsCurrLayerUpdating(false);
     563           0 :             Layer::EndUpdater                   aEndUpdater;
     564           0 :             LayerSharedPtr                      pCurrLayer;
     565           0 :             LayerShapeMap::const_iterator       aIter( maAllShapes.begin() );
     566           0 :             const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
     567           0 :             while( aIter != aEnd )
     568             :             {
     569           0 :                 LayerSharedPtr pLayer = aIter->second.lock();
     570           0 :                 if( pLayer != pCurrLayer )
     571             :                 {
     572           0 :                     pCurrLayer = pLayer;
     573           0 :                     bIsCurrLayerUpdating = pCurrLayer->isUpdatePending();
     574             : 
     575           0 :                     if( bIsCurrLayerUpdating )
     576           0 :                         aEndUpdater = pCurrLayer->beginUpdate();
     577             :                 }
     578             : 
     579           0 :                 if( bIsCurrLayerUpdating &&
     580           0 :                     !aIter->first->isBackgroundDetached() &&
     581           0 :                     pCurrLayer->isInsideUpdateArea(aIter->first) )
     582             :                 {
     583           0 :                     if( !aIter->first->render() )
     584           0 :                         bRet = false;
     585             :                 }
     586             : 
     587           0 :                 ++aIter;
     588           0 :             }
     589             : 
     590           0 :             return bRet;
     591             :         }
     592             : 
     593             :         namespace
     594             :         {
     595             :             /** Little wrapper around a Canvas, to render one-shot
     596             :                 into a canvas
     597             :              */
     598           0 :             class DummyLayer : public ViewLayer
     599             :             {
     600             :             public:
     601           0 :                 explicit DummyLayer( const ::cppcanvas::CanvasSharedPtr& rCanvas ) :
     602           0 :                     mpCanvas( rCanvas )
     603             :                 {
     604           0 :                 }
     605             : 
     606           0 :                 virtual bool isOnView(boost::shared_ptr<View> const& /*rView*/) const SAL_OVERRIDE
     607             :                 {
     608           0 :                     return true; // visible on all views
     609             :                 }
     610             : 
     611           0 :                 virtual ::cppcanvas::CanvasSharedPtr getCanvas() const SAL_OVERRIDE
     612             :                 {
     613           0 :                     return mpCanvas;
     614             :                 }
     615             : 
     616           0 :                 virtual void clear() const SAL_OVERRIDE
     617             :                 {
     618             :                     // NOOP
     619           0 :                 }
     620             : 
     621           0 :                 virtual void clearAll() const SAL_OVERRIDE
     622             :                 {
     623             :                     // NOOP
     624           0 :                 }
     625             : 
     626           0 :                 virtual ::cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& /*rSpriteSizePixel*/,
     627             :                                                                          double                    /*nSpritePrio*/ ) const SAL_OVERRIDE
     628             :                 {
     629           0 :                     ENSURE_OR_THROW( false,
     630             :                                       "DummyLayer::createSprite(): This method is not supposed to be called!" );
     631             :                     return ::cppcanvas::CustomSpriteSharedPtr();
     632             :                 }
     633             : 
     634           0 :                 virtual void setPriority( const basegfx::B1DRange& /*rRange*/ ) SAL_OVERRIDE
     635             :                 {
     636             :                     OSL_FAIL( "BitmapView::setPriority(): This method is not supposed to be called!" );
     637           0 :                 }
     638             : 
     639           0 :                 virtual ::com::sun::star::geometry::IntegerSize2D getTranslationOffset() const SAL_OVERRIDE
     640             :                 {
     641           0 :                     return geometry::IntegerSize2D(0,0);
     642             :                 }
     643             : 
     644           0 :                 virtual ::basegfx::B2DHomMatrix getTransformation() const SAL_OVERRIDE
     645             :                 {
     646           0 :                     return mpCanvas->getTransformation();
     647             :                 }
     648             : 
     649           0 :                 virtual ::basegfx::B2DHomMatrix getSpriteTransformation() const SAL_OVERRIDE
     650             :                 {
     651             :                     OSL_FAIL( "BitmapView::getSpriteTransformation(): This method is not supposed to be called!" );
     652           0 :                     return ::basegfx::B2DHomMatrix();
     653             :                 }
     654             : 
     655           0 :                 virtual void setClip( const ::basegfx::B2DPolyPolygon& /*rClip*/ ) SAL_OVERRIDE
     656             :                 {
     657             :                     OSL_FAIL( "BitmapView::setClip(): This method is not supposed to be called!" );
     658           0 :                 }
     659             : 
     660           0 :                 virtual bool resize( const ::basegfx::B2DRange& /*rArea*/ ) SAL_OVERRIDE
     661             :                 {
     662             :                     OSL_FAIL( "BitmapView::resize(): This method is not supposed to be called!" );
     663           0 :                     return false;
     664             :                 }
     665             : 
     666             :             private:
     667             :                 ::cppcanvas::CanvasSharedPtr mpCanvas;
     668             :             };
     669             :         }
     670             : 
     671           0 :         bool LayerManager::renderTo( const ::cppcanvas::CanvasSharedPtr& rTargetCanvas ) const
     672             :         {
     673           0 :             bool bRet( true );
     674           0 :             ViewLayerSharedPtr pTmpLayer( new DummyLayer( rTargetCanvas ) );
     675             : 
     676           0 :             LayerShapeMap::const_iterator       aIter( maAllShapes.begin() );
     677           0 :             const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
     678           0 :             while( aIter != aEnd )
     679             :             {
     680             :                 try
     681             :                 {
     682             :                     // forward to all shape's addViewLayer method (which
     683             :                     // we request to render the Shape on the new
     684             :                     // ViewLayer. Since we add the shapes in the
     685             :                     // maShapeSet order (which is also the render order),
     686             :                     // this is equivalent to a subsequent render() call)
     687           0 :                     aIter->first->addViewLayer( pTmpLayer,
     688           0 :                                                 true );
     689             : 
     690             :                     // and remove again, this is only temporary
     691           0 :                     aIter->first->removeViewLayer( pTmpLayer );
     692             :                 }
     693           0 :                 catch( uno::Exception& )
     694             :                 {
     695             :                     // TODO(E1): Might be superfluous. Nowadays,
     696             :                     // addViewLayer swallows all errors, anyway.
     697             :                     OSL_FAIL( OUStringToOString(
     698             :                                     comphelper::anyToString( cppu::getCaughtException() ),
     699             :                                     RTL_TEXTENCODING_UTF8 ).getStr() );
     700             : 
     701             :                     // at least one shape could not be rendered
     702           0 :                     bRet = false;
     703             :                 }
     704             : 
     705           0 :                 ++aIter;
     706             :             }
     707             : 
     708           0 :             return bRet;
     709             :         }
     710             : 
     711           0 :         void LayerManager::addUpdateArea( ShapeSharedPtr const& rShape )
     712             :         {
     713             :             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
     714           0 :             ENSURE_OR_THROW( rShape, "LayerManager::addUpdateArea(): invalid Shape" );
     715             : 
     716           0 :             const LayerShapeMap::const_iterator aShapeEntry( maAllShapes.find(rShape) );
     717             : 
     718           0 :             if( aShapeEntry == maAllShapes.end() )
     719           0 :                 return;
     720             : 
     721           0 :             LayerSharedPtr pLayer = aShapeEntry->second.lock();
     722           0 :             if( pLayer )
     723           0 :                 pLayer->addUpdateRange( rShape->getUpdateArea() );
     724             :         }
     725             : 
     726           0 :         void LayerManager::commitLayerChanges( std::size_t              nCurrLayerIndex,
     727             :                                                LayerShapeMap::const_iterator  aFirstLayerShape,
     728             :                                                LayerShapeMap::const_iterator  aEndLayerShapes )
     729             :         {
     730           0 :             const bool bLayerExists( maLayers.size() > nCurrLayerIndex );
     731           0 :             if( bLayerExists )
     732             :             {
     733           0 :                 const LayerSharedPtr& rLayer( maLayers.at(nCurrLayerIndex) );
     734           0 :                 const bool bLayerResized( rLayer->commitBounds() );
     735             :                 rLayer->setPriority( basegfx::B1DRange(nCurrLayerIndex,
     736           0 :                                                        nCurrLayerIndex+1) );
     737             : 
     738           0 :                 if( bLayerResized )
     739             :                 {
     740             :                     // need to re-render whole layer - start from
     741             :                     // clean state
     742           0 :                     rLayer->clearContent();
     743             : 
     744             :                     // render and remove from update set
     745           0 :                     while( aFirstLayerShape != aEndLayerShapes )
     746             :                     {
     747           0 :                         maUpdateShapes.erase(aFirstLayerShape->first);
     748           0 :                         aFirstLayerShape->first->render();
     749           0 :                         ++aFirstLayerShape;
     750             :                     }
     751             :                 }
     752             :             }
     753           0 :         }
     754             : 
     755           0 :         LayerSharedPtr LayerManager::createForegroundLayer() const
     756             :         {
     757             :             OSL_ASSERT( mbActive );
     758             : 
     759             :             LayerSharedPtr pLayer( Layer::createLayer(
     760           0 :                                        maPageBounds ));
     761             : 
     762             :             // create ViewLayers for all registered views, and add to
     763             :             // newly created layer.
     764             :             ::std::for_each( mrViews.begin(),
     765             :                              mrViews.end(),
     766             :                              boost::bind( &Layer::addView,
     767             :                                           boost::cref(pLayer),
     768           0 :                                           _1 ));
     769             : 
     770           0 :             return pLayer;
     771             :         }
     772             : 
     773           0 :         void LayerManager::updateShapeLayers( bool bBackgroundLayerPainted )
     774             :         {
     775             :             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
     776             :             OSL_ASSERT( mbActive );
     777             : 
     778             :             // do we need to process shapes?
     779           0 :             if( !mbLayerAssociationDirty )
     780           0 :                 return;
     781             : 
     782           0 :             if( mbDisableAnimationZOrder )
     783             :             {
     784             :                 // layer setup happened elsewhere, is only bg layer
     785             :                 // anyway.
     786           0 :                 mbLayerAssociationDirty = false;
     787           0 :                 return;
     788             :             }
     789             : 
     790             :             // scan through maAllShapes, and determine shape animation
     791             :             // discontinuities: when a shape that has
     792             :             // isBackgroundDetached() return false follows a shape
     793             :             // with isBackgroundDetached() true, the former and all
     794             :             // following ones must be moved into an own layer.
     795             : 
     796             :             // to avoid tons of temporaries, create weak_ptr to Layers
     797             :             // beforehand
     798           0 :             std::vector< LayerWeakPtr > aWeakLayers(maLayers.size());
     799           0 :             std::copy(maLayers.begin(),maLayers.end(),aWeakLayers.begin());
     800             : 
     801           0 :             std::size_t                   nCurrLayerIndex(0);
     802           0 :             bool                          bIsBackgroundLayer(true);
     803           0 :             bool                          bLastWasBackgroundDetached(false); // last shape sprite state
     804           0 :             LayerShapeMap::iterator       aCurrShapeEntry( maAllShapes.begin() );
     805           0 :             LayerShapeMap::iterator       aCurrLayerFirstShapeEntry( maAllShapes.begin() );
     806           0 :             const LayerShapeMap::iterator aEndShapeEntry ( maAllShapes.end() );
     807           0 :             ShapeUpdateSet                aUpdatedShapes; // shapes that need update
     808           0 :             while( aCurrShapeEntry != aEndShapeEntry )
     809             :             {
     810           0 :                 const ShapeSharedPtr pCurrShape( aCurrShapeEntry->first );
     811             :                 const bool bThisIsBackgroundDetached(
     812           0 :                     pCurrShape->isBackgroundDetached() );
     813             : 
     814           0 :                 if( bLastWasBackgroundDetached == true &&
     815           0 :                     bThisIsBackgroundDetached == false )
     816             :                 {
     817             :                     // discontinuity found - current shape needs to
     818             :                     // get into a new layer
     819             : 
     820             : 
     821             :                     // commit changes to previous layer
     822             :                     commitLayerChanges(nCurrLayerIndex,
     823             :                                        aCurrLayerFirstShapeEntry,
     824           0 :                                        aCurrShapeEntry);
     825           0 :                     aCurrLayerFirstShapeEntry=aCurrShapeEntry;
     826           0 :                     ++nCurrLayerIndex;
     827           0 :                     bIsBackgroundLayer = false;
     828             : 
     829           0 :                     if( aWeakLayers.size() <= nCurrLayerIndex ||
     830           0 :                         aWeakLayers.at(nCurrLayerIndex) != aCurrShapeEntry->second )
     831             :                     {
     832             :                         // no more layers left, or shape was not
     833             :                         // member of this layer - create a new one
     834           0 :                         maLayers.insert( maLayers.begin()+nCurrLayerIndex,
     835           0 :                                          createForegroundLayer() );
     836             :                         aWeakLayers.insert( aWeakLayers.begin()+nCurrLayerIndex,
     837           0 :                                             maLayers[nCurrLayerIndex] );
     838             :                     }
     839             :                 }
     840             : 
     841             :                 OSL_ASSERT( maLayers.size() == aWeakLayers.size() );
     842             : 
     843             :                 // note: using indices here, since vector::insert
     844             :                 // above invalidates iterators
     845           0 :                 LayerSharedPtr& rCurrLayer( maLayers.at(nCurrLayerIndex) );
     846           0 :                 LayerWeakPtr& rCurrWeakLayer( aWeakLayers.at(nCurrLayerIndex) );
     847           0 :                 if( rCurrWeakLayer != aCurrShapeEntry->second )
     848             :                 {
     849             :                     // mismatch: shape is not contained in current
     850             :                     // layer - move shape to that layer, then.
     851           0 :                     maLayers.at(nCurrLayerIndex)->setShapeViews(
     852           0 :                         pCurrShape );
     853             : 
     854             :                     // layer got new shape(s), need full repaint, if
     855             :                     // non-sprite shape
     856           0 :                     if( !bThisIsBackgroundDetached && pCurrShape->isVisible() )
     857             :                     {
     858           0 :                         LayerSharedPtr pOldLayer( aCurrShapeEntry->second.lock() );
     859           0 :                         if( pOldLayer )
     860             :                         {
     861             :                             // old layer still valid? then we need to
     862             :                             // repaint former shape area
     863             :                             pOldLayer->addUpdateRange(
     864           0 :                                 pCurrShape->getUpdateArea() );
     865             :                         }
     866             : 
     867             :                         // render on new layer (only if not
     868             :                         // explicitly disabled)
     869           0 :                         if( !(bBackgroundLayerPainted && bIsBackgroundLayer) )
     870           0 :                             maUpdateShapes.insert( pCurrShape );
     871             :                     }
     872             : 
     873           0 :                     aCurrShapeEntry->second = rCurrWeakLayer;
     874             :                 }
     875             : 
     876             :                 // update layerbounds regardless of the fact that the
     877             :                 // shape might be contained in said layer
     878             :                 // already. updateBounds() is dumb and needs to
     879             :                 // collect all shape bounds.
     880             :                 // of course, no need to expand layer bounds for
     881             :                 // shapes that reside in sprites themselves.
     882           0 :                 if( !bThisIsBackgroundDetached && !bIsBackgroundLayer )
     883           0 :                     rCurrLayer->updateBounds( pCurrShape );
     884             : 
     885           0 :                 bLastWasBackgroundDetached = bThisIsBackgroundDetached;
     886           0 :                 ++aCurrShapeEntry;
     887           0 :             }
     888             : 
     889             :             // commit very last layer data
     890             :             commitLayerChanges(nCurrLayerIndex,
     891             :                                aCurrLayerFirstShapeEntry,
     892           0 :                                aCurrShapeEntry);
     893             : 
     894             :             // any layers left? Bin them!
     895           0 :             if( maLayers.size() > nCurrLayerIndex+1 )
     896           0 :                 maLayers.erase(maLayers.begin()+nCurrLayerIndex+1,
     897           0 :                                maLayers.end());
     898             : 
     899           0 :             mbLayerAssociationDirty = false;
     900             :         }
     901             :     }
     902           0 : }
     903             : 
     904             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10