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