[Libreoffice-commits] .: Branch 'feature/svg-export' - 5 commits - filter/source slideshow/source

Marco Cecchetti mcecchetti at kemper.freedesktop.org
Mon Jun 25 07:34:41 PDT 2012


 filter/source/svg/presentation_engine.js                     |  305 ++++++++---
 slideshow/source/engine/animationnodes/animationbasenode.cxx |   10 
 slideshow/source/engine/animationnodes/basecontainernode.cxx |   39 +
 slideshow/source/engine/animationnodes/basecontainernode.hxx |    4 
 4 files changed, 268 insertions(+), 90 deletions(-)

New commits:
commit 78e4336eee71646c7f671372991a800b70fe3d08
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 02ab194bf792529a8bb00edfa5d66780958fcf50
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 c4e925c10fcfb6aa4296fe084e79120649f4d41f
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 7ee06ea260b33b6cba9cf0573265b28986c8247c
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 9ed9793..344c3ec 100644
--- a/slideshow/source/engine/animationnodes/basecontainernode.hxx
+++ b/slideshow/source/engine/animationnodes/basecontainernode.hxx
@@ -60,6 +60,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:
@@ -75,6 +76,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
@@ -92,6 +95,7 @@ protected:
     typedef ::std::vector<AnimationNodeSharedPtr> VectorOfNodes;
     VectorOfNodes       maChildren;
     ::std::size_t       mnFinishedChildren;
+    double       mnLeftIterations;
 
 private:
     const bool          mbDurationIndefinite;
commit eb0c40b0bd13c0710f58e08eae23f2b40adf2567
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();


More information about the Libreoffice-commits mailing list