filter/source/svg/presentation_engine.js |  649 ++++++++++++++++++++++++-------
 sd/source/core/CustomAnimationEffect.cxx |   13 
 sd/xml/effects.xml                       |   12 
 3 files changed, 524 insertions(+), 150 deletions(-)

New commits:
commit 248f71c2486c8b651827f960b82b8294f9f79913
Author: Marco Cecchetti <mrcek...@gmail.com>
Date:   Mon Jul 9 00:59:05 2012 +0200

    Added support for interactive animation sequence to the JavaScript engine.
    
    Now it is possible to start an effect by clicking on a given shape.

diff --git a/filter/source/svg/presentation_engine.js 
b/filter/source/svg/presentation_engine.js
index a5a3a3f..cccbcd0 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -222,7 +222,7 @@ function getDefaultCharCodeDictionary()
 }
 
 
-function slideOnMouseDown( aEvt )
+function slideOnMouseUp( aEvt )
 {
     if (!aEvt)
         aEvt = window.event;
@@ -236,8 +236,12 @@ function slideOnMouseDown( aEvt )
 
     if( 0 != nOffset )
         dispatchEffects( nOffset );
+    return true; // the click has been handled
 }
 
+document.handleClick = slideOnMouseUp;
+
+
 /** Event handler for mouse wheel events in slide mode.
  *  based on http://adomas.org/javascript-mouse-wheel/
  *
@@ -309,7 +313,7 @@ function mouseHandlerDispatch( aEvt, anAction )
 }
 
 //Set mouse event handler.
-document.onmousedown = function( aEvt ) { return mouseHandlerDispatch( aEvt, 
MOUSE_DOWN ); };
+document.onmouseup = function( aEvt ) { return mouseHandlerDispatch( aEvt, 
MOUSE_UP ); };
 //document.onmousemove = function( aEvt ) { return mouseHandlerDispatch( aEvt, 
MOUSE_MOVE ); };
 
 /** Function to supply the default mouse handler dictionary.
@@ -324,13 +328,17 @@ function getDefaultMouseHandlerDictionary()
     mouseHandlerDict[INDEX_MODE] = new Object();
 
     // slide mode
-    mouseHandlerDict[SLIDE_MODE][MOUSE_DOWN]
-        = function( aEvt ) { return slideOnMouseDown( aEvt ); };
+    mouseHandlerDict[SLIDE_MODE][MOUSE_UP]
+        //= function( aEvt ) { return slideOnMouseDown( aEvt ); };
+        = function( aEvt ) { return ( aSlideShow.aEventMultiplexer ) ?
+                                        
aSlideShow.aEventMultiplexer.notifyMouseClick( aEvt )
+                                        : slideOnMouseUp( aEvt ); };
+
     mouseHandlerDict[SLIDE_MODE][MOUSE_WHEEL]
         = function( aEvt ) { return slideOnMouseWheel( aEvt ); };
 
     // index mode
-    mouseHandlerDict[INDEX_MODE][MOUSE_DOWN]
+    mouseHandlerDict[INDEX_MODE][MOUSE_UP]
         = function( aEvt ) { return toggleSlideIndex(); };
 //    mouseHandlerDict[INDEX_MODE][MOUSE_MOVE]
 //        = function( aEvt ) { return theSlideIndexPage.updateSelection( aEvt 
); };
@@ -1433,7 +1441,7 @@ var NAVDBG = new DebugPrinter();
 NAVDBG.off();
 
 var ANIMDBG = new DebugPrinter();
-ANIMDBG.on();
+ANIMDBG.off();
 
 var aRegisterEventDebugPrinter = new DebugPrinter();
 aRegisterEventDebugPrinter.off();
@@ -5047,11 +5055,11 @@ NodeContext.prototype.makeSourceEventElement = 
function( sId, aEventBaseElem )
         return null;
     }
 
-    if( !this.aAnimationNodeMap[ sId ] )
+    if( !this.aSourceEventElementMap[ sId ] )
     {
-        this.aAnimationNodeMap[ sId ] = new SourceEventElement( 
aEventBaseElem, this.aContext.aEventMultiplexer );
+        this.aSourceEventElementMap[ sId ] = new SourceEventElement( sId, 
aEventBaseElem, this.aContext.aEventMultiplexer );
     }
-    return this.aAnimationNodeMap[ sId ];
+    return this.aSourceEventElementMap[ sId ];
 };
 
 
@@ -5323,7 +5331,7 @@ BaseNode.prototype.resolve = function()
         {
             this.aActivationEvent = makeDelay( bind( this, this.activate ), 
this.getBegin().getOffset() + this.nStartDelay );
         }
-        registerEvent( this.getBegin(), this.aActivationEvent, 
this.aNodeContext );
+        registerEvent( this.getId(), this.getBegin(), this.aActivationEvent, 
this.aNodeContext );
 
         return true;
     }
@@ -9378,6 +9386,7 @@ function SlideAnimations( aSlideShowContext )
     this.aAnimatedElementMap = new Object();
     this.aSourceEventElementMap = new Object();
     this.aNextEffectEventArray = new NextEffectEventArray();
+    this.aInteractiveAnimationSequenceMap = new Object();
     this.aEventMultiplexer = new EventMultiplexer( 
aSlideShowContext.aTimerEventQueue );
     this.aRootNode = null;
     this.bElementsParsed = false;
@@ -9385,6 +9394,11 @@ function SlideAnimations( aSlideShowContext )
     this.aContext.aAnimationNodeMap = this.aAnimationNodeMap;
     this.aContext.aAnimatedElementMap = this.aAnimatedElementMap;
     this.aContext.aSourceEventElementMap = this.aSourceEventElementMap;
+
+    // We set up a low priority for the invocation of document.handleClick
+    // in order to make clicks on shapes, that start interactive animation
+    // sequence (on click), have an higher priority.
+    this.aEventMultiplexer.registerMouseClickHandler( document, 100 );
 }
 
 
@@ -9433,7 +9447,12 @@ SlideAnimations.prototype.start = function()
     if( !this.bElementsParsed )
         return false;
 
-    aSlideShow.setSlideEvents( this.aNextEffectEventArray, 
this.aEventMultiplexer );
+    this.chargeSourceEvents();
+    this.chargeInterAnimEvents();
+
+    aSlideShow.setSlideEvents( this.aNextEffectEventArray,
+                               this.aInteractiveAnimationSequenceMap,
+                               this.aEventMultiplexer );
 
     if( this.aContext.bFirstRun == undefined )
         this.aContext.bFirstRun = true;
@@ -9489,7 +9508,21 @@ SlideAnimations.prototype.clearNextEffectEvents = 
function()
     this.aContext.bFirstRun = undefined;
 };
 
+SlideAnimations.prototype.chargeSourceEvents = function()
+{
+    for( var id in this.aSourceEventElementMap )
+    {
+        this.aSourceEventElementMap[id].charge();
+    }
+};
 
+SlideAnimations.prototype.chargeInterAnimEvents = function()
+{
+    for( var id in this.aInteractiveAnimationSequenceMap )
+    {
+        this.aInteractiveAnimationSequenceMap[id].chargeEvents();
+    }
+};
 
 
/**********************************************************************************************
  *      Event classes and helper functions
@@ -9578,7 +9611,7 @@ function makeDelay( aFunctor, nTimeout )
 
 
 // 
------------------------------------------------------------------------------------------
 //
-function registerEvent( aTiming, aEvent, aNodeContext )
+function registerEvent( nNodeId, aTiming, aEvent, aNodeContext )
 {
     var aSlideShowContext = aNodeContext.aContext;
     var eTimingType = aTiming.getType();
@@ -9603,6 +9636,14 @@ function registerEvent( aTiming, aEvent, aNodeContext )
             log( 'registerEvent: next effect event array not initialized' );
             return;
         }
+        var aInteractiveAnimationSequenceMap =
+            aSlideShowContext.aInteractiveAnimationSequenceMap;
+        if( !aInteractiveAnimationSequenceMap )
+        {
+            log( 'registerEvent: interactive animation sequence map not 
initialized' );
+            return;
+        }
+
         switch( eTimingType )
         {
             case EVENT_TIMING:
@@ -9618,6 +9659,12 @@ function registerEvent( aTiming, aEvent, aNodeContext )
                     }
                     var aSourceEventElement = 
aNodeContext.makeSourceEventElement( sEventBaseElemId, aEventBaseElem );
 
+                    if( !aInteractiveAnimationSequenceMap[ nNodeId ] )
+                    {
+                        var aInteractiveAnimationSequence = new 
InteractiveAnimationSequence( nNodeId );
+                        aInteractiveAnimationSequenceMap[ nNodeId ] = 
aInteractiveAnimationSequence;
+                    }
+
                     var bEventRegistered = false;
                     switch( eEventType )
                     {
@@ -9629,7 +9676,12 @@ function registerEvent( aTiming, aEvent, aNodeContext )
                             log( 'generateEvent: not handled event type: ' + 
eEventType );
                     }
                     if( bEventRegistered )
-                        aSourceEventElement.addEventListener( eEventType  );
+                    {
+                        var aStartEvent = aInteractiveAnimationSequenceMap[ 
nNodeId ].getStartEvent();
+                        var aEndEvent = aInteractiveAnimationSequenceMap[ 
nNodeId ].getEndEvent();
+                        aEventMultiplexer.registerEvent( eEventType, 
aSourceEventElement.getId(), aStartEvent );
+                        aEventMultiplexer.registerEvent( 
EVENT_TRIGGER_END_EVENT, nNodeId, aEndEvent );
+                    }
                 }
                 else  // no base event element present
                 {
@@ -9680,82 +9732,173 @@ registerEvent.DBG = function( aTiming, nTime )
 
 
 // 
------------------------------------------------------------------------------------------
 //
-function SourceEventElement( aElement, aEventMultiplexer )
+function SourceEventElement( sId, aElement, aEventMultiplexer )
 {
-    this.nId = getUniqueId();
+    this.sId = sId;
     this.aElement = aElement;
     this.aEventMultiplexer = aEventMultiplexer;
-    this.aEventListenerStateArray = new Array();
-}
 
+    this.aEventMultiplexer.registerMouseClickHandler( this, 1000 );
+
+    this.bClickHandled = false;
+    this.bIsPointerOver = false;
+    this.aElement.addEventListener( 'mouseover', bind2( 
SourceEventElement.prototype.onMouseEnter, this), false );
+    this.aElement.addEventListener( 'mouseout', bind2( 
SourceEventElement.prototype.onMouseLeave, this), false );
+}
 
 SourceEventElement.prototype.getId = function()
 {
-    return this.nId;
+    return this.sId;
 };
 
-SourceEventElement.prototype.isEqualTo = function( aSourceEventElement )
+SourceEventElement.prototype.onMouseEnter = function()
 {
-    return ( this.getId() == aSourceEventElement.getId() );
+    this.bIsPointerOver = true;
 };
 
-SourceEventElement.prototype.onClick = function()
+SourceEventElement.prototype.onMouseLeave = function()
 {
-    this.aEventMultiplexer.notifyClickEvent( this );
+    this.bIsPointerOver = false;
 };
 
-SourceEventElement.prototype.isEventListenerRegistered = function( eEventType )
+SourceEventElement.prototype.charge = function()
 {
-    return this.aEventListenerStateArray[ eEventType ];
+    this.bClickHandled = false;
 };
 
-SourceEventElement.prototype.addEventListener = function( eEventType )
+SourceEventElement.prototype.handleClick = function( aMouseEvent )
 {
-    if( !this.aElement )
-        return false;
+    if( !this.bIsPointerOver ) return false;
 
-    this.aEventListenerStateArray[ eEventType ] = true;
-    switch( eEventType )
-    {
-        case EVENT_TRIGGER_ON_CLICK:
-            this.aElement.addEventListener( 'click', this.onClick, false );
-            break;
-        default:
-            log( 'SourceEventElement.addEventListener: not handled event type: 
' + eEventType );
-            return false;
-    }
+    if( this.bClickHandled )
+        return true;
+
+    this.aEventMultiplexer.notifyEvent( EVENT_TRIGGER_ON_CLICK, this.getId() );
+    aSlideShow.update();
+    this.bClickHandled = true;
     return true;
 };
 
-SourceEventElement.prototype.removeEventListener = function( eEventType )
+
+
+// 
------------------------------------------------------------------------------------------
 //
+function InteractiveAnimationSequence( nId )
 {
-    if( !this.aElement )
-        return false;
+    this.nId = nId;
+    this.bIsRunning = false;
+    this.aStartEvent = null;
+    this.aEndEvent = null;
+}
 
-    this.aEventListenerStateArray[ eEventType ] = false;
-    switch( eEventType )
+InteractiveAnimationSequence.prototype.getId = function()
+{
+    return this.nId;
+};
+
+InteractiveAnimationSequence.prototype.getStartEvent = function()
+{
+    if( !this.aStartEvent )
     {
-        case EVENT_TRIGGER_ON_CLICK:
-            this.aElement.removeEventListener( 'click', this.onClick, false );
-            break;
-        default:
-            log( 'SourceEventElement.removeEventListener: not handled event 
type: ' + eEventType );
-            return false;
+        this.aStartEvent =
+            makeEvent( bind2( InteractiveAnimationSequence.prototype.start, 
this ) );
     }
-    return true;
+    return this.aStartEvent;
 };
 
+InteractiveAnimationSequence.prototype.getEndEvent = function()
+{
+    if( !this.aEndEvent )
+    {
+        this.aEndEvent =
+            makeEvent( bind2( InteractiveAnimationSequence.prototype.end, this 
) );
+    }
+    return this.aEndEvent;
+};
+
+InteractiveAnimationSequence.prototype.chargeEvents = function()
+{
+    if( this.aStartEvent )      this.aStartEvent.charge();
+    if( this.aEndEvent )        this.aEndEvent.charge();
+};
+
+InteractiveAnimationSequence.prototype.isRunning = function()
+{
+    return this.bIsRunning;
+};
+
+InteractiveAnimationSequence.prototype.start = function()
+{
+    aSlideShow.notifyInteractiveAnimationSequenceStart( this.getId() );
+    this.bIsRunning = true;
+};
+
+InteractiveAnimationSequence.prototype.end = function()
+{
+    aSlideShow.notifyInteractiveAnimationSequenceEnd( this.getId() );
+    this.bIsRunning = false;
+};
+
+// 
------------------------------------------------------------------------------------------
 //
+/** class PriorityEntry
+ *  It provides an entry type for priority queues.
+ *  Higher is the value of nPriority higher is the priority of the created 
entry.
+ *
+ *  @param aValue
+ *      The object to be prioritized.
+ *  @param nPriority
+ *      An integral number representing the object priority.
+ *
+ */
+function PriorityEntry( aValue, nPriority )
+{
+    this.aValue = aValue;
+    this.nPriority = nPriority;
+}
+
+/** EventEntry.compare
+ *  Compare priority of two entries.
+ *
+ *  @param aLhsEntry
+ *      An instance of type PriorityEntry.
+ *  @param aRhsEntry
+ *      An instance of type PriorityEntry.
+ *  @return {Boolean}
+ *      True if the first entry has higher priority of the second entry,
+ *      false otherwise.
+ */
+PriorityEntry.compare = function( aLhsEntry, aRhsEntry )
+{
+    return ( aLhsEntry.nPriority < aRhsEntry.nPriority );
+};
 
 // 
------------------------------------------------------------------------------------------
 //
 function EventMultiplexer( aTimerEventQueue )
 {
     this.aTimerEventQueue = aTimerEventQueue;
     this.aEventMap = new Object();
+    this.aMouseClickHandlerSet = new PriorityQueue( PriorityEntry.compare );
     this.aSkipEffectEvent = null;
     this.aRewindCurrentEffectEvent = null;
     this.aRewindLastEffectEvent = null;
 }
 
+EventMultiplexer.prototype.registerMouseClickHandler = function( aHandler, 
nPriority )
+{
+    var aHandlerEntry = new PriorityEntry( aHandler, nPriority );
+    this.aMouseClickHandlerSet.push( aHandlerEntry );
+};
+
+EventMultiplexer.prototype.notifyMouseClick = function( aMouseEvent )
+{
+    var aMouseClickHandlerSet = this.aMouseClickHandlerSet;
+    var nSize = aMouseClickHandlerSet.size();
+    for( var i = 0; i < nSize; ++i )
+    {
+        var aHandlerEntry = aMouseClickHandlerSet.aSequence[i];
+        if( aHandlerEntry.aValue.handleClick( aMouseEvent ) )
+            break;
+    }
+};
 
 EventMultiplexer.prototype.registerEvent = function( eEventType, aNotifierId, 
aEvent )
 {
@@ -11284,12 +11427,17 @@ function SlideShow()
     this.aTimerEventQueue = new TimerEventQueue( this.aTimer );
     this.aActivityQueue = new ActivityQueue( this.aTimer );
     this.aNextEffectEventArray = null;
+    this.aInteractiveAnimationSequenceMap = null;
     this.aEventMultiplexer = null;
 
-    this.aContext = new SlideShowContext( this.aTimerEventQueue, 
this.aEventMultiplexer,
-                                          this.aNextEffectEventArray, 
this.aActivityQueue );
+    this.aContext = new SlideShowContext( this.aTimerEventQueue,
+                                          this.aEventMultiplexer,
+                                          this.aNextEffectEventArray,
+                                          
this.aInteractiveAnimationSequenceMap,
+                                          this.aActivityQueue );
     this.nCurrentEffect = 0;
     this.eDirection = FORWARD;
+    this.nTotalInteracAnimSeqRunning = 0;
     this.bIsIdle = true;
     this.bIsEnabled = true;
     this.bIsRewinding = false;
@@ -11299,19 +11447,27 @@ function SlideShow()
 }
 
 
-SlideShow.prototype.setSlideEvents = function( aNextEffectEventArray, 
aEventMultiplexer )
+SlideShow.prototype.setSlideEvents = function( aNextEffectEventArray,
+                                               
aInteractiveAnimationSequenceMap,
+                                               aEventMultiplexer )
 {
     if( !aNextEffectEventArray )
         log( 'SlideShow.setSlideEvents: aNextEffectEventArray is not valid' );
 
+    if( !aInteractiveAnimationSequenceMap )
+        log( 'SlideShow.setSlideEvents:aInteractiveAnimationSequenceMap  is 
not valid' );
+
     if( !aEventMultiplexer )
         log( 'SlideShow.setSlideEvents: aEventMultiplexer is not valid' );
 
     this.aContext.aNextEffectEventArray = aNextEffectEventArray;
     this.aNextEffectEventArray = aNextEffectEventArray;
+    this.aContext.aInteractiveAnimationSequenceMap = 
aInteractiveAnimationSequenceMap;
+    this.aInteractiveAnimationSequenceMap = aInteractiveAnimationSequenceMap;
     this.aContext.aEventMultiplexer = aEventMultiplexer;
     this.aEventMultiplexer = aEventMultiplexer;
     this.nCurrentEffect = 0;
+    this.nTotalInteracAnimSeqRunning = 0;
 };
 
 SlideShow.prototype.createSlideTransition = function( aSlideTransitionHandler, 
aLeavingSlide, aEnteringSlide, aTransitionEndEvent )
@@ -11361,6 +11517,11 @@ SlideShow.prototype.isRunning = function()
     return !this.bIsIdle;
 };
 
+SlideShow.prototype.isInterAnimSeqRunning = function()
+{
+    return ( this.nTotalInteracAnimSeqRunning > 0 );
+};
+
 SlideShow.prototype.isEnabled = function()
 {
     return this.bIsEnabled;
@@ -11393,11 +11554,27 @@ SlideShow.prototype.notifyTransitionEnd = function( 
nSlideIndex )
     }
 };
 
+SlideShow.prototype.notifyInteractiveAnimationSequenceStart = function( 
nNodeId )
+{
+    ++this.nTotalInteracAnimSeqRunning;
+};
+
+SlideShow.prototype.notifyInteractiveAnimationSequenceEnd = function( nNodeId )
+{
+    assert( this.nTotalInteracAnimSeqRunning > 0,
+            'SlideShow.notifyInteractiveAnimationSequenceStart: ' +
+            'the total number of running interactive application is zero' );
+    --this.nTotalInteracAnimSeqRunning;
+};
+
 SlideShow.prototype.nextEffect = function()
 {
     if( !this.isEnabled() )
         return false;
 
+    if( this.isInterAnimSeqRunning() )
+        return true;
+
     if( this.isRunning() )
     {
         this.skipCurrentEffect();
@@ -11443,6 +11620,9 @@ SlideShow.prototype.skipEffect = function()
     if( this.bIsSkipping || this.bIsRewinding )
         return true;
 
+    if( this.isInterAnimSeqRunning() )
+        return true;
+
     if( this.isRunning() )
     {
         this.skipCurrentEffect();
@@ -11478,6 +11658,9 @@ SlideShow.prototype.skipAllEffects = function()
     if( this.bIsSkippingAll )
         return true;
 
+    if( this.isInterAnimSeqRunning() )
+        return true;
+
     this.bIsSkippingAll = true;
     if( this.isRunning() )
     {
@@ -11513,6 +11696,9 @@ SlideShow.prototype.rewindEffect = function()
     if( this.bIsSkipping || this.bIsRewinding )
         return;
 
+    if( this.isInterAnimSeqRunning() )
+        return true;
+
     if( this.nCurrentEffect == 0 )
     {
         this.rewindToPreviousSlide();
@@ -11717,11 +11903,12 @@ var aSlideShow = null;
 
 
 // 
------------------------------------------------------------------------------------------
 //
-function SlideShowContext( aTimerEventQueue, aEventMultiplexer, 
aNextEffectEventArray, aActivityQueue)
+function SlideShowContext( aTimerEventQueue, aEventMultiplexer, 
aNextEffectEventArray, aInteractiveAnimationSequenceMap, aActivityQueue)
 {
     this.aTimerEventQueue = aTimerEventQueue;
     this.aEventMultiplexer = aEventMultiplexer;
     this.aNextEffectEventArray = aNextEffectEventArray;
+    this.aInteractiveAnimationSequenceMap = aInteractiveAnimationSequenceMap;
     this.aActivityQueue = aActivityQueue;
     this.bIsSkipping = false;
 }
commit 247be8bada5dfb1fe3acb7625a1b230d55b592d3
Author: Marco Cecchetti <mrcek...@gmail.com>
Date:   Thu Jul 5 19:17:26 2012 +0200

    Bug fix: now the JavaScript engine parse the ‘counter-clockwise’ value 
correctly.
    Previously it expected ‘counterclockwise’.

diff --git a/filter/source/svg/presentation_engine.js 
b/filter/source/svg/presentation_engine.js
index 984eaef..a5a3a3f 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -4117,9 +4117,9 @@ aColorSpaceOutMap = [ 'rgb', 'hsl' ];
 var CLOCKWISE               = 0;
 var COUNTERCLOCKWISE        = 1;
 
-aClockDirectionInMap = { 'clockwise': CLOCKWISE, 'counterclockwise': 
COUNTERCLOCKWISE };
+aClockDirectionInMap = { 'clockwise': CLOCKWISE, 'counter-clockwise': 
COUNTERCLOCKWISE };
 
-aClockDirectionOutMap = [ 'clockwise', 'counterclockwise' ];
+aClockDirectionOutMap = [ 'clockwise', 'counter-clockwise' ];
 
 
 // Attribute Value Types
commit 48265b1ce5b9003c754397415d30425df88e3581
Author: Marco Cecchetti <mrcek...@gmail.com>
Date:   Thu Jul 5 18:50:39 2012 +0200

    Bug fix: now the darken and lighten effects work in the right way.
    
    Edited the effects.xml and changed effect direction to counterclockwise.

diff --git a/sd/xml/effects.xml b/sd/xml/effects.xml
index be341ef..b555a32 100644
--- a/sd/xml/effects.xml
+++ b/sd/xml/effects.xml
@@ -1172,9 +1172,9 @@
     <anim:par smil:begin="indefinite" smil:fill="hold">
     <anim:par smil:begin="0" smil:fill="hold">
     <anim:par smil:begin="0" smil:fill="hold" pres:node-type="on-click" 
pres:preset-class="emphasis" pres:preset-id="ooo-emphasis-darken">
-        <anim:animateColor smil:dur="0.5" smil:fill="hold" 
smil:attributeName="color" smil:by="hsl(0,-12%,-25%)" 
anim:color-interpolation="hsl" anim:color-interpolation-direction="clockwise"/>
-        <anim:animateColor smil:dur="0.5" smil:fill="hold" 
smil:attributeName="fill-color" smil:by="hsl(0,-12%,-25%)" 
anim:color-interpolation="hsl" anim:color-interpolation-direction="clockwise"/>
-        <anim:animateColor smil:dur="0.5" smil:fill="hold" 
smil:attributeName="stroke-color" smil:by="hsl(0,-12%,-25%)" 
anim:color-interpolation="hsl" anim:color-interpolation-direction="clockwise"/>
+        <anim:animateColor smil:dur="0.5" smil:fill="hold" 
smil:attributeName="color" smil:by="hsl(0,-12%,-25%)" 
anim:color-interpolation="hsl" 
anim:color-interpolation-direction="counterclockwise"/>
+        <anim:animateColor smil:dur="0.5" smil:fill="hold" 
smil:attributeName="fill-color" smil:by="hsl(0,-12%,-25%)" 
anim:color-interpolation="hsl" 
anim:color-interpolation-direction="counterclockwise"/>
+        <anim:animateColor smil:dur="0.5" smil:fill="hold" 
smil:attributeName="stroke-color" smil:by="hsl(0,-12%,-25%)" 
anim:color-interpolation="hsl" 
anim:color-interpolation-direction="counterclockwise"/>
         <anim:set smil:dur="0.5" smil:fill="hold" smil:attributeName="fill" 
smil:to="solid"/>
     </anim:par>
     </anim:par>
@@ -1200,9 +1200,9 @@
     <anim:par smil:begin="indefinite" smil:fill="hold">
     <anim:par smil:begin="0" smil:fill="hold">
     <anim:par smil:begin="0" smil:fill="hold" pres:node-type="on-click" 
pres:preset-class="emphasis" pres:preset-id="ooo-emphasis-lighten">
-        <anim:animateColor smil:dur="0.5" smil:fill="hold" 
smil:attributeName="color" smil:by="hsl(0,12%,25%)" 
anim:color-interpolation="hsl" anim:color-interpolation-direction="clockwise"/>
-        <anim:animateColor smil:dur="0.5" smil:fill="hold" 
smil:attributeName="fill-color" smil:by="hsl(0,12%,25%)" 
anim:color-interpolation="hsl" anim:color-interpolation-direction="clockwise"/>
-        <anim:animateColor smil:dur="0.5" smil:fill="hold" 
smil:attributeName="stroke-color" smil:by="hsl(0,12%,25%)" 
anim:color-interpolation="hsl" anim:color-interpolation-direction="clockwise"/>
+        <anim:animateColor smil:dur="0.5" smil:fill="hold" 
smil:attributeName="color" smil:by="hsl(0,12%,25%)" 
anim:color-interpolation="hsl" 
anim:color-interpolation-direction="counterclockwise"/>
+        <anim:animateColor smil:dur="0.5" smil:fill="hold" 
smil:attributeName="fill-color" smil:by="hsl(0,12%,25%)" 
anim:color-interpolation="hsl" 
anim:color-interpolation-direction="counterclockwise"/>
+        <anim:animateColor smil:dur="0.5" smil:fill="hold" 
smil:attributeName="stroke-color" smil:by="hsl(0,12%,25%)" 
anim:color-interpolation="hsl" 
anim:color-interpolation-direction="counterclockwise"/>
         <anim:set smil:dur="0.5" smil:fill="hold" smil:attributeName="fill" 
smil:to="solid"/>
     </anim:par>
     </anim:par>
commit 978e9607e63c227e2f7fe865af94485a7042531a
Author: Marco Cecchetti <mrcek...@gmail.com>
Date:   Thu Jul 5 16:35:02 2012 +0200

    Bug fix: now repeated animations and begin=’after effect ‘ works 
properly together.
    
    Modified the CustomAnimationEffect class in order to take into account the 
repeatCount
    attribute value when computing the node effect absolute duration.

diff --git a/sd/source/core/CustomAnimationEffect.cxx 
b/sd/source/core/CustomAnimationEffect.cxx
index 16756a5..625376f 100644
--- a/sd/source/core/CustomAnimationEffect.cxx
+++ b/sd/source/core/CustomAnimationEffect.cxx
@@ -281,6 +281,10 @@ void CustomAnimationEffect::setNode( const 
::com::sun::star::uno::Reference< ::c
     }
 
     mfAbsoluteDuration = mfDuration;
+    double fRepeatCount = 1.0;
+    if( (mxNode->getRepeatCount()) >>= fRepeatCount )
+        mfAbsoluteDuration *= fRepeatCount;
+
     checkForText();
 }
 
@@ -755,7 +759,9 @@ void CustomAnimationEffect::setDuration( double fDuration )
     {
         double fScale = fDuration / mfDuration;
         mfDuration = fDuration;
-        mfAbsoluteDuration = mfDuration;
+        double fRepeatCount = 1.0;
+        getRepeatCount() >>= fRepeatCount;
+        mfAbsoluteDuration = mfDuration * fRepeatCount;
 
         // calculate effect duration and get target shape
         Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY 
);
@@ -954,7 +960,12 @@ sal_Int16 CustomAnimationEffect::getFill() const
 void CustomAnimationEffect::setRepeatCount( const Any& rRepeatCount )
 {
     if( mxNode.is() )
+    {
         mxNode->setRepeatCount( rRepeatCount );
+        double fRepeatCount = 1.0;
+        rRepeatCount >>= fRepeatCount;
+        mfAbsoluteDuration = mfDuration * fRepeatCount;
+    }
 }
 
 // --------------------------------------------------------------------
commit 2e91423ace0a4b0051b3b1beb9e1e461378437a4
Author: Marco Cecchetti <mrcek...@gmail.com>
Date:   Thu Jul 5 10:19:47 2012 +0200

    Bug fix: now a clip-based transition works correctly when mode=’out’ 
and reverse method involves flipping.

diff --git a/filter/source/svg/presentation_engine.js 
b/filter/source/svg/presentation_engine.js
index f042263..984eaef 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -7933,8 +7933,10 @@ ClippingFunctor.prototype.perform = function( nT, 
nWidth, nHeight )
 {
     var aClipPoly = this.aParametricPolyPolygon.perform( 
this.bForwardParameterSweep ? nT : (1 - nT) );
 
-    if( this.bFlip )
-        aClipPoly.changeOrientation();
+    // Note: even if the reverse method involves flipping we don't need to
+    // change the clip-poly orientation because we utilize the 'nonzero'
+    // clip-rule.
+    // See: http://www.w3.org/TR/SVG11/painting.html#FillRuleProperty
 
     if( this.bSubtractPolygon )
     {
commit ef43a2a37ce48ae3d41957034b94c6d0463d16df
Author: Marco Cecchetti <mrcek...@gmail.com>
Date:   Wed Jul 4 18:50:46 2012 +0200

    Provided support for rewinding to the previous slide and for skipping / 
rewinding all effects.
    
    The following method of the SlideShow class has been implemented:
    skipAllEffects, rewindToPreviousSlide, rewindAllEffects.
    Commented out the calls to the initAnimatedElement methods for 
ValueListActivity and
    FromToByActivity class as it is the source of a bug.

diff --git a/filter/source/svg/presentation_engine.js 
b/filter/source/svg/presentation_engine.js
index 2e66561..f042263 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -150,13 +150,13 @@ function getDefaultKeyCodeDictionary()
     keyCodeDict[SLIDE_MODE][RIGHT_KEY]
         = function() { return dispatchEffects(1); };
     keyCodeDict[SLIDE_MODE][UP_KEY]
-        = function() { return skipEffects(-1); };
+        = function() { return aSlideShow.rewindEffect(); };
     keyCodeDict[SLIDE_MODE][DOWN_KEY]
         = function() { return skipEffects(1); };
     keyCodeDict[SLIDE_MODE][PAGE_UP_KEY]
-        = function() { return switchSlide( -1, true ); };
+        = function() { return aSlideShow.rewindAllEffects(); };
     keyCodeDict[SLIDE_MODE][PAGE_DOWN_KEY]
-        = function() { return switchSlide( 1, true ); };
+        = function() { return skipAllEffects(); };
     keyCodeDict[SLIDE_MODE][HOME_KEY]
         = function() { return aSlideShow.displaySlide( 0, true ); };
     keyCodeDict[SLIDE_MODE][END_KEY]
@@ -1433,7 +1433,7 @@ var NAVDBG = new DebugPrinter();
 NAVDBG.off();
 
 var ANIMDBG = new DebugPrinter();
-ANIMDBG.off();
+ANIMDBG.on();
 
 var aRegisterEventDebugPrinter = new DebugPrinter();
 aRegisterEventDebugPrinter.off();
@@ -2985,6 +2985,15 @@ function dispatchEffects(dir)
     }
 }
 
+function skipAllEffects()
+{
+    var bRet = aSlideShow.skipAllEffects();
+    if( !bRet )
+    {
+        switchSlide( 1, true );
+    }
+}
+
 function skipEffects(dir)
 {
     if( dir == 1 )
@@ -2993,12 +3002,12 @@ function skipEffects(dir)
 
         if( !bRet )
         {
-            switchSlide( 1, false );
+            switchSlide( 1, true );
         }
     }
     else
     {
-        switchSlide( dir, false );
+        switchSlide( dir, true );
     }
 }
 
@@ -10725,7 +10734,7 @@ function FromToByActivityTemplate( BaseType ) // 
template parameter
         this.nIteration = 0;
         this.bCumulative = bAccumulate;
 
-        this.initAnimatedElement();
+        //this.initAnimatedElement();
 
     }
     extend( FromToByActivity, BaseType );
@@ -10931,7 +10940,7 @@ function  ValueListActivityTemplate( BaseType ) // 
template parameter
         this.bCumulative = bAccumulate;
         this.aLastValue = this.aValueList[ this.aValueList.length - 1 ];
 
-        this.initAnimatedElement();
+        //this.initAnimatedElement();
     }
     extend( ValueListActivity, BaseType );
 
@@ -10943,7 +10952,7 @@ function  ValueListActivityTemplate( BaseType ) // 
template parameter
             ANIMDBG.print( 'createValueListActivity: value[' + i + '] = ' + 
this.aValueList[i] );
         }
 
-        this.initAnimatedElement();
+        //this.initAnimatedElement();
     };
 
     ValueListActivity.prototype.initAnimatedElement = function()
@@ -11283,6 +11292,7 @@ function SlideShow()
     this.bIsEnabled = true;
     this.bIsRewinding = false;
     this.bIsSkipping = false;
+    this.bIsSkippingAll = false;
     this.bNoSlideTransition = false;
 }
 
@@ -11422,30 +11432,6 @@ SlideShow.prototype.skipCurrentEffect = function()
     this.bIsSkipping = false;
 };
 
-/** rewindEffect
- *  Rewind the current playing effect or the last played one.
- *
- */
-SlideShow.prototype.rewindEffect = function()
-{
-    if( this.bIsSkipping || this.bIsRewinding )
-        return true;
-
-    this.bIsRewinding = true;
-    if( this.isRunning() )
-    {
-        this.aEventMultiplexer.notifyRewindCurrentEffectEvent();
-    }
-    else
-    {
-        this.aEventMultiplexer.notifyRewindLastEffectEvent();
-    }
-    if( this.nCurrentEffect > 0 )
-        --this.nCurrentEffect;
-    this.update();
-    this.bIsRewinding = false;
-};
-
 /** skipEffect
  *  Skip the next effect to be played.
  *
@@ -11478,6 +11464,105 @@ SlideShow.prototype.skipEffect = function()
     return true;
 };
 
+/** skipAllEffects
+ *  Skip all left effects on the current slide.
+ *
+ *  @return {Boolean}
+ *      True if it already skipping or when it has ended skipping,
+ *      false if the next slide needs to be displayed.
+ */
+SlideShow.prototype.skipAllEffects = function()
+{
+    if( this.bIsSkippingAll )
+        return true;
+
+    this.bIsSkippingAll = true;
+    if( this.isRunning() )
+    {
+        this.skipCurrentEffect();
+    }
+    else if( !this.aNextEffectEventArray
+               || ( this.nCurrentEffect >= this.aNextEffectEventArray.size() ) 
)
+    {
+        this.bIsSkippingAll = false;
+        return false;
+    }
+
+    // Pay attention here: a new next effect event is appended to
+    // aNextEffectEventArray only after the related animation node has been
+    // resolved, that is only after the animation node related to the previous
+    // effect has notified to be deactivated to the main sequence time 
container.
+    // So you should avoid any optimization here because the size of
+    // aNextEffectEventArray will going on increasing after every skip action.
+    while( this.nCurrentEffect < this.aNextEffectEventArray.size() )
+    {
+        this.skipEffect();
+    }
+    this.bIsSkippingAll = false;
+    return true;
+};
+
+/** rewindEffect
+ *  Rewind the current playing effect or the last played one.
+ *
+ */
+SlideShow.prototype.rewindEffect = function()
+{
+    if( this.bIsSkipping || this.bIsRewinding )
+        return;
+
+    if( this.nCurrentEffect == 0 )
+    {
+        this.rewindToPreviousSlide();
+        return;
+    }
+
+    this.bIsRewinding = true;
+    if( this.isRunning() )
+    {
+        this.aEventMultiplexer.notifyRewindCurrentEffectEvent();
+    }
+    else
+    {
+        this.aEventMultiplexer.notifyRewindLastEffectEvent();
+    }
+    if( this.nCurrentEffect > 0 )
+        --this.nCurrentEffect;
+    this.update();
+    this.bIsRewinding = false;
+};
+
+/** rewindToPreviousSlide
+ *  Displays the previous slide with all effects played.
+ *
+ */
+SlideShow.prototype.rewindToPreviousSlide = function()
+{
+    if( this.isRunning() )
+        return;
+    var nNewSlide = nCurSlide - 1;
+    this.displaySlide( nNewSlide, true );
+    this.skipAllEffects();
+};
+
+/** rewindAllEffects
+ *  Rewind all effects already played on the current slide.
+ *
+ */
+SlideShow.prototype.rewindAllEffects = function()
+{
+    if( this.nCurrentEffect == 0 )
+    {
+        this.rewindToPreviousSlide();
+        return;
+    }
+
+     while( this.nCurrentEffect > 0 )
+     {
+         this.rewindEffect();
+     }
+};
+
 SlideShow.prototype.displaySlide = function( nNewSlide, bSkipSlideTransition )
 {
     var aMetaDoc = theMetaDoc;
commit ecca9699d12a6a24265779668507e9f6d930694c
Author: Marco Cecchetti <mrcek...@gmail.com>
Date:   Tue Jul 3 19:22:34 2012 +0200

    Performed some clean up and added documentation comments.

diff --git a/filter/source/svg/presentation_engine.js 
b/filter/source/svg/presentation_engine.js
index 9b62dd7..2e66561 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -6281,6 +6281,7 @@ BaseContainerNode.prototype.removeEffect = function()
     var nChildrenCount = this.aChildrenArray.length;
     if( nChildrenCount == 0 )
         return;
+    // We remove effect in reverse order.
     for( var i = nChildrenCount - 1; i >= 0; --i )
     {
         if( ( this.aChildrenArray[i].getState() & ( FROZEN_NODE | ENDED_NODE ) 
) == 0 )
@@ -6465,11 +6466,24 @@ SequentialTimeContainer.prototype.notifyDeactivating = 
function( aNotifier )
     }
 };
 
+/** skipEffect
+ *  Skip the current playing shape effect.
+ *  Requires: the current node is the main sequence root node.
+ *
+ *  @param aChildNode
+ *      An animation node representing the root node of the shape effect being
+ *      played.
+ */
 SequentialTimeContainer.prototype.skipEffect = function( aChildNode )
 {
     if( this.isChildNode( aChildNode ) )
     {
+        // First off we end all queued activities.
         this.getContext().aActivityQueue.endAll();
+        // We signal that we are going to skip all subsequent animations by
+        // setting the bIsSkipping flag to 'true', then all queued events are
+        // fired immediately. In such a way the correct order of the various
+        // events that belong to the animation time-line is preserved.
         this.getContext().bIsSkipping = true;
         this.getContext().aTimerEventQueue.forceEmpty();
         this.getContext().bIsSkipping = false;
@@ -6478,63 +6492,122 @@ SequentialTimeContainer.prototype.skipEffect = 
function( aChildNode )
     }
     else
     {
-        log( 'SequentialTimeContainer.skipEffect: unknown child: ' + 
aChildNode.getId() );
+        log( 'SequentialTimeContainer.skipEffect: unknown child: '
+                 + aChildNode.getId() );
     }
 };
 
+/** rewindCurrentEffect
+ *  Rewind a playing shape effect.
+ *  Requires: the current node is the main sequence root node.
+ *
+ *  @param aChildNode
+ *      An animation node representing the root node of the shape effect being
+ *      played
+ */
 SequentialTimeContainer.prototype.rewindCurrentEffect = function( aChildNode )
 {
     if( this.isChildNode( aChildNode ) )
     {
-        assert( !this.bIsRewinding, 
'SequentialTimeContainer.rewindCurrentEffect: is already rewinding.' );
+        assert( !this.bIsRewinding,
+                'SequentialTimeContainer.rewindCurrentEffect: is already 
rewinding.' );
 
+        // We signal we are rewinding so the notifyDeactivating method returns
+        // immediately without increment the finished children counter and
+        // resolve the next child.
         this.bIsRewinding = true;
+        // First off we end all queued activities.
         this.getContext().aActivityQueue.endAll();
+        // We signal that we are going to skip all subsequent animations by
+        // setting the bIsSkipping flag to 'true', then all queued events are
+        // fired immediately. In such a way the correct order of the various
+        // events that belong to the animation time-line is preserved.
         this.getContext().bIsSkipping = true;
         this.getContext().aTimerEventQueue.forceEmpty();
         this.getContext().bIsSkipping = false;
+        // We end all new activities appended to the activity queue by
+        // the fired events.
         this.getContext().aActivityQueue.endAll();
 
+        // Now we perform a final 'end' and restore the animated shape to
+        // the state it was before the current effect was applied.
         aChildNode.end();
         aChildNode.removeEffect();
+        // Finally we place the child node to the 'unresolved' state and
+        // resolve it again.
         aChildNode.init();
         this.resolveChild( aChildNode );
         this.bIsRewinding = false;
     }
     else
     {
-        log( 'SequentialTimeContainer.rewindCurrentEffect: unknown child: ' + 
aChildNode.getId() );
+        log( 'SequentialTimeContainer.rewindCurrentEffect: unknown child: '
+                 + aChildNode.getId() );
     }
 };
 
+/** rewindLastEffect
+ *  Rewind the last ended effect.
+ *  Requires: the current node is the main sequence root node.
+ *
+ *  @param aChildNode
+ *      An animation node representing the root node of the next shape effect
+ *      to be played.
+ */
 SequentialTimeContainer.prototype.rewindLastEffect = function( aChildNode )
 {
     if( this.isChildNode( aChildNode ) )
     {
-        assert( !this.bIsRewinding, 'SequentialTimeContainer.rewindLastEffect: 
is already rewinding.' );
+        assert( !this.bIsRewinding,
+                'SequentialTimeContainer.rewindLastEffect: is already 
rewinding.' );
 
+        // We signal we are rewinding so the notifyDeactivating method returns
+        // immediately without increment the finished children counter and
+        // resolve the next child.
         this.bIsRewinding = true;
+        // We end the current effect and remove any change it applies on the
+        // animated shape.
         this.getContext().aTimerEventQueue.forceEmpty();
         this.getContext().aActivityQueue.clear();
-
         aChildNode.end();
         aChildNode.removeEffect();
+
+        // As we rewind the previous effect we need to decrease the finished
+        // children counter.
         --this.nFinishedChildren;
         var aPreviousChildNode = this.aChildrenArray[ this.nFinishedChildren ];
+        // No need to invoke the end method for the previous child as it is
+        // already in the ENDED state.
+
         aPreviousChildNode.removeEffect();
+        // We place the child node to the 'unresolved' state.
         aPreviousChildNode.init();
-        // We need to re-initialize it too, because it is in state ENDED now,
-        // and cannot be resolved again later.
+        // We need to re-initialize the old current child too, because it is
+        // in ENDED state now, On the contrary it cannot be resolved again 
later.
         aChildNode.init();
         this.resolveChild( aPreviousChildNode );
         this.bIsRewinding = false;
     }
     else
     {
-        log( 'SequentialTimeContainer.rewindLastEffect: unknown child: ' + 
aChildNode.getId() );
+        log( 'SequentialTimeContainer.rewindLastEffect: unknown child: '
+                 + aChildNode.getId() );
     }
 };
 
+/** resolveChild
+ *  Resolve the passed child.
+ *  In case this node is a main sequence root node events for skipping and
+ *  rewinding the effect related to the passed child node are created and
+ *  registered.
+ *
+ *  @param aChildNode
+ *      An animation node representing the root node of the next shape effect
+ *      to be played.
+ *  @return
+ *      It returns true if the passed child has been resolved successfully,
+ *      false otherwise.
+ */
 SequentialTimeContainer.prototype.resolveChild = function( aChildNode )
 {
     var bResolved = aChildNode.resolve();
@@ -6551,7 +6624,7 @@ SequentialTimeContainer.prototype.resolveChild = 
function( aChildNode )
             this.aRewindCurrentEffectEvent.dispose();
 
         this.aRewindCurrentEffectEvent = makeEvent( bind2( 
SequentialTimeContainer.prototype.rewindCurrentEffect, this, aChildNode ) );
-        this.aContext.aEventMultiplexer.registerRewindEffectEvent( 
this.aRewindCurrentEffectEvent );
+        this.aContext.aEventMultiplexer.registerRewindCurrentEffectEvent( 
this.aRewindCurrentEffectEvent );
 
         if( this.aRewindLastEffectEvent )
             this.aRewindLastEffectEvent.dispose();
@@ -8529,11 +8602,6 @@ AnimatedElement.prototype.getId = function()
     return this.aActiveElement.getAttribute( 'id' );
 };
 
-AnimatedElement.prototype.isUpdated = function()
-{
-    return this.bIsUpdated;
-};
-
 AnimatedElement.prototype.getAdditiveMode = function()
 {
     return this.eAdditiveMode;
@@ -8571,8 +8639,7 @@ AnimatedElement.prototype.notifySlideStart = function()
 
 AnimatedElement.prototype.notifyAnimationStart = function()
 {
-    this.DBG( '.notifyAnimationStart invoked' );
-    this.bIsUpdated = false;
+    // empty body
 };
 
 AnimatedElement.prototype.notifyAnimationEnd = function()
@@ -8582,28 +8649,16 @@ AnimatedElement.prototype.notifyAnimationEnd = 
function()
 
 AnimatedElement.prototype.notifyNextEffectStart = function( nEffectIndex )
 {
-//    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;
+    // empty body
 };
 
+/** saveState
+ *  Save the state of the managed animated element and append it to aStateSet
+ *  using the passed animation node id as key.
+ *
+ *  @param nAnimationNodeId
+ *      A non negative integer representing the unique id of an animation node.
+ */
 AnimatedElement.prototype.saveState = function( nAnimationNodeId )
 {
     ANIMDBG.print( 'AnimatedElement(' + this.getId() + ').saveState(' + 
nAnimationNodeId +')' );
@@ -8620,6 +8675,16 @@ AnimatedElement.prototype.saveState = function( 
nAnimationNodeId )
 
 };
 
+/** restoreState
+ *  Restore the state of the managed animated element to the state with key
+ *  the passed animation node id.
+ *
+ *  @param nAnimationNodeId
+ *      A non negative integer representing the unique id of an animation node.
+ *
+ *  @return
+ *      True if the restoring operation is successful, false otherwise.
+ */
 AnimatedElement.prototype.restoreState = function( nAnimationNodeId )
 {
     if( !this.aStateSet[ nAnimationNodeId ] )
@@ -9676,7 +9741,7 @@ function EventMultiplexer( aTimerEventQueue )
     this.aTimerEventQueue = aTimerEventQueue;
     this.aEventMap = new Object();
     this.aSkipEffectEvent = null;
-    this.aRewindEffectEvent = null;
+    this.aRewindCurrentEffectEvent = null;
     this.aRewindLastEffectEvent = null;
 }
 
@@ -9727,17 +9792,17 @@ EventMultiplexer.prototype.notifySkipEffectEvent = 
function()
     }
 };
 
-EventMultiplexer.prototype.registerRewindEffectEvent = function( aEvent )
+EventMultiplexer.prototype.registerRewindCurrentEffectEvent = function( aEvent 
)
 {
-    this.aRewindEffectEvent = aEvent;
+    this.aRewindCurrentEffectEvent = aEvent;
 };
 
-EventMultiplexer.prototype.notifyRewindEffectEvent = function()
+EventMultiplexer.prototype.notifyRewindCurrentEffectEvent = function()
 {
-    if( this.aRewindEffectEvent )
+    if( this.aRewindCurrentEffectEvent )
     {
-        this.aTimerEventQueue.addEvent( this.aRewindEffectEvent );
-        this.aRewindEffectEvent = null;
+        this.aTimerEventQueue.addEvent( this.aRewindCurrentEffectEvent );
+        this.aRewindCurrentEffectEvent = null;
     }
 };
 
@@ -11342,6 +11407,10 @@ SlideShow.prototype.nextEffect = function()
     return true;
 };
 
+/** skipCurrentEffect
+ *  Skip the current playing effect.
+ *
+ */
 SlideShow.prototype.skipCurrentEffect = function()
 {
     if( this.bIsSkipping || this.bIsRewinding )
@@ -11353,6 +11422,10 @@ SlideShow.prototype.skipCurrentEffect = function()
     this.bIsSkipping = false;
 };
 
+/** rewindEffect
+ *  Rewind the current playing effect or the last played one.
+ *
+ */
 SlideShow.prototype.rewindEffect = function()
 {
     if( this.bIsSkipping || this.bIsRewinding )
@@ -11361,17 +11434,22 @@ SlideShow.prototype.rewindEffect = function()
     this.bIsRewinding = true;
     if( this.isRunning() )
     {
-        this.aEventMultiplexer.notifyRewindEffectEvent();
+        this.aEventMultiplexer.notifyRewindCurrentEffectEvent();
     }
     else
     {
         this.aEventMultiplexer.notifyRewindLastEffectEvent();
     }
-    --this.nCurrentEffect;
+    if( this.nCurrentEffect > 0 )
+        --this.nCurrentEffect;
     this.update();
     this.bIsRewinding = false;
 };
 
+/** skipEffect
+ *  Skip the next effect to be played.
+ *
+ */
 SlideShow.prototype.skipEffect = function()
 {
     if( this.bIsSkipping || this.bIsRewinding )
@@ -11400,16 +11478,6 @@ SlideShow.prototype.skipEffect = function()
     return true;
 };
 
-//SlideShow.prototype.previousEffect = function()
-//{
-//    if( this.nCurrentEffect <= 0 )
-//        return false;
-//    this.eDirection = BACKWARD;
-//    this.aNextEffectEventArray.at( this.nCurrentEffect ).fire();
-//    --this.nCurrentEffect;
-//    return true;
-//};
-
 SlideShow.prototype.displaySlide = function( nNewSlide, bSkipSlideTransition )
 {
     var aMetaDoc = theMetaDoc;
commit 12a52aaeecd60df958f75323ae9ca7684486e1ed
Author: Marco Cecchetti <mrcek...@gmail.com>
Date:   Tue Jul 3 15:39:32 2012 +0200

    Changed the rewindCurrentEffect method.
    
    The change was needed because rewinding a playing shape transition effect 
based on
    a clip-path doesn’t work properly on Firefox and Internet Explorer.

diff --git a/filter/source/svg/presentation_engine.js 
b/filter/source/svg/presentation_engine.js
index d705658..9b62dd7 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -6489,8 +6489,11 @@ SequentialTimeContainer.prototype.rewindCurrentEffect = 
function( aChildNode )
         assert( !this.bIsRewinding, 
'SequentialTimeContainer.rewindCurrentEffect: is already rewinding.' );
 
         this.bIsRewinding = true;
+        this.getContext().aActivityQueue.endAll();
+        this.getContext().bIsSkipping = true;
         this.getContext().aTimerEventQueue.forceEmpty();
-        this.getContext().aActivityQueue.clear();
+        this.getContext().bIsSkipping = false;
+        this.getContext().aActivityQueue.endAll();
 
         aChildNode.end();
         aChildNode.removeEffect();
commit d501d66a69340869227f2051b912614b04799d2c
Author: Marco Cecchetti <mrcek...@gmail.com>
Date:   Mon Jul 2 23:36:35 2012 +0200

    Skipping a single effect works in JavaScript even if the effect is rewinded 
(fill=remove).
    
    Added a bIsSkipping flag to the SlideShowContext class and modified the 
activate_st method
    of the AnimationBaseNode class. Now when we are skipping the managed 
activity is
    not appended to the activity class but the end method is executed 
immediately.
    In such a way the correct order of the various events that belong to the 
animation time-line
    is preserved.

diff --git a/filter/source/svg/presentation_engine.js 
b/filter/source/svg/presentation_engine.js
index c71cad6..d705658 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -5745,7 +5745,14 @@ AnimationBaseNode.prototype.activate_st = function()
     {
         this.saveStateOfAnimatedElement();
         this.aActivity.setTargets( this.getAnimatedElement() );
-        this.getContext().aActivityQueue.addActivity( this.aActivity );
+        if( this.getContext().bIsSkipping  )
+        {
+            this.aActivity.end();
+        }
+        else
+        {
+            this.getContext().aActivityQueue.addActivity( this.aActivity );
+        }
     }
     else
     {
@@ -5821,8 +5828,7 @@ AnimationBaseNode.prototype.saveStateOfAnimatedElement = 
function()
 
 AnimationBaseNode.prototype.removeEffect = function()
 {
-    log( 'AnimationBaseNode.removeEffect invoked' );
-    this.getAnimatedElement().setTo( this.getId() );
+    this.getAnimatedElement().restoreState( this.getId() );
 };
 
 AnimationBaseNode.prototype.getTargetElement = function()
@@ -6175,7 +6181,7 @@ 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 );
+            this.removeEffect();
     }
 };
 
@@ -6277,8 +6283,14 @@ BaseContainerNode.prototype.removeEffect = function()
         return;
     for( var i = nChildrenCount - 1; i >= 0; --i )
     {
-        if( ( this.aChildrenArray[i].getState() & FROZEN_NODE | ENDED_NODE ) 
== 0 )
+        if( ( this.aChildrenArray[i].getState() & ( FROZEN_NODE | ENDED_NODE ) 
) == 0 )
+        {
+            log( 'BaseContainerNode.removeEffect: child(id:'
+                 + this.aChildrenArray[i].getId() + ') is neither frozen nor 
ended;'
+                 + ' state: '
+                 + aTransitionModeOutMap[ this.aChildrenArray[i].getState() ] 
);
             continue;
+        }
         this.aChildrenArray[i].removeEffect();
     }
 };
@@ -6458,7 +6470,9 @@ SequentialTimeContainer.prototype.skipEffect = function( 
aChildNode )
     if( this.isChildNode( aChildNode ) )
     {
         this.getContext().aActivityQueue.endAll();
+        this.getContext().bIsSkipping = true;
         this.getContext().aTimerEventQueue.forceEmpty();
+        this.getContext().bIsSkipping = false;
         var aEvent = makeEvent( bind2( aChildNode.deactivate, aChildNode ) );
         this.getContext().aTimerEventQueue.addEvent( aEvent );
     }
@@ -8589,6 +8603,7 @@ AnimatedElement.prototype.notifyNextEffectStart = 
function( nEffectIndex )
 
 AnimatedElement.prototype.saveState = function( nAnimationNodeId )
 {
+    ANIMDBG.print( 'AnimatedElement(' + this.getId() + ').saveState(' + 
nAnimationNodeId +')' );
     if( !this.aStateSet[ nAnimationNodeId ] )
     {
         this.aStateSet[ nAnimationNodeId ] = new Object();
@@ -8602,15 +8617,17 @@ AnimatedElement.prototype.saveState = function( 
nAnimationNodeId )
 
 };
 
-AnimatedElement.prototype.setTo = function( nAnimationNodeId )
+AnimatedElement.prototype.restoreState = function( nAnimationNodeId )
 {
     if( !this.aStateSet[ nAnimationNodeId ] )
     {
-        log( 'AnimatedElement(' + this.getId() + ').setTo: state '
+        log( 'AnimatedElement(' + this.getId() + ').restoreState: state '
                  +nAnimationNodeId  + ' is not valid' );
         return false;
     }
 
+    ANIMDBG.print( 'AnimatedElement(' + this.getId() + ').restoreState(' + 
nAnimationNodeId +')' );
+
     var aState = this.aStateSet[ nAnimationNodeId ];
     var bRet = this.setToElement( aState.aElement );
     if( bRet )
@@ -11196,8 +11213,8 @@ function SlideShow()
     this.eDirection = FORWARD;
     this.bIsIdle = true;
     this.bIsEnabled = true;
-    this.bIsSkipping = false;
     this.bIsRewinding = false;
+    this.bIsSkipping = false;
     this.bNoSlideTransition = false;
 }
 
@@ -11548,6 +11565,7 @@ function SlideShowContext( aTimerEventQueue, 
aEventMultiplexer, aNextEffectEvent
     this.aEventMultiplexer = aEventMultiplexer;
     this.aNextEffectEventArray = aNextEffectEventArray;
     this.aActivityQueue = aActivityQueue;
+    this.bIsSkipping = false;
 }
 
 
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to