diff options
author | Marco Cecchetti <mrcekets@gmail.com> | 2012-06-19 18:53:14 +0200 |
---|---|---|
committer | Marco Cecchetti <mrcekets@gmail.com> | 2012-06-28 12:28:06 +0200 |
commit | 1ef95a7206979756a885b7bea4c788684f5e7b61 (patch) | |
tree | 1e821e8d5856ba62200bb84f3c767c4d3f01bfea | |
parent | 17ac2bb3b37d738488c12b26387822d62c4e8ded (diff) |
Added support for the repeatCount attribute for time containers.
The support is limited to the case when the value of the repeatCount attribute is an integral
number and the duration time is defined implicitly by the active duration of the time container
children. The accumulate attribute is not handled.
The support for such a feature has been implemented for both the C++ and the JavaScript
presentation engine.
4 files changed, 155 insertions, 41 deletions
diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js index 0c566c843a83..13a0a3b351ef 100644 --- a/filter/source/svg/presentation_engine.js +++ b/filter/source/svg/presentation_engine.js @@ -1439,7 +1439,7 @@ var aRegisterEventDebugPrinter = new DebugPrinter(); aRegisterEventDebugPrinter.off(); var aTimerEventQueueDebugPrinter = new DebugPrinter(); -aTimerEventQueueDebugPrinter.off(); +aTimerEventQueueDebugPrinter.on(); var aEventMultiplexerDebugPrinter = new DebugPrinter(); aEventMultiplexerDebugPrinter.off(); @@ -4522,7 +4522,7 @@ function createStateTransitionTable() aTable[FROZEN_NODE] = INVALID_NODE; // this state is unreachable here aTable[ENDED_NODE] = ENDED_NODE; // this state is a sink here (cannot restart) -// transition table for restart=NEVER, fill=FREEZE + // transition table for restart=NEVER, fill=FREEZE aTable = aSTT[RESTART_MODE_NEVER][FILL_MODE_FREEZE] = aSTT[RESTART_MODE_NEVER][FILL_MODE_HOLD] = @@ -5352,8 +5352,8 @@ BaseNode.prototype.resolve = function() BaseNode.prototype.activate = function() { -// log( 'restart mode: ' + aRestartModeOutMap[ this.getRestartMode() ] ); -// log( 'fill mode: ' + aFillModeOutMap[ this.getFillMode() ] ); + log( 'restart mode: ' + aRestartModeOutMap[ this.getRestartMode() ] ); + log( 'fill mode: ' + aFillModeOutMap[ this.getFillMode() ] ); if( ! this.checkValidNode() ) return false; @@ -5687,6 +5687,7 @@ function AnimationBaseNode( aAnimElem, aParentNode, aNodeContext ) this.bIsContainer = false; this.aTargetElement = null; this.aAnimatedElement = null; + this.nAnimatedElementOriginalState = 0; this.aActivity = null; this.nMinFrameCount = undefined; @@ -5734,7 +5735,7 @@ AnimationBaseNode.prototype.parseElement = function() if( this.aTargetElement ) { // set up target element initial visibility - if( true && aAnimElem.getAttribute( 'attributeName' ) === 'visibility' ) + if( aAnimElem.getAttribute( 'attributeName' ) === 'visibility' ) { if( aAnimElem.getAttribute( 'to' ) === 'visible' ) this.aTargetElement.setAttribute( 'visibility', 'hidden' ); @@ -5774,6 +5775,7 @@ AnimationBaseNode.prototype.activate_st = function() { if( this.aActivity ) { + this.nAnimatedElementOriginalState = this.getAnimatedElement().getCurrentState(); this.aActivity.setTargets( this.getAnimatedElement() ); this.getContext().aActivityQueue.addActivity( this.aActivity ); } @@ -5842,6 +5844,16 @@ AnimationBaseNode.prototype.hasPendingAnimation = function() return true; }; +AnimationBaseNode.prototype.saveStateOfAnimatedElement = function() +{ + this.getAnimatedElement().saveState(); +}; + +AnimationBaseNode.prototype.removeEffect = function() +{ + this.getAnimatedElement().setTo( this.nAnimatedElementOriginalState ); +}; + AnimationBaseNode.prototype.getTargetElement = function() { return this.aTargetElement; @@ -6096,6 +6108,7 @@ function BaseContainerNode( aAnimElem, aParentNode, aNodeContext ) this.aChildrenArray = new Array(); this.nFinishedChildren = 0; this.bDurationIndefinite = false; + this.nLeftIterations = 1; this.eImpressNodeType = undefined; this.ePresetClass = undefined; @@ -6157,6 +6170,13 @@ BaseContainerNode.prototype.appendChildNode = function( aAnimationNode ) BaseContainerNode.prototype.init_st = function() { + this.nLeftIterations = this.getRepeatCount(); + + return this.init_children(); +}; + +BaseContainerNode.prototype.init_children = function() +{ this.nFinishedChildren = 0; var nChildrenCount = this.aChildrenArray.length; var nInitChildren = 0; @@ -6170,6 +6190,7 @@ BaseContainerNode.prototype.init_st = function() return ( nChildrenCount == nInitChildren ); }; + BaseContainerNode.prototype.deactivate_st = function( eDestState ) { if( eDestState == FROZEN_NODE ) @@ -6245,12 +6266,49 @@ BaseContainerNode.prototype.notifyDeactivatedChild = function( aChildNode ) if( bFinished && this.isDurationIndefinite() ) { - this.deactivate(); + if( this.nLeftIterations >= 1.0 ) + { + this.nLeftIterations -= 1.0; + } + if( this.nLeftIterations >= 1.0 ) + { + bFinished = false; + var aRepetitionEvent = makeDelay( bind( this, this.repeat ), 0.0 ); + this.aContext.aTimerEventQueue.addEvent( aRepetitionEvent ); + } + else + { + this.deactivate(); + } } return bFinished; }; +BaseContainerNode.prototype.repeat = function() +{ + this.deactivate_st( ENDED_NODE ); + this.removeEffect(); + var bInitialized = this.init_children(); + if( bInitialized ) + this.activate_st(); + return bInitialized; +}; + +BaseContainerNode.prototype.removeEffect = function() +{ + this.forEachChildNode( mem_fn( 'removeEffect' ), FROZEN_NODE | ENDED_NODE ); +}; + +BaseContainerNode.prototype.saveStateOfAnimatedElement = function() +{ + var nChildrenCount = this.aChildrenArray.length; + for( var i = 0; i < nChildrenCount; ++i ) + { + this.aChildrenArray[i].saveStateOfAnimatedElement(); + } +} + BaseContainerNode.prototype.forEachChildNode = function( aFunction, eNodeStateMask ) { if( !eNodeStateMask ) @@ -6420,6 +6478,11 @@ SequentialTimeContainer.prototype.resolveChild = function( aChildNode ) if( bResolved && this.isMainSequenceRootNode() ) { + aChildNode.saveStateOfAnimatedElement(); + } + + if( bResolved && this.isMainSequenceRootNode() ) + { // skip/rewind events handling } return bResolved; @@ -8307,7 +8370,7 @@ function AnimatedElement( aElement ) this.aPreviousElement = null; this.aElementArray = new Array(); - this.nCurrentState = 0; + this.nCurrentState = -1; this.eAdditiveMode = ADDITIVE_MODE_REPLACE; this.bIsUpdated = true; @@ -8316,7 +8379,7 @@ function AnimatedElement( aElement ) this.aICTM = document.documentElement.createSVGMatrix(); this.setCTM(); - this.aElementArray[0] = this.aActiveElement.cloneNode( true ); + //this.aElementArray[0] = this.aActiveElement.cloneNode( true ); } AnimatedElement.prototype.initElement = function() @@ -8382,6 +8445,11 @@ AnimatedElement.prototype.getId = function() return this.aActiveElement.getAttribute( 'id' ); }; +AnimatedElement.prototype.getCurrentState = function() +{ + return this.nCurrentState; +}; + AnimatedElement.prototype.isUpdated = function() { return this.bIsUpdated; @@ -8432,26 +8500,35 @@ AnimatedElement.prototype.notifyAnimationEnd = function() AnimatedElement.prototype.notifyNextEffectStart = function( nEffectIndex ) { - assert( this.nCurrentState === nEffectIndex, - 'AnimatedElement(' + this.getId() + ').notifyNextEffectStart: assertion (current state == effect index) failed' ); +// assert( this.nCurrentState === nEffectIndex, +// 'AnimatedElement(' + this.getId() + ').notifyNextEffectStart: assertion (current state == effect index) failed' ); +// +// if( this.isUpdated() ) +// { +// if( !this.aElementArray[ nEffectIndex ] ) +// { +// this.aElementArray[ nEffectIndex ] = this.aElementArray[ this.nCurrentState ]; +// this.DBG( '.notifyNextEffectStart(' + nEffectIndex + '): new state set to previous one ' ); +// } +// } +// else +// { +// if( !this.aElementArray[ nEffectIndex ] ) +// { +// this.aElementArray[ nEffectIndex ] = this.aActiveElement.cloneNode( true ); +// this.DBG( '.notifyNextEffectStart(' + nEffectIndex + '): cloned active state ' ); +// } +// } +// ++this.nCurrentState; +}; - if( this.isUpdated() ) +AnimatedElement.prototype.saveState = function() +{ + ++this.nCurrentState; + if( !this.aElementArray[ this.nCurrentState ] ) { - if( !this.aElementArray[ nEffectIndex ] ) - { - this.aElementArray[ nEffectIndex ] = this.aElementArray[ this.nCurrentState ]; - this.DBG( '.notifyNextEffectStart(' + nEffectIndex + '): new state set to previous one ' ); - } + this.aElementArray[ this.nCurrentState ] = this.aActiveElement.cloneNode( true ); } - else - { - if( !this.aElementArray[ nEffectIndex ] ) - { - this.aElementArray[ nEffectIndex ] = this.aActiveElement.cloneNode( true ); - this.DBG( '.notifyNextEffectStart(' + nEffectIndex + '): cloned active state ' ); - } - } - ++this.nCurrentState; }; AnimatedElement.prototype.setToFirst = function() @@ -8464,12 +8541,19 @@ AnimatedElement.prototype.setToLast = function() this.setTo( this.aElementArray.length - 1 ); }; -AnimatedElement.prototype.setTo = function( nEffectIndex ) +AnimatedElement.prototype.setTo = function( nNewState ) { - var bRet = this.setToElement( this.aElementArray[ nEffectIndex ] ); + if( !this.aElementArray[ nNewState ] ) + { + log( 'AnimatedElement(' + this.getId() + ').setTo: state ' + + nNewState + ' is not valid' ); + return false; + } + + var bRet = this.setToElement( this.aElementArray[ nNewState ] ); if( bRet ) { - this.nCurrentState = nEffectIndex; + this.nCurrentState = nNewState; var aBBox = this.getBBox(); var aBaseBBox = this.getBaseBBox(); @@ -10613,7 +10697,7 @@ function FromToByActivityTemplate( BaseType ) // template parameter { if( this.aAnimation ) { - if( this.isAutoreverse() ) + if( this.isAutoReverse() ) this.aAnimation.perform( this.aStartValue ); else this.aAnimation.perform( this.aEndValue ); diff --git a/slideshow/source/engine/animationnodes/animationbasenode.cxx b/slideshow/source/engine/animationnodes/animationbasenode.cxx index ed6349522f22..719276dbca4b 100644 --- a/slideshow/source/engine/animationnodes/animationbasenode.cxx +++ b/slideshow/source/engine/animationnodes/animationbasenode.cxx @@ -422,16 +422,6 @@ AnimationBaseNode::fillCommonParameters() const else aRepeats.reset( nRepeats / nDuration ); } - // This is a temporary workaround: - // as the repeatCount attribute is defined on the <par> parent node - // and activities are created only for animation node leaves, that - // actual performs a shape effect, we get the repeatCount value - // from the parent node. - else if( ( getXAnimationNode()->getType() != animations::AnimationNodeType::SET ) - && (getParentNode()->getXAnimationNode()->getRepeatCount() >>= nRepeats) ) - { - aRepeats.reset( nRepeats ); - } else { // no double value for both values - Timing::INDEFINITE? diff --git a/slideshow/source/engine/animationnodes/basecontainernode.cxx b/slideshow/source/engine/animationnodes/basecontainernode.cxx index e9a53ac12bca..3ac076a19a18 100644 --- a/slideshow/source/engine/animationnodes/basecontainernode.cxx +++ b/slideshow/source/engine/animationnodes/basecontainernode.cxx @@ -32,10 +32,12 @@ #include <canvas/verbosetrace.hxx> #include "basecontainernode.hxx" +#include "eventqueue.hxx" #include "tools.hxx" #include "nodetools.hxx" #include "delayevent.hxx" +#include <boost/bind.hpp> #include <boost/mem_fn.hpp> #include <algorithm> @@ -65,7 +67,15 @@ void BaseContainerNode::dispose() bool BaseContainerNode::init_st() { + if( !(getXAnimationNode()->getRepeatCount() >>= mnLeftIterations) ) + mnLeftIterations = 1.0; + return init_children(); +} + +bool BaseContainerNode::init_children() +{ mnFinishedChildren = 0; + // initialize all children return (std::count_if( maChildren.begin(), maChildren.end(), @@ -75,6 +85,7 @@ bool BaseContainerNode::init_st() void BaseContainerNode::deactivate_st( NodeState eDestState ) { + mnLeftIterations = 0.0; if (eDestState == FROZEN) { // deactivate all children that are not FROZEN or ENDED: forEachChildNode( boost::mem_fn(&AnimationNode::deactivate), @@ -137,19 +148,44 @@ bool BaseContainerNode::notifyDeactivatedChild( std::size_t const nSize = maChildren.size(); OSL_ASSERT( mnFinishedChildren < nSize ); ++mnFinishedChildren; - bool const bFinished = (mnFinishedChildren >= nSize); + bool bFinished = (mnFinishedChildren >= nSize); // all children finished, and we've got indefinite duration? // think of ParallelTimeContainer::notifyDeactivating() // if duration given, we will be deactivated by some end event // @see fillCommonParameters() if (bFinished && isDurationIndefinite()) { - deactivate(); + if( mnLeftIterations >= 1.0 ) + { + mnLeftIterations -= 1.0; + } + if( mnLeftIterations >= 1.0 ) + { + bFinished = false; + EventSharedPtr aRepetitionEvent = + makeDelay( boost::bind( &BaseContainerNode::repeat, this ), + 0.0, + "BaseContainerNode::repeat"); + getContext().mrEventQueue.addEvent( aRepetitionEvent ); + } + else + { + deactivate(); + } } return bFinished; } +bool BaseContainerNode::repeat() +{ + deactivate_st( ENDED ); + sal_Bool bState = init_children(); + if( bState ) + activate_st(); + return bState; +} + #if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL) void BaseContainerNode::showState() const { diff --git a/slideshow/source/engine/animationnodes/basecontainernode.hxx b/slideshow/source/engine/animationnodes/basecontainernode.hxx index f4a0d78ac79a..4a9c6cd9057d 100644 --- a/slideshow/source/engine/animationnodes/basecontainernode.hxx +++ b/slideshow/source/engine/animationnodes/basecontainernode.hxx @@ -51,6 +51,7 @@ protected: private: virtual bool init_st(); + virtual bool init_children(); virtual void deactivate_st( NodeState eDestState ); virtual bool hasPendingAnimation() const; // force to be implemented by derived class: @@ -66,6 +67,8 @@ protected: /// @return true: if all children have been deactivated bool notifyDeactivatedChild( AnimationNodeSharedPtr const& pChildNode ); + bool repeat(); + template <typename FuncT> inline void forEachChildNode( FuncT const& func, int nodeStateMask = -1 ) const @@ -83,6 +86,7 @@ protected: typedef ::std::vector<AnimationNodeSharedPtr> VectorOfNodes; VectorOfNodes maChildren; ::std::size_t mnFinishedChildren; + double mnLeftIterations; private: const bool mbDurationIndefinite; |