[Libreoffice-commits] .: 8 commits - filter/source slideshow/source
Marco Cecchetti
mcecchetti at kemper.freedesktop.org
Thu Jun 28 03:28:55 PDT 2012
filter/source/svg/presentation_engine.js | 400 ++++++++---
slideshow/source/engine/activities/activitiesfactory.cxx | 75 +-
slideshow/source/engine/animationnodes/animationbasenode.cxx | 4
slideshow/source/engine/animationnodes/basecontainernode.cxx | 40 +
slideshow/source/engine/animationnodes/basecontainernode.hxx | 4
slideshow/source/engine/color.cxx | 25
slideshow/source/inc/hslcolor.hxx | 2
slideshow/source/inc/rgbcolor.hxx | 2
8 files changed, 452 insertions(+), 100 deletions(-)
New commits:
commit ed92cdd7f131bc37957d91d9ff171a2c5c2716c7
Author: Marco Cecchetti <mrcekets at gmail.com>
Date: Tue Jun 26 22:08:02 2012 +0200
Bug fix: now skip effect work correctly with repeated animations
diff --git a/slideshow/source/engine/animationnodes/basecontainernode.cxx b/slideshow/source/engine/animationnodes/basecontainernode.cxx
index 6dab08e..e2a3a66 100644
--- a/slideshow/source/engine/animationnodes/basecontainernode.cxx
+++ b/slideshow/source/engine/animationnodes/basecontainernode.cxx
@@ -85,6 +85,7 @@ bool BaseContainerNode::init_children()
void BaseContainerNode::deactivate_st( NodeState eDestState )
{
+ mnLeftIterations = 0; // in order to make skip effect work correctly
if (eDestState == FROZEN) {
// deactivate all children that are not FROZEN or ENDED:
forEachChildNode( boost::mem_fn(&AnimationNode::deactivate),
@@ -178,7 +179,7 @@ bool BaseContainerNode::notifyDeactivatedChild(
bool BaseContainerNode::repeat()
{
- deactivate_st( ENDED );
+ forEachChildNode( boost::mem_fn(&AnimationNode::end), ~ENDED );
sal_Bool bState = init_children();
if( bState )
activate_st();
commit 5525b212faadc83df458b0911d416a734357ea30
Author: Marco Cecchetti <mrcekets at gmail.com>
Date: Sat Jun 23 21:12:58 2012 +0200
Modified the JavaScript implementation for repeated animations.
That has been needed because of Firefox that does not compute the bounding box of a
shape with zero width and height properly.
diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index 4dba32e..5161780 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -1433,13 +1433,13 @@ var NAVDBG = new DebugPrinter();
NAVDBG.off();
var ANIMDBG = new DebugPrinter();
-ANIMDBG.on();
+ANIMDBG.off();
var aRegisterEventDebugPrinter = new DebugPrinter();
aRegisterEventDebugPrinter.off();
var aTimerEventQueueDebugPrinter = new DebugPrinter();
-aTimerEventQueueDebugPrinter.on();
+aTimerEventQueueDebugPrinter.off();
var aEventMultiplexerDebugPrinter = new DebugPrinter();
aEventMultiplexerDebugPrinter.off();
@@ -4585,49 +4585,6 @@ function createStateTransitionTable()
var aStateTransitionTable = createStateTransitionTable();
-
-
-
-// ------------------------------------------------------------------------------------------ //
-// Transition tables
-
-// transition table for restart=NEVER, fill=FREEZE
-var aStateTransitionTable_Never_Freeze =
-[
- INVALID_NODE,
- RESOLVED_NODE | ENDED_NODE, // active successors for UNRESOLVED
- ACTIVE_NODE | ENDED_NODE, // active successors for RESOLVED
- INVALID_NODE,
- FROZEN_NODE | ENDED_NODE, // active successors for ACTIVE: freeze object
- INVALID_NODE,
- INVALID_NODE,
- INVALID_NODE,
- ENDED_NODE, // active successors for FROZEN: end
- INVALID_NODE,
- INVALID_NODE,
- INVALID_NODE,
- INVALID_NODE,
- INVALID_NODE,
- INVALID_NODE,
- INVALID_NODE,
- ENDED_NODE // active successors for ENDED:
- // this state is a sink here (cannot restart)
-];
-
-
-// Table guide
-var aTableGuide =
-[
- null,
- null,
- null,
- aStateTransitionTable_Never_Freeze,
- null,
- null
-];
-
-
-
// ------------------------------------------------------------------------------------------ //
function getTransitionTable( eRestartMode, eFillMode )
{
@@ -5352,9 +5309,6 @@ BaseNode.prototype.resolve = function()
BaseNode.prototype.activate = function()
{
- log( 'restart mode: ' + aRestartModeOutMap[ this.getRestartMode() ] );
- log( 'fill mode: ' + aFillModeOutMap[ this.getFillMode() ] );
-
if( ! this.checkValidNode() )
return false;
@@ -8373,7 +8327,7 @@ function AnimatedElement( aElement )
this.aClipPathContent = null;
this.aPreviousElement = null;
- this.aElementArray = new Array();
+ this.aStateArray = new Array();
this.nCurrentState = -1;
this.eAdditiveMode = ADDITIVE_MODE_REPLACE;
this.bIsUpdated = true;
@@ -8486,7 +8440,8 @@ AnimatedElement.prototype.setToElement = function( aElement )
AnimatedElement.prototype.notifySlideStart = function()
{
- this.setToFirst();
+ this.nCurrentState = -1;
+ //this.setToFirst();
this.DBG( '.notifySlideStart invoked' );
};
@@ -8529,9 +8484,15 @@ AnimatedElement.prototype.notifyNextEffectStart = function( nEffectIndex )
AnimatedElement.prototype.saveState = function()
{
++this.nCurrentState;
- if( !this.aElementArray[ this.nCurrentState ] )
+ if( !this.aStateArray[ this.nCurrentState ] )
{
- this.aElementArray[ this.nCurrentState ] = this.aActiveElement.cloneNode( true );
+ this.aStateArray[ this.nCurrentState ] = new Object();
+ var aState = this.aStateArray[ this.nCurrentState ];
+ aState.aElement = this.aActiveElement.cloneNode( true );
+ aState.nCenterX = this.nCenterX;
+ aState.nCenterY = this.nCenterY;
+ aState.nScaleFactorX = this.nScaleFactorX;
+ aState.nScaleFactorY = this.nScaleFactorY;
}
};
@@ -8542,29 +8503,28 @@ AnimatedElement.prototype.setToFirst = function()
AnimatedElement.prototype.setToLast = function()
{
- this.setTo( this.aElementArray.length - 1 );
+ this.setTo( this.aStateArray.length - 1 );
};
AnimatedElement.prototype.setTo = function( nNewState )
{
- if( !this.aElementArray[ nNewState ] )
+ if( !this.aStateArray[ nNewState ] )
{
log( 'AnimatedElement(' + this.getId() + ').setTo: state '
+ nNewState + ' is not valid' );
return false;
}
- var bRet = this.setToElement( this.aElementArray[ nNewState ] );
+ var aState = this.aStateArray[ nNewState ];
+ var bRet = this.setToElement( aState.aElement );
if( bRet )
{
this.nCurrentState = nNewState;
- var aBBox = this.getBBox();
- var aBaseBBox = this.getBaseBBox();
- this.nCenterX = aBBox.x + aBBox.width / 2;
- this.nCenterY = aBBox.y + aBBox.height / 2;
- this.nScaleFactorX = aBBox.width / aBaseBBox.width;
- this.nScaleFactorY = aBBox.height / aBaseBBox.height;
+ this.nCenterX = aState.nCenterX;
+ this.nCenterY = aState.nCenterY;
+ this.nScaleFactorX = aState.nScaleFactorX;
+ this.nScaleFactorY = aState.nScaleFactorY;
}
return bRet;
};
commit 06859010450505885a34313711a0d9d1fbaa30f2
Author: Marco Cecchetti <mrcekets at gmail.com>
Date: Sat Jun 23 18:58:07 2012 +0200
Fixed a bug that prevented repeated animations to work properly when the repeatCount
value is greater than 2.
diff --git a/slideshow/source/engine/animationnodes/basecontainernode.cxx b/slideshow/source/engine/animationnodes/basecontainernode.cxx
index 3ac076a..6dab08e 100644
--- a/slideshow/source/engine/animationnodes/basecontainernode.cxx
+++ b/slideshow/source/engine/animationnodes/basecontainernode.cxx
@@ -85,7 +85,6 @@ bool BaseContainerNode::init_children()
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),
commit 19da52d09b74a7de98be454fd48f807758e18c96
Author: Marco Cecchetti <mrcekets at gmail.com>
Date: Thu Jun 21 18:55:50 2012 +0200
Now the rewind option is handled by the JavaScript engine too.
diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index 13a0a3b..4dba32e 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -5799,6 +5799,8 @@ AnimationBaseNode.prototype.deactivate_st = function( eDestState )
{
if( this.aActivity )
this.aActivity.dispose();
+ if( ( this.getFillMode() == FILL_MODE_REMOVE ) && this.getAnimatedElement() )
+ this.removeEffect();
}
};
@@ -6202,6 +6204,8 @@ BaseContainerNode.prototype.deactivate_st = function( eDestState )
{
// end all children that are not ENDED:
this.forEachChildNode( mem_fn( 'end' ), ~ENDED_NODE );
+ if( this.getFillMode() == FILL_MODE_REMOVE )
+ this.forEachChildNode( mem_fn( 'removeEffect' ), ENDED_NODE );
}
};
@@ -8562,6 +8566,7 @@ AnimatedElement.prototype.setTo = function( nNewState )
this.nScaleFactorX = aBBox.width / aBaseBBox.width;
this.nScaleFactorY = aBBox.height / aBaseBBox.height;
}
+ return bRet;
};
AnimatedElement.prototype.getBaseBBox = function()
commit 1ef95a7206979756a885b7bea4c788684f5e7b61
Author: Marco Cecchetti <mrcekets at gmail.com>
Date: Tue Jun 19 18:53:14 2012 +0200
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.
diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index 0c566c8..13a0a3b 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 ed63495..719276d 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 e9a53ac..3ac076a 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 f4a0d78..4a9c6cd 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;
commit 17ac2bb3b37d738488c12b26387822d62c4e8ded
Author: Marco Cecchetti <mrcekets at gmail.com>
Date: Mon Jun 18 18:49:30 2012 +0200
Ported all transition tables. Now restart mode is set up as the SMIL spec requires.
diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index 13efb60..0c566c8 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -1433,7 +1433,7 @@ var NAVDBG = new DebugPrinter();
NAVDBG.off();
var ANIMDBG = new DebugPrinter();
-ANIMDBG.off();
+ANIMDBG.on();
var aRegisterEventDebugPrinter = new DebugPrinter();
aRegisterEventDebugPrinter.off();
@@ -4503,6 +4503,94 @@ aTransitionInfoTable[FADE_TRANSITION][FADEOVERCOLOR_TRANS_SUBTYPE] =
// ------------------------------------------------------------------------------------------ //
// Transition tables
+function createStateTransitionTable()
+{
+ var aSTT = {}
+ var aTable = null;
+
+ aSTT[RESTART_MODE_NEVER] = {};
+ aSTT[RESTART_MODE_WHEN_NOT_ACTIVE] = {};
+ aSTT[RESTART_MODE_ALWAYS] = {};
+
+ // transition table for restart=NEVER, fill=REMOVE
+ aTable =
+ aSTT[RESTART_MODE_NEVER][FILL_MODE_REMOVE] = {};
+ aTable[INVALID_NODE] = INVALID_NODE;
+ aTable[UNRESOLVED_NODE] = RESOLVED_NODE | ENDED_NODE;
+ aTable[RESOLVED_NODE] = ACTIVE_NODE | ENDED_NODE;
+ aTable[ACTIVE_NODE] = ENDED_NODE;
+ 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
+ aTable =
+ aSTT[RESTART_MODE_NEVER][FILL_MODE_FREEZE] =
+ aSTT[RESTART_MODE_NEVER][FILL_MODE_HOLD] =
+ aSTT[RESTART_MODE_NEVER][FILL_MODE_TRANSITION] = {};
+ aTable[INVALID_NODE] = INVALID_NODE;
+ aTable[UNRESOLVED_NODE] = RESOLVED_NODE | ENDED_NODE;
+ aTable[RESOLVED_NODE] = ACTIVE_NODE | ENDED_NODE;
+ aTable[ACTIVE_NODE] = FROZEN_NODE | ENDED_NODE;
+ aTable[FROZEN_NODE] = ENDED_NODE;
+ aTable[ENDED_NODE] = ENDED_NODE; // this state is a sink here (cannot restart)
+
+ // transition table for restart=WHEN_NOT_ACTIVE, fill=REMOVE
+ aTable =
+ aSTT[RESTART_MODE_WHEN_NOT_ACTIVE][FILL_MODE_REMOVE] = {};
+ aTable[INVALID_NODE] = INVALID_NODE;
+ aTable[UNRESOLVED_NODE] = RESOLVED_NODE | ENDED_NODE;
+ aTable[RESOLVED_NODE] = ACTIVE_NODE | ENDED_NODE;
+ aTable[ACTIVE_NODE] = ENDED_NODE;
+ aTable[FROZEN_NODE] = INVALID_NODE; // this state is unreachable here
+ aTable[ENDED_NODE] = RESOLVED_NODE | ACTIVE_NODE | ENDED_NODE; // restart is possible
+
+ // transition table for restart=WHEN_NOT_ACTIVE, fill=FREEZE
+ aTable =
+ aSTT[RESTART_MODE_WHEN_NOT_ACTIVE][FILL_MODE_FREEZE] =
+ aSTT[RESTART_MODE_WHEN_NOT_ACTIVE][FILL_MODE_HOLD] =
+ aSTT[RESTART_MODE_WHEN_NOT_ACTIVE][FILL_MODE_TRANSITION] = {};
+ aTable[INVALID_NODE] = INVALID_NODE;
+ aTable[UNRESOLVED_NODE] = RESOLVED_NODE | ENDED_NODE;
+ aTable[RESOLVED_NODE] = ACTIVE_NODE | ENDED_NODE;
+ aTable[ACTIVE_NODE] = FROZEN_NODE | ENDED_NODE;
+ aTable[FROZEN_NODE] = RESOLVED_NODE | ACTIVE_NODE | ENDED_NODE; // restart is possible
+ aTable[ENDED_NODE] = RESOLVED_NODE | ACTIVE_NODE | ENDED_NODE; // restart is possible
+
+ // transition table for restart=ALWAYS, fill=REMOVE
+ aTable =
+ aSTT[RESTART_MODE_ALWAYS][FILL_MODE_REMOVE] = {};
+ aTable[INVALID_NODE] = INVALID_NODE;
+ aTable[UNRESOLVED_NODE] = RESOLVED_NODE | ENDED_NODE;
+ aTable[RESOLVED_NODE] = ACTIVE_NODE | ENDED_NODE;
+ aTable[ACTIVE_NODE] = RESOLVED_NODE | ACTIVE_NODE | ENDED_NODE; // restart is possible
+ aTable[FROZEN_NODE] = INVALID_NODE; // this state is unreachable here
+ aTable[ENDED_NODE] = RESOLVED_NODE | ACTIVE_NODE | ENDED_NODE; // restart is possible
+
+ // transition table for restart=ALWAYS, fill=FREEZE
+ aTable =
+ aSTT[RESTART_MODE_ALWAYS][FILL_MODE_FREEZE] =
+ aSTT[RESTART_MODE_ALWAYS][FILL_MODE_HOLD] =
+ aSTT[RESTART_MODE_ALWAYS][FILL_MODE_TRANSITION] = {};
+ aTable[INVALID_NODE] = INVALID_NODE;
+ aTable[UNRESOLVED_NODE] = RESOLVED_NODE | ENDED_NODE;
+ aTable[RESOLVED_NODE] = ACTIVE_NODE | ENDED_NODE;
+ aTable[ACTIVE_NODE] = RESOLVED_NODE | ACTIVE_NODE | FROZEN_NODE | ENDED_NODE;
+ aTable[FROZEN_NODE] = RESOLVED_NODE | ACTIVE_NODE | ENDED_NODE; // restart is possible
+ aTable[ENDED_NODE] = RESOLVED_NODE | ACTIVE_NODE | ENDED_NODE; // restart is possible
+
+
+ return aSTT;
+}
+
+var aStateTransitionTable = createStateTransitionTable();
+
+
+
+
+
+// ------------------------------------------------------------------------------------------ //
+// Transition tables
+
// transition table for restart=NEVER, fill=FREEZE
var aStateTransitionTable_Never_Freeze =
[
@@ -4543,11 +4631,24 @@ var aTableGuide =
// ------------------------------------------------------------------------------------------ //
function getTransitionTable( eRestartMode, eFillMode )
{
- var nRestartValue = 0; // never
+ // If restart mode has not been resolved we use 'never'.
+ // Note: RESTART_MODE_DEFAULT == RESTART_MODE_INHERIT.
+ if( eRestartMode == RESTART_MODE_DEFAULT )
+ {
+ log( 'getTransitionTable: unexpected restart mode: ' + eRestartMode
+ + '. Used NEVER instead.');
+ eRestartMode = RESTART_MODE_NEVER;
+ }
- var nFillValue = 1; // frozen
+ // If fill mode has not been resolved we use 'remove'.
+ // Note: FILL_MODE_DEFAULT == FILL_MODE_INHERIT
+ if( eFillMode == FILL_MODE_DEFAULT ||
+ eFillMode == FILL_MODE_AUTO )
+ {
+ eFillMode = FILL_MODE_REMOVE;
+ }
- return aTableGuide[ 3*nFillValue + nRestartValue ];
+ return aStateTransitionTable[eRestartMode][eFillMode];
}
@@ -5178,8 +5279,7 @@ BaseNode.prototype.parseElement = function()
this.eRestartMode = this.getParentNode().getRestartMode();
else
// SMIL recommendation document says to set it to 'always'
- // but we follow the slideshow engine C++ implementation
- this.eRestartMode = RESTART_MODE_NEVER;
+ this.eRestartMode = RESTART_MODE_ALWAYS;
// resolve accelerate and decelerate attributes
// from the SMIL recommendation document: if the individual values of the accelerate
@@ -5192,9 +5292,6 @@ BaseNode.prototype.parseElement = function()
this.nDecelerate = 0.0;
}
- // TODO: at present we are able to manage only this case
- this.eFillMode = FILL_MODE_FREEZE;
- this.eRestartMode = RESTART_MODE_NEVER;
this.aStateTransTable = getTransitionTable( this.getRestartMode(), this.getFillMode() );
return true;
@@ -5255,6 +5352,9 @@ BaseNode.prototype.resolve = function()
BaseNode.prototype.activate = function()
{
+// log( 'restart mode: ' + aRestartModeOutMap[ this.getRestartMode() ] );
+// log( 'fill mode: ' + aFillModeOutMap[ this.getFillMode() ] );
+
if( ! this.checkValidNode() )
return false;
@@ -5289,7 +5389,7 @@ BaseNode.prototype.deactivate = function()
var aStateTrans = new StateTransition( this );
if( aStateTrans.enter( FROZEN_NODE, true /* FORCE */ ) )
{
- this.deactivate_st();
+ this.deactivate_st( FROZEN_NODE );
aStateTrans.commit();
this.notifyEndListeners();
commit 372c47309a192e67220913309fa1ccffdff8cde1
Author: Marco Cecchetti <mrcekets at gmail.com>
Date: Wed Jun 13 19:50:38 2012 +0200
Now to animations and repeated to animations are handled by the C++ presentation engine
as the SMIL spec describes.
diff --git a/slideshow/source/engine/activities/activitiesfactory.cxx b/slideshow/source/engine/activities/activitiesfactory.cxx
index f142456..a99a32a 100644
--- a/slideshow/source/engine/activities/activitiesfactory.cxx
+++ b/slideshow/source/engine/activities/activitiesfactory.cxx
@@ -167,6 +167,9 @@ public:
mpFormula( rParms.mpFormula ),
maStartValue(),
maEndValue(),
+ maPreviousValue(),
+ maStartInterpolationValue(),
+ mnIteration( 0 ),
mpAnim( rAnim ),
maInterpolator( rInterpolator ),
mbDynamicStartValue( false ),
@@ -220,6 +223,9 @@ public:
}
else
{
+ maStartValue = aAnimationStartValue;
+ maStartInterpolationValue = maStartValue;
+
// By or To animation. According to SMIL spec,
// the To value takes precedence over the By
// value, if both are specified
@@ -232,6 +238,7 @@ public:
// the to animation interpolates between
// the _running_ underlying value and the to value (as the end value)
mbDynamicStartValue = true;
+ maPreviousValue = maStartValue;
maEndValue = *maTo;
}
else if( maBy )
@@ -255,15 +262,61 @@ public:
{
if (this->isDisposed() || !mpAnim)
return;
- (*mpAnim)(
- getPresentationValue(
- accumulate( maEndValue,
- mbCumulative * nRepeatCount, // means: mbCumulative ? nRepeatCount : 0,
- maInterpolator( (mbDynamicStartValue
- ? mpAnim->getUnderlyingValue()
- : maStartValue),
- maEndValue,
- nModifiedTime ) ) ) );
+
+ // According to SMIL 3.0 spec 'to' animation if no other (lower priority)
+ // animations are active or frozen then a simple interpolation is performed.
+ // That is, the start interpolation value is constant while the animation
+ // is running, and is equal to the underlying value retrieved when
+ // the animation start.
+ // However if another animation is manipulating the underlying value,
+ // the 'to' animation will initially add to the effect of the lower priority
+ // animation, and increasingly dominate it as it nears the end of the
+ // simple duration, eventually overriding it completely.
+ // That is, each time the underlying value is changed between two
+ // computations of the animation function the new underlying value is used
+ // as start value for the interpolation.
+ // See:
+ // http://www.w3.org/TR/SMIL3/smil-animation.html#animationNS-ToAnimation
+ // (Figure 6 - Effect of Additive to animation example)
+ // Moreover when a 'to' animation is repeated, at each new iteration
+ // the start interpolation value is reset to the underlying value
+ // of the animated property when the animation started,
+ // as it is shown in the example provided by the SMIL 3.0 spec.
+ // This is exactly as Firefox performs SVG 'to' animations.
+ if( mbDynamicStartValue )
+ {
+ if( mnIteration != nRepeatCount )
+ {
+ mnIteration = nRepeatCount;
+ maStartInterpolationValue = maStartValue;
+ }
+ else
+ {
+ ValueType aActualValue = mpAnim->getUnderlyingValue();
+ if( aActualValue != maPreviousValue )
+ maStartInterpolationValue = aActualValue;
+ }
+ }
+
+ ValueType aValue = maInterpolator( maStartInterpolationValue,
+ maEndValue, nModifiedTime );
+
+ // According to the SMIL spec:
+ // Because 'to' animation is defined in terms of absolute values of
+ // the target attribute, cumulative animation is not defined.
+ if( mbCumulative && !mbDynamicStartValue )
+ {
+ // aValue = this.aEndValue * nRepeatCount + aValue;
+ aValue = accumulate( maEndValue, nRepeatCount, aValue );
+ }
+
+ (*mpAnim)( getPresentationValue( aValue ) );
+
+ if( mbDynamicStartValue )
+ {
+ maPreviousValue = mpAnim->getUnderlyingValue();
+ }
+
}
using BaseType::perform;
@@ -316,6 +369,10 @@ private:
ValueType maStartValue;
ValueType maEndValue;
+ mutable ValueType maPreviousValue;
+ mutable ValueType maStartInterpolationValue;
+ mutable sal_uInt32 mnIteration;
+
::boost::shared_ptr< AnimationType > mpAnim;
Interpolator< ValueType > maInterpolator;
bool mbDynamicStartValue;
diff --git a/slideshow/source/engine/animationnodes/animationbasenode.cxx b/slideshow/source/engine/animationnodes/animationbasenode.cxx
index df1bcc5..ed63495 100644
--- a/slideshow/source/engine/animationnodes/animationbasenode.cxx
+++ b/slideshow/source/engine/animationnodes/animationbasenode.cxx
@@ -33,6 +33,7 @@
#include <cppuhelper/exc_hlp.hxx>
#include <comphelper/anytostring.hxx>
#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/animations/AnimationNodeType.hpp>
#include <com/sun/star/animations/Timing.hpp>
#include <com/sun/star/animations/AnimationAdditiveMode.hpp>
#include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
@@ -421,7 +422,18 @@ AnimationBaseNode::fillCommonParameters() const
else
aRepeats.reset( nRepeats / nDuration );
}
- else {
+ // 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?
animations::Timing eTiming;
diff --git a/slideshow/source/engine/color.cxx b/slideshow/source/engine/color.cxx
index dc5092b..c9ce4f2 100644
--- a/slideshow/source/engine/color.cxx
+++ b/slideshow/source/engine/color.cxx
@@ -217,6 +217,19 @@ namespace slideshow
return maHSLTriple.mnLuminance;
}
+
+ sal_Bool operator==( const HSLColor& rLHS, const HSLColor& rRHS )
+ {
+ return ( rLHS.getHue() == rRHS.getHue() &&
+ rLHS.getSaturation() == rRHS.getSaturation() &&
+ rLHS.getLuminance() == rRHS.getLuminance() );
+ }
+
+ sal_Bool operator!=( const HSLColor& rLHS, const HSLColor& rRHS )
+ {
+ return !( rLHS == rRHS );
+ }
+
HSLColor operator+( const HSLColor& rLHS, const HSLColor& rRHS )
{
return HSLColor( rLHS.getHue() + rRHS.getHue(),
@@ -346,6 +359,18 @@ namespace slideshow
255 );
}
+ sal_Bool operator==( const RGBColor& rLHS, const RGBColor& rRHS )
+ {
+ return ( rLHS.getRed() == rRHS.getRed() &&
+ rLHS.getGreen() == rRHS.getGreen() &&
+ rLHS.getBlue() == rRHS.getBlue() );
+ }
+
+ sal_Bool operator!=( const RGBColor& rLHS, const RGBColor& rRHS )
+ {
+ return !( rLHS == rRHS );
+ }
+
RGBColor operator+( const RGBColor& rLHS, const RGBColor& rRHS )
{
return RGBColor( rLHS.getRed() + rRHS.getRed(),
diff --git a/slideshow/source/inc/hslcolor.hxx b/slideshow/source/inc/hslcolor.hxx
index 6659923..15500c7 100644
--- a/slideshow/source/inc/hslcolor.hxx
+++ b/slideshow/source/inc/hslcolor.hxx
@@ -88,6 +88,8 @@ namespace slideshow
double mnMagicValue;
};
+ sal_Bool operator==( const HSLColor& rLHS, const HSLColor& rRHS );
+ sal_Bool operator!=( const HSLColor& rLHS, const HSLColor& rRHS );
HSLColor operator+( const HSLColor& rLHS, const HSLColor& rRHS );
HSLColor operator*( const HSLColor& rLHS, const HSLColor& rRHS );
HSLColor operator*( double nFactor, const HSLColor& rRHS );
diff --git a/slideshow/source/inc/rgbcolor.hxx b/slideshow/source/inc/rgbcolor.hxx
index fc161f7..844f324 100644
--- a/slideshow/source/inc/rgbcolor.hxx
+++ b/slideshow/source/inc/rgbcolor.hxx
@@ -84,6 +84,8 @@ namespace slideshow
RGBTriple maRGBTriple;
};
+ sal_Bool operator==( const RGBColor& rLHS, const RGBColor& rRHS );
+ sal_Bool operator!=( const RGBColor& rLHS, const RGBColor& rRHS );
RGBColor operator+( const RGBColor& rLHS, const RGBColor& rRHS );
RGBColor operator*( const RGBColor& rLHS, const RGBColor& rRHS );
RGBColor operator*( double nFactor, const RGBColor& rRHS );
commit b9cfef37900cea634dc6fb987498b840230399bd
Author: Marco Cecchetti <mrcekets at gmail.com>
Date: Tue Jun 12 21:42:41 2012 +0200
Now to animations and repeated to animations are handled by the JavaScript engine as the
SMIL spec describes.
diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index 1ce3e16..13efb60 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -3375,6 +3375,13 @@ RGBColor.prototype.clone = function()
return new RGBColor( this.nRed, this.nGreen, this.nBlue );
};
+RGBColor.prototype.equal = function( aRGBColor )
+{
+ return ( this.nRed == aRGBColor.nRed ) &&
+ ( this.nGreen == aRGBColor.nGreen ) &&
+ ( this.nBlue == aRGBColor.nBlue );
+};
+
RGBColor.prototype.add = function( aRGBColor )
{
this.nRed += aRGBColor.nRed;
@@ -3488,6 +3495,13 @@ HSLColor.prototype.clone = function()
return new HSLColor( this.nHue, this.nSaturation, this.nLuminance );
};
+HSLColor.prototype.equal = function( aHSLColor )
+{
+ return ( this.nHue == aHSLColor.nHue ) &&
+ ( this.nSaturation += aHSLColor.nSaturation ) &&
+ ( this.nLuminance += aHSLColor.nLuminance );
+};
+
HSLColor.prototype.add = function( aHSLColor )
{
this.nHue += aHSLColor.nHue;
@@ -3990,11 +4004,11 @@ aPresetIdInMap = {};
// Restart Modes
-RESTART_MODE_DEFAULT = 0;
-RESTART_MODE_INHERIT = 0;
-RESTART_MODE_ALWAYS = 1;
-RESTART_MODE_WHEN_NOT_ACTIVE = 2;
-RESTART_MODE_NEVER = 3;
+var RESTART_MODE_DEFAULT = 0;
+var RESTART_MODE_INHERIT = 0;
+var RESTART_MODE_ALWAYS = 1;
+var RESTART_MODE_WHEN_NOT_ACTIVE = 2;
+var RESTART_MODE_NEVER = 3;
aRestartModeInMap = {
'inherit' : RESTART_MODE_DEFAULT,
@@ -4168,7 +4182,7 @@ BOXWIPE_TRANSITION = 2;
FOURBOXWIPE_TRANSITION = 3;
ELLIPSEWIPE_TRANSITION = 4; // 17
CLOCKWIPE_TRANSITION = 5; // 22
-PINWHEELWIPE_TRANSITION = 6 // 23
+PINWHEELWIPE_TRANSITION = 6; // 23
PUSHWIPE_TRANSITION = 7; // 35
SLIDEWIPE_TRANSITION = 8; // 36
FADE_TRANSITION = 9; // 37
@@ -9613,6 +9627,11 @@ var aOperatorSetMap = new Array();
// number operators
aOperatorSetMap[ NUMBER_PROPERTY ] = new Object();
+aOperatorSetMap[ NUMBER_PROPERTY ].equal = function( a, b )
+{
+ return ( a === b );
+};
+
aOperatorSetMap[ NUMBER_PROPERTY ].add = function( a, b )
{
return ( a + b );
@@ -9626,6 +9645,11 @@ aOperatorSetMap[ NUMBER_PROPERTY ].scale = function( k, v )
// color operators
aOperatorSetMap[ COLOR_PROPERTY ] = new Object();
+aOperatorSetMap[ COLOR_PROPERTY ].equal = function( a, b )
+{
+ return a.equal( b );
+};
+
aOperatorSetMap[ COLOR_PROPERTY ].add = function( a, b )
{
var c = a.clone();
@@ -10318,11 +10342,15 @@ function FromToByActivityTemplate( BaseType ) // template parameter
this.aBy = aByValue;
this.aStartValue = null;
this.aEndValue = null;
+ this.aPreviousValue = null;
+ this.aStartInterpolationValue = null;
this.aAnimation = aAnimation;
this.aInterpolator = aInterpolator;
+ this.equal = aOperatorSet.equal;
this.add = aOperatorSet.add;
this.scale = aOperatorSet.scale;
this.bDynamicStartValue = false;
+ this.nIteration = 0;
this.bCumulative = bAccumulate;
this.initAnimatedElement();
@@ -10378,6 +10406,9 @@ function FromToByActivityTemplate( BaseType ) // template parameter
}
else
{
+ this.aStartValue = aAnimationStartValue;
+ this.aStartInterpolationValue = this.aStartValue;
+
// By or To animation. According to SMIL spec,
// the To value takes precedence over the By
// value, if both are specified
@@ -10390,6 +10421,7 @@ function FromToByActivityTemplate( BaseType ) // template parameter
// the to animation interpolates between
// the _running_ underlying value and the to value (as the end value)
this.bDynamicStartValue = true;
+ this.aPreviousValue = this.aStartValue;
this.aEndValue = this.aTo;
}
else if( this.aBy )
@@ -10420,18 +10452,61 @@ function FromToByActivityTemplate( BaseType ) // template parameter
return;
}
- var aValue = this.bDynamicStartValue ? this.aAnimation.getUnderlyingValue()
- : this.aStartValue;
- aValue = this.aInterpolator( aValue, this.aEndValue, nModifiedTime );
+ // According to SMIL 3.0 spec 'to' animation if no other (lower priority)
+ // animations are active or frozen then a simple interpolation is performed.
+ // That is, the start interpolation value is constant while the animation
+ // is running, and is equal to the underlying value retrieved when
+ // the animation start.
+ // However if another animation is manipulating the underlying value,
+ // the 'to' animation will initially add to the effect of the lower priority
+ // animation, and increasingly dominate it as it nears the end of the
+ // simple duration, eventually overriding it completely.
+ // That is, each time the underlying value is changed between two
+ // computations of the animation function the new underlying value is used
+ // as start value for the interpolation.
+ // See:
+ // http://www.w3.org/TR/SMIL3/smil-animation.html#animationNS-ToAnimation
+ // (Figure 6 - Effect of Additive to animation example)
+ // Moreover when a 'to' animation is repeated, at each new iteration
+ // the start interpolation value is reset to the underlying value
+ // of the animated property when the animation started,
+ // as it is shown in the example provided by the SMIL 3.0 spec.
+ // This is exactly as Firefox performs SVG 'to' animations.
+ if( this.bDynamicStartValue )
+ {
+ if( this.nIteration != nRepeatCount )
+ {
+ this.nIteration = nRepeatCount;
+ this.aStartInterpolationValue = this.aStartValue;
+ }
+ else
+ {
+ var aActualValue = this.aAnimation.getUnderlyingValue();
+ if( !this.equal( aActualValue, this.aPreviousValue ) )
+ this.aStartInterpolationValue = aActualValue;
+ }
+ }
- if( this.bCumulative )
+ var aValue = this.aInterpolator( this.aStartInterpolationValue,
+ this.aEndValue, nModifiedTime );
+
+ // According to the SMIL spec:
+ // Because 'to' animation is defined in terms of absolute values of
+ // the target attribute, cumulative animation is not defined.
+ if( this.bCumulative && !this.bDynamicStartValue )
{
// aValue = this.aEndValue * nRepeatCount + aValue;
aValue = this.add( this.scale( nRepeatCount, this.aEndValue ), aValue );
}
this.aAnimation.perform( aValue );
+
+ if( this.bDynamicStartValue )
+ {
+ this.aPreviousValue = this.aAnimation.getUnderlyingValue();
+ }
+
};
FromToByActivity.prototype.performEnd = function()
More information about the Libreoffice-commits
mailing list