LCOV - code coverage report
Current view: top level - slideshow/source/engine/slide - layermanager.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 310 0.0 %
Date: 2012-08-25 Functions: 0 43 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     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                 :            :             }
      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 happend 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
     607                 :            :                 {
     608                 :          0 :                     return true; // visible on all views
     609                 :            :                 }
     610                 :            : 
     611                 :          0 :                 virtual ::cppcanvas::CanvasSharedPtr getCanvas() const
     612                 :            :                 {
     613                 :          0 :                     return mpCanvas;
     614                 :            :                 }
     615                 :            : 
     616                 :          0 :                 virtual void clear() const
     617                 :            :                 {
     618                 :            :                     // NOOP
     619                 :          0 :                 }
     620                 :            : 
     621                 :          0 :                 virtual void clearAll() const
     622                 :            :                 {
     623                 :            :                     // NOOP
     624                 :          0 :                 }
     625                 :            : 
     626                 :          0 :                 virtual ::cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& /*rSpriteSizePixel*/,
     627                 :            :                                                                          double                    /*nSpritePrio*/ ) const
     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*/ )
     635                 :            :                 {
     636                 :            :                     OSL_FAIL( "BitmapView::setPriority(): This method is not supposed to be called!" );
     637                 :          0 :                 }
     638                 :            : 
     639                 :          0 :                 virtual ::basegfx::B2DHomMatrix getTransformation() const
     640                 :            :                 {
     641                 :          0 :                     return mpCanvas->getTransformation();
     642                 :            :                 }
     643                 :            : 
     644                 :          0 :                 virtual ::basegfx::B2DHomMatrix getSpriteTransformation() const
     645                 :            :                 {
     646                 :            :                     OSL_FAIL( "BitmapView::getSpriteTransformation(): This method is not supposed to be called!" );
     647                 :          0 :                     return ::basegfx::B2DHomMatrix();
     648                 :            :                 }
     649                 :            : 
     650                 :          0 :                 virtual void setClip( const ::basegfx::B2DPolyPolygon& /*rClip*/ )
     651                 :            :                 {
     652                 :            :                     OSL_FAIL( "BitmapView::setClip(): This method is not supposed to be called!" );
     653                 :          0 :                 }
     654                 :            : 
     655                 :          0 :                 virtual bool resize( const ::basegfx::B2DRange& /*rArea*/ )
     656                 :            :                 {
     657                 :            :                     OSL_FAIL( "BitmapView::resize(): This method is not supposed to be called!" );
     658                 :          0 :                     return false;
     659                 :            :                 }
     660                 :            : 
     661                 :            :             private:
     662                 :            :                 ::cppcanvas::CanvasSharedPtr mpCanvas;
     663                 :            :             };
     664                 :            :         }
     665                 :            : 
     666                 :          0 :         bool LayerManager::renderTo( const ::cppcanvas::CanvasSharedPtr& rTargetCanvas ) const
     667                 :            :         {
     668                 :          0 :             bool bRet( true );
     669                 :          0 :             ViewLayerSharedPtr pTmpLayer( new DummyLayer( rTargetCanvas ) );
     670                 :            : 
     671                 :          0 :             LayerShapeMap::const_iterator       aIter( maAllShapes.begin() );
     672                 :          0 :             const LayerShapeMap::const_iterator aEnd ( maAllShapes.end() );
     673                 :          0 :             while( aIter != aEnd )
     674                 :            :             {
     675                 :            :                 try
     676                 :            :                 {
     677                 :            :                     // forward to all shape's addViewLayer method (which
     678                 :            :                     // we request to render the Shape on the new
     679                 :            :                     // ViewLayer. Since we add the shapes in the
     680                 :            :                     // maShapeSet order (which is also the render order),
     681                 :            :                     // this is equivalent to a subsequent render() call)
     682                 :          0 :                     aIter->first->addViewLayer( pTmpLayer,
     683                 :          0 :                                                 true );
     684                 :            : 
     685                 :            :                     // and remove again, this is only temporary
     686                 :          0 :                     aIter->first->removeViewLayer( pTmpLayer );
     687                 :            :                 }
     688                 :          0 :                 catch( uno::Exception& )
     689                 :            :                 {
     690                 :            :                     // TODO(E1): Might be superfluous. Nowadays,
     691                 :            :                     // addViewLayer swallows all errors, anyway.
     692                 :            :                     OSL_FAIL( rtl::OUStringToOString(
     693                 :            :                                     comphelper::anyToString( cppu::getCaughtException() ),
     694                 :            :                                     RTL_TEXTENCODING_UTF8 ).getStr() );
     695                 :            : 
     696                 :            :                     // at least one shape could not be rendered
     697                 :          0 :                     bRet = false;
     698                 :            :                 }
     699                 :            : 
     700                 :          0 :                 ++aIter;
     701                 :            :             }
     702                 :            : 
     703                 :          0 :             return bRet;
     704                 :            :         }
     705                 :            : 
     706                 :          0 :         void LayerManager::addUpdateArea( ShapeSharedPtr const& rShape )
     707                 :            :         {
     708                 :            :             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
     709                 :          0 :             ENSURE_OR_THROW( rShape, "LayerManager::addUpdateArea(): invalid Shape" );
     710                 :            : 
     711                 :          0 :             const LayerShapeMap::const_iterator aShapeEntry( maAllShapes.find(rShape) );
     712                 :            : 
     713                 :          0 :             if( aShapeEntry == maAllShapes.end() )
     714                 :          0 :                 return;
     715                 :            : 
     716                 :          0 :             LayerSharedPtr pLayer = aShapeEntry->second.lock();
     717                 :          0 :             if( pLayer )
     718                 :          0 :                 pLayer->addUpdateRange( rShape->getUpdateArea() );
     719                 :            :         }
     720                 :            : 
     721                 :          0 :         void LayerManager::commitLayerChanges( std::size_t              nCurrLayerIndex,
     722                 :            :                                                LayerShapeMap::const_iterator  aFirstLayerShape,
     723                 :            :                                                LayerShapeMap::const_iterator  aEndLayerShapes )
     724                 :            :         {
     725                 :          0 :             const bool bLayerExists( maLayers.size() > nCurrLayerIndex );
     726                 :          0 :             if( bLayerExists )
     727                 :            :             {
     728                 :          0 :                 const LayerSharedPtr& rLayer( maLayers.at(nCurrLayerIndex) );
     729                 :          0 :                 const bool bLayerResized( rLayer->commitBounds() );
     730                 :            :                 rLayer->setPriority( basegfx::B1DRange(nCurrLayerIndex,
     731                 :          0 :                                                        nCurrLayerIndex+1) );
     732                 :            : 
     733                 :          0 :                 if( bLayerResized )
     734                 :            :                 {
     735                 :            :                     // need to re-render whole layer - start from
     736                 :            :                     // clean state
     737                 :          0 :                     rLayer->clearContent();
     738                 :            : 
     739                 :            :                     // render and remove from update set
     740                 :          0 :                     while( aFirstLayerShape != aEndLayerShapes )
     741                 :            :                     {
     742                 :          0 :                         maUpdateShapes.erase(aFirstLayerShape->first);
     743                 :          0 :                         aFirstLayerShape->first->render();
     744                 :          0 :                         ++aFirstLayerShape;
     745                 :            :                     }
     746                 :            :                 }
     747                 :            :             }
     748                 :          0 :         }
     749                 :            : 
     750                 :          0 :         LayerSharedPtr LayerManager::createForegroundLayer() const
     751                 :            :         {
     752                 :            :             OSL_ASSERT( mbActive );
     753                 :            : 
     754                 :            :             LayerSharedPtr pLayer( Layer::createLayer(
     755                 :          0 :                                        maPageBounds ));
     756                 :            : 
     757                 :            :             // create ViewLayers for all registered views, and add to
     758                 :            :             // newly created layer.
     759                 :            :             ::std::for_each( mrViews.begin(),
     760                 :            :                              mrViews.end(),
     761                 :            :                              boost::bind( &Layer::addView,
     762                 :            :                                           boost::cref(pLayer),
     763                 :          0 :                                           _1 ));
     764                 :            : 
     765                 :          0 :             return pLayer;
     766                 :            :         }
     767                 :            : 
     768                 :          0 :         void LayerManager::updateShapeLayers( bool bBackgroundLayerPainted )
     769                 :            :         {
     770                 :            :             OSL_ASSERT( !maLayers.empty() ); // always at least background layer
     771                 :            :             OSL_ASSERT( mbActive );
     772                 :            : 
     773                 :            :             // do we need to process shapes?
     774                 :          0 :             if( !mbLayerAssociationDirty )
     775                 :            :                 return;
     776                 :            : 
     777                 :          0 :             if( mbDisableAnimationZOrder )
     778                 :            :             {
     779                 :            :                 // layer setup happened elsewhere, is only bg layer
     780                 :            :                 // anyway.
     781                 :          0 :                 mbLayerAssociationDirty = false;
     782                 :            :                 return;
     783                 :            :             }
     784                 :            : 
     785                 :            :             // scan through maAllShapes, and determine shape animation
     786                 :            :             // discontinuities: when a shape that has
     787                 :            :             // isBackgroundDetached() return false follows a shape
     788                 :            :             // with isBackgroundDetached() true, the former and all
     789                 :            :             // following ones must be moved into an own layer.
     790                 :            : 
     791                 :            :             // to avoid tons of temporaries, create weak_ptr to Layers
     792                 :            :             // beforehand
     793                 :          0 :             std::vector< LayerWeakPtr > aWeakLayers(maLayers.size());
     794                 :          0 :             std::copy(maLayers.begin(),maLayers.end(),aWeakLayers.begin());
     795                 :            : 
     796                 :          0 :             std::size_t                   nCurrLayerIndex(0);
     797                 :          0 :             bool                          bIsBackgroundLayer(true);
     798                 :          0 :             bool                          bLastWasBackgroundDetached(false); // last shape sprite state
     799                 :          0 :             LayerShapeMap::iterator       aCurrShapeEntry( maAllShapes.begin() );
     800                 :          0 :             LayerShapeMap::iterator       aCurrLayerFirstShapeEntry( maAllShapes.begin() );
     801                 :          0 :             const LayerShapeMap::iterator aEndShapeEntry ( maAllShapes.end() );
     802                 :          0 :             ShapeUpdateSet                aUpdatedShapes; // shapes that need update
     803                 :          0 :             while( aCurrShapeEntry != aEndShapeEntry )
     804                 :            :             {
     805                 :          0 :                 const ShapeSharedPtr pCurrShape( aCurrShapeEntry->first );
     806                 :            :                 const bool bThisIsBackgroundDetached(
     807                 :          0 :                     pCurrShape->isBackgroundDetached() );
     808                 :            : 
     809                 :          0 :                 if( bLastWasBackgroundDetached == true &&
     810                 :            :                     bThisIsBackgroundDetached == false )
     811                 :            :                 {
     812                 :            :                     // discontinuity found - current shape needs to
     813                 :            :                     // get into a new layer
     814                 :            :                     // --------------------------------------------
     815                 :            : 
     816                 :            :                     // commit changes to previous layer
     817                 :            :                     commitLayerChanges(nCurrLayerIndex,
     818                 :            :                                        aCurrLayerFirstShapeEntry,
     819                 :          0 :                                        aCurrShapeEntry);
     820                 :          0 :                     aCurrLayerFirstShapeEntry=aCurrShapeEntry;
     821                 :          0 :                     ++nCurrLayerIndex;
     822                 :          0 :                     bIsBackgroundLayer = false;
     823                 :            : 
     824                 :          0 :                     if( aWeakLayers.size() <= nCurrLayerIndex ||
     825                 :          0 :                         aWeakLayers.at(nCurrLayerIndex) != aCurrShapeEntry->second )
     826                 :            :                     {
     827                 :            :                         // no more layers left, or shape was not
     828                 :            :                         // member of this layer - create a new one
     829                 :          0 :                         maLayers.insert( maLayers.begin()+nCurrLayerIndex,
     830                 :          0 :                                          createForegroundLayer() );
     831                 :            :                         aWeakLayers.insert( aWeakLayers.begin()+nCurrLayerIndex,
     832                 :          0 :                                             maLayers[nCurrLayerIndex] );
     833                 :            :                     }
     834                 :            :                 }
     835                 :            : 
     836                 :            :                 OSL_ASSERT( maLayers.size() == aWeakLayers.size() );
     837                 :            : 
     838                 :            :                 // note: using indices here, since vector::insert
     839                 :            :                 // above invalidates iterators
     840                 :          0 :                 LayerSharedPtr& rCurrLayer( maLayers.at(nCurrLayerIndex) );
     841                 :          0 :                 LayerWeakPtr& rCurrWeakLayer( aWeakLayers.at(nCurrLayerIndex) );
     842                 :          0 :                 if( rCurrWeakLayer != aCurrShapeEntry->second )
     843                 :            :                 {
     844                 :            :                     // mismatch: shape is not contained in current
     845                 :            :                     // layer - move shape to that layer, then.
     846                 :          0 :                     maLayers.at(nCurrLayerIndex)->setShapeViews(
     847                 :          0 :                         pCurrShape );
     848                 :            : 
     849                 :            :                     // layer got new shape(s), need full repaint, if
     850                 :            :                     // non-sprite shape
     851                 :          0 :                     if( !bThisIsBackgroundDetached && pCurrShape->isVisible() )
     852                 :            :                     {
     853                 :          0 :                         LayerSharedPtr pOldLayer( aCurrShapeEntry->second.lock() );
     854                 :          0 :                         if( pOldLayer )
     855                 :            :                         {
     856                 :            :                             // old layer still valid? then we need to
     857                 :            :                             // repaint former shape area
     858                 :            :                             pOldLayer->addUpdateRange(
     859                 :          0 :                                 pCurrShape->getUpdateArea() );
     860                 :            :                         }
     861                 :            : 
     862                 :            :                         // render on new layer (only if not
     863                 :            :                         // explicitly disabled)
     864                 :          0 :                         if( !(bBackgroundLayerPainted && bIsBackgroundLayer) )
     865                 :          0 :                             maUpdateShapes.insert( pCurrShape );
     866                 :            :                     }
     867                 :            : 
     868                 :          0 :                     aCurrShapeEntry->second = rCurrWeakLayer;
     869                 :            :                 }
     870                 :            : 
     871                 :            :                 // update layerbounds regardless of the fact that the
     872                 :            :                 // shape might be contained in said layer
     873                 :            :                 // already. updateBounds() is dumb and needs to
     874                 :            :                 // collect all shape bounds.
     875                 :            :                 // of course, no need to expand layer bounds for
     876                 :            :                 // shapes that reside in sprites themselves.
     877                 :          0 :                 if( !bThisIsBackgroundDetached && !bIsBackgroundLayer )
     878                 :          0 :                     rCurrLayer->updateBounds( pCurrShape );
     879                 :            : 
     880                 :          0 :                 bLastWasBackgroundDetached = bThisIsBackgroundDetached;
     881                 :          0 :                 ++aCurrShapeEntry;
     882                 :          0 :             }
     883                 :            : 
     884                 :            :             // commit very last layer data
     885                 :            :             commitLayerChanges(nCurrLayerIndex,
     886                 :            :                                aCurrLayerFirstShapeEntry,
     887                 :          0 :                                aCurrShapeEntry);
     888                 :            : 
     889                 :            :             // any layers left? Bin them!
     890                 :          0 :             if( maLayers.size() > nCurrLayerIndex+1 )
     891                 :          0 :                 maLayers.erase(maLayers.begin()+nCurrLayerIndex+1,
     892                 :          0 :                                maLayers.end());
     893                 :            : 
     894                 :          0 :             mbLayerAssociationDirty = false;
     895                 :            :         }
     896                 :            :     }
     897                 :          0 : }
     898                 :            : 
     899                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10