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

Marco Cecchetti mcecchetti at kemper.freedesktop.org
Sat Jun 2 03:21:45 PDT 2012


 filter/source/svg/presentation_engine.js | 1310 +++++++++++++++++++++++++------
 filter/source/svg/svgexport.cxx          |  354 ++++----
 filter/source/svg/svgfilter.hxx          |   14 
 3 files changed, 1301 insertions(+), 377 deletions(-)

New commits:
commit a450beccf54896e48371ea87a5ac347906b01284
Author: Marco Cecchetti <mrcekets at gmail.com>
Date:   Thu May 31 21:45:13 2012 +0200

    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.

diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index 53ab747..7b17623 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 a1a82b8..623e719 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";
@@ -1010,6 +1011,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" ) );
+                            }
+                        }
+
                     }
                 }
 
commit 0ace8bbf0945710a7945316ace01bf4b64715097
Author: Marco Cecchetti <mrcekets at gmail.com>
Date:   Tue May 29 21:01:00 2012 +0200

    The new slide elements structure is created by the svg export filter
    directly. Master page elements structure reverted to old one, adapted
    the embedded script. Exporting a single slide is supported again.

diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index 6aeabe1..53ab747 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -630,6 +630,7 @@ var aOOOElemTextField = 'ooo:text_field';
 
 // ooo attributes
 var aOOOAttrNumberOfSlides = 'number-of-slides';
+var aOOOAttrStartSlideNumber= 'start-slide-number';
 var aOOOAttrNumberingType = 'page-numbering-type';
 
 var aOOOAttrSlide = 'slide';
@@ -929,98 +930,6 @@ function isTextFieldElement( aElement )
            ( sClassName === aDateTimeClassName );
 }
 
-
-
-function tempWrapMasterPages()
-{
-    var aSlideGroupElement = document.createElementNS( NSS['svg'], 'g' );
-    aSlideGroupElement.setAttribute( 'class', 'SlideGroup' );
-    //aSlideGroupElement.onmousedown = function( aEvt ) { return mouseHandlerDispatch( aEvt, MOUSE_DOWN ); };
-    //aSlideGroupElement.setAttribute( 'visibility', 'hidden' );
-
-
-    var aDrawPageSet = getElementsByClassName(ROOT_NODE, 'Slide');
-    ROOT_NODE.insertBefore( aSlideGroupElement, aDrawPageSet[0] );
-
-    var aMasterPageSet = getElementsByClassName(ROOT_NODE, 'Master_Slide');
-    if( aMasterPageSet )
-    {
-        var aDefsElement = document.createElementNS( NSS['svg'], 'defs' );
-
-        ROOT_NODE.insertBefore( aDefsElement, aMasterPageSet[0] );
-        var i;
-        for( i = 0; i < aMasterPageSet.length; ++i)
-        {
-            var aMasterPage = ROOT_NODE.removeChild( aMasterPageSet[i] );
-            aDefsElement.appendChild( aMasterPage );
-        }
-    }
-}
-
-function tempCreateSlideView( aPageElement )
-{
-    if( !aPageElement )
-        return;
-
-    var aSlideGroupElement = getElementByClassName( ROOT_NODE, 'SlideGroup' );
-
-    var sId = aPageElement.getAttribute( 'id' );
-    var sName = aPageElement.getAttributeNS( NSS['ooo'], 'name' );
-    var sClipPath = aPageElement.getAttribute( 'clip-path' );
-
-    aPageElement.removeAttribute( 'id' );
-    aPageElement.removeAttributeNS( NSS['ooo'], 'name' );
-    aPageElement.removeAttribute( 'visibility' );
-    aPageElement.removeAttribute( 'clip-path' );
-    aPageElement.setAttribute( 'class', aPageClassName );
-
-    var aVisibilityStatusElement = document.createElementNS( NSS['svg'], 'g' );
-    aVisibilityStatusElement.setAttribute( 'visibility', 'hidden' );
-
-    var aSlideElement = document.createElementNS( NSS['svg'], 'g' );
-    aSlideElement.setAttribute( 'id', sId );
-    aSlideElement.setAttributeNS( NSS['ooo'], 'name', sName );
-    aSlideElement.setAttribute( 'clip-path', sClipPath );
-    aSlideElement.setAttribute( 'class', 'Slide' );
-    aVisibilityStatusElement.appendChild( aSlideElement );
-
-    aPageElement.parentNode.removeChild( aPageElement );
-    aSlideElement.appendChild( aPageElement );
-    aSlideGroupElement.appendChild( aVisibilityStatusElement );
-}
-
-function tempModMasterPage( aMasterPageElement, sId )
-{
-    if( !aMasterPageElement )
-        return;
-
-
-    var aBackgroundObjectsElement =
-        getElementByClassName( aMasterPageElement, 'BackgroundObjects' );
-
-    var aBackgroundShapesElement = document.createElementNS( NSS['svg'], 'g' );
-    aBackgroundShapesElement.setAttribute( 'id', 'bs-' + sId );
-    aBackgroundShapesElement.setAttribute( 'class', 'BackgroundShapes' );
-
-
-    if( aBackgroundObjectsElement.hasChildNodes() )
-    {
-        var aChildNode = aBackgroundObjectsElement.firstElementChild;
-        while( aChildNode )
-        {
-            var aNextChildNode= aChildNode.nextElementSibling;
-            if( !isTextFieldElement( aChildNode ) )
-            {
-                aBackgroundObjectsElement.removeChild( aChildNode );
-                aBackgroundShapesElement.appendChild( aChildNode );
-            }
-            aChildNode = aNextChildNode;
-        }
-    }
-    aBackgroundObjectsElement.appendChild( aBackgroundShapesElement );
-}
-
-
 // ------------------------------------------------------------------------------------------ //
 /*********************
  ** Debug Utilities **
@@ -1102,9 +1011,6 @@ aAnimatedElementDebugPrinter.off();
  */
 function MetaDocument()
 {
-    // TODO to be implemented in C++
-    tempWrapMasterPages();
-
     // We look for the svg element that provides the following presentation
     // properties:
     // - the number of slides in the presentation;
@@ -1120,7 +1026,7 @@ function MetaDocument()
     assert( typeof this.nNumberOfSlides == 'number' && this.nNumberOfSlides > 0,
             'MetaDocument: number of slides is zero or undefined.' );
     // - the index of the slide to show when the presentation starts;
-    this.nStartSlideNumber = 0;
+    this.nStartSlideNumber = parseInt( aMetaDocElem.getAttributeNS( NSS['ooo'], aOOOAttrStartSlideNumber ) ) || 0;
     // - the numbering type used in the presentation, default type is arabic.
     this.sPageNumberingType = aMetaDocElem.getAttributeNS( NSS['ooo'], aOOOAttrNumberingType ) || 'arabic';
 
@@ -1241,13 +1147,6 @@ function MetaSlide( sMetaSlideId, aMetaDoc )
             'MetaSlide: slide element <' + this.slideId + '> not found.' );
     this.nSlideNumber = parseInt( this.slideId.substr(2) );
 
-    // ------------------------------
-    // TODO: to be implemented in C++
-    tempCreateSlideView(this.slideElement);
-    this.slideElement = this.theDocument.getElementById( this.slideId );
-    assert( this.slideElement, 'MetaSlide: slide element <' + this.slideId + '> not found.' );
-    // ------------------------------
-
     // Each slide element is wrapped by a <g> element that is responsible for
     // the slide element visibility. In fact the visibility attribute has
     // to be set on the parent of the slide element and not directly on
@@ -1434,12 +1333,11 @@ getSlideAnimationsRoot : function()
 
 }; // end MetaSlide prototype
 
-/** Class MasterPage **
+/** Class MasterPage
  *  This class gives direct access to a master page element and to the following
  *  elements included in the master page:
  *  - the background element,
  *  - the background objects group element,
- *  - the background shapes group element.
  *  Moreover for each text field element a Placeholder object is created which
  *  manages the text field element itself.
  *
@@ -1449,23 +1347,19 @@ getSlideAnimationsRoot : function()
  *          background image
  *      </g>
  *      <g class='BackgroundObjects'>
- *          <g class='BackgroundFields'>
- *              <g class='Date/Time'>
- *                  date/time placeholder
- *              </g>
- *              <g class='Header'>
- *                  header placeholder
- *              </g>
- *              <g class='Footer'>
- *                  footer placeholder
- *              </g>
- *              <g class='Slide_Number'>
- *                  slide number placeholder
- *              </g>
+ *          <g class='Date/Time'>
+ *              date/time placeholder
  *          </g>
- *          <g class='BackgroundShapes'>
- *              shapes
+ *          <g class='Header'>
+ *              header placeholder
  *          </g>
+ *          <g class='Footer'>
+ *              footer placeholder
+ *          </g>
+ *          <g class='Slide_Number'>
+ *              slide number placeholder
+ *          </g>
+ *          shapes
  *      </g>
  *  </g>
  *
@@ -1482,19 +1376,12 @@ function MasterPage( sMasterPageId )
     assert( this.element,
             'MasterPage: master page element <' + this.id + '> not found.' );
 
-    // ------------------------------
-    // TODO: to be implemented in C++
-    tempModMasterPage( this.element, this.id );
-    this.element = document.getElementById( this.id );
-    assert( this.element, 'MasterPage: master page element <' + this.id + '> not found.' );
-    // ------------------------------
-
     // The master page background element and its id attribute.
     this.background = getElementByClassName( this.element, 'Background' );
     if( this.background )
     {
         this.backgroundId = this.background.getAttribute( 'id' );
-//      this.backgroundVisibility = initVisibilityProperty( this.background );
+        this.backgroundVisibility = initVisibilityProperty( this.background );
     }
     else
     {
@@ -1508,7 +1395,7 @@ function MasterPage( sMasterPageId )
     if( this.backgroundObjects )
     {
         this.backgroundObjectsId = this.backgroundObjects.getAttribute( 'id' );
-//      this.backgroundObjectsVisibility = initVisibilityProperty( this.backgroundObjects );
+        this.backgroundObjectsVisibility = initVisibilityProperty( this.backgroundObjects );
     }
     else
     {
@@ -1516,24 +1403,9 @@ function MasterPage( sMasterPageId )
         log( 'MasterPage: the background objects element is not valid.' );
     }
 
-    // The background shapes group element that contains all the shape of
-    // the master page that are not text fields.
-    this.backgroundShapes = getElementByClassName( this.backgroundObjects, 'BackgroundShapes' );
-    if( this.backgroundShapes )
-    {
-        this.backgroundShapesId = this.backgroundShapes.getAttribute( 'id' );
-    }
-    else
-    {
-        this.backgroundShapesId = '';
-        log( 'MasterPage: the background shapes element is not valid.' );
-    }
-
     // We populate the collection of placeholders.
     this.aPlaceholderShapeSet = new Object();
     this.initPlaceholderShapes();
-
-    this.removeVisibilityAttributes();
 }
 
 MasterPage.prototype =
@@ -1546,13 +1418,6 @@ initPlaceholderShapes : function()
     this.aPlaceholderShapeSet[ aDateTimeClassName ] = new PlaceholderShape( this, aDateTimeClassName );
     this.aPlaceholderShapeSet[ aFooterClassName ] = new PlaceholderShape( this, aFooterClassName );
     this.aPlaceholderShapeSet[ aHeaderClassName ] = new PlaceholderShape( this, aHeaderClassName );
-},
-
-removeVisibilityAttributes : function()
-{
-    this.element.removeAttribute( 'visibility' );
-    this.background.removeAttribute( 'visibility' );
-    this.backgroundObjects.removeAttribute( 'visibility' );
 }
 
 }; // end MasterPage prototype
@@ -1601,8 +1466,6 @@ PlaceholderShape.prototype.init = function()
     var aTextFieldElement = getElementByClassName( this.masterPage.backgroundObjects, this.className );
     if( aTextFieldElement )
     {
-        aTextFieldElement.removeAttribute( 'visibility' ); // TODO to be handled in C++ ?
-
         var aPlaceholderElement = getElementByClassName( aTextFieldElement, 'PlaceholderText' );
         if( aPlaceholderElement )
         {
@@ -1809,7 +1672,7 @@ MasterPageView.prototype.createElement = function()
         this.aBackgroundShapesElement = theDocument.createElementNS( NSS['svg'], 'use' );
         this.aBackgroundShapesElement.setAttribute( 'class', 'BackgroundShapes' );
         setNSAttribute( 'xlink', this.aBackgroundShapesElement,
-                        'href', '#' + this.aMasterPage.backgroundShapesId );
+                        'href', '#' + this.aMasterPage.backgroundObjectsId );
 
         // node linking
         this.aBackgroundObjectsElement.appendChild( this.aBackgroundFieldsElement );
@@ -1900,6 +1763,8 @@ TextFieldHandler.prototype.cloneElement = function()
     assert( this.aTextFieldElement,
             'TextFieldHandler.cloneElement: aTextFieldElement is not defined' );
     this.aTextFieldElement.setAttribute( 'id', this.sId );
+    // Text field placeholder visibility is always set to 'hidden'.
+    this.aTextFieldElement.removeAttribute( 'visibility' );
     // The actual <text> element where the field content has to be placed.
     this.aTextPlaceholderElement = getElementByClassName( this.aTextFieldElement, 'PlaceholderText' );
     assert( this.aTextPlaceholderElement,
@@ -1940,7 +1805,7 @@ TextFieldHandler.prototype.setTextContent = function( sText )
 {
     if( !this.aTextPlaceholderElement )
     {
-        log( 'TextFieldHandler.setTextContent: text element is not valid in placeholder of type '
+        log( 'PlaceholderShape.setTextContent: text element is not valid in placeholder of type '
                 + this.className + ' that belongs to master slide ' + this.masterPage.id );
         return;
     }
diff --git a/filter/source/svg/svgexport.cxx b/filter/source/svg/svgexport.cxx
index 39e8feb..a1a82b8 100644
--- a/filter/source/svg/svgexport.cxx
+++ b/filter/source/svg/svgexport.cxx
@@ -74,6 +74,7 @@ static const char    aOOOElemTextField[] = NSPREFIX "text_field";
 
 // ooo xml attributes for meta_slides
 static const char    aOOOAttrNumberOfSlides[] = NSPREFIX "number-of-slides";
+static const char    aOOOAttrStartSlideNumber[] = NSPREFIX "start-slide-number";
 static const char    aOOOAttrNumberingType[] = NSPREFIX "page-numbering-type";
 
 // ooo xml attributes for meta_slide
@@ -645,22 +646,6 @@ sal_Bool SVGFilter::implLookForFirstVisiblePage()
                     ( ( xPropSet->getPropertyValue( B2UCONST( "Visible" ) ) >>= bVisible ) && bVisible ) )
                 {
                     mnVisiblePage = nCurPage;
-
-                    Reference< XMasterPageTarget > xMasterTarget( xDrawPage, UNO_QUERY );
-                    if( xMasterTarget.is() )
-                    {
-                        Reference< XDrawPage > xMasterPage( xMasterTarget->getMasterPage() );
-
-                        for( sal_Int32 nMaster = 0, nMasterCount = mMasterPageTargets.getLength();
-                             ( nMaster < nMasterCount ) && ( -1 == mnVisibleMasterPage );
-                             ++nMaster )
-                        {
-                            const Reference< XDrawPage > & xMasterTestPage = mMasterPageTargets[nMaster];
-
-                            if( xMasterTestPage.is() && xMasterTestPage == xMasterPage )
-                                mnVisibleMasterPage = nMaster;
-                        }
-                    }
                 }
             }
         }
@@ -683,7 +668,7 @@ sal_Bool SVGFilter::implExportDocument()
 
     mbSinglePage = (nLastPage == 0) || !bExperimentalMode;
     mnVisiblePage = -1;
-    mnVisibleMasterPage = -1;
+//    mnVisibleMasterPage = -1;
 
     const Reference< XPropertySet >             xDefaultPagePropertySet( mxDefaultPage, UNO_QUERY );
     const Reference< XExtendedDocumentHandler > xExtDocHandler( mpSVGExport->GetDocHandler(), UNO_QUERY );
@@ -809,8 +794,8 @@ sal_Bool SVGFilter::implExportDocument()
                 mpSVGFontExport->EmbedFonts();
             }
 
-            implExportPages( mMasterPageTargets, 0, mMasterPageTargets.getLength() - 1, mnVisibleMasterPage, sal_True /* is a master page */ );
-            implExportPages( mSelectedPages, 0, nLastPage, mnVisiblePage, sal_False /* is not a master page */ );
+            implExportMasterPages( mMasterPageTargets, 0, mMasterPageTargets.getLength() - 1 );
+            implExportDrawPages( mSelectedPages, 0, nLastPage );
 
             if( !mbSinglePage )
             {
@@ -872,6 +857,7 @@ sal_Bool SVGFilter::implGenerateMetaData()
 
         mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", B2UCONST( aOOOElemMetaSlides ) );
         mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrNumberOfSlides, OUString::valueOf( nCount ) );
+        mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrStartSlideNumber, OUString::valueOf( mnVisiblePage ) );
 
         /*
          *  Add a (global) Page Numbering Type attribute for the document
@@ -886,6 +872,9 @@ sal_Bool SVGFilter::implGenerateMetaData()
             SdrPage* pSdrPage = pSvxDrawPage->GetSdrPage();
             SdrModel* pSdrModel = pSdrPage->GetModel();
             nPageNumberingType = pSdrModel->GetPageNumType();
+
+            // That is used by CalcFieldHdl method.
+            mVisiblePagePropSet.nPageNumberingType = nPageNumberingType;
         }
         if( nPageNumberingType != SVX_NUMBER_NONE )
         {
@@ -1021,20 +1010,6 @@ sal_Bool SVGFilter::implGenerateMetaData()
                         {
                             mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrMasterObjectsVisibility, B2UCONST( "hidden" ) );
                         }
-                        if( i == mnVisiblePage )
-                        {
-                            mVisiblePagePropSet.bIsBackgroundVisible = bBackgroundVisibility;
-                            mVisiblePagePropSet.bAreBackgroundObjectsVisible = bBackgroundObjectsVisibility;
-                            mVisiblePagePropSet.bIsPageNumberFieldVisible = bPageNumberVisibility;
-                            mVisiblePagePropSet.bIsDateTimeFieldVisible = bDateTimeVisibility;
-                            mVisiblePagePropSet.bIsFooterFieldVisible = bFooterVisibility;
-                            mVisiblePagePropSet.bIsHeaderFieldVisible = bHeaderVisibility;
-                            mVisiblePagePropSet.nPageNumberingType = nPageNumberingType;
-                            mVisiblePagePropSet.bIsDateTimeFieldFixed = bDateTimeFixed;
-                            mVisiblePagePropSet.nDateTimeFormat = aVariableDateTimeField.format;
-                            mVisiblePagePropSet.sDateTimeText = aFixedDateTimeField.text;
-                            mVisiblePagePropSet.sFooterText = aFooterField.text;
-                        }
                     }
                 }
 
@@ -1241,17 +1216,21 @@ sal_Bool SVGFilter::implGetPagePropSet( const Reference< XDrawPage > & rxPage )
     return bRet;
 }
 
+
 // -----------------------------------------------------------------------------
 
-sal_Bool SVGFilter::implExportPages( const SVGFilter::XDrawPageSequence & rxPages,
-                                     sal_Int32 nFirstPage, sal_Int32 nLastPage,
-                                     sal_Int32 nVisiblePage, sal_Bool bMaster )
+sal_Bool SVGFilter::implExportMasterPages( const SVGFilter::XDrawPageSequence & rxPages,
+                                           sal_Int32 nFirstPage, sal_Int32 nLastPage )
 {
     DBG_ASSERT( nFirstPage <= nLastPage,
                 "SVGFilter::implExportPages: nFirstPage > nLastPage" );
 
-    sal_Bool bRet = sal_False;
+    // When the exported slides are more than one we wrap master page elements
+    // with a svg <defs> element.
+    OUString aContainerTag = (mbSinglePage) ? B2UCONST( "g" ) : B2UCONST( "defs" );
+    SvXMLElementExport aContainerElement( *mpSVGExport, XML_NAMESPACE_NONE, aContainerTag, sal_True, sal_True );
 
+    sal_Bool bRet = sal_False;
     for( sal_Int32 i = nFirstPage; i <= nLastPage; ++i )
     {
         if( rxPages[i].is() )
@@ -1264,127 +1243,168 @@ sal_Bool SVGFilter::implExportPages( const SVGFilter::XDrawPageSequence & rxPage
                 const OUString & sPageId = implGetValidIDFromInterface( rxPages[i] );
                 mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sPageId );
 
-                OUString sPageName = implGetInterfaceName( rxPages[i] );
-                if( !(sPageName.isEmpty() || mbSinglePage ))
-                    mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrName, sPageName );
+                bRet = implExportPage( sPageId, rxPages[i], xShapes, sal_True /* is a master page */ ) || bRet;
+            }
+        }
+    }
+    return bRet;
+}
 
-                {
-                    {
-                        Reference< XExtendedDocumentHandler > xExtDocHandler( mpSVGExport->GetDocHandler(), UNO_QUERY );
+// -----------------------------------------------------------------------------
 
-                        if( xExtDocHandler.is() )
-                        {
-                            OUString aDesc;
+sal_Bool SVGFilter::implExportDrawPages( const SVGFilter::XDrawPageSequence & rxPages,
+                                           sal_Int32 nFirstPage, sal_Int32 nLastPage )
+{
+    DBG_ASSERT( nFirstPage <= nLastPage,
+                "SVGFilter::implExportPages: nFirstPage > nLastPage" );
 
-                            if( bMaster )
-                                aDesc = B2UCONST( "Master_Slide" );
-                            else
-                                aDesc = B2UCONST( "Slide" );
+    // We wrap all slide in a group element with class name "SlideGroup".
+    mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "SlideGroup" ) );
+    SvXMLElementExport aExp( *mpSVGExport, XML_NAMESPACE_NONE, "g", sal_True, sal_True );
 
-                            mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", aDesc );
-                        }
-                    }
+    sal_Bool bRet = sal_False;
+    for( sal_Int32 i = nFirstPage; i <= nLastPage; ++i )
+    {
+        Reference< XShapes > xShapes( rxPages[i], UNO_QUERY );
 
-                    // We don't set a visibility attribute for a master page element
-                    // as the visibility of each master page sub element (background,
-                    // placeholder shapes, background objects) is managed separately.
-                    OUString aAttrVisibilityValue;
-                    if( !bMaster )
-                    {
-                        if( i == nVisiblePage )
-                            aAttrVisibilityValue = B2UCONST( "visible" );
-                        else
-                            aAttrVisibilityValue = B2UCONST( "hidden" );
-                        mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", aAttrVisibilityValue );
-                    }
-                    else
-                    {   // when we export the shapes of a master page (implExportShape) we need
-                        // to know if it is the master page targeted by the initially visible slide
-                        mbIsPageVisible = ( i == nVisiblePage );
-                    }
+        if( xShapes.is() )
+        {
+            // Insert the <g> open tag related to the svg element for
+            // handling a slide visibility.
+            // In case the exported slides are more than one the initial
+            // visibility of each slide is set to 'hidden'.
+            if( !mbSinglePage )
+            {
+                mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", B2UCONST( "hidden" ) );
+            }
+            SvXMLElementExport aGElement( *mpSVGExport, XML_NAMESPACE_NONE, "g", sal_True, sal_True );
 
-                    // Adding a clip path to each exported slide and master page,
-                    // so in case bitmaps or other elements exceed the slide margins
-                    // they are trimmed, even when they are shown inside a thumbnail view.
-                    OUString sClipPathAttrValue = B2UCONST( "url(#" ) + msClipPathId + B2UCONST( ")" );
-                    mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "clip-path", sClipPathAttrValue );
+            {
+                // add id attribute
+                const OUString & sPageId = implGetValidIDFromInterface( rxPages[i] );
+                mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sPageId );
 
-                    // insert the <g> open tag related to the Slide/Master_Slide
-                    SvXMLElementExport aExp( *mpSVGExport, XML_NAMESPACE_NONE, "g", sal_True, sal_True );
+                mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "Slide" ) );
 
-                    // In case the page has a background object we append it .
-                    if( (mpObjects->find( rxPages[i] ) != mpObjects->end()) )
-                    {
-                        const GDIMetaFile& rMtf = (*mpObjects)[ rxPages[i] ].GetRepresentation();
-                        if( rMtf.GetActionSize() )
-                        {
-                            // background id = "bg-" + page id
-                            OUString sBackgroundId = B2UCONST( "bg-" );
-                            sBackgroundId += sPageId;
-                            mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sBackgroundId );
-
-                            // At present (LibreOffice 3.4.0) the 'IsBackgroundVisible' property is not handled
-                            // by Impress; anyway we handle this property as referring only to the visibility
-                            // of the master page background. So if a slide has its own background object,
-                            // the visibility of such a background object is always inherited from the visibility
-                            // of the parent slide regardless of the value of the 'IsBackgroundVisible' property.
-                            // This means that we need to set up the visibility attribute only for the background
-                            // element of a master page.
-                            if( bMaster )
-                            {
-                                if( i == nVisiblePage && mVisiblePagePropSet.bIsBackgroundVisible )
-                                    aAttrVisibilityValue = B2UCONST( "visible" );
-                                else
-                                    aAttrVisibilityValue = B2UCONST( "hidden" );
-                                mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", aAttrVisibilityValue );
-                            }
+                // Adding a clip path to each exported slide , so in case
+                // bitmaps or other elements exceed the slide margins, they are
+                // trimmed, even when they are shown inside a thumbnail view.
+                OUString sClipPathAttrValue = B2UCONST( "url(#" ) + msClipPathId + B2UCONST( ")" );
+                mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "clip-path", sClipPathAttrValue );
+
+                SvXMLElementExport aSlideElement( *mpSVGExport, XML_NAMESPACE_NONE, "g", sal_True, sal_True );
+
+                bRet = implExportPage( sPageId, rxPages[i], xShapes, sal_False /* is not a master page */ ) || bRet;
+            }
+        } // append the </g> closing tag related to the svg element handling the slide visibility
+    }
 
-                            mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class",  B2UCONST( "Background" ) );
+    return bRet;
+}
 
-                            // insert the <g> open tag related to the Background
-                            SvXMLElementExport aExp2( *mpSVGExport, XML_NAMESPACE_NONE, "g", sal_True, sal_True );
+// -----------------------------------------------------------------------------
+sal_Bool SVGFilter::implExportPage( const ::rtl::OUString & sPageId,
+                                    const Reference< XDrawPage > & rxPage,
+                                    const Reference< XShapes > & xShapes,
+                                    sal_Bool bMaster )
+{
+    sal_Bool bRet = sal_False;
 
-                            // append all elements that make up the Background
-                            const Point aNullPt;
-                            mpSVGWriter->WriteMetaFile( aNullPt, rMtf.GetPrefSize(), rMtf, SVGWRITER_WRITE_FILL );
-                        }   // insert the </g> closing tag related to the Background
-                    }
+    {
+        OUString sPageName = implGetInterfaceName( rxPage );
+        if( !(sPageName.isEmpty() || mbSinglePage ))
+            mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrName, sPageName );
 
-                    // In case we are dealing with a master page we need to to group all its shapes
-                    // into a group element, this group will make up the so named "background objects"
-                    if( bMaster )
-                    {
-                        // background objects id = "bo-" + page id
-                        OUString sBackgroundObjectsId = B2UCONST( "bo-" );
-                        sBackgroundObjectsId += sPageId;
-                        mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sBackgroundObjectsId );
+        {
+            Reference< XExtendedDocumentHandler > xExtDocHandler( mpSVGExport->GetDocHandler(), UNO_QUERY );
 
-                        if( i == nVisiblePage && mVisiblePagePropSet.bAreBackgroundObjectsVisible )
-                            aAttrVisibilityValue = B2UCONST( "visible" );
-                        else
-                            aAttrVisibilityValue = B2UCONST( "hidden" );
-                        mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", aAttrVisibilityValue );
-                        mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class",  B2UCONST( "BackgroundObjects" ) );
+            if( xExtDocHandler.is() )
+            {
+                OUString aDesc;
 
-                        // insert the <g> open tag related to the Background Objects
-                        SvXMLElementExport aExp2( *mpSVGExport, XML_NAMESPACE_NONE, "g", sal_True, sal_True );
+                if( bMaster )
+                    aDesc = B2UCONST( "Master_Slide" );
+                else
+                    aDesc = B2UCONST( "Page" );
 
-                        // append all shapes that make up the Master Slide
-                        bRet = implExportShapes( xShapes ) || bRet;
-                    }   // append the </g> closing tag related to the Background Objects
-                    else
+                mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", aDesc );
+            }
+        }
+
+        // insert the <g> open tag related to the DrawPage/MasterPage
+        SvXMLElementExport aExp( *mpSVGExport, XML_NAMESPACE_NONE, "g", sal_True, sal_True );
+
+        // In case the page has a background object we append it .
+        if( (mpObjects->find( rxPage ) != mpObjects->end()) )
+        {
+            const GDIMetaFile& rMtf = (*mpObjects)[ rxPage ].GetRepresentation();
+            if( rMtf.GetActionSize() )
+            {
+                // background id = "bg-" + page id
+                OUString sBackgroundId = B2UCONST( "bg-" );
+                sBackgroundId += sPageId;
+                mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sBackgroundId );
+
+                // At present (LibreOffice 3.4.0) the 'IsBackgroundVisible' property is not handled
+                // by Impress; anyway we handle this property as referring only to the visibility
+                // of the master page background. So if a slide has its own background object,
+                // the visibility of such a background object is always inherited from the visibility
+                // of the parent slide regardless of the value of the 'IsBackgroundVisible' property.
+                // This means that we need to set up the visibility attribute only for the background
+                // element of a master page.
+                if( mbSinglePage && bMaster )
+                {
+                    if( !mVisiblePagePropSet.bIsBackgroundVisible )
                     {
-                        // append all shapes that make up the Slide
-                        bRet = implExportShapes( xShapes ) || bRet;
+                        mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", B2UCONST( "hidden" ) );
                     }
-                }  // append the </g> closing tag related to the Slide/Master_Slide
+                }
+
+                mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class",  B2UCONST( "Background" ) );
+
+                // insert the <g> open tag related to the Background
+                SvXMLElementExport aExp2( *mpSVGExport, XML_NAMESPACE_NONE, "g", sal_True, sal_True );
+
+                // append all elements that make up the Background
+                const Point aNullPt;
+                mpSVGWriter->WriteMetaFile( aNullPt, rMtf.GetPrefSize(), rMtf, SVGWRITER_WRITE_FILL );
+            }   // insert the </g> closing tag related to the Background
+        }
+
+        // In case we are dealing with a master page we need to to group all its shapes
+        // into a group element, this group will make up the so named "background objects"
+        if( bMaster )
+        {
+            // background objects id = "bo-" + page id
+            OUString sBackgroundObjectsId = B2UCONST( "bo-" );
+            sBackgroundObjectsId += sPageId;
+            mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sBackgroundObjectsId );
+            if( mbSinglePage )
+            {
+                if( !mVisiblePagePropSet.bAreBackgroundObjectsVisible )
+                {
+                    mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", B2UCONST( "hidden" ) );
+                }
             }
+            mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class",  B2UCONST( "BackgroundObjects" ) );
+
+            // insert the <g> open tag related to the Background Objects
+            SvXMLElementExport aExp2( *mpSVGExport, XML_NAMESPACE_NONE, "g", sal_True, sal_True );
+
+            // append all shapes that make up the Master Slide
+            bRet = implExportShapes( xShapes ) || bRet;
+        }   // append the </g> closing tag related to the Background Objects
+        else
+        {
+            // append all shapes that make up the Slide
+            bRet = implExportShapes( xShapes ) || bRet;
         }
-    }
+    }  // append the </g> closing tag related to the Slide/Master_Slide
 
     return bRet;
 }
 
+
 // -----------------------------------------------------------------------------
 
 sal_Bool SVGFilter::implExportShapes( const Reference< XShapes >& rxShapes )
@@ -1448,34 +1468,24 @@ sal_Bool SVGFilter::implExportShape( const Reference< XShape >& rxShape )
                 const Size  aSize( aBoundRect.Width, aBoundRect.Height );
 
                 if( rMtf.GetActionSize() )
-                {   // for text field shapes we set up visibility and text-adjust attributes
-                    // TODO should we set up visibility for all text field shapes to hidden at start ?
+                {   // for text field shapes we set up text-adjust attributes
+                    // and set visibility to hidden
                     OUString aShapeClass = implGetClassFromShape( rxShape );
                     if( mbPresentation )
                     {
-                        sal_Bool bIsPageNumber = aShapeClass == "Slide_Number";
-                        sal_Bool bIsFooter = aShapeClass == "Footer";
-                        sal_Bool bIsDateTime = aShapeClass == "Date/Time";
+                        sal_Bool bIsPageNumber  = ( aShapeClass == "Slide_Number" );
+                        sal_Bool bIsFooter      = ( aShapeClass == "Footer" );
+                        sal_Bool bIsDateTime    = ( aShapeClass == "Date/Time" );
                         if( bIsPageNumber || bIsDateTime || bIsFooter )
                         {
-                            // to notify to the SVGActionWriter::ImplWriteActions method
-                            // that we are dealing with a placeholder shape
-                            pElementId = &sPlaceholderTag;
-
-                            // if the text field does not belong to the visible page its svg:visibility
-                            // attribute is set to 'hidden'; else it depends on the related property of the visible page
-                            OUString aAttrVisibilityValue( B2UCONST( "hidden" ) );
-                            if(mbIsPageVisible && mVisiblePagePropSet.bAreBackgroundObjectsVisible && (
-                                    ( bIsPageNumber && mVisiblePagePropSet.bIsPageNumberFieldVisible ) ||
-                                    ( bIsDateTime && mVisiblePagePropSet.bIsDateTimeFieldVisible ) ||
-                                    ( bIsFooter && mVisiblePagePropSet.bIsFooterFieldVisible ) ) )
-                            {
-                                aAttrVisibilityValue = B2UCONST( "visible" );
-                            }
-                            mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", aAttrVisibilityValue );
-
                             if( !mbSinglePage )
                             {
+                                // to notify to the SVGActionWriter::ImplWriteActions method
+                                // that we are dealing with a placeholder shape
+                                pElementId = &sPlaceholderTag;
+
+                                mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", B2UCONST( "hidden" ) );
+
                                 sal_uInt16 nTextAdjust = ParagraphAdjust_LEFT;
                                 OUString sTextAdjust;
                                 xShapePropSet->getPropertyValue( B2UCONST( "ParaAdjust" ) ) >>= nTextAdjust;
@@ -1496,6 +1506,16 @@ sal_Bool SVGFilter::implExportShape( const Reference< XShape >& rxShape )
                                 }
                                 mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrTextAdjust, sTextAdjust );
                             }
+                            else // single page case
+                            {
+                                if( !mVisiblePagePropSet.bAreBackgroundObjectsVisible || (
+                                    ( bIsPageNumber && !mVisiblePagePropSet.bIsPageNumberFieldVisible ) ||
+                                    ( bIsDateTime && !mVisiblePagePropSet.bIsDateTimeFieldVisible ) ||
+                                    ( bIsFooter && !mVisiblePagePropSet.bIsFooterFieldVisible ) ) )
+                                {
+                                    mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", B2UCONST( "hidden" ) );
+                                }
+                            }
                         }
                     }
                     mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", aShapeClass );
@@ -1766,12 +1786,13 @@ IMPL_LINK( SVGFilter, CalcFieldHdl, EditFieldInfo*, pInfo )
     if( pInfo && mbPresentation )
     {
         bFieldProcessed = true;
-        // to notify to the SVGActionWriter::ImplWriteText method
-        // that we are dealing with a placeholder shape
-        OUString   aRepresentation = sPlaceholderTag;
-
+        OUString   aRepresentation = B2UCONST("");
         if( !mbSinglePage )
         {
+            // to notify to the SVGActionWriter::ImplWriteText method
+            // that we are dealing with a placeholder shape
+            aRepresentation = sPlaceholderTag;
+
             if( !mCreateOjectsCurrentMasterPage.is() )
             {
                 OSL_FAIL( "error: !mCreateOjectsCurrentMasterPage.is()" );
@@ -1926,7 +1947,7 @@ IMPL_LINK( SVGFilter, CalcFieldHdl, EditFieldInfo*, pInfo )
             }
             pInfo->SetRepresentation( aRepresentation );
         }
-        else
+        else  // single page case
         {
             if( mVisiblePagePropSet.bAreBackgroundObjectsVisible )
             {
@@ -1970,7 +1991,6 @@ IMPL_LINK( SVGFilter, CalcFieldHdl, EditFieldInfo*, pInfo )
                     }
                 }
             }
-
             pInfo->SetRepresentation( aRepresentation );
         }
     }
diff --git a/filter/source/svg/svgfilter.hxx b/filter/source/svg/svgfilter.hxx
index 9b5c7fe..0f52b3e 100644
--- a/filter/source/svg/svgfilter.hxx
+++ b/filter/source/svg/svgfilter.hxx
@@ -65,6 +65,7 @@
 #include <boost/unordered_set.hpp>
 #include <boost/unordered_map.hpp>
 #include <osl/diagnose.h>
+#include <sal/log.hxx>
 #include <rtl/process.h>
 #include <basegfx/polygon/b2dpolypolygon.hxx>
 #include <basegfx/polygon/b2dpolygonclipper.hxx>
@@ -273,8 +274,6 @@ private:
     sal_Bool                            mbExportAll;
     sal_Bool                            mbSinglePage;
     sal_Int32                           mnVisiblePage;
-    sal_Int32                           mnVisibleMasterPage;
-    sal_Bool                            mbIsPageVisible;
     PagePropertySet                     mVisiblePagePropSet;
     ::rtl::OUString                     msClipPathId;
     UCharSetMapMap                      mTextFieldCharSets;
@@ -302,9 +301,14 @@ private:
     sal_Bool                            implExportDocument();
     sal_Bool                            implExportAnimations();
 
-    sal_Bool                            implExportPages( const XDrawPageSequence& rxPages,
-                                                         sal_Int32 nFirstPage, sal_Int32 nLastPage,
-                                                         sal_Int32 nVisiblePage, sal_Bool bMaster );
+    sal_Bool                            implExportMasterPages( const XDrawPageSequence& rxPages,
+                                                               sal_Int32 nFirstPage, sal_Int32 nLastPage );
+    sal_Bool                            implExportDrawPages( const XDrawPageSequence& rxPages,
+                                                             sal_Int32 nFirstPage, sal_Int32 nLastPage );
+    sal_Bool                            implExportPage( const ::rtl::OUString & sPageId,
+                                                        const Reference< XDrawPage > & rxPage,
+                                                        const Reference< XShapes > & xShapes,
+                                                        sal_Bool bMaster );
 
     sal_Bool                            implExportShapes( const Reference< XShapes >& rxShapes );
     sal_Bool                            implExportShape( const Reference< XShape >& rxShape );


More information about the Libreoffice-commits mailing list