/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
void LayerManager::deactivate()
{ // TODO(F3): This is mostly a hack. Problem is, there's // currently no smart way of telling shapes "remove your // sprites". Others, like MediaShapes, listen to // start/stop animation events, which is too much overhead // for all shapes, though.
constbool bMoreThanOneLayer(maLayers.size() > 1); if (mnActiveSprites || bMoreThanOneLayer)
{ // clear all viewlayers, dump everything but the // background layer - this will also remove all shape // sprites for (auto& rShape : maAllShapes)
rShape.first->clearAllViewLayers();
for (auto& rShape : maAllShapes)
rShape.second.reset();
if (bMoreThanOneLayer)
maLayers.erase(maLayers.begin() + 1, maLayers.end());
mbLayerAssociationDirty = true;
}
mbActive = false;
// only background layer left
OSL_ASSERT( maLayers.size() == 1 && maLayers.front()->isBackgroundLayer() );
}
void LayerManager::viewAdded( const UnoViewSharedPtr& rView )
{ // view must be member of mrViews container
OSL_ASSERT( std::find(mrViews.begin(),
mrViews.end(),
rView) != mrViews.end() );
// add View to all registered shapes
manageViews(
[&rView]( const LayerSharedPtr& pLayer )
{ return pLayer->addView( rView ); },
[]( const ShapeSharedPtr& pShape, const ViewLayerSharedPtr& pLayer )
{ return pShape->addViewLayer( pLayer, true ); } );
// in case we haven't reached all layers from the // maAllShapes, issue addView again for good measure for( constauto& pLayer : maLayers )
pLayer->addView( rView );
}
void LayerManager::viewRemoved( const UnoViewSharedPtr& rView )
{ // view must not be member of mrViews container anymore
OSL_ASSERT( std::find(mrViews.begin(),
mrViews.end(),
rView) == mrViews.end() );
// remove View from all registered shapes
manageViews(
[&rView]( const LayerSharedPtr& pLayer )
{ return pLayer->removeView( rView ); },
[]( const ShapeSharedPtr& pShape, const ViewLayerSharedPtr& pLayer )
{ return pShape->removeViewLayer( pLayer ); } );
// in case we haven't reached all layers from the // maAllShapes, issue removeView again for good measure for( constauto& pLayer : maLayers )
pLayer->removeView( rView );
}
void LayerManager::viewChanged( const UnoViewSharedPtr& rView )
{ // view must be member of mrViews container
OSL_ASSERT( std::find(mrViews.begin(),
mrViews.end(),
rView) != mrViews.end() );
// TODO(P2): selectively update only changed view
viewsChanged();
}
// Enter shape area to the update area, but only if shape // is visible and not in sprite mode (otherwise, updating // the area doesn't do actual harm, but costs time) // Actually, also add it if it was listed in // maUpdateShapes (might have just gone invisible). if( bShapeUpdateNotified ||
(rShape->isVisible() &&
!rShape->isBackgroundDetached()) )
{
LayerSharedPtr pLayer = aShapeEntry->second.lock(); if( pLayer )
{ // store area early, once the shape is removed from // the layers, it no longer has any view references
pLayer->addUpdateRange( rShape->getUpdateArea() );
}
}
// don't add to shape hash, we're dupes to the // original XShape anyway - all subset shapes return // the same XShape as the original one.
// add shape to corresponding layer
implAddShape( pSubset );
// update original shape, it now shows less content // (the subset is removed from its displayed // output). Subset shape is updated within // implAddShape(). if( rOrigShape->isVisible() )
notifyShapeUpdate( rOrigShape );
}
// update original shape, it now shows more content // (the subset is added back to its displayed output) if( rOrigShape->isVisible() )
notifyShapeUpdate( rOrigShape );
}
}
// if this call _really_ enabled the animation mode at // rShape, insert it to our enter animation queue, to // perform the necessary layer reorg lazily on // LayerManager::update()/render(). if( bPrevAnimState != rShape->isBackgroundDetached() )
{
++mnActiveSprites;
mbLayerAssociationDirty = true;
// area needs update (shape is removed from normal // slide, and now rendered as an autonomous // sprite). store in update set if( rShape->isVisible() )
addUpdateArea( rShape );
}
// TODO(P1): this can lead to potential wasted effort, if // a shape gets toggled animated/unanimated a few times // between two frames, returning to the original state.
}
// if this call _really_ ended the animation mode at // rShape, insert it to our leave animation queue, to // perform the necessary layer reorg lazily on // LayerManager::update()/render(). if( bPrevAnimState != rShape->isBackgroundDetached() )
{
--mnActiveSprites;
mbLayerAssociationDirty = true;
// shape needs update, no previous rendering, fast // update possible. if( rShape->isVisible() )
notifyShapeUpdate( rShape );
}
// TODO(P1): this can lead to potential wasted effort, if // a shape gets toggled animated/unanimated a few times // between two frames, returning to the original state.
}
// send update() calls to every shape in the // maUpdateShapes set, which is _animated_ (i.e. a // sprite). for( constauto& pShape : maUpdateShapes )
{ if( pShape->isBackgroundDetached() )
{ // can update shape directly, without // affecting layer content (shape is // currently displayed in a sprite) if( !pShape->update() )
bRet = false; // delay error exit
} else
{ // TODO(P2): addUpdateArea() involves log(n) // search for shape layer. Have a frequent // shape/layer association cache, or ptr back to // layer at the shape?
// cannot update shape directly, it's not // animated and update() calls will prolly // overwrite other page content.
addUpdateArea( pShape );
}
}
maUpdateShapes.clear();
return bRet;
}
bool LayerManager::update()
{ bool bRet = true;
if( !mbActive ) return bRet;
// going to render - better flush any pending layer reorg // now
updateShapeLayers(false);
// all sprites
bRet = updateSprites();
// any non-sprite update areas left? if( std::none_of( maLayers.begin(),
maLayers.end(),
std::mem_fn( &Layer::isUpdatePending ) ) ) return bRet; // nope, done.
// update each shape on each layer, that has // isUpdatePending() bool bIsCurrLayerUpdating(false);
Layer::EndUpdater aEndUpdater;
LayerSharedPtr pCurrLayer; for( constauto& rShape : maAllShapes )
{
LayerSharedPtr pLayer = rShape.second.lock(); if( pLayer != pCurrLayer )
{
pCurrLayer = std::move(pLayer);
bIsCurrLayerUpdating = pCurrLayer->isUpdatePending();
namespace
{ /** Little wrapper around a Canvas, to render one-shot into a canvas
*/ class DummyLayer : public ViewLayer
{ public: explicit DummyLayer( ::cppcanvas::CanvasSharedPtr xCanvas ) :
mpCanvas(std::move( xCanvas ))
{
}
virtualbool isOnView(ViewSharedPtr const& /*rView*/) const override
{ returntrue; // visible on all views
}
virtual ::cppcanvas::CustomSpriteSharedPtr createSprite( const ::basegfx::B2DSize& /*rSpriteSizePixel*/, double/*nSpritePrio*/ ) const override
{
ENSURE_OR_THROW( false, "DummyLayer::createSprite(): This method is not supposed to be called!" ); return ::cppcanvas::CustomSpriteSharedPtr();
}
virtualvoid setPriority( const basegfx::B1DRange& /*rRange*/ ) override
{
OSL_FAIL( "BitmapView::setPriority(): This method is not supposed to be called!" );
}
virtual ::basegfx::B2DHomMatrix getSpriteTransformation() const override
{
OSL_FAIL( "BitmapView::getSpriteTransformation(): This method is not supposed to be called!" ); return ::basegfx::B2DHomMatrix();
}
virtualvoid setClip( const ::basegfx::B2DPolyPolygon& /*rClip*/ ) override
{
OSL_FAIL( "BitmapView::setClip(): This method is not supposed to be called!" );
}
virtualbool resize( const ::basegfx::B2DRange& /*rArea*/ ) override
{
OSL_FAIL( "BitmapView::resize(): This method is not supposed to be called!" ); returnfalse;
}
for( constauto& rShape : maAllShapes )
{ try
{ // forward to all shape's addViewLayer method (which // we request to render the Shape on the new // ViewLayer. Since we add the shapes in the // maShapeSet order (which is also the render order), // this is equivalent to a subsequent render() call)
rShape.first->addViewLayer( pTmpLayer, true );
// and remove again, this is only temporary
rShape.first->removeViewLayer( pTmpLayer );
} catch( uno::Exception& )
{ // TODO(E1): Might be superfluous. Nowadays, // addViewLayer swallows all errors, anyway.
TOOLS_WARN_EXCEPTION( "slideshow", "" ); // at least one shape could not be rendered
bRet = false;
}
}
// create ViewLayers for all registered views, and add to // newly created layer. for( constauto& rView : mrViews )
pLayer->addView( rView );
return pLayer;
}
void LayerManager::updateShapeLayers( bool bBackgroundLayerPainted )
{
OSL_ASSERT( !maLayers.empty() ); // always at least background layer
OSL_ASSERT( mbActive );
// do we need to process shapes? if( !mbLayerAssociationDirty ) return;
if( mbDisableAnimationZOrder )
{ // layer setup happened elsewhere, is only bg layer // anyway.
mbLayerAssociationDirty = false; return;
}
// scan through maAllShapes, and determine shape animation // discontinuities: when a shape that has // isBackgroundDetached() return false follows a shape // with isBackgroundDetached() true, the former and all // following ones must be moved into an own layer.
// to avoid tons of temporaries, create weak_ptr to Layers // beforehand
std::vector< LayerWeakPtr > aWeakLayers(maLayers.begin(),maLayers.end());
if( aWeakLayers.size() <= nCurrLayerIndex ||
notEqual(aWeakLayers.at(nCurrLayerIndex), aCurrShapeEntry->second) )
{ // no more layers left, or shape was not // member of this layer - create a new one
maLayers.insert( maLayers.begin()+nCurrLayerIndex,
createForegroundLayer() );
aWeakLayers.insert( aWeakLayers.begin()+nCurrLayerIndex,
maLayers[nCurrLayerIndex] );
}
}
// note: using indices here, since vector::insert // above invalidates iterators
LayerSharedPtr& rCurrLayer( maLayers.at(nCurrLayerIndex) );
LayerWeakPtr& rCurrWeakLayer( aWeakLayers.at(nCurrLayerIndex) ); if( notEqual(rCurrWeakLayer, aCurrShapeEntry->second) )
{ // mismatch: shape is not contained in current // layer - move shape to that layer, then.
maLayers.at(nCurrLayerIndex)->setShapeViews(
pCurrShape );
// layer got new shape(s), need full repaint, if // non-sprite shape if( !bThisIsBackgroundDetached && pCurrShape->isVisible() )
{
LayerSharedPtr pOldLayer( aCurrShapeEntry->second.lock() ); if( pOldLayer )
{ // old layer still valid? then we need to // repaint former shape area
pOldLayer->addUpdateRange(
pCurrShape->getUpdateArea() );
}
// render on new layer (only if not // explicitly disabled) if( !(bBackgroundLayerPainted && bIsBackgroundLayer) )
maUpdateShapes.insert( pCurrShape );
}
aCurrShapeEntry->second = rCurrWeakLayer;
}
// update layerbounds regardless of the fact that the // shape might be contained in said layer // already. updateBounds() is dumb and needs to // collect all shape bounds. // of course, no need to expand layer bounds for // shapes that reside in sprites themselves. if( !bThisIsBackgroundDetached && !bIsBackgroundLayer )
rCurrLayer->updateBounds( pCurrShape );
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.