diff options
author | Marco Cecchetti <mrcekets@gmail.com> | 2012-05-31 21:45:13 +0200 |
---|---|---|
committer | Marco Cecchetti <mrcekets@gmail.com> | 2012-06-15 10:14:59 +0200 |
commit | a962bffa18e81032423e1c5c7065125d27caa163 (patch) | |
tree | 9cff760042fa27c962d3d7860292b8c8490c018c /filter | |
parent | a4f7622bcc32b14811f3969dcd073f79560b3967 (diff) |
Enabled support for fade, slide wipe and push wipe slide transitions.
Ported or implemented the following classes: SlideTransition,
AnimatedSlide, SlideChangeBase, FadingSlideChange,
FadingOverColorSlideChange, MovingSlideChange.
Modified and added new methods to: MetaSlide, SlideShow.
Diffstat (limited to 'filter')
-rw-r--r-- | filter/source/svg/presentation_engine.js | 1135 | ||||
-rw-r--r-- | filter/source/svg/svgexport.cxx | 14 |
2 files changed, 1092 insertions, 57 deletions
diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js index 53ab74782963..7b17623cba90 100644 --- a/filter/source/svg/presentation_engine.js +++ b/filter/source/svg/presentation_engine.js @@ -635,6 +635,7 @@ var aOOOAttrNumberingType = 'page-numbering-type'; var aOOOAttrSlide = 'slide'; var aOOOAttrMaster = 'master'; +var aOOOAttrHasTransition = 'has-transition'; var aOOOAttrBackgroundVisibility = 'background-visibility'; var aOOOAttrMasterObjectsVisibility = 'master-objects-visibility'; var aOOOAttrPageNumberVisibility = 'page-number-visibility'; @@ -1194,6 +1195,16 @@ function MetaSlide( sMetaSlideId, aMetaDoc ) this.aTextFieldContentProviderSet[aFooterClassName] = this.initFixedTextFieldContentProvider( aOOOAttrFooterField ); this.aTextFieldContentProviderSet[aHeaderClassName] = this.initFixedTextFieldContentProvider( aOOOAttrHeaderField ); + // We look for slide transition. + this.aTransitionHandler = null; + this.bHasTransition = this.initHasTransition() || true; + if( this.bHasTransition ) + { + this.aTransitionHandler = new SlideTransition( this.getSlideAnimationsRoot(), this.slideId ); + if( this.aTransitionHandler.isValid() ) + log( this.aTransitionHandler.info() ); + } + // We initialize the SlideAnimationsHandler object this.aSlideAnimationsHandler = new SlideAnimations( aSlideShow.getContext() ); this.aSlideAnimationsHandler.importAnimations( this.getSlideAnimationsRoot() ); @@ -1210,7 +1221,8 @@ MetaSlide.prototype = /*** public methods ***/ /** show - * Set the visibility property of the slide to 'inherit'. + * Set the visibility property of the slide to 'inherit' + * and update the master page view. */ show : function() { @@ -1261,6 +1273,12 @@ initMasterPage : function() return this.theMetaDoc.aMasterPageSet[ sMasterPageId ]; }, +initHasTransition : function() +{ + var sHasTransition = this.element.getAttributeNS( NSS['ooo'], aOOOAttrHasTransition ); + return ( sHasTransition === 'true' ); +}, + initVisibilityProperty : function( aVisibilityAttribute, nDefaultValue ) { var nVisibility = nDefaultValue; @@ -1596,6 +1614,15 @@ MasterPageView.prototype.createElement = function() 'MasterPageView.createElement: failed to create a master page view element.' ); aMasterPageViewElement.setAttribute( 'class', 'MasterPageView' ); + // we place a white rect below any else element + // that is also a workaround for some kind of slide transition + // when the master page is empty + var aWhiteRect = theDocument.createElementNS( NSS['svg'], 'rect' ); + aWhiteRect.setAttribute( 'width', String( WIDTH ) ); + aWhiteRect.setAttribute( 'height', String( HEIGHT) ); + aWhiteRect.setAttribute( 'fill', '#FFFFFF' ); + aMasterPageViewElement.appendChild( aWhiteRect ); + // init the Background element if( this.aMetaSlide.nIsBackgroundVisible ) { @@ -2491,7 +2518,7 @@ function dispatchEffects(dir) function skipEffects(dir) { // TODO to be implemented - switchSlide(dir); + switchSlide(dir, true); } function switchSlide( nOffset, bSkipTransition ) @@ -2616,6 +2643,67 @@ function bind( aObject, aMethod ) }; } +function bind2( aFunction ) +{ + var aBoundArgList = arguments; + + var aResultFunction = null; + + switch( aBoundArgList.length ) + { + case 1: aResultFunction = function() + { + return aFunction.call( arguments[0], arguments[1], + arguments[2], arguments[3], + arguments[4] ); + }; + break; + case 2: aResultFunction = function() + { + return aFunction.call( aBoundArgList[1], arguments[0], + arguments[1], arguments[2], + arguments[3] ); + }; + break; + case 3: aResultFunction = function() + { + return aFunction.call( aBoundArgList[1], aBoundArgList[2], + arguments[0], arguments[1], + arguments[2] ); + }; + break; + case 4: aResultFunction = function() + { + return aFunction.call( aBoundArgList[1], aBoundArgList[2], + aBoundArgList[3], arguments[0], + arguments[1] ); + }; + break; + case 5: aResultFunction = function() + { + return aFunction.call( aBoundArgList[1], aBoundArgList[2], + aBoundArgList[3], aBoundArgList[4], + arguments[0] ); + }; + break; + default: + log( 'bind2: arity not handled.' ); + } + + return aResultFunction; +} + +//function concat3( s1, s2, s3 ) +//{ +// log( s1 + s2 + s3 ); +//} +// +//var bound1 = bind2( concat3, 'Qui' ); +//bound1( 'Quo', 'Qua' ); +// +//var bound2 = bind2( concat3, 'Qui', 'Quo' ); +//bound2( 'Qua' ); + function getCurrentSystemTime() { return ( new Date() ).getTime(); @@ -3333,31 +3421,59 @@ var aAttributeMap = }; +// Transition Classes +TRANSITION_INVALID = 0; // Invalid type +TRANSITION_CLIP_POLYPOLYGON = 1; // Transition expressed by parametric clip polygon +TRANSITION_SPECIAL = 2; // Transition expressed by hand-crafted function + +aTransitionClassOutMap = ['invalid', 'clip polypolygon', 'special']; + + // Transition Types BARWIPE_TRANSITION = 1; -FADE_TRANSITION = 2; // 37 +PUSHWIPE_TRANSITION = 2; // 35 +SLIDEWIPE_TRANSITION = 3; // 36 +FADE_TRANSITION = 4; // 37 aTransitionTypeInMap = { 'barWipe' : BARWIPE_TRANSITION, + 'pushWipe' : PUSHWIPE_TRANSITION, + 'slideWipe' : SLIDEWIPE_TRANSITION, 'fade' : FADE_TRANSITION }; -aTransitionTypeOutMap = [ '', 'barWipe', 'fade' ]; +aTransitionTypeOutMap = [ '', 'barWipe', 'pushWipe', 'slideWipe', 'fade' ]; // Transition Subtypes DEFAULT_TRANS_SUBTYPE = 0; LEFTTORIGHT_TRANS_SUBTYPE = 1; TOPTOBOTTOM_TRANS_SUBTYPE = 2; -CROSSFADE_TRANS_SUBTYPE = 3; // 101 +FROMLEFT_TRANS_SUBTYPE = 3; // 97 +FROMTOP_TRANS_SUBTYPE = 4; +FROMRIGHT_TRANS_SUBTYPE = 5; +FROMBOTTOM_TRANS_SUBTYPE = 6 +CROSSFADE_TRANS_SUBTYPE = 7; +FADETOCOLOR_TRANS_SUBTYPE = 8; +FADEFROMCOLOR_TRANS_SUBTYPE = 9; +FADEOVERCOLOR_TRANS_SUBTYPE = 10; // 104 aTransitionSubtypeInMap = { 'leftToRight' : LEFTTORIGHT_TRANS_SUBTYPE, 'topToBottom' : TOPTOBOTTOM_TRANS_SUBTYPE, - 'crossfade' : CROSSFADE_TRANS_SUBTYPE + 'fromLeft' : FROMLEFT_TRANS_SUBTYPE, + 'fromTop' : FROMTOP_TRANS_SUBTYPE, + 'fromRight' : FROMRIGHT_TRANS_SUBTYPE, + 'fromBottom' : FROMBOTTOM_TRANS_SUBTYPE, + 'crossfade' : CROSSFADE_TRANS_SUBTYPE, + 'fadeToColor' : FADETOCOLOR_TRANS_SUBTYPE, + 'fadeFromColor' : FADEFROMCOLOR_TRANS_SUBTYPE, + 'fadeOverColor' : FADEOVERCOLOR_TRANS_SUBTYPE }; -aTransitionSubtypeOutMap = [ 'default', 'leftToRight', 'topToBottom', 'crossfade' ]; +aTransitionSubtypeOutMap = [ 'default', 'leftToRight', 'topToBottom', 'fromLeft', + 'fromTop', 'fromRight', 'fromBottom', 'crossfade', + 'fadeToColor', 'fadeFromColor', 'fadeOverColor' ]; // Transition Modes @@ -3368,6 +3484,116 @@ aTransitionModeInMap = { 'out': TRANSITION_MODE_OUT, 'in': TRANSITION_MODE_IN }; aTransitionModeOutMap = [ 'out', 'in' ]; +// Transition Reverse Methods + +// Ignore direction attribute altogether. +// (If it has no sensible meaning for this transition.) +REVERSEMETHOD_IGNORE = 0; +// Revert by changing the direction of the parameter sweep. +// (From 1->0 instead of 0->1) +REVERSEMETHOD_INVERT_SWEEP = 1; +// Revert by subtracting the generated polygon from the target bound rect. +REVERSEMETHOD_SUBTRACT_POLYGON = 2; +// Combination of REVERSEMETHOD_INVERT_SWEEP and REVERSEMETHOD_SUBTRACT_POLYGON. +REVERSEMETHOD_SUBTRACT_AND_INVERT = 3; +// Reverse by rotating polygon 180 degrees. +REVERSEMETHOD_ROTATE_180 = 4; +// Reverse by flipping polygon at the y axis. +REVERSEMETHOD_FLIP_X = 5; +// Reverse by flipping polygon at the x axis. +REVERSEMETHOD_FLIP_Y = 6; + +aReverseMethodOutMap = ['ignore', 'invert sweep', 'subtract polygon', + 'subtract and invert', 'rotate 180', 'flip x', 'flip y']; + +// ------------------------------------------------------------------------------------------ // +// Transition filter info table + +var aTransitionInfoTable = {}; + +// type: fake transition +aTransitionInfoTable[0] = {}; +// subtype: default +aTransitionInfoTable[0][0] = +{ + 'class' : TRANSITION_INVALID, + 'rotationAngle' : 0.0, + 'scaleX' : 0.0, + 'scaleY' : 0.0, + 'reverseMethod' : REVERSEMETHOD_IGNORE, + 'outInvertsSweep' : false, + 'scaleIsotropically' : false +}; + + +aTransitionInfoTable[BARWIPE_TRANSITION] = {}; +aTransitionInfoTable[BARWIPE_TRANSITION][LEFTTORIGHT_TRANS_SUBTYPE] = +{ + 'class' : TRANSITION_CLIP_POLYPOLYGON, + 'rotationAngle' : 0.0, + 'scaleX' : 1.0, + 'scaleY' : 1.0, + 'reverseMethod' : REVERSEMETHOD_FLIP_X, + 'outInvertsSweep' : false, + 'scaleIsotropically' : false +}; +aTransitionInfoTable[BARWIPE_TRANSITION][TOPTOBOTTOM_TRANS_SUBTYPE] = +{ + 'class' : TRANSITION_CLIP_POLYPOLYGON, + 'rotationAngle' : 90.0, + 'scaleX' : 1.0, + 'scaleY' : 1.0, + 'reverseMethod' : REVERSEMETHOD_FLIP_Y, + 'outInvertsSweep' : false, + 'scaleIsotropically' : false +}; + +aTransitionInfoTable[PUSHWIPE_TRANSITION] = {}; +aTransitionInfoTable[PUSHWIPE_TRANSITION][FROMLEFT_TRANS_SUBTYPE] = +aTransitionInfoTable[PUSHWIPE_TRANSITION][FROMTOP_TRANS_SUBTYPE] = +aTransitionInfoTable[PUSHWIPE_TRANSITION][FROMRIGHT_TRANS_SUBTYPE] = +aTransitionInfoTable[PUSHWIPE_TRANSITION][FROMBOTTOM_TRANS_SUBTYPE] = +{ + 'class' : TRANSITION_SPECIAL, + 'rotationAngle' : 0.0, + 'scaleX' : 1.0, + 'scaleY' : 1.0, + 'reverseMethod' : REVERSEMETHOD_IGNORE, + 'outInvertsSweep' : true, + 'scaleIsotropically' : false +}; + +aTransitionInfoTable[SLIDEWIPE_TRANSITION] = {}; +aTransitionInfoTable[SLIDEWIPE_TRANSITION][FROMLEFT_TRANS_SUBTYPE] = +aTransitionInfoTable[SLIDEWIPE_TRANSITION][FROMTOP_TRANS_SUBTYPE] = +aTransitionInfoTable[SLIDEWIPE_TRANSITION][FROMRIGHT_TRANS_SUBTYPE] = +aTransitionInfoTable[SLIDEWIPE_TRANSITION][FROMBOTTOM_TRANS_SUBTYPE] = +{ + 'class' : TRANSITION_SPECIAL, + 'rotationAngle' : 0.0, + 'scaleX' : 1.0, + 'scaleY' : 1.0, + 'reverseMethod' : REVERSEMETHOD_IGNORE, + 'outInvertsSweep' : true, + 'scaleIsotropically' : false +}; + +aTransitionInfoTable[FADE_TRANSITION] = {}; +aTransitionInfoTable[FADE_TRANSITION][CROSSFADE_TRANS_SUBTYPE] = +aTransitionInfoTable[FADE_TRANSITION][FADETOCOLOR_TRANS_SUBTYPE] = +aTransitionInfoTable[FADE_TRANSITION][FADEFROMCOLOR_TRANS_SUBTYPE] = +aTransitionInfoTable[FADE_TRANSITION][FADEOVERCOLOR_TRANS_SUBTYPE] = +{ + 'class' : TRANSITION_SPECIAL, + 'rotationAngle' : 0.0, + 'scaleX' : 1.0, + 'scaleY' : 1.0, + 'reverseMethod' : REVERSEMETHOD_IGNORE, + 'outInvertsSweep' : true, + 'scaleIsotropically' : false +}; + + // ------------------------------------------------------------------------------------------ // // Transition tables @@ -5847,6 +6073,453 @@ HSLAnimationWrapper.prototype.getUnderlyingValue = function() // ------------------------------------------------------------------------------------------ // +/** Class SlideChangeBase + * The base abstract class of classes performing slide transitions. + * + * @param aLeavingSlide + * An object of type AnimatedSlide handling the leaving slide. + * @param aEnteringSlide + * An object of type AnimatedSlide handling the entering slide. + */ +function SlideChangeBase(aLeavingSlide, aEnteringSlide) +{ + this.aLeavingSlide = aLeavingSlide; + this.aEnteringSlide = aEnteringSlide; + this.bIsFinished = false; +} + +/** start + * The transition initialization is performed here. + */ +SlideChangeBase.prototype.start = function() +{ + if( this.bIsFinished ) + return; +}; + +/** start + * The transition clean up is performed here. + */ +SlideChangeBase.prototype.end = function() +{ + if( this.bIsFinished ) + return; + + this.aLeavingSlide.hide(); + this.aEnteringSlide.reset(); + this.aLeavingSlide.reset(); + + this.bIsFinished = true; +}; + +/** perform + * This method is responsible for performing the slide transition. + * + * @param nValue + * The time parameter. + * @return {Boolean} + * If the transition is performed returns tue else returns false. + */ +SlideChangeBase.prototype.perform = function( nValue ) +{ + if( this.bIsFinished ) return false; + + if( this.aLeavingSlide ) + this.performOut( nValue ); + + if( this.aEnteringSlide ) + this.performIn( nValue ); + + return true; +}; + +SlideChangeBase.prototype.getUnderlyingValue = function() +{ + return 0.0; +}; + +SlideChangeBase.prototype.performIn = function( nValue ) +{ + log( 'SlideChangeBase.performIn: abstract method called' ); +}; + +SlideChangeBase.prototype.performOut = function( nValue ) +{ + log( 'SlideChangeBase.performOut: abstract method called' ); +}; + + + +// ------------------------------------------------------------------------------------------ // +/** Class FadingSlideChange + * This class performs a slide transition by fading out the leaving slide and + * fading in the entering slide. + * + * @param aLeavingSlide + * An object of type AnimatedSlide handling the leaving slide. + * @param aEnteringSlide + * An object of type AnimatedSlide handling the entering slide. + */ +function FadingSlideChange( aLeavingSlide, aEnteringSlide ) +{ + FadingSlideChange.superclass.constructor.call( this, aLeavingSlide, aEnteringSlide ); + this.bFirstRun = true; +} +extend( FadingSlideChange, SlideChangeBase ); + +/** start + * This method notifies to the slides involved in the transition the attributes + * appended to the slide elements for performing the animation. + * Moreover it sets the entering slide in the initial state and makes the slide + * visible. + */ +FadingSlideChange.prototype.start = function() +{ + FadingSlideChange.superclass.start.call( this ); + this.aEnteringSlide.notifyUsedAttribute( 'opacity' ); + this.aLeavingSlide.notifyUsedAttribute( 'opacity' ); + this.aEnteringSlide.setOpacity( 0.0 ); + this.aEnteringSlide.show(); +}; + +/** performIn + * This method set the opacity of the entering slide according to the passed + * time value. + * + * @param nT + * The time parameter. + */ +FadingSlideChange.prototype.performIn = function( nT ) +{ + this.aEnteringSlide.setOpacity( nT ); +}; + +/** performOut + * This method set the opacity of the leaving slide according to the passed + * time value. + * + * @param nT + * The time parameter. + */ +FadingSlideChange.prototype.performOut = function( nT ) +{ + + this.aLeavingSlide.setOpacity( 1 - nT ); +}; + + + +// ------------------------------------------------------------------------------------------ // +/** Class FadingOverColorSlideChange + * This class performs a slide transition by fading out the leaving slide to + * a given color and fading in the entering slide from the same color. + * + * @param aLeavingSlide + * An object of type AnimatedSlide handling the leaving slide. + * @param aEnteringSlide + * An object of type AnimatedSlide handling the entering slide. + * @param sFadeColor + * A string representing the color the leaving slide fades out to and + * the entering slide fade in from. + */ +function FadingOverColorSlideChange( aLeavingSlide, aEnteringSlide, sFadeColor ) +{ + FadingSlideChange.superclass.constructor.call( this, aLeavingSlide, aEnteringSlide ); + this.sFadeColor = sFadeColor; + if( !this.sFadeColor ) + { + log( 'FadingOverColorSlideChange: sFadeColor not valid.' ); + this.sFadeColor = '#000000'; + } + this.aColorPlaneElement = this.createColorPlaneElement(); +} +extend( FadingOverColorSlideChange, SlideChangeBase ); + +/** start + * This method notifies to the slides involved in the transition the attributes + * appended to the slide elements for performing the animation. + * Moreover it inserts the color plane element below the leaving slide. + * Finally it sets the entering slide in the initial state and makes + * the slide visible. + */ +FadingOverColorSlideChange.prototype.start = function() +{ + FadingOverColorSlideChange.superclass.start.call( this ); + this.aEnteringSlide.notifyUsedAttribute( 'opacity' ); + this.aLeavingSlide.notifyUsedAttribute( 'opacity' ); + this.aLeavingSlide.insertBefore( this.aColorPlaneElement ); + this.aEnteringSlide.setOpacity( 0.0 ); + this.aEnteringSlide.show(); +}; + +/** end + * This method removes the color plane element. + */ +FadingOverColorSlideChange.prototype.end = function() +{ + FadingOverColorSlideChange.superclass.end.call( this ); + this.aLeavingSlide.removeElement( this.aColorPlaneElement ); +}; + +/** performIn + * This method set the opacity of the entering slide according to the passed + * time value. + * + * @param nT + * The time parameter. + */ +FadingOverColorSlideChange.prototype.performIn = function( nT ) +{ + this.aEnteringSlide.setOpacity( (nT > 0.55) ? 2.0*(nT-0.55) : 0.0 ); +}; + +/** performOut + * This method set the opacity of the leaving slide according to the passed + * time value. + * + * @param nT + * The time parameter. + */ +FadingOverColorSlideChange.prototype.performOut = function( nT ) +{ + this.aLeavingSlide.setOpacity( (nT > 0.45) ? 0.0 : 2.0*(0.45-nT) ); +}; + +FadingOverColorSlideChange.prototype.createColorPlaneElement = function() +{ + var aColorPlaneElement = document.createElementNS( NSS['svg'], 'rect' ); + aColorPlaneElement.setAttribute( 'width', String( this.aLeavingSlide.getWidth() ) ); + aColorPlaneElement.setAttribute( 'height', String( this.aLeavingSlide.getHeight() ) ); + aColorPlaneElement.setAttribute( 'fill', this.sFadeColor ); + return aColorPlaneElement; +}; + + + +// ------------------------------------------------------------------------------------------ // +/** Class MovingSlideChange + * This class performs a slide transition that involves translating the leaving + * slide and/or the entering one in a given direction. + * + * @param aLeavingSlide + * An object of type AnimatedSlide handling the leaving slide. + * @param aEnteringSlide + * An object of type AnimatedSlide handling the entering slide. + * @param aLeavingDirection + * A 2D vector object {x, y}. + * @param aEnteringDirection + * A 2D vector object {x, y}. + */ +function MovingSlideChange( aLeavingSlide, aEnteringSlide, + aLeavingDirection, aEnteringDirection ) +{ + MovingSlideChange.superclass.constructor.call( this, aLeavingSlide, aEnteringSlide ); + this.aLeavingDirection = aLeavingDirection; + this.aEnteringDirection = aEnteringDirection; +} +extend( MovingSlideChange, SlideChangeBase ); + +/** start + * This method notifies to the slides involved in the transition the attributes + * appended to the slide elements for performing the animation. + * Moreover it sets the entering slide in the initial state and makes the slide + * visible. + */ +MovingSlideChange.prototype.start = function() +{ + MovingSlideChange.superclass.start.call( this ); + this.aEnteringSlide.notifyUsedAttribute( 'transform' ); + this.aLeavingSlide.notifyUsedAttribute( 'transform' ); + // Before setting the 'visibility' attribute of the entering slide to 'visible' + // we translate it to the initial position so that it is not really visible + // because it is clipped out. + this.performIn( 0 ); + this.aEnteringSlide.show(); +}; + +/** performIn + * This method set the position of the entering slide according to the passed + * time value. + * + * @param nT + * The time parameter. + */ +MovingSlideChange.prototype.performIn = function( nT ) +{ + var nS = nT - 1; + var dx = nS * this.aEnteringDirection.x * this.aEnteringSlide.getWidth(); + var dy = nS * this.aEnteringDirection.y * this.aEnteringSlide.getHeight(); + this.aEnteringSlide.translate( dx, dy ); +}; + +/** performOut + * This method set the position of the leaving slide according to the passed + * time value. + * + * @param nT + * The time parameter. + */ +MovingSlideChange.prototype.performOut = function( nT ) +{ + var dx = nT * this.aLeavingDirection.x * this.aLeavingSlide.getWidth(); + var dy = nT * this.aLeavingDirection.y * this.aLeavingSlide.getHeight(); + this.aLeavingSlide.translate( dx, dy ); +}; + + + +// ------------------------------------------------------------------------------------------ // +/** Class AnimatedSlide + * This class handle a slide element during a slide transition. + * + * @param aMetaSlide + * The MetaSlide object related to the slide element to be handled. + */ +function AnimatedSlide( aMetaSlide ) +{ + if( !aMetaSlide ) + { + log( 'AnimatedSlide constructor: meta slide is not valid' ); + } + + this.aMetaSlide = aMetaSlide; + this.aSlideElement = this.aMetaSlide.slideElement; + + this.aUsedAttributeSet = new Array(); +} + +/** show + * Set the visibility property of the slide to 'inherit' + * and update the master page view. + */ +AnimatedSlide.prototype.show = function() +{ + this.aMetaSlide.show(); +}; + +/** hide + * Set the visibility property of the slide to 'hidden'. + */ +AnimatedSlide.prototype.hide = function() +{ + this.aMetaSlide.hide(); +}; + +/** notifyUsedAttribute + * Populate the set of attribute used for the transition. + * + * @param sName + * A string representing an attribute name. + */ +AnimatedSlide.prototype.notifyUsedAttribute = function( sName ) +{ + this.aUsedAttributeSet.push( sName ); +}; + +/** reset + * Remove from the handled slide element any attribute that was appended for + * performing the transition. + */ +AnimatedSlide.prototype.reset = function() +{ + var i; + for( i = 0; i < this.aUsedAttributeSet.length; ++i ) + { + var sAttrName = this.aUsedAttributeSet[i]; + this.aSlideElement.removeAttribute( sAttrName ); + } + this.aUsedAttributeSet = new Array(); +}; + +/** insertBefore + * Insert an svg element before the handled slide element. + * + * @param aElement + * A svg element. + */ +AnimatedSlide.prototype.insertBefore = function( aElement ) +{ + if( aElement ) + { + this.aSlideElement.parentNode.insertBefore( aElement, this.aSlideElement ); + } +}; + +/** appendElement + * Insert an svg element after the handled slide element. + * + * @param aElement + * A svg element. + */ +AnimatedSlide.prototype.appendElement = function( aElement ) +{ + if( aElement ) + { + this.aSlideElement.parentNode.appendChild( aElement ); + } +}; + +/** appendElement + * Remove an svg element. + * + * @param aElement + * A svg element. + */ +AnimatedSlide.prototype.removeElement = function( aElement ) +{ + if( aElement ) + { + this.aSlideElement.parentNode.removeChild( aElement ); + } +}; + +/** getWidth + * + * @return {Number} + * The slide width. + */ +AnimatedSlide.prototype.getWidth = function() +{ + return WIDTH; +}; + +/** getHeight + * + * @return {Number} + * The slide height. + */ +AnimatedSlide.prototype.getHeight = function() +{ + return HEIGHT; +}; + +/** setOpacity + * + * @param nValue + * A number in the [0,1] range representing the slide opacity. + */ +AnimatedSlide.prototype.setOpacity = function( nValue ) +{ + this.aSlideElement.setAttribute( 'opacity', nValue ); +}; + +/** translate + * Translate the handled slide. + * + * @param nDx + * A number representing the translation that occurs in the x direction. + * @param nDy + * A number representing the translation that occurs in the y direction. + */ +AnimatedSlide.prototype.translate = function( nDx, nDy ) +{ + var sTransformAttr = 'translate(' + nDx + ',' + nDy + ')'; + this.aSlideElement.setAttribute( 'transform', sTransformAttr ); +}; + + + +// ------------------------------------------------------------------------------------------ // function AnimatedElement( aElement ) { if( !aElement ) @@ -6275,6 +6948,302 @@ AnimatedElement.prototype.DBG = function( sMessage, nTime ) // ------------------------------------------------------------------------------------------ // +/** Class SlideTransition + * This class is responsible for initializing the properties of a slide + * transition and create the object that actually will perform the transition. + * + * @param aAnimationsRootElement + * The <defs> element wrapping all animations for the related slide. + * @param aSlideId + * A string representing a slide id. + */ +function SlideTransition( aAnimationsRootElement, aSlideId ) +{ + this.sSlideId = aSlideId; + this.bIsValid = false; + this.eTransitionType = undefined; + this.eTransitionSubType = undefined; + this.bReverseDirection = false; + this.eTransitionMode = TRANSITION_MODE_IN; + this.sFadeColor = null; + this.aDuration = null; + this.nMinFrameCount = undefined; + + if( aAnimationsRootElement ) + { + if( aAnimationsRootElement.firstElementChild && + ( aAnimationsRootElement.firstElementChild.getAttribute( 'begin' ) === (this.sSlideId + '.begin') ) ) + { + var aTransitionFilterElement = aAnimationsRootElement.firstElementChild.firstElementChild; + if( aTransitionFilterElement && ( aTransitionFilterElement.localName === 'transitionFilter' ) ) + { + this.aElement = aTransitionFilterElement; + this.parseElement(); + } + aAnimationsRootElement.removeChild( aAnimationsRootElement.firstElementChild ); + } + } +} + +SlideTransition.prototype.createSlideTransition = function( aLeavingSlide, aEnteringSlide ) +{ + if( !this.isValid() ) + return null; + if( this.eTransitionType == 0 ) + return null; + + if( !aEnteringSlide ) + { + log( 'SlideTransition.createSlideTransition: invalid entering slide.' ); + return null; + } + + var aTransitionInfo = aTransitionInfoTable[this.eTransitionType][this.eTransitionSubType]; + var eTransitionClass = aTransitionInfo['class']; + + switch( eTransitionClass ) + { + default: + case TRANSITION_INVALID: + log( 'SlideTransition.createSlideTransition: transition class: TRANSITION_INVALID' ); + return null; + + case TRANSITION_CLIP_POLYPOLYGON: + return null; + + case TRANSITION_SPECIAL: + switch( this.eTransitionType ) + { + default: + log( 'SlideTransition.createSlideTransition: ' + + 'transition class: TRANSITION_SPECIAL, ' + + 'unknown transition type: ' + this.eTransitionType ); + return null; + + case PUSHWIPE_TRANSITION: + { + var bCombined = false; + var aDirection = null; + switch( this.eTransitionSubType ) + { + default: + log( 'SlideTransition.createSlideTransition: ' + + 'transition type: PUSHWIPE_TRANSITION, ' + + 'unknown transition subtype: ' + this.eTransitionSubType ); + return null; + case FROMTOP_TRANS_SUBTYPE: + aDirection = { x: 0.0, y: 1.0 }; + break; + case FROMBOTTOM_TRANS_SUBTYPE: + aDirection = { x: 0.0, y: -1.0 }; + break; + case FROMLEFT_TRANS_SUBTYPE: + aDirection = { x: 1.0, y: 0.0 }; + break; + case FROMRIGHT_TRANS_SUBTYPE: + aDirection = { x: -1.0, y: 0.0 }; + break; + } + if( bCombined ) + return null; + else + return new MovingSlideChange( aLeavingSlide, aEnteringSlide, aDirection, aDirection ); + } + + case SLIDEWIPE_TRANSITION: + { + var aInDirection = null; + switch( this.eTransitionSubType ) + { + default: + log( 'SlideTransition.createSlideTransition: ' + + 'transition type: SLIDEWIPE_TRANSITION, ' + + 'unknown transition subtype: ' + this.eTransitionSubType ); + return null; + case FROMTOP_TRANS_SUBTYPE: + aInDirection = { x: 0.0, y: 1.0 }; + break; + case FROMBOTTOM_TRANS_SUBTYPE: + aInDirection = { x: 0.0, y: -1.0 }; + break; + case FROMLEFT_TRANS_SUBTYPE: + aInDirection = { x: 1.0, y: 0.0 }; + break; + case FROMRIGHT_TRANS_SUBTYPE: + aInDirection = { x: -1.0, y: 0.0 }; + break; + } + var aNoDirection = { x: 0.0, y: 0.0 }; + if( !this.bReverseDirection ) + { + return new MovingSlideChange( aLeavingSlide, aEnteringSlide, aNoDirection, aInDirection ); + } + else + { + return new MovingSlideChange( aLeavingSlide, aEnteringSlide, aInDirection, aNoDirection ); + } + } + + case FADE_TRANSITION: + switch( this.eTransitionSubType ) + { + default: + log( 'SlideTransition.createSlideTransition: ' + + 'transition type: FADE_TRANSITION, ' + + 'unknown transition subtype: ' + this.eTransitionSubType ); + return null; + case CROSSFADE_TRANS_SUBTYPE: + return new FadingSlideChange( aLeavingSlide, aEnteringSlide ); + case FADEOVERCOLOR_TRANS_SUBTYPE: + return new FadingOverColorSlideChange( aLeavingSlide, aEnteringSlide, this.getFadeColor() ); + } + } + } +}; + +SlideTransition.prototype.parseElement = function() +{ + var aAnimElem = this.aElement; + + // type attribute + this.eTransitionType = undefined; + var sTypeAttr = aAnimElem.getAttribute( 'type' ); + if( sTypeAttr && aTransitionTypeInMap[ sTypeAttr ] ) + { + this.eTransitionType = aTransitionTypeInMap[ sTypeAttr ]; + } + else + { + log( 'SlideTransition.parseElement: transition type not valid: ' + sTypeAttr ); + } + + // subtype attribute + this.eTransitionSubType = undefined; + var sSubTypeAttr = aAnimElem.getAttribute( 'subtype' ); + if( sSubTypeAttr && aTransitionSubtypeInMap[ sSubTypeAttr ] ) + { + this.eTransitionSubType = aTransitionSubtypeInMap[ sSubTypeAttr ]; + this.bIsValid = true; + } + else + { + log( 'SlideTransition.parseElement: transition subtype not valid: ' + sSubTypeAttr ); + } + + // direction attribute + this.bReverseDirection = false; + var sDirectionAttr = aAnimElem.getAttribute( 'direction' ); + if( sDirectionAttr == 'reverse' ) + this.bReverseDirection = true; + + // mode attribute: + this.eTransitionMode = TRANSITION_MODE_IN; + var sModeAttr = aAnimElem.getAttribute( 'mode' ); + if( sModeAttr === 'out' ) + this.eTransitionMode = TRANSITION_MODE_OUT; + + // fade color + this.sFadeColor = null; + if( this.eTransitionType == FADE_TRANSITION && + ( this.eTransitionSubType == FADEFROMCOLOR_TRANS_SUBTYPE || + this.eTransitionSubType == FADEOVERCOLOR_TRANS_SUBTYPE || + this.eTransitionSubType == FADETOCOLOR_TRANS_SUBTYPE ) ) + { + var sColorAttr = aAnimElem.getAttribute( 'fadeColor' ); + if( sColorAttr ) + this.sFadeColor = sColorAttr; + else + this.sFadeColor='#000000'; + } + + + // dur attribute + this.aDuration = null; + var sDurAttr = aAnimElem.getAttribute( 'dur' ); + this.aDuration = new Duration( sDurAttr ); + if( !this.aDuration.isSet() ) + { + this.aDuration = new Duration( null ); // duration == 0.0 + } + + // set up min frame count value; + this.nMinFrameCount = ( this.getDuration().isValue() ) + ? ( this.getDuration().getValue() * MINIMUM_FRAMES_PER_SECONDS ) + : MINIMUM_FRAMES_PER_SECONDS; + if( this.nMinFrameCount < 1.0 ) + this.nMinFrameCount = 1; + else if( this.nMinFrameCount > MINIMUM_FRAMES_PER_SECONDS ) + this.nMinFrameCount = MINIMUM_FRAMES_PER_SECONDS; + +}; + +SlideTransition.prototype.isValid = function() +{ + return this.bIsValid; +}; + +SlideTransition.prototype.getTransitionType = function() +{ + return this.eTransitionType; +}; + +SlideTransition.prototype.getTransitionSubType = function() +{ + return this.eTransitionSubType; +}; + +SlideTransition.prototype.getTransitionMode = function() +{ + return this.eTransitionMode; +}; + +SlideTransition.prototype.getFadeColor = function() +{ + return this.sFadeColor; +}; + +SlideTransition.prototype.getReverseDirection = function() +{ + return this.bReverseDirection; +}; + +SlideTransition.prototype.getDuration = function() +{ + return this.aDuration; +}; + +SlideTransition.prototype.getMinFrameCount = function() +{ + return this.nMinFrameCount; +}; + +SlideTransition.prototype.info = function() +{ + + var sInfo ='slide transition <' + this.sSlideId + '>: '; + // transition type + sInfo += '; type: ' + aTransitionTypeOutMap[ String( this.getTransitionType() ) ]; + + // transition subtype + sInfo += '; subtype: ' + aTransitionSubtypeOutMap[ this.getTransitionSubType() ]; + + // transition direction + if( this.getReverseDirection() ) + sInfo += '; direction: reverse'; + + // transition mode + sInfo += '; mode: ' + aTransitionModeOutMap[ this.getTransitionMode() ]; + + // duration + if( this.getDuration() ) + sInfo += '; duration: ' + this.getDuration().info(); + + return sInfo; +}; + + + +// ------------------------------------------------------------------------------------------ // // SlideAnimations function SlideAnimations( aSlideShowContext ) @@ -6911,12 +7880,14 @@ function ActivityParamSet() this.aEndEvent = null; this.aTimerEventQueue = null; this.aActivityQueue = null; + this.nMinDuration = undefined; + this.nMinNumberOfFrames = MINIMUM_FRAMES_PER_SECONDS; + this.bAutoReverse = false; this.nRepeatCount = 1.0; this.nAccelerationFraction = 0.0; this.nDecelerationFraction = 0.0; - this.bAutoReverse = false; - this.nMinDuration = undefined; - this.nMinNumberOfFrames = MINIMUM_FRAMES_PER_SECONDS; + this.nSlideWidth = undefined; + this.nSlideHeight = undefined; this.aDiscreteTimes = new Array(); } @@ -8091,6 +9062,7 @@ function SlideShow() this.eDirection = FORWARD; this.bIsIdle = true; this.bIsEnabled = true; + this.bNoSlideTransition = false; } @@ -8109,6 +9081,48 @@ SlideShow.prototype.setSlideEvents = function( aNextEffectEventArray, aEventMult this.nCurrentEffect = 0; }; +SlideShow.prototype.createSlideTransition = function( aSlideTransitionHandler, aLeavingSlide, aEnteringSlide, aTransitionEndEvent ) +{ + if( !aEnteringSlide ) + { + log( 'SlideShow.createSlideTransition: entering slide element is not valid.' ); + return null; + } + + if( this.bNoSlideTransition ) return null; + + var aAnimatedLeavingSlide = null; + if( aLeavingSlide ) + aAnimatedLeavingSlide = new AnimatedSlide( aLeavingSlide ); + var aAnimatedEnteringSlide = new AnimatedSlide( aEnteringSlide ); + + var aSlideTransition = aSlideTransitionHandler.createSlideTransition( aAnimatedLeavingSlide, aAnimatedEnteringSlide ); + if( !aSlideTransition ) return null; + + // compute duration + var nDuration = 0.001; + if( aSlideTransitionHandler.getDuration().isValue() ) + { + nDuration = aSlideTransitionHandler.getDuration().getValue(); + } + else + { + log( 'SlideShow.createSlideTransition: duration is not a number' ); + } + + var aCommonParameterSet = new ActivityParamSet(); + aCommonParameterSet.aEndEvent = aTransitionEndEvent; + aCommonParameterSet.aTimerEventQueue = this.aTimerEventQueue; + aCommonParameterSet.aActivityQueue = this.aActivityQueue; + aCommonParameterSet.nMinDuration = nDuration; + aCommonParameterSet.nMinNumberOfFrames = aSlideTransitionHandler.getMinFrameCount(); + aCommonParameterSet.nSlideWidth = WIDTH; + aCommonParameterSet.nSlideHeight = HEIGHT; + + return new SimpleActivity( aCommonParameterSet, aSlideTransition, FORWARD ); + +}; + SlideShow.prototype.isRunning = function() { return !this.bIsIdle; @@ -8133,6 +9147,21 @@ SlideShow.prototype.notifySlideStart = function( nSlideIndex ) aAnimatedElementMap[ sId ].notifySlideStart(); }; +SlideShow.prototype.notifyTransitionEnd = function( nSlideIndex ) +{ + theMetaDoc.setCurrentSlide( nSlideIndex ); + if( this.isEnabled() ) + { + // clear all queues + this.dispose(); + + this.notifySlideStart( nSlideIndex ); + + theMetaDoc.getCurrentSlide().aSlideAnimationsHandler.start(); + this.update(); + } +}; + SlideShow.prototype.nextEffect = function() { if( !this.isEnabled() ) @@ -8199,62 +9228,52 @@ SlideShow.prototype.displaySlide = function( nNewSlide, bSkipSlideTransition ) } } - if( !bSkipSlideTransition ) + if( this.isEnabled() && !bSkipSlideTransition ) { // create slide transition and add to activity queue - // to be implemented - aMetaDoc.setCurrentSlide( nNewSlide ); - } - else - { - aMetaDoc.setCurrentSlide( nNewSlide ); - } - - // handle new slide - if( this.isEnabled() ) - { - this.notifySlideStart( nNewSlide ); - - aMetaDoc.getCurrentSlide().aSlideAnimationsHandler.start(); - this.update(); - } - + if ( ( nOldSlide !== undefined ) && + ( ( nNewSlide > nOldSlide ) || + ( ( nNewSlide == 0) && ( nOldSlide == (aMetaDoc.nNumberOfSlides - 1) ) ) ) ) + { + var aOldMetaSlide = aMetaDoc.aMetaSlideSet[nOldSlide]; + var aNewMetaSlide = aMetaDoc.aMetaSlideSet[nNewSlide]; - /* - var nOldSlide = nCurSlide; - nCurSlide = nNewSlide; + var aSlideTransitionHandler = aNewMetaSlide.aTransitionHandler; + if( aSlideTransitionHandler && aSlideTransitionHandler.isValid() ) + { + var aLeavingSlide = aOldMetaSlide; + var aEnteringSlide = aNewMetaSlide; + var aTransitionEndEvent = makeEvent( bind2( this.notifyTransitionEnd, this, nNewSlide ) ); - var oldMetaSlide = aMetaDoc.aMetaSlideSet[nOldSlide]; - var newMetaSlide = aMetaDoc.aMetaSlideSet[nNewSlide]; + var aTransitionActivity = + this.createSlideTransition( aSlideTransitionHandler, aLeavingSlide, + aEnteringSlide, aTransitionEndEvent ); - if( !this.isEnabled() ) - { - oldMetaSlide.hide(); - newMetaSlide.show(); - return; + if( aTransitionActivity ) + { + this.aActivityQueue.addActivity( aTransitionActivity ); + this.update(); + } + else + { + this.notifyTransitionEnd( nNewSlide ); + } + } + else + { + this.notifyTransitionEnd( nNewSlide ); + } + } + else + { + this.notifyTransitionEnd( nNewSlide ); + } } - - // force end animations and hide current slide - oldMetaSlide.hide(); - oldMetaSlide.aSlideAnimationsHandler.end( bSkipSlideTransition ); - - // clear all queues - this.dispose(); - - // prepare to show a new slide - this.notifySlideStart(); - - if( !bSkipSlideTransition ) + else { - // create slide transition and add to activity queue - // to be implemented + this.notifyTransitionEnd( nNewSlide ); } - // show next slide and start animations - newMetaSlide.show(); - newMetaSlide.aSlideAnimationsHandler.start(); - this.update(); - */ }; SlideShow.prototype.update = function() @@ -8268,6 +9287,8 @@ SlideShow.prototype.update = function() this.aFrameSynchronization.synchronize(); + this.aActivityQueue.processDequeued(); + ROOT_NODE.unsuspendRedraw(suspendHandle); ROOT_NODE.forceRedraw(); this.aTimer.releaseTimer(); diff --git a/filter/source/svg/svgexport.cxx b/filter/source/svg/svgexport.cxx index 12a3ed37228d..3d048129ae6e 100644 --- a/filter/source/svg/svgexport.cxx +++ b/filter/source/svg/svgexport.cxx @@ -88,6 +88,7 @@ static const char aOOOAttrFooterVisibility[] = NSPREFIX "footer-visibility"; static const char aOOOAttrDateTimeField[] = NSPREFIX "date-time-field"; static const char aOOOAttrFooterField[] = NSPREFIX "footer-field"; static const char aOOOAttrHeaderField[] = NSPREFIX "header-field"; +static const char aOOOAttrHasTransition[] = NSPREFIX "has-transition"; // ooo xml attributes for pages and shapes static const char aOOOAttrName[] = NSPREFIX "name"; @@ -1013,6 +1014,19 @@ sal_Bool SVGFilter::implGenerateMetaData() { mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrMasterObjectsVisibility, B2UCONST( "hidden" ) ); } + + // We look for a slide transition. + // Transition properties are exported together with animations. + sal_Int16 nTransitionType(0); + if( xPropSet->getPropertyValue( B2UCONST( "TransitionType" ) ) >>= nTransitionType ) + { + sal_Int16 nTransitionSubType(0); + if( xPropSet->getPropertyValue( B2UCONST( "TransitionSubtype" ) ) >>= nTransitionSubType ) + { + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrHasTransition, B2UCONST( "true" ) ); + } + } + } } |