summaryrefslogtreecommitdiff
path: root/filter
diff options
context:
space:
mode:
authorMarco Cecchetti <mrcekets@gmail.com>2012-06-06 19:19:44 +0200
committerMarco Cecchetti <mrcekets@gmail.com>2012-06-15 10:14:59 +0200
commit6016a685482aaa7e2ef80b31ee5196238665face (patch)
tree77cf5cb2ee5c376a5f903c333411435d95f3a377 /filter
parenta962bffa18e81032423e1c5c7065125d27caa163 (diff)
Enabled support for clipping-based slide transitions (barnWipe,
fourBoxWipe, ellipseWipe, pinWheelWipe). Ported or implemented the following classes or functions: ClippedSlideChange, PathTools.normalizePath, ClippingFunctor, createClipPolyPolygon, BarWipePath, FourBoxWipePath, PathTools.createPathFromEllipse, EllipseWipePath, PinWheelWipePath. Extended the following SVG DOM classes: SVGMatrix, SVGPathElement, SVGPathSegMovetoAbs, SVGPathSegLinetoAbs, SVGPathSegCurvetoQuadraticAbs, SVGPathSegCurvetoCubicAbs. Modified and added new methods to: MetaDocument, AnimatedSlide, SlideTransition, TransitionInfoTable.
Diffstat (limited to 'filter')
-rw-r--r--filter/source/svg/presentation_engine.js1555
-rw-r--r--filter/source/svg/svgexport.cxx1
2 files changed, 1523 insertions, 33 deletions
diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index 7b17623cba90..0b09ffedbfa8 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -390,6 +390,463 @@ function indexSetPageSlide( nIndex )
* @licstart
*
* The following is the license notice for the part of JavaScript code of this
+ * page included between the '@dojostart' and the '@dojoend' notes.
+ */
+
+/***** **********************************************************************
+ *
+ * The "New" BSD License:
+ * **********************
+ * Copyright (c) 2005-2012, The Dojo Foundation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the Dojo Foundation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+
+/*****
+ * @licend
+ *
+ * The above is the license notice for the part of JavaScript code of this
+ * page included between the '@dojostart' and the '@dojoend' notes.
+ */
+
+
+
+/*****
+ * @dojostart
+ *
+ * The following code is a derivative work of some part of the dojox.gfx library.
+ * @source http://svn.dojotoolkit.org/src/dojox/trunk/gfx/arc.js
+ */
+
+
+function degToRad( degree )
+{
+ return (Math.PI * degree / 180);
+}
+
+function radToDeg( radiant )
+{
+ return (180 * radiant / Math.PI);
+}
+
+
+var PathTools = new Object();
+
+
+PathTools.unitArcAsBezier = function( alpha )
+{
+ // summary: return a start point, 1st and 2nd control points, and an end point of
+ // a an arc, which is reflected on the x axis
+ // alpha: Number
+ // angle in radians, the arc will be 2 * angle size
+ var cosa = Math.cos(alpha);
+ var sina = Math.sin(alpha);
+ var p2 = {x: cosa + (4 / 3) * (1 - cosa), y: sina - (4 / 3) * cosa * (1 - cosa) / sina};
+
+ return { // Object
+ s: {x: cosa, y: -sina},
+ c1: {x: p2.x, y: -p2.y},
+ c2: p2,
+ e: {x: cosa, y: sina}
+ };
+};
+
+PathTools.arcAsBezier = function( last, rx, ry, xRotg, large, sweep, x, y )
+{
+ // summary: calculates an arc as a series of Bezier curves
+ // given the last point and a standard set of SVG arc parameters,
+ // it returns an array of arrays of parameters to form a series of
+ // absolute Bezier curves.
+ // last: Object
+ // a point-like object as a start of the arc
+ // rx: Number
+ // a horizontal radius for the virtual ellipse
+ // ry: Number
+ // a vertical radius for the virtual ellipse
+ // xRotg: Number
+ // a rotation of an x axis of the virtual ellipse in degrees
+ // large: Boolean
+ // which part of the ellipse will be used (the larger arc if true)
+ // sweep: Boolean
+ // direction of the arc (CW if true)
+ // x: Number
+ // the x coordinate of the end point of the arc
+ // y: Number
+ // the y coordinate of the end point of the arc
+
+ // constants
+ var twoPI = 2 * Math.PI, pi4 = Math.PI / 4, pi8 = Math.PI / 8,
+ pi48 = pi4 + pi8, curvePI4 = PathTools.unitArcAsBezier(pi8);
+
+ // calculate parameters
+ large = Boolean(large);
+ sweep = Boolean(sweep);
+
+ var xRot = degToRad( xRotg );
+ var rx2 = rx * rx, ry2 = ry * ry;
+ var m = document.documentElement.createSVGMatrix();
+ m = m.rotate(-xRotg);
+ var p = document.documentElement.createSVGPoint();
+ p.x = (last.x - x) / 2; p.y = (last.y - y) / 2;
+ var pa = p.matrixTransform( m );
+
+ var pax2 = pa.x * pa.x, pay2 = pa.y * pa.y;
+ var c1 = Math.sqrt((rx2 * ry2 - rx2 * pay2 - ry2 * pax2) / (rx2 * pay2 + ry2 * pax2));
+
+ if( isNaN(c1) ) { c1 = 0; }
+
+ var ca = {
+ x: c1 * rx * pa.y / ry,
+ y: -c1 * ry * pa.x / rx
+ };
+
+ if( large == sweep )
+ {
+ ca = {x: -ca.x, y: -ca.y};
+ }
+
+ // the center
+ m = document.documentElement.createSVGMatrix();
+ m = m.translate( (last.x + x) / 2, (last.y + y) / 2 ).rotate( xRotg );
+ p.x = ca.x; p.y = ca.y;
+ var c = p.matrixTransform( m );
+
+ // calculate the elliptic transformation
+ m = document.documentElement.createSVGMatrix();
+ var elliptic_transform = m.translate( c.x, c.y ).rotate( xRotg ).scaleNonUniform( rx, ry );
+
+ // start, end, and size of our arc
+ var inversed = elliptic_transform.inverse();
+ p.x = last.x; p.y = last.y;
+ var sp = p.matrixTransform( inversed );
+ p.x = x; p.y = y;
+ var ep = p.matrixTransform( inversed );
+ var startAngle = Math.atan2(sp.y, sp.x);
+ var endAngle = Math.atan2(ep.y, ep.x);
+ var theta = startAngle - endAngle; // size of our arc in radians
+
+ if( sweep ) { theta = -theta; }
+ if( theta < 0 )
+ {
+ theta += twoPI;
+ }
+ else if( theta > twoPI )
+ {
+ theta -= twoPI;
+ }
+
+ // draw curve chunks
+ var alpha = pi8, curve = curvePI4;
+ var step = sweep ? alpha : -alpha;
+ var result = [];
+
+ var aPathElement = document.createElementNS( NSS['svg'], 'path' );
+
+ for(var angle = theta; angle > 0; angle -= pi4)
+ {
+ if( angle < pi48 )
+ {
+ alpha = angle / 2;
+ curve = PathTools.unitArcAsBezier(alpha);
+ step = sweep ? alpha : -alpha;
+ angle = 0; // stop the loop
+ }
+ var c2, e;
+ var M = elliptic_transform.rotate( radToDeg( startAngle + step ) );
+
+ if( sweep )
+ {
+ p.x = curve.c1.x; p.y = curve.c1.y;
+ c1 = p.matrixTransform( M );
+ p.x = curve.c2.x; p.y = curve.c2.y;
+ c2 = p.matrixTransform( M );
+ p.x = curve.e.x; p.y = curve.e.y;
+ e = p.matrixTransform( M );
+ }
+ else
+ {
+ p.x = curve.c2.x; p.y = curve.c2.y;
+ c1 = p.matrixTransform( M );
+ p.x = curve.c1.x; p.y = curve.c1.y;
+ c2 = p.matrixTransform( M );
+ p.x = curve.s.x; p.y = curve.s.y;
+ e = p.matrixTransform( M );
+ }
+
+ // draw the curve
+ var aCubicBezierSeg = aPathElement.createSVGPathSegCurvetoCubicAbs( e.x, e.y, c1.x, c1.y, c2.x, c2.y );
+ result.push( aCubicBezierSeg );
+
+ startAngle += 2 * step;
+ }
+ return result; // Array
+};
+
+
+
+/*****
+ * @dojoend
+ *
+ * The above code is a derivative work of some part of the dojox.gfx library.
+ * @source http://svn.dojotoolkit.org/src/dojox/trunk/gfx/arc.js
+ */
+
+
+
+
+/** normalizePath
+ *
+ * @param sPath
+ * A string representing a svg <path> element list of commands.
+ * @return {String}
+ * A string representing the same svg <path> passed as input defined by
+ * using only the following commands: M, L, Q, C.
+ */
+PathTools.normalizePath = function( sPath )
+{
+ var PATHSEG_CLOSEPATH = 1;
+ var PATHSEG_MOVETO_ABS = 2;
+ var PATHSEG_MOVETO_REL = 3;
+ var PATHSEG_LINETO_ABS = 4;
+ var PATHSEG_LINETO_REL = 5;
+ var PATHSEG_CURVETO_CUBIC_ABS = 6;
+ var PATHSEG_CURVETO_CUBIC_REL = 7;
+ var PATHSEG_CURVETO_QUADRATIC_ABS = 8;
+ var PATHSEG_CURVETO_QUADRATIC_REL = 9;
+ var PATHSEG_ARC_ABS = 10;
+ var PATHSEG_ARC_REL = 11;
+ var PATHSEG_LINETO_HORIZONTAL_ABS = 12;
+ var PATHSEG_LINETO_HORIZONTAL_REL = 13;
+ var PATHSEG_LINETO_VERTICAL_ABS = 14;
+ var PATHSEG_LINETO_VERTICAL_REL = 15;
+ var PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16;
+ var PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17;
+ var PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18;
+ var PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19;
+
+ var aPath = document.createElementNS( NSS['svg'], 'path' );
+ aPath.setAttribute( 'd', sPath );
+ var aPathSegList = aPath.pathSegList;
+ if( !aPathSegList )
+ {
+ log( 'normalizePath: no path segment list supported, abort.' );
+ return '';
+ }
+ var nSize = aPathSegList.numberOfItems;
+
+ var aPreviousPathSeg = null;
+ var nCurrentX = 0;
+ var nCurrentY = 0;
+ var nInitialX = 0;
+ var nInitialY = 0;
+ var aPathSeg = null;
+ var aAbsPathSeg = null;
+
+ var i;
+ for( i = 0; i < nSize; ++i )
+ {
+
+ aPathSeg = aPathSegList.getItem( i );
+ switch( aPathSeg.pathSegType )
+ {
+ case PATHSEG_CLOSEPATH:
+ aAbsPathSeg = aPath.createSVGPathSegLinetoAbs( nInitialX, nInitialY );
+ aPathSegList.replaceItem( aAbsPathSeg, i );
+ break;
+ case PATHSEG_MOVETO_ABS:
+ nInitialX = aPathSeg.x;
+ nInitialY = aPathSeg.y;
+ break;
+ case PATHSEG_MOVETO_REL:
+ nCurrentX += aPathSeg.x;
+ nCurrentY += aPathSeg.y;
+ aAbsPathSeg = aPath.createSVGPathSegMovetoAbs( nCurrentX, nCurrentY );
+ aPathSegList.replaceItem( aAbsPathSeg, i );
+ nInitialX = nCurrentX;
+ nInitialY = nCurrentY;
+ break;
+ case PATHSEG_LINETO_ABS:
+ break;
+ case PATHSEG_LINETO_REL:
+ nCurrentX += aPathSeg.x;
+ nCurrentY += aPathSeg.y;
+ aAbsPathSeg = aPath.createSVGPathSegLinetoAbs( nCurrentX, nCurrentY );
+ aPathSegList.replaceItem( aAbsPathSeg, i );
+ break;
+ case PATHSEG_CURVETO_CUBIC_ABS:
+ break;
+ case PATHSEG_CURVETO_CUBIC_REL:
+ var nX1 = nCurrentX + aPathSeg.x1;
+ var nY1 = nCurrentY + aPathSeg.y1;
+ var nX2 = nCurrentX + aPathSeg.x2;
+ var nY2 = nCurrentY + aPathSeg.y2;
+ var nX = nCurrentX + aPathSeg.x;
+ var nY = nCurrentY + aPathSeg.y;
+ aAbsPathSeg = aPath.createSVGPathSegCurvetoCubicAbs( nX, nY, nX1, nY1, nX2, nY2 );
+ aPathSegList.replaceItem( aAbsPathSeg, i );
+ break;
+ case PATHSEG_CURVETO_QUADRATIC_ABS:
+ break;
+ case PATHSEG_CURVETO_QUADRATIC_REL:
+ nX1 = nCurrentX + aPathSeg.x1;
+ nY1 = nCurrentY + aPathSeg.y1;
+ nX = nCurrentX + aPathSeg.x;
+ nY = nCurrentY + aPathSeg.y;
+ aAbsPathSeg = aPath.createSVGPathSegCurvetoQuadraticAbs( nX, nY, nX1, nY1 );
+ aPathSegList.replaceItem( aAbsPathSeg, i );
+ break;
+ case PATHSEG_ARC_REL:
+ aPathSeg.x += nCurrentX;
+ aPathSeg.y += nCurrentY;
+ case PATHSEG_ARC_ABS:
+ var aCubicBezierSegList
+ = PathTools.arcAsBezier( { x: nCurrentX, y: nCurrentY },
+ aPathSeg.r1, aPathSeg.r2,
+ aPathSeg.angle,
+ aPathSeg.largeArcFlag,
+ aPathSeg.sweepFlag,
+ aPathSeg.x, aPathSeg.y );
+ var nLength = aCubicBezierSegList.length;
+ if( nLength > 0 )
+ {
+ var k;
+ for( k = 0; k < nLength; ++k )
+ {
+ aPathSegList.insertItemBefore( aCubicBezierSegList[k], i );
+ i += 1;
+ }
+ aPathSegList.removeItem( i );
+ i -= 1;
+ nSize += ( nLength - 1 );
+ }
+ break;
+ case PATHSEG_LINETO_HORIZONTAL_REL:
+ aPathSeg.x += nCurrentX;
+ // fall through intended
+ case PATHSEG_LINETO_HORIZONTAL_ABS:
+ aAbsPathSeg = aPath.createSVGPathSegLinetoAbs( aPathSeg.x, nCurrentY );
+ aPathSegList.replaceItem( aAbsPathSeg, i );
+ break;
+ case PATHSEG_LINETO_VERTICAL_REL:
+ aPathSeg.y += nCurrentY;
+ // fall through intended
+ case PATHSEG_LINETO_VERTICAL_ABS:
+ aAbsPathSeg = aPath.createSVGPathSegLinetoAbs( nCurrentX, aPathSeg.y );
+ aPathSegList.replaceItem( aAbsPathSeg, i );
+ break;
+ case PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
+ aPathSeg.x += nCurrentX;
+ aPathSeg.y += nCurrentY;
+ aPathSeg.x2 += nCurrentX;
+ aPathSeg.y2 += nCurrentY;
+ // fall through intended
+ case PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
+ if( aPreviousPathSeg.pathSegType == PATHSEG_CURVETO_CUBIC_ABS )
+ {
+ nX1 = 2*nCurrentX - aPreviousPathSeg.x2;
+ nY1 = 2*nCurrentY - aPreviousPathSeg.y2;
+ }
+ else
+ {
+ nX1 = nCurrentX;
+ nY1 = nCurrentY;
+ }
+ aAbsPathSeg = aPath.createSVGPathSegCurvetoCubicAbs( aPathSeg.x, aPathSeg.y,
+ nX1, nY1,
+ aPathSeg.x2, aPathSeg.y2 );
+ aPathSegList.replaceItem( aAbsPathSeg, i );
+ break;
+ case PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
+ aPathSeg.x += nCurrentX;
+ aPathSeg.y += nCurrentY;
+ // fall through intended
+ case PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
+ if( aPreviousPathSeg.pathSegType == PATHSEG_CURVETO_QUADRATIC_ABS )
+ {
+ nX1 = 2*nCurrentX - aPreviousPathSeg.x1;
+ nY1 = 2*nCurrentY - aPreviousPathSeg.y1;
+ }
+ else
+ {
+ nX1 = nCurrentX;
+ nY1 = nCurrentY;
+ }
+ aAbsPathSeg = aPath.createSVGPathSegCurvetoQuadraticAbs( aPathSeg.x, aPathSeg.y, nX1, nY1 );
+ aPathSegList.replaceItem( aAbsPathSeg, i );
+ break;
+ default:
+ log( 'normalizePath: unknown path segment, index: ' + String(i) );
+ }
+ aPreviousPathSeg = aPathSegList.getItem( i );
+ nCurrentX = aPreviousPathSeg.x;
+ nCurrentY = aPreviousPathSeg.y;
+ }
+ return aPath.getAttribute( 'd' );
+};
+
+
+/** createPathFromEllipse
+ *
+ * @param nCX
+ * The ellipse center x coordinate.
+ * @param nCY
+ * The ellipse center y coordinate.
+ * @param nXRay
+ * The ellipse x-ray.
+ * @param nYRay
+ * The ellipse y-ray.
+ * @return {String}
+ * A string representing a list of path commands that approximate
+ * the ellipse.
+ */
+PathTools.createPathFromEllipse = function( nCX, nCY, nXRay, nYRay )
+{
+ var V1X = nCX, V1Y = nCY - nYRay;
+ var V2X = nCX + nXRay, V2Y = nCY;
+ var V3X = nCX, V3Y = nCY + nYRay;
+ var V4X = nCX - nXRay, V4Y = nCY;
+
+ var sPathData = 'M ' + V1X + ' ' + V1Y +
+ ' A ' + nXRay + ' ' + nYRay + ' 0 0 1 ' + V2X + ' ' + V2Y +
+ ' A ' + nXRay + ' ' + nYRay + ' 0 0 1 ' + V3X + ' ' + V3Y +
+ ' A ' + nXRay + ' ' + nYRay + ' 0 0 1 ' + V4X + ' ' + V4Y +
+ ' A ' + nXRay + ' ' + nYRay + ' 0 0 1 ' + V1X + ' ' + V1Y;
+
+ sPathData = PathTools.normalizePath( sPathData );
+ return sPathData;
+};
+
+
+
+
+/*****
+ * @licstart
+ *
+ * The following is the license notice for the part of JavaScript code of this
* page included between the '@stdlibstart' and the '@stdlibend' notes.
*/
@@ -627,6 +1084,7 @@ window.onload = init;
var aOOOElemMetaSlides = 'ooo:meta_slides';
var aOOOElemMetaSlide = 'ooo:meta_slide';
var aOOOElemTextField = 'ooo:text_field';
+var aPresentationClipPathId = 'presentation_clip_path';
// ooo attributes
var aOOOAttrNumberOfSlides = 'number-of-slides';
@@ -651,6 +1109,7 @@ var aOOOAttrDateTimeFormat = 'date-time-format';
var aOOOAttrTextAdjust = 'text-adjust';
// element class names
+var aClipPathGroupClassName = 'ClipPathGroup';
var aPageClassName = 'Page';
var aSlideNumberClassName = 'Slide_Number';
var aDateTimeClassName = 'Date/Time';
@@ -1031,6 +1490,15 @@ function MetaDocument()
// - the numbering type used in the presentation, default type is arabic.
this.sPageNumberingType = aMetaDocElem.getAttributeNS( NSS['ooo'], aOOOAttrNumberingType ) || 'arabic';
+ // The <defs> element used for wrapping <clipPath>.
+ this.aClipPathGroup = getElementByClassName( ROOT_NODE, aClipPathGroupClassName );
+ assert( this.aClipPathGroup, 'MetaDocument: the clip path group element is not valid.');
+
+ // The <clipPath> element used to clip all slides.
+ this.aPresentationClipPath = document.getElementById( aPresentationClipPathId );
+ assert( this.aPresentationClipPath,
+ 'MetaDocument: the presentation clip path element element is not valid.');
+
// The collections for handling properties of each slide, svg elements
// related to master pages and content and properties of text fields.
this.aMetaSlideSet = new Array();
@@ -3145,6 +3613,250 @@ HSLColor.interpolate = function( aFrom, aTo, nT, bCCW )
+/**********************************************************************************************
+ * SVGMatrix extensions
+ **********************************************************************************************/
+
+SVGIdentityMatrix = document.documentElement.createSVGMatrix();
+
+SVGMatrix.prototype.setToIdentity = function()
+{
+ this.a = this.d = 1;
+ this.b = this.c = this.d = this.e = 0;
+};
+
+SVGMatrix.prototype.setToRotationAroundPoint = function( nX, nY, nAngle )
+{
+ nAngle = degToRad( nAngle );
+ var nSin = Math.sin( nAngle );
+ var nCos = Math.cos( nAngle );
+
+ this.a = nCos; this.c = -nSin; this.e = nX * (1 - nCos) + nY * nSin;
+ this.b = nSin; this.d = nCos; this.f = nY * (1 - nCos) - nX * nSin;
+};
+
+
+
+/**********************************************************************************************
+ * SVGPath extensions
+ **********************************************************************************************/
+
+SVGPathElement.prototype.appendPath = function( aPath )
+{
+ var sPathData = this.getAttribute( 'd' );
+ sPathData += ( ' ' + aPath.getAttribute( 'd' ) );
+ this.setAttribute( 'd', sPathData );
+};
+
+/** SVGPathElement.matrixTransform
+ * Apply the transformation defined by the passed matrix to the referenced
+ * svg <path> element.
+ * After the transformation 'this' element is modified in order to reference
+ * the transformed path.
+ *
+ * @param aSVGMatrix
+ * An SVGMatrix instance.
+ */
+SVGPathElement.prototype.matrixTransform = function( aSVGMatrix )
+{
+ var aPathSegList = this.pathSegList;
+ var nLength = aPathSegList.numberOfItems;
+ var i;
+ for( i = 0; i < nLength; ++i )
+ {
+ aPathSegList.getItem( i ).matrixTransform( aSVGMatrix );
+ }
+};
+
+/** SVGPathElement.changeOrientation
+ * Invert the path orientation by inverting the path command list.
+ *
+ */
+SVGPathElement.prototype.changeOrientation = function()
+{
+ var aPathSegList = this.pathSegList;
+ var nLength = aPathSegList.numberOfItems;
+ if( nLength == 0 ) return;
+
+ var nCurrentX = 0;
+ var nCurrentY = 0;
+
+ var aPathSeg = aPathSegList.getItem( 0 );
+ if( aPathSeg.pathSegTypeAsLetter == 'M' )
+ {
+ nCurrentX = aPathSeg.x;
+ nCurrentY = aPathSeg.y;
+ aPathSegList.removeItem( 0 );
+ --nLength;
+ }
+
+ var i;
+ for( i = 0; i < nLength; ++i )
+ {
+ aPathSeg = aPathSegList.getItem( i );
+ var aPoint = aPathSeg.changeOrientation( nCurrentX, nCurrentY );
+ nCurrentX = aPoint.x;
+ nCurrentY = aPoint.y;
+ }
+
+
+ for( i = nLength - 2; i >= 0; --i )
+ {
+ aPathSeg = aPathSegList.removeItem( i );
+ aPathSegList.appendItem( aPathSeg );
+ }
+
+ var aMovePathSeg = this.createSVGPathSegMovetoAbs( nCurrentX, nCurrentY );
+ aPathSegList.insertItemBefore( aMovePathSeg, 0 );
+
+}
+
+/** matrixTransform and changeOrientation
+ * We implement these methods for each path segment type still present
+ * after the path normalization (M, L, Q, C).
+ *
+ * Note: Opera doesn't have any SVGPathSeg* class and rises an error.
+ * We exploit this fact for providing a different implementation.
+ */
+try
+{ // Firefox, Google Chrome, Internet Explorer, Safari.
+
+ SVGPathSegMovetoAbs.prototype.matrixTransform = function( aSVGMatrix )
+ {
+ SVGPathMatrixTransform( this, aSVGMatrix );
+ };
+
+ SVGPathSegLinetoAbs.prototype.matrixTransform = function( aSVGMatrix )
+ {
+ SVGPathMatrixTransform( this, aSVGMatrix );
+ };
+
+ SVGPathSegCurvetoQuadraticAbs.prototype.matrixTransform = function( aSVGMatrix )
+ {
+ SVGPathMatrixTransform( this, aSVGMatrix );
+ var nX = this.x1;
+ this.x1 = aSVGMatrix.a * nX + aSVGMatrix.c * this.y1 + aSVGMatrix.e;
+ this.y1 = aSVGMatrix.b * nX + aSVGMatrix.d * this.y1 + aSVGMatrix.f;
+ };
+
+ SVGPathSegCurvetoCubicAbs.prototype.matrixTransform = function( aSVGMatrix )
+ {
+ SVGPathMatrixTransform( this, aSVGMatrix );
+ var nX = this.x1;
+ this.x1 = aSVGMatrix.a * nX + aSVGMatrix.c * this.y1 + aSVGMatrix.e;
+ this.y1 = aSVGMatrix.b * nX + aSVGMatrix.d * this.y1 + aSVGMatrix.f;
+ nX = this.x2;
+ this.x2 = aSVGMatrix.a * nX + aSVGMatrix.c * this.y2 + aSVGMatrix.e;
+ this.y2 = aSVGMatrix.b * nX + aSVGMatrix.d * this.y2 + aSVGMatrix.f;
+ };
+
+
+ SVGPathSegMovetoAbs.prototype.changeOrientation = function( nCurrentX, nCurrentY )
+ {
+ var aPoint = { x: this.x, y: this.y };
+ this.x = nCurrentX;
+ this.y = nCurrentY;
+ return aPoint;
+ };
+
+ SVGPathSegLinetoAbs.prototype.changeOrientation = function( nCurrentX, nCurrentY )
+ {
+ var aPoint = { x: this.x, y: this.y };
+ this.x = nCurrentX;
+ this.y = nCurrentY;
+ return aPoint;
+ };
+
+ SVGPathSegCurvetoQuadraticAbs.prototype.changeOrientation = function( nCurrentX, nCurrentY )
+ {
+ var aPoint = { x: this.x, y: this.y };
+ this.x = nCurrentX;
+ this.y = nCurrentY;
+ return aPoint;
+ };
+
+ SVGPathSegCurvetoCubicAbs.prototype.changeOrientation = function( nCurrentX, nCurrentY )
+ {
+ var aPoint = { x: this.x, y: this.y };
+ this.x = nCurrentX;
+ this.y = nCurrentY;
+ var nX = this.x1;
+ this.x1 = this.x2;
+ this.x2 = nX;
+ var nY = this.y1;
+ this.y1 = this.y2;
+ this.y2 = nY;
+ return aPoint;
+ };
+
+}
+catch( e )
+{ // Opera
+
+ if( e.name == 'ReferenceError' )
+ {
+ SVGPathSeg.prototype.matrixTransform = function( aSVGMatrix )
+ {
+ var nX;
+ switch( this.pathSegTypeAsLetter )
+ {
+ case 'C':
+ nX = this.x2;
+ this.x2 = aSVGMatrix.a * nX + aSVGMatrix.c * this.y2 + aSVGMatrix.e;
+ this.y2 = aSVGMatrix.b * nX + aSVGMatrix.d * this.y2 + aSVGMatrix.f;
+ // fall through intended
+ case 'Q':
+ nX = this.x1;
+ this.x1 = aSVGMatrix.a * nX + aSVGMatrix.c * this.y1 + aSVGMatrix.e;
+ this.y1 = aSVGMatrix.b * nX + aSVGMatrix.d * this.y1 + aSVGMatrix.f;
+ // fall through intended
+ case 'M':
+ case 'L':
+ SVGPathMatrixTransform( this, aSVGMatrix );
+ break;
+ default:
+ log( 'SVGPathSeg.matrixTransform: unexpected path segment type: '
+ + this.pathSegTypeAsLetter );
+ }
+ };
+
+ SVGPathSeg.prototype.changeOrientation = function( nCurrentX, nCurrentY )
+ {
+ switch( this.pathSegTypeAsLetter )
+ {
+ case 'C':
+ var nX = this.x1;
+ this.x1 = this.x2;
+ this.x2 = nX;
+ var nY = this.y1;
+ this.y1 = this.y2;
+ this.y2 = nY;
+ // fall through intended
+ case 'M':
+ case 'L':
+ case 'Q':
+ var aPoint = { x: this.x, y: this.y };
+ this.x = nCurrentX;
+ this.y = nCurrentY;
+ return aPoint;
+ default:
+ log( 'SVGPathSeg.changeOrientation: unexpected path segment type: '
+ + this.pathSegTypeAsLetter );
+ return null;
+ }
+ }
+ }
+ else throw e;
+}
+
+function SVGPathMatrixTransform( aPath, aSVGMatrix )
+{
+ var nX = aPath.x;
+ aPath.x = aSVGMatrix.a * nX + aSVGMatrix.c * aPath.y + aSVGMatrix.e;
+ aPath.y = aSVGMatrix.b * nX + aSVGMatrix.d * aPath.y + aSVGMatrix.f;
+}
+
+
/**********************************************************************************************
* AnimationNode Class Hierarchy
@@ -3431,36 +4143,75 @@ aTransitionClassOutMap = ['invalid', 'clip polypolygon', 'special'];
// Transition Types
BARWIPE_TRANSITION = 1;
-PUSHWIPE_TRANSITION = 2; // 35
-SLIDEWIPE_TRANSITION = 3; // 36
-FADE_TRANSITION = 4; // 37
+BOXWIPE_TRANSITION = 2;
+FOURBOXWIPE_TRANSITION = 3;
+ELLIPSEWIPE_TRANSITION = 4; // 17
+CLOCKWIPE_TRANSITION = 5; // 22
+PINWHEELWIPE_TRANSITION = 6 // 23
+PUSHWIPE_TRANSITION = 7; // 35
+SLIDEWIPE_TRANSITION = 8; // 36
+FADE_TRANSITION = 9; // 37
aTransitionTypeInMap = {
'barWipe' : BARWIPE_TRANSITION,
+ 'boxWipe' : BOXWIPE_TRANSITION,
+ 'fourBoxWipe' : FOURBOXWIPE_TRANSITION,
+ 'ellipseWipe' : ELLIPSEWIPE_TRANSITION,
+ 'clockWipe' : CLOCKWIPE_TRANSITION,
+ 'pinWheelWipe' : PINWHEELWIPE_TRANSITION,
'pushWipe' : PUSHWIPE_TRANSITION,
'slideWipe' : SLIDEWIPE_TRANSITION,
'fade' : FADE_TRANSITION
};
-aTransitionTypeOutMap = [ '', 'barWipe', 'pushWipe', 'slideWipe', 'fade' ];
+aTransitionTypeOutMap = [ '', 'barWipe', 'boxWipe', 'fourBoxWipe', 'ellipseWipe',
+ 'clockWipe', 'pinWheelWipe', 'pushWipe', 'slideWipe',
+ 'fade' ];
// Transition Subtypes
DEFAULT_TRANS_SUBTYPE = 0;
LEFTTORIGHT_TRANS_SUBTYPE = 1;
TOPTOBOTTOM_TRANS_SUBTYPE = 2;
-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
+CORNERSIN_TRANS_SUBTYPE = 3; // 11
+CORNERSOUT_TRANS_SUBTYPE = 4;
+VERTICAL_TRANS_SUBTYPE = 5;
+HORIZONTAL_TRANS_SUBTYPE = 6; // 14
+CIRCLE_TRANS_SUBTYPE = 7; // 27
+CLOCKWISETWELVE_TRANS_SUBTYPE = 8; // 33
+CLOCKWISETHREE_TRANS_SUBTYPE = 9;
+CLOCKWISESIX_TRANS_SUBTYPE = 10;
+CLOCKWISENINE_TRANS_SUBTYPE = 11;
+TWOBLADEVERTICAL_TRANS_SUBTYPE = 12;
+TWOBLADEHORIZONTAL_TRANS_SUBTYPE = 13;
+FOURBLADE_TRANS_SUBTYPE = 14; // 39
+FROMLEFT_TRANS_SUBTYPE = 15; // 97
+FROMTOP_TRANS_SUBTYPE = 16;
+FROMRIGHT_TRANS_SUBTYPE = 17;
+FROMBOTTOM_TRANS_SUBTYPE = 18;
+CROSSFADE_TRANS_SUBTYPE = 19;
+FADETOCOLOR_TRANS_SUBTYPE = 20;
+FADEFROMCOLOR_TRANS_SUBTYPE = 21;
+FADEOVERCOLOR_TRANS_SUBTYPE = 22;
+THREEBLADE_TRANS_SUBTYPE = 23;
+EIGHTBLADE_TRANS_SUBTYPE = 24;
+ONEBLADE_TRANS_SUBTYPE = 25; // 107
aTransitionSubtypeInMap = {
'leftToRight' : LEFTTORIGHT_TRANS_SUBTYPE,
'topToBottom' : TOPTOBOTTOM_TRANS_SUBTYPE,
+ 'cornersIn' : CORNERSIN_TRANS_SUBTYPE,
+ 'cornersOut' : CORNERSOUT_TRANS_SUBTYPE,
+ 'vertical' : VERTICAL_TRANS_SUBTYPE,
+ 'horizontal' : HORIZONTAL_TRANS_SUBTYPE,
+ 'circle' : CIRCLE_TRANS_SUBTYPE,
+ 'clockwiseTwelve' : CLOCKWISETWELVE_TRANS_SUBTYPE,
+ 'clockwiseThree' : CLOCKWISETHREE_TRANS_SUBTYPE,
+ 'clockwiseSix' : CLOCKWISESIX_TRANS_SUBTYPE,
+ 'clockwiseNine' : CLOCKWISENINE_TRANS_SUBTYPE,
+ 'twoBladeVertical' : TWOBLADEVERTICAL_TRANS_SUBTYPE,
+ 'twoBladeHorizontal': TWOBLADEHORIZONTAL_TRANS_SUBTYPE,
+ 'fourBlade' : FOURBLADE_TRANS_SUBTYPE,
'fromLeft' : FROMLEFT_TRANS_SUBTYPE,
'fromTop' : FROMTOP_TRANS_SUBTYPE,
'fromRight' : FROMRIGHT_TRANS_SUBTYPE,
@@ -3468,12 +4219,19 @@ aTransitionSubtypeInMap = {
'crossfade' : CROSSFADE_TRANS_SUBTYPE,
'fadeToColor' : FADETOCOLOR_TRANS_SUBTYPE,
'fadeFromColor' : FADEFROMCOLOR_TRANS_SUBTYPE,
- 'fadeOverColor' : FADEOVERCOLOR_TRANS_SUBTYPE
+ 'fadeOverColor' : FADEOVERCOLOR_TRANS_SUBTYPE,
+ 'threeBlade' : THREEBLADE_TRANS_SUBTYPE,
+ 'eightBlade' : EIGHTBLADE_TRANS_SUBTYPE,
+ 'oneBlade' : ONEBLADE_TRANS_SUBTYPE
};
-aTransitionSubtypeOutMap = [ 'default', 'leftToRight', 'topToBottom', 'fromLeft',
- 'fromTop', 'fromRight', 'fromBottom', 'crossfade',
- 'fadeToColor', 'fadeFromColor', 'fadeOverColor' ];
+aTransitionSubtypeOutMap = [ 'default', 'leftToRight', 'topToBottom', 'cornersIn',
+ 'cornersOut', 'vertical', 'horizontal', 'circle',
+ 'clockwiseTwelve', 'clockwiseThree', 'clockwiseSix',
+ 'clockwiseNine', 'twoBladeVertical', 'twoBladeHorizontal',
+ 'fourBlade', 'fromLeft', 'fromTop', 'fromRight',
+ 'fromBottom', 'crossfade', 'fadeToColor', 'fadeFromColor',
+ 'fadeOverColor', 'threeBlade', 'eightBlade', 'oneBlade' ];
// Transition Modes
@@ -3548,6 +4306,119 @@ aTransitionInfoTable[BARWIPE_TRANSITION][TOPTOBOTTOM_TRANS_SUBTYPE] =
'scaleIsotropically' : false
};
+aTransitionInfoTable[FOURBOXWIPE_TRANSITION] = {};
+aTransitionInfoTable[FOURBOXWIPE_TRANSITION][CORNERSIN_TRANS_SUBTYPE] =
+aTransitionInfoTable[FOURBOXWIPE_TRANSITION][CORNERSOUT_TRANS_SUBTYPE] =
+{
+ 'class' : TRANSITION_CLIP_POLYPOLYGON,
+ 'rotationAngle' : 0.0,
+ 'scaleX' : 1.0,
+ 'scaleY' : 1.0,
+ 'reverseMethod' : REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ 'outInvertsSweep' : true,
+ 'scaleIsotropically' : false
+};
+
+aTransitionInfoTable[ELLIPSEWIPE_TRANSITION] = {};
+aTransitionInfoTable[ELLIPSEWIPE_TRANSITION][CIRCLE_TRANS_SUBTYPE] =
+{
+ 'class' : TRANSITION_CLIP_POLYPOLYGON,
+ 'rotationAngle' : 0.0,
+ 'scaleX' : 1.0,
+ 'scaleY' : 1.0,
+ 'reverseMethod' : REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ 'outInvertsSweep' : true,
+ 'scaleIsotropically' : true
+};
+aTransitionInfoTable[ELLIPSEWIPE_TRANSITION][HORIZONTAL_TRANS_SUBTYPE] =
+{
+ 'class' : TRANSITION_CLIP_POLYPOLYGON,
+ 'rotationAngle' : 0.0,
+ 'scaleX' : 1.0,
+ 'scaleY' : 1.0,
+ 'reverseMethod' : REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ 'outInvertsSweep' : true,
+ 'scaleIsotropically' : false
+};
+aTransitionInfoTable[ELLIPSEWIPE_TRANSITION][VERTICAL_TRANS_SUBTYPE] =
+{
+ 'class' : TRANSITION_CLIP_POLYPOLYGON,
+ 'rotationAngle' : 90.0,
+ 'scaleX' : 1.0,
+ 'scaleY' : 1.0,
+ 'reverseMethod' : REVERSEMETHOD_SUBTRACT_AND_INVERT,
+ 'outInvertsSweep' : true,
+ 'scaleIsotropically' : false
+};
+
+aTransitionInfoTable[CLOCKWIPE_TRANSITION] = {};
+aTransitionInfoTable[CLOCKWIPE_TRANSITION][CLOCKWISETWELVE_TRANS_SUBTYPE] =
+{
+ 'class' : TRANSITION_CLIP_POLYPOLYGON,
+ 'rotationAngle' : 0.0,
+ 'scaleX' : 1.0,
+ 'scaleY' : 1.0,
+ 'reverseMethod' : REVERSEMETHOD_FLIP_X,
+ 'outInvertsSweep' : true,
+ 'scaleIsotropically' : false
+};
+aTransitionInfoTable[CLOCKWIPE_TRANSITION][CLOCKWISETHREE_TRANS_SUBTYPE] =
+{
+ 'class' : TRANSITION_CLIP_POLYPOLYGON,
+ 'rotationAngle' : 90.0,
+ 'scaleX' : 1.0,
+ 'scaleY' : 1.0,
+ 'reverseMethod' : REVERSEMETHOD_FLIP_Y,
+ 'outInvertsSweep' : true,
+ 'scaleIsotropically' : false
+};
+aTransitionInfoTable[CLOCKWIPE_TRANSITION][CLOCKWISESIX_TRANS_SUBTYPE] =
+{
+ 'class' : TRANSITION_CLIP_POLYPOLYGON,
+ 'rotationAngle' : 180.0,
+ 'scaleX' : 1.0,
+ 'scaleY' : 1.0,
+ 'reverseMethod' : REVERSEMETHOD_FLIP_X,
+ 'outInvertsSweep' : true,
+ 'scaleIsotropically' : false
+};
+aTransitionInfoTable[CLOCKWIPE_TRANSITION][CLOCKWISENINE_TRANS_SUBTYPE] =
+{
+ 'class' : TRANSITION_CLIP_POLYPOLYGON,
+ 'rotationAngle' : 270.0,
+ 'scaleX' : 1.0,
+ 'scaleY' : 1.0,
+ 'reverseMethod' : REVERSEMETHOD_FLIP_Y,
+ 'outInvertsSweep' : true,
+ 'scaleIsotropically' : false
+};
+
+aTransitionInfoTable[PINWHEELWIPE_TRANSITION] = {};
+aTransitionInfoTable[PINWHEELWIPE_TRANSITION][ONEBLADE_TRANS_SUBTYPE] =
+aTransitionInfoTable[PINWHEELWIPE_TRANSITION][TWOBLADEVERTICAL_TRANS_SUBTYPE] =
+aTransitionInfoTable[PINWHEELWIPE_TRANSITION][THREEBLADE_TRANS_SUBTYPE] =
+aTransitionInfoTable[PINWHEELWIPE_TRANSITION][FOURBLADE_TRANS_SUBTYPE] =
+aTransitionInfoTable[PINWHEELWIPE_TRANSITION][EIGHTBLADE_TRANS_SUBTYPE] =
+{
+ 'class' : TRANSITION_CLIP_POLYPOLYGON,
+ 'rotationAngle' : 0.0,
+ 'scaleX' : 1.0,
+ 'scaleY' : 1.0,
+ 'reverseMethod' : REVERSEMETHOD_FLIP_X,
+ 'outInvertsSweep' : true,
+ 'scaleIsotropically' : true
+};
+aTransitionInfoTable[PINWHEELWIPE_TRANSITION][TWOBLADEHORIZONTAL_TRANS_SUBTYPE] =
+{
+ 'class' : TRANSITION_CLIP_POLYPOLYGON,
+ 'rotationAngle' : -90.0,
+ 'scaleX' : 1.0,
+ 'scaleY' : 1.0,
+ 'reverseMethod' : REVERSEMETHOD_FLIP_Y,
+ 'outInvertsSweep' : true,
+ 'scaleIsotropically' : true
+};
+
aTransitionInfoTable[PUSHWIPE_TRANSITION] = {};
aTransitionInfoTable[PUSHWIPE_TRANSITION][FROMLEFT_TRANS_SUBTYPE] =
aTransitionInfoTable[PUSHWIPE_TRANSITION][FROMTOP_TRANS_SUBTYPE] =
@@ -6369,6 +7240,540 @@ MovingSlideChange.prototype.performOut = function( nT )
// ------------------------------------------------------------------------------------------ //
+/** Class ClippedSlideChange
+ * This class performs a slide transition where the entering slide wipes
+ * the leaving one out. The wipe effect is achieved by clipping the entering
+ * slide with a parametric path.
+ *
+ * @param aLeavingSlide
+ * An object of type AnimatedSlide handling the leaving slide.
+ * @param aEnteringSlide
+ * An object of type AnimatedSlide handling the entering slide.
+ * @param aParametricPolyPolygon
+ * An object handling a <path> element that depends on a parameter.
+ * @param aTransitionInfo
+ * The set of parameters defining the slide transition to be performed.
+ * @param bIsDirectionForward
+ * The direction the slide transition has to be performed.
+ */
+function ClippedSlideChange( aLeavingSlide, aEnteringSlide, aParametricPolyPolygon,
+ aTransitionInfo, bIsDirectionForward )
+{
+ ClippedSlideChange.superclass.constructor.call( this, aLeavingSlide, aEnteringSlide );
+
+ var bIsModeIn = true;
+ this.aClippingFunctor= new ClippingFunctor( aParametricPolyPolygon, aTransitionInfo,
+ bIsDirectionForward, bIsModeIn );
+}
+extend( ClippedSlideChange, 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.
+ */
+ClippedSlideChange.prototype.start = function()
+{
+ ClippedSlideChange.superclass.start.call( this );
+ this.aEnteringSlide.notifyUsedAttribute( 'clip-path' );;
+ 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.
+ */
+ClippedSlideChange.prototype.performIn = function( nT )
+{
+ var nWidth = this.aEnteringSlide.getWidth();
+ var nHeight = this.aEnteringSlide.getHeight();
+ var aPolyPolygonElement = this.aClippingFunctor.perform( nT, nWidth, nHeight );
+ this.aEnteringSlide.setClipPath( aPolyPolygonElement );
+};
+
+ClippedSlideChange.prototype.performOut = function( nT )
+{
+ // empty body
+};
+
+
+
+// ------------------------------------------------------------------------------------------ //
+/** Class ClippingFunctor
+ * This class is responsible for computing the <path> used for clipping
+ * the entering slide in a polypolygon clipping slide transition or the
+ * animated shape in a transition filter effect.
+ *
+ * @param aParametricPolyPolygon
+ * An object that handle a <path> element defined in the [0,1]x[0,1]
+ * unit square and that depends on a parameter.
+ * @param aTransitionInfo
+ * The set of parameters defining the slide transition to be performed.
+ * @param bIsDirectionForward
+ * The direction the slide transition has to be performed.
+ * @param bIsModeIn
+ * The direction the filter effect has to be performed
+ */
+function ClippingFunctor( aParametricPolyPolygon, aTransitionInfo,
+ bIsDirectionForward, bIsModeIn)
+{
+ this.aParametricPolyPolygon = aParametricPolyPolygon;
+ this.aStaticTransformation = null;
+ this.bForwardParameterSweep = true;
+ this.bSubtractPolygon = false;
+ this.bScaleIsotropically = aTransitionInfo.scaleIsotropically;
+ this.bFlip = false;
+
+ assert( this.aParametricPolyPolygon,
+ 'ClippingFunctor: parametric polygon is not valid' );
+
+ if( aTransitionInfo.rotationAngle != 0.0 ||
+ aTransitionInfo.scaleX != 1.0 || aTransitionInfo.scaleY != 1.0 )
+ {
+ // note: operations must be defined in reverse order.
+ this.aStaticTransformation = SVGIdentityMatrix.translate( 0.5, 0.5 );
+ if( aTransitionInfo.scaleX != 1.0 || aTransitionInfo.scaleY != 1.0 )
+ this.aStaticTransformation
+ = this.aStaticTransformation.scaleNonUniform( aTransitionInfo.scaleX,
+ aTransitionInfo.scaleY );
+ if( aTransitionInfo.rotationAngle != 0.0 )
+ this.aStaticTransformation
+ = this.aStaticTransformation.rotate( aTransitionInfo.rotationAngle );
+ this.aStaticTransformation = this.aStaticTransformation.translate( -0.5, -0.5 );
+ }
+ else
+ {
+ this.aStaticTransformation = document.documentElement.createSVGMatrix();
+ }
+
+ if( !bIsDirectionForward )
+ {
+ var aMatrix = null;
+ switch( aTransitionInfo.reverseMethod )
+ {
+ default:
+ log( 'ClippingFunctor: unexpected reverse method.' )
+ break;
+ case REVERSEMETHOD_IGNORE:
+ break;
+ case REVERSEMETHOD_INVERT_SWEEP:
+ this.bForwardParameterSweep = !this.bForwardParameterSweep;
+ break;
+ case REVERSEMETHOD_SUBTRACT_POLYGON:
+ this.bSubtractPolygon = !this.bSubtractPolygon;
+ break;
+ case REVERSEMETHOD_SUBTRACT_AND_INVERT:
+ this.bForwardParameterSweep = !this.bForwardParameterSweep;
+ this.bSubtractPolygon = !this.bSubtractPolygon;
+ break;
+ case REVERSEMETHOD_ROTATE_180:
+ aMatrix = document.documentElement.createSVGMatrix();
+ aMatrix.setToRotationAroundPoint( 0.5, 0.5, 180 );
+ this.aStaticTransformation = aMatrix.multiply( this.aStaticTransformation );
+ break;
+ case REVERSEMETHOD_FLIP_X:
+ aMatrix = document.documentElement.createSVGMatrix();
+ // |-1 0 1 |
+ // | 0 1 0 |
+ aMatrix.a = -1; aMatrix.e = 1.0;
+ this.aStaticTransformation = aMatrix.multiply( this.aStaticTransformation );
+ this.bFlip = true;
+ break;
+ case REVERSEMETHOD_FLIP_Y:
+ aMatrix = document.documentElement.createSVGMatrix();
+ // | 1 0 0 |
+ // | 0 -1 1 |
+ aMatrix.d = -1; aMatrix.f = 1.0;
+ this.aStaticTransformation = aMatrix.multiply( this.aStaticTransformation );
+ this.bFlip = true;
+ break;
+ }
+ }
+
+ if( !bIsModeIn )
+ {
+ if( aTransitionInfo.outInvertsSweep )
+ {
+ this.bForwardParameterSweep = !this.bForwardParameterSweep;
+ }
+ else
+ {
+ this.bSubtractPolygon = !this.bSubtractPolygon;
+ }
+ }
+}
+
+/** perform
+ *
+ * @param nT
+ * A parameter in [0,1] representing normalized time.
+ * @param nWidth
+ * The width of the bounding box of the slide/shape to be clipped.
+ * @param nHeight
+ * The height of the bounding box of the slide/shape to be clipped.
+ * @return {SVGPathElement}
+ * A svg <path> element representing the path to be used for the clipping
+ * operation.
+ */
+ClippingFunctor.prototype.perform = function( nT, nWidth, nHeight )
+{
+ var aClipPoly = this.aParametricPolyPolygon.perform( this.bForwardParameterSweep ? nT : (1 - nT) );
+
+ if( this.bFlip )
+ aClipPoly.changeOrientation();
+
+ if( this.bSubtractPolygon )
+ {
+
+ }
+
+ var aMatrix;
+ if( this.bScaleIsotropically )
+ {
+ var nScaleFactor = Math.max( nWidth, nHeight );
+ // translate( scale( aStaticTransformation() ) )
+ // note: operations must be defined in reverse order.
+ aMatrix = SVGIdentityMatrix.translate( -( nScaleFactor - nWidth ) / 2.0,
+ -( nScaleFactor - nHeight ) / 2.0 );
+ aMatrix = aMatrix.scale( nScaleFactor );
+ aMatrix = aMatrix.multiply( this.aStaticTransformation );
+ }
+ else
+ {
+ aMatrix = SVGIdentityMatrix.scaleNonUniform( nWidth, nHeight );
+ aMatrix = aMatrix.multiply( this.aStaticTransformation );
+ }
+
+ aClipPoly.matrixTransform( aMatrix );
+
+ return aClipPoly;
+};
+
+
+
+// ------------------------------------------------------------------------------------------ //
+/** createClipPolyPolygon
+ *
+ * @param nType
+ * An enumerator representing the transition type.
+ * @param nSubtype
+ * An enumerator representing the transition subtype.
+ * @return
+ * An object that handles a parametric <path> element.
+ */
+function createClipPolyPolygon( nType, nSubtype )
+{
+ switch( nType )
+ {
+ default:
+ log( 'createClipPolyPolygon: unknown transition type: ' + nType );
+ return null;
+ case BARWIPE_TRANSITION:
+ return new BarWipePath( 1 );
+ case FOURBOXWIPE_TRANSITION:
+ return new FourBoxWipePath( nSubtype === CORNERSOUT_TRANS_SUBTYPE );
+ case ELLIPSEWIPE_TRANSITION:
+ return new EllipseWipePath( nSubtype );
+ case PINWHEELWIPE_TRANSITION:
+ var nBlades;
+ switch( nSubtype )
+ {
+ case ONEBLADE_TRANS_SUBTYPE:
+ nBlades = 1;
+ break;
+ case DEFAULT_TRANS_SUBTYPE:
+ case TWOBLADEVERTICAL_TRANS_SUBTYPE:
+ nBlades = 2;
+ break;
+ case TWOBLADEHORIZONTAL_TRANS_SUBTYPE:
+ nBlades = 2;
+ break;
+ case THREEBLADE_TRANS_SUBTYPE:
+ nBlades = 3;
+ break;
+ case FOURBLADE_TRANS_SUBTYPE:
+ nBlades = 4;
+ break;
+ case EIGHTBLADE_TRANS_SUBTYPE:
+ nBlades = 8;
+ break;
+ default:
+ log( 'createClipPolyPolygon: unknown subtype: ' + nSubtype );
+ return null;
+ }
+ return new PinWheelWipePath( nBlades );
+ }
+}
+
+
+
+// ------------------------------------------------------------------------------------------ //
+function createUnitSquarePath()
+{
+ var aPath = document.createElementNS( NSS['svg'], 'path' );
+ var sD = 'M 0 0 L 1 0 L 1 1 L 0 1 L 0 0';
+ aPath.setAttribute( 'd', sD );
+ return aPath;
+}
+
+function pruneScaleValue( nVal )
+{
+ if( nVal < 0.0 )
+ return (nVal < -0.00001 ? nVal : -0.00001);
+ else
+ return (nVal > 0.00001 ? nVal : 0.00001);
+}
+
+// ------------------------------------------------------------------------------------------ //
+/** Class BarWipePath
+ * This class handles a <path> element that defines a unit square and
+ * transforms it accordingly to a parameter in the [0,1] range for performing
+ * a left to right barWipe transition.
+ *
+ * @param nBars
+ * The number of bars to be generated.
+ */
+function BarWipePath( nBars /* nBars > 1: blinds effect */ )
+{
+ this.nBars = nBars;
+ if( this.nBars === undefined || this.nBars < 1 )
+ this.nBars = 1;
+ this.aBasePath = createUnitSquarePath();
+}
+
+/** perform
+ *
+ * @param nT
+ * A parameter in [0,1] representing the width of the generated bars.
+ * @return {SVGPathElement}
+ * A svg <path> element representing a multi-bars.
+ */
+BarWipePath.prototype.perform = function( nT )
+{
+
+ var aMatrix = SVGIdentityMatrix.scaleNonUniform( pruneScaleValue( nT / this.nBars ), 1.0 );
+
+ var aPolyPath = this.aBasePath.cloneNode( true );
+ aPolyPath.matrixTransform( aMatrix );
+
+ if( this.nBars > 1 )
+ {
+ var i;
+ var aTransform;
+ var aPath;
+ for( i = this.nBars - 1; i > 0; --i )
+ {
+ aTransform = SVGIdentityMatrix.translate( i / this.nBars, 0.0 );
+ aTransform = aTransform.multiply( aMatrix );
+ aPath = this.aBasePath.cloneNode( true );
+ aPath.matrixTransform( aTransform );
+ aPolyPath.appendPath( aPath );
+ }
+ }
+ return aPolyPath;
+};
+
+
+
+// ------------------------------------------------------------------------------------------ //
+/** Class FourBoxWipePath
+ * This class handles a path made up by four squares and is utilized for
+ * performing fourBoxWipe transitions.
+ *
+ * @param bCornersOut
+ * If true the transition subtype is cornersOut else is cornersIn.
+ */
+function FourBoxWipePath( bCornersOut )
+{
+ this.bCornersOut = bCornersOut;
+ this.aBasePath = createUnitSquarePath();
+}
+
+FourBoxWipePath.prototype.perform = function( nT )
+{
+ var aMatrix;
+ var d = pruneScaleValue( nT / 2.0 );
+
+ if( this.bCornersOut )
+ {
+ aMatrix = SVGIdentityMatrix.translate( -0.25, -0.25 ).scale( d ).translate( -0.5, -0.5 );
+ }
+ else
+ {
+ aMatrix = SVGIdentityMatrix.translate( -0.5, -0.5 ).scale( d );
+ }
+
+
+ var aTransform = aMatrix;
+ // top left
+ var aSquare = this.aBasePath.cloneNode( true );
+ aSquare.matrixTransform( aTransform );
+ var aPolyPath = aSquare;
+ // bottom left, flip on x-axis:
+ aMatrix = SVGIdentityMatrix.flipY();
+ aTransform = aMatrix.multiply( aTransform );
+ aSquare = this.aBasePath.cloneNode( true );
+ aSquare.matrixTransform( aTransform );
+ aSquare.changeOrientation();
+ aPolyPath.appendPath( aSquare );
+ // bottom right, flip on y-axis:
+ aMatrix = SVGIdentityMatrix.flipX();
+ aTransform = aMatrix.multiply( aTransform );
+ aSquare = this.aBasePath.cloneNode( true );
+ aSquare.matrixTransform( aTransform );
+ aPolyPath.appendPath( aSquare );
+ // top right, flip on x-axis:
+ aMatrix = SVGIdentityMatrix.flipY();
+ aTransform = aMatrix.multiply( aTransform );
+ aSquare = this.aBasePath.cloneNode( true );
+ aSquare.matrixTransform( aTransform );
+ aSquare.changeOrientation();
+ aPolyPath.appendPath( aSquare );
+
+ aMatrix = SVGIdentityMatrix.translate( 0.5, 0.5 );
+ aPolyPath.matrixTransform( aMatrix );
+
+ return aPolyPath;
+};
+
+
+
+// ------------------------------------------------------------------------------------------ //
+/** Class EllipseWipePath
+ * This class handles a parametric ellipse represented by a path made up of
+ * cubic Bezier curve segments that helps in performing the ellipseWipe
+ * transition.
+ *
+ * @param eSubtype
+ * The transition subtype.
+ */
+function EllipseWipePath( eSubtype )
+{
+ this.eSubtype = eSubtype;
+
+ var sPathData;
+
+ switch( eSubtype )
+ {
+ case DEFAULT_TRANS_SUBTYPE:
+ case CIRCLE_TRANS_SUBTYPE:
+ // precomputed circle( 0.5, 0.5, SQRT2 / 2 )
+ sPathData = 'M 0.5 -0.207107 ' +
+ 'C 0.687536 -0.207107 0.867392 -0.132608 1 0 ' +
+ 'C 1.13261 0.132608 1.20711 0.312464 1.20711 0.5 ' +
+ 'C 1.20711 0.687536 1.13261 0.867392 1 1 ' +
+ 'C 0.867392 1.13261 0.687536 1.20711 0.5 1.20711 ' +
+ 'C 0.312464 1.20711 0.132608 1.13261 0 1 ' +
+ 'C -0.132608 0.867392 -0.207107 0.687536 -0.207107 0.5 ' +
+ 'C -0.207107 0.312464 -0.132608 0.132608 0 0 ' +
+ 'C 0.132608 -0.132608 0.312464 -0.207107 0.5 -0.207107';
+ break;
+ case VERTICAL_TRANS_SUBTYPE:
+ sPathData = '';
+ break;
+ case HORIZONTAL_TRANS_SUBTYPE:
+ sPathData = '';
+ break;
+ default:
+ log( 'EllipseWipePath: unknown subtype: ' + eSubtype );
+ }
+
+ this.aBasePath = document.createElementNS( NSS['svg'], 'path' );
+ this.aBasePath.setAttribute( 'd', sPathData );
+}
+
+EllipseWipePath.prototype.perform = function( nT )
+{
+
+ var aTransform = SVGIdentityMatrix.translate( 0.5, 0.5 ).scale( nT ).translate( -0.5, -0.5 );
+ var aEllipse = this.aBasePath.cloneNode( true );
+ aEllipse.matrixTransform( aTransform );
+
+ return aEllipse;
+};
+
+
+
+// ------------------------------------------------------------------------------------------ //
+/** Class PinWheelWipePath
+ * This class handles a parametric poly-path that is used for performing
+ * a spinWheelWipe transition.
+ *
+ * @param nBlades
+ * Number of blades generated by the transition.
+ */
+function PinWheelWipePath( nBlades )
+{
+ this.nBlades = nBlades;
+ if( !this.nBlades || this.nBlades < 1 )
+ this.nBlades = 1;
+}
+
+PinWheelWipePath.calcCenteredClock = function( nT, nE )
+{
+ var nMAX_EDGE = 2;
+
+ var aTransform = SVGIdentityMatrix.rotate( nT * 360 );
+
+ var aPoint = document.documentElement.createSVGPoint();
+ aPoint.y = -nMAX_EDGE;
+ aPoint = aPoint.matrixTransform( aTransform );
+
+ var sPathData = 'M ' + aPoint.x + ' ' + aPoint.y + ' ';
+ if( nT >= 0.875 )
+ // L -e -e
+ sPathData += 'L ' + '-' + nE + ' -' + nE + ' ';
+ if( nT >= 0.625 )
+ // L -e e
+ sPathData += 'L ' + '-' + nE + ' ' + nE + ' ';
+ if( nT >= 0.375 )
+ // L e e
+ sPathData += 'L ' + nE + ' ' + nE + ' ';
+ if( nT >= 0.125 )
+ // L e -e
+ sPathData += 'L ' + nE + ' -' + nE + ' ';
+
+ // L 0 -e
+ sPathData += 'L 0 -' + nE + ' ';
+ sPathData += 'L 0 0 ';
+ // Z
+ sPathData += 'L ' + aPoint.x + ' ' + aPoint.y;
+
+ var aPath = document.createElementNS( NSS['svg'], 'path' );
+ aPath.setAttribute( 'd', sPathData );
+ return aPath;
+};
+
+PinWheelWipePath.prototype.perform = function( nT )
+{
+ var aBasePath = PinWheelWipePath.calcCenteredClock( nT / this.nBlades,
+ 2.0 /* max edge when rotating */ );
+
+ var aPolyPath = aBasePath.cloneNode( true );
+ var aPath;
+ var aRotation;
+ var i;
+ for( i = this.nBlades - 1; i > 0; --i )
+ {
+ aRotation = SVGIdentityMatrix.rotate( (i * 360) / this.nBlades );
+ aPath = aBasePath.cloneNode( true );
+ aPath.matrixTransform( aRotation );
+ aPolyPath.appendPath( aPath );
+ }
+
+ var aTransform = SVGIdentityMatrix.translate( 0.5, 0.5 ).scale( 0.5 );
+ aPolyPath.matrixTransform( aTransform );
+
+ return aPolyPath;
+};
+
+
+// ------------------------------------------------------------------------------------------ //
/** Class AnimatedSlide
* This class handle a slide element during a slide transition.
*
@@ -6384,8 +7789,13 @@ function AnimatedSlide( aMetaSlide )
this.aMetaSlide = aMetaSlide;
this.aSlideElement = this.aMetaSlide.slideElement;
+ this.sSlideId = this.aMetaSlide.slideId;
this.aUsedAttributeSet = new Array();
+
+ this.aClipPathElement = null;
+ this.aClipPathContent = null;
+ this.bIsClipped = false;
}
/** show
@@ -6413,7 +7823,15 @@ AnimatedSlide.prototype.hide = function()
*/
AnimatedSlide.prototype.notifyUsedAttribute = function( sName )
{
- this.aUsedAttributeSet.push( sName );
+ if( sName == 'clip-path' )
+ {
+ this.initClipPath();
+ this.bIsClipped = true;
+ }
+ else
+ {
+ this.aUsedAttributeSet.push( sName );
+ }
};
/** reset
@@ -6422,6 +7840,12 @@ AnimatedSlide.prototype.notifyUsedAttribute = function( sName )
*/
AnimatedSlide.prototype.reset = function()
{
+ if( this.bIsClipped )
+ {
+ this.cleanClipPath();
+ this.bIsClipped = false;
+ }
+
var i;
for( i = 0; i < this.aUsedAttributeSet.length; ++i )
{
@@ -6431,6 +7855,55 @@ AnimatedSlide.prototype.reset = function()
this.aUsedAttributeSet = new Array();
};
+/** initClipPath
+ * Create a new clip path element and append it to the clip path def group.
+ * Moreover the created <clipPath> element is referenced by the handled slide
+ * element.
+ */
+AnimatedSlide.prototype.initClipPath = function()
+{
+ // We create the clip path element.
+ this.aClipPathElement = document.createElementNS( NSS['svg'], 'clipPath' );
+
+ var sId = 'clip-path-' + this.sSlideId;
+ this.aClipPathElement.setAttribute( 'id', sId );
+ //this.aClipPathElement.setAttribute( 'clipPathUnits', 'userSpaceOnUse' );
+
+ // We create and append a placeholder content.
+ this.aClipPathContent = document.createElementNS( NSS['svg'], 'path' );
+ var sPathData = 'M 0 0 h ' + WIDTH + ' v ' + HEIGHT + ' h -' + WIDTH + ' z';
+ this.aClipPathContent.setAttribute( 'd', sPathData );
+ this.aClipPathElement.appendChild( this.aClipPathContent );
+
+ // We insert it into the svg document.
+ var aClipPathGroup = theMetaDoc.aClipPathGroup;
+ aClipPathGroup.appendChild( this.aClipPathElement );
+
+ // Finally we set the reference to the created clip path.
+ // We set it on the parent element because a slide element already
+ // owns a clip path attribute.
+ var sRef = 'url(#' + sId + ')';
+ this.aSlideElement.parentNode.setAttribute( 'clip-path', sRef );
+};
+
+/** cleanClipPath
+ * Removes the related <clipPath> element from the <defs> group,
+ * and remove the 'clip-path' attribute from the slide element.
+ *
+ */
+AnimatedSlide.prototype.cleanClipPath = function()
+{
+ this.aSlideElement.parentNode.removeAttribute( 'clip-path' );
+
+ if( this.aClipPathElement )
+ {
+ var aClipPathGroup = theMetaDoc.aClipPathGroup;
+ aClipPathGroup.removeChild( this.aClipPathElement );
+ this.aClipPathElement = null;
+ this.aClipPathContent = null;
+ }
+};
+
/** insertBefore
* Insert an svg element before the handled slide element.
*
@@ -6459,7 +7932,7 @@ AnimatedSlide.prototype.appendElement = function( aElement )
}
};
-/** appendElement
+/** removeElement
* Remove an svg element.
*
* @param aElement
@@ -6517,6 +7990,25 @@ AnimatedSlide.prototype.translate = function( nDx, nDy )
this.aSlideElement.setAttribute( 'transform', sTransformAttr );
};
+/** setClipPath
+ * Replace the current content of the <clipPath> element with the one
+ * passed through the parameter.
+ *
+ * @param aClipPathContent
+ * A <g> element representing a <path> element used for clipping.
+ */
+AnimatedSlide.prototype.setClipPath = function( aClipPathContent )
+{
+ // Earlier we used to replace the current <path> element with the passed one,
+ // anyway that does not work in IE9, so we replace the 'd' attribute, only.
+ if( this.aClipPathContent )
+ {
+// this.aClipPathElement.replaceChild( aClipPathContent, this.aClipPathContent );
+// this.aClipPathContent = aClipPathContent;
+ var sPathData = aClipPathContent.getAttribute( 'd' );
+ this.aClipPathContent.setAttribute( 'd', sPathData );
+ }
+};
// ------------------------------------------------------------------------------------------ //
@@ -7009,7 +8501,10 @@ SlideTransition.prototype.createSlideTransition = function( aLeavingSlide, aEnte
return null;
case TRANSITION_CLIP_POLYPOLYGON:
- return null;
+ var aParametricPolyPolygon
+ = createClipPolyPolygon( this.eTransitionType, this.eTransitionSubType );
+ return new ClippedSlideChange( aLeavingSlide, aEnteringSlide, aParametricPolyPolygon,
+ aTransitionInfo, this.isDirectionForward() );
case TRANSITION_SPECIAL:
switch( this.eTransitionType )
@@ -7136,12 +8631,6 @@ SlideTransition.prototype.parseElement = function()
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 &&
@@ -7202,9 +8691,9 @@ SlideTransition.prototype.getFadeColor = function()
return this.sFadeColor;
};
-SlideTransition.prototype.getReverseDirection = function()
+SlideTransition.prototype.isDirectionForward = function()
{
- return this.bReverseDirection;
+ return !this.bReverseDirection;
};
SlideTransition.prototype.getDuration = function()
@@ -7228,7 +8717,7 @@ SlideTransition.prototype.info = function()
sInfo += '; subtype: ' + aTransitionSubtypeOutMap[ this.getTransitionSubType() ];
// transition direction
- if( this.getReverseDirection() )
+ if( !this.isDirectionForward() )
sInfo += '; direction: reverse';
// transition mode
@@ -9155,8 +10644,6 @@ SlideShow.prototype.notifyTransitionEnd = function( nSlideIndex )
// clear all queues
this.dispose();
- this.notifySlideStart( nSlideIndex );
-
theMetaDoc.getCurrentSlide().aSlideAnimationsHandler.start();
this.update();
}
@@ -9228,6 +10715,8 @@ SlideShow.prototype.displaySlide = function( nNewSlide, bSkipSlideTransition )
}
}
+ this.notifySlideStart( nNewSlide );
+
if( this.isEnabled() && !bSkipSlideTransition )
{
// create slide transition and add to activity queue
@@ -9279,7 +10768,7 @@ SlideShow.prototype.displaySlide = function( nNewSlide, bSkipSlideTransition )
SlideShow.prototype.update = function()
{
this.aTimer.holdTimer();
- var suspendHandle = ROOT_NODE.suspendRedraw( PREFERRED_FRAME_RATE * 1000 );
+ //var suspendHandle = ROOT_NODE.suspendRedraw( PREFERRED_FRAME_RATE * 1000 );
// process queues
this.aTimerEventQueue.process();
@@ -9289,8 +10778,8 @@ SlideShow.prototype.update = function()
this.aActivityQueue.processDequeued();
- ROOT_NODE.unsuspendRedraw(suspendHandle);
- ROOT_NODE.forceRedraw();
+ //ROOT_NODE.unsuspendRedraw(suspendHandle);
+ //ROOT_NODE.forceRedraw();
this.aTimer.releaseTimer();
var bActivitiesLeft = ( ! this.aActivityQueue.isEmpty() );
diff --git a/filter/source/svg/svgexport.cxx b/filter/source/svg/svgexport.cxx
index 3d048129ae6e..bcb2e2935ead 100644
--- a/filter/source/svg/svgexport.cxx
+++ b/filter/source/svg/svgexport.cxx
@@ -748,6 +748,7 @@ sal_Bool SVGFilter::implExportDocument()
// Create a ClipPath element that will be used for cutting bitmaps and other elements that could exceed the page margins.
{
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", B2UCONST( "ClipPathGroup" ) );
SvXMLElementExport aDefsElem( *mpSVGExport, XML_NAMESPACE_NONE, "defs", sal_True, sal_True );
{
mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", msClipPathId );