ooo-build r11695 - in trunk: . patches/src680 patches/svgimport



Author: strba
Date: Sun Feb 24 10:34:43 2008
New Revision: 11695
URL: http://svn.gnome.org/viewvc/ooo-build?rev=11695&view=rev

Log:
2008-02-24  Fridrich Strba  <fridrich strba bluewin ch>

	* patches/svgimport/svg-import-basegfx.diff,
	patches/src680/svg-import-basegfx.diff: fix an issue with closed bezier
	polygons (patch Thorsten Behrens).



Modified:
   trunk/ChangeLog
   trunk/patches/src680/svg-import-basegfx.diff
   trunk/patches/svgimport/svg-import-basegfx.diff

Modified: trunk/patches/src680/svg-import-basegfx.diff
==============================================================================
--- trunk/patches/src680/svg-import-basegfx.diff	(original)
+++ trunk/patches/src680/svg-import-basegfx.diff	Sun Feb 24 10:34:43 2008
@@ -1,58 +1,773 @@
-diff --git a/basegfx/inc/basegfx/polygon/b2dpolypolygontools.hxx b/basegfx/inc/basegfx/polygon/b2dpolypolygontools.hxx
-index a84ad15..14ac14f 100644
---- basegfx/inc/basegfx/polygon/b2dpolypolygontools.hxx
-+++ basegfx/inc/basegfx/polygon/b2dpolypolygontools.hxx
-@@ -127,19 +127,37 @@ namespace basegfx
-         /** Read poly-polygon from SVG.
+--- basegfx/source/polygon/b2dsvgpolypolygon.cxx	2008-02-24 11:25:04.000000000 +0100
++++ basegfx/source/polygon/b2dsvgpolypolygon.cxx	2008-02-24 11:24:13.000000000 +0100
+@@ -665,6 +665,32 @@
+             return true;
+         }
  
-         	This function imports a poly-polygon from an SVG-D
--        	statement. Currently, elliptical arc elements are not yet
-+        	attribute. Currently, elliptical arc elements are not yet
-         	supported (and ignored during parsing).
++        bool importFromSvgPoints( B2DPolygon&            o_rPoly,
++                                  const ::rtl::OUString& rSvgPointsAttribute )
++        {
++            o_rPoly.clear();
++            const sal_Int32 nLen(rSvgPointsAttribute.getLength());
++            sal_Int32 nPos(0);
++            double nX, nY;
++
++            // skip initial whitespace
++            lcl_skipSpaces(nPos, rSvgPointsAttribute, nLen);
++
++            while(nPos < nLen)
++            {
++                if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgPointsAttribute, nLen)) return false;
++                if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgPointsAttribute, nLen)) return false;
++                
++                // add point        
++                o_rPoly.append(B2DPoint(nX, nY));
++
++                // skip to next number, or finish
++                lcl_skipSpaces(nPos, rSvgPointsAttribute, nLen);
++            }
++
++            return true;
++        }
++
+         ::rtl::OUString exportToSvgD(
+ 			const B2DPolyPolygon& rPolyPolygon,
+ 			bool bUseRelativeCoordinates, 
+@@ -678,13 +704,23 @@
+             {
+                 const B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(i));
+                 const sal_uInt32 nPointCount(aPolygon.count());
++
++                // simply skip empty polygons - avoids special-casing
++                // this below for the n+1 fix for closed polygons
++                if( !aPolygon.count() )
++                    continue;
++
+                 const bool bPolyUsesControlPoints(aPolygon.areControlPointsUsed());
++                // to correctly write out closed curves, need to
++                // output first point twice (so output one additional
++                // point)
++                const sal_uInt32 nExtendedPointCount(nPointCount + aPolygon.isClosed()*bPolyUsesControlPoints);
+                 sal_Unicode aLastSVGCommand(' '); // last SVG command char
+ 				B2DPoint aLeft, aRight; // for quadratic bezier test
  
-             @param o_rPolyPoly
-             The output poly-polygon
+-                for(sal_uInt32 j(0); j < nPointCount; j++)
++                for(sal_uInt32 j(0); j<nExtendedPointCount; j++)
+                 {
+-                    const B2DPoint aCurrent(aPolygon.getB2DPoint(j));
++                    const B2DPoint aCurrent(aPolygon.getB2DPoint(j%nPointCount));
  
--            @param rSvgDStatement
--            A valid SVG-D statement
-+            @param rSvgDAttribute
-+            A valid SVG-D attribute string
+                     if(0 == j)
+                     {
+@@ -697,15 +733,17 @@
+                     else
+                     {
+ 						// handle edge from j-1 to j
+-						const bool bEdgeIsBezier(bPolyUsesControlPoints
+-							&& (aPolygon.isNextControlPointUsed(j - 1) || aPolygon.isPrevControlPointUsed(j)));
+-
++						const bool bEdgeIsBezier(
++                            bPolyUsesControlPoints
++                            && (aPolygon.isNextControlPointUsed((j - 1)%nPointCount) 
++                                || aPolygon.isPrevControlPointUsed(j%nPointCount)));
++                        
+                         if(bEdgeIsBezier)
+                         {
+                             // handle bezier edge
+-                            const B2DPoint aControl0(aPolygon.getNextControlPoint(j - 1));
+-                            const B2DPoint aControl1(aPolygon.getPrevControlPoint(j));
+-							const B2VectorContinuity aPrevCont(aPolygon.getContinuityInPoint(j - 1));
++                            const B2DPoint aControl0(aPolygon.getNextControlPoint((j - 1)%nPointCount));
++                            const B2DPoint aControl1(aPolygon.getPrevControlPoint(j%nPointCount));
++							const B2VectorContinuity aPrevCont(aPolygon.getContinuityInPoint((j - 1)%nPointCount));
+ 							const bool bSymmetricControlVector(CONTINUITY_C2 == aPrevCont);
+ 							bool bIsQuadraticBezier(false);
  
-             @return true, if the string was successfully parsed
-          */
--        bool importFromSvgD( B2DPolyPolygon& o_rPolyPoly,
--                             const ::rtl::OUString& 	rSvgDStatement );
-+        bool importFromSvgD( B2DPolyPolygon&        o_rPolyPoly,
-+                             const ::rtl::OUString& rSvgDAttribute );
-+
-+        /** Read poly-polygon from SVG.
-+
-+        	This function imports a poly-polygon from an SVG points
-+        	attribute (a plain list of coordinate pairs).
-+
-+            @param o_rPoly
-+            The output polygon. Note that svg:points can only define a
-+            single polygon
+@@ -798,7 +836,13 @@
+                         }
+                         else
+                         {
+-                            // normal straight line points
++                            // normal straight line points - no need
++                            // to write extra segments for closed
++                            // polygons here (see n+1 fix above for
++                            // reasoning)
++                            if( j==nPointCount )
++                                continue;
++
+                             if(aLastPoint.getX() == aCurrent.getX())
+                             {
+ 								// export as vertical line
+--- basegfx/source/polygon/b2dsvgpolypolygon.cxx.orig	1970-01-01 01:00:00.000000000 +0100
++++ basegfx/source/polygon/b2dsvgpolypolygon.cxx.orig	2008-02-23 23:29:27.000000000 +0100
+@@ -0,0 +1,887 @@
++/*************************************************************************
++ *
++ *  OpenOffice.org - a multi-platform office productivity suite
++ *
++ *  $RCSfile: b2dsvgpolypolygon.cxx,v $
++ *
++ *  $Revision: 1.7 $
++ *
++ *  last change: $Author: obo $ $Date: 2007/07/18 11:07:24 $
++ *
++ *  The Contents of this file are made available subject to
++ *  the terms of GNU Lesser General Public License Version 2.1.
++ *
++ *
++ *    GNU Lesser General Public License Version 2.1
++ *    =============================================
++ *    Copyright 2005 by Sun Microsystems, Inc.
++ *    901 San Antonio Road, Palo Alto, CA 94303, USA
++ *
++ *    This library is free software; you can redistribute it and/or
++ *    modify it under the terms of the GNU Lesser General Public
++ *    License version 2.1, as published by the Free Software Foundation.
++ *
++ *    This library is distributed in the hope that it will be useful,
++ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ *    Lesser General Public License for more details.
++ *
++ *    You should have received a copy of the GNU Lesser General Public
++ *    License along with this library; if not, write to the Free Software
++ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ *    MA  02111-1307  USA
++ *
++ ************************************************************************/
++
++// MARKER(update_precomp.py): autogen include statement, do not remove
++#include "precompiled_basegfx.hxx"
++
++#include <basegfx/polygon/b2dpolypolygontools.hxx>
++#include <basegfx/polygon/b2dpolypolygon.hxx>
++
++#ifndef _RTL_USTRING_
++#include <rtl/ustring.hxx>
++#endif
++#ifndef INCLUDED_RTL_MATH_HXX
++#include <rtl/math.hxx>
++#endif
++
++namespace basegfx
++{
++	namespace tools
++	{
++        namespace
++        {
++            void lcl_skipSpaces(sal_Int32& 				io_rPos, 
++                                const ::rtl::OUString& 	rStr, 
++                                const sal_Int32 		nLen)
++            {
++                while( io_rPos < nLen &&
++                       sal_Unicode(' ') == rStr[io_rPos] )
++                {
++                    ++io_rPos;
++                }
++            }
 +
-+            @param rSvgPointsAttribute
-+            A valid SVG points attribute string
++            void lcl_skipSpacesAndCommas(sal_Int32& 			io_rPos, 
++                                         const ::rtl::OUString& rStr, 
++                                         const sal_Int32 		nLen)
++            {
++                while(io_rPos < nLen 
++                      && (sal_Unicode(' ') == rStr[io_rPos] || sal_Unicode(',') == rStr[io_rPos]))
++                {
++                    ++io_rPos;
++                }
++            }
 +
-+            @return true, if the string was successfully parsed
-+         */
-+        bool importFromSvgPoints( B2DPolygon&            o_rPoly,
-+                                  const ::rtl::OUString& rSvgPointsAttribute );
++            bool lcl_isOnNumberChar(const ::rtl::OUString& rStr, const sal_Int32 nPos, bool bSignAllowed = true)
++            {
++                const sal_Unicode aChar(rStr[nPos]);
++
++                const bool bPredicate( (sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
++                                       || (bSignAllowed && sal_Unicode('+') == aChar)
++                                       || (bSignAllowed && sal_Unicode('-') == aChar) );
++
++                return bPredicate;
++            }
++
++            bool lcl_getDoubleChar(double& 					o_fRetval,
++                                   sal_Int32& 				io_rPos, 
++                                   const ::rtl::OUString& 	rStr, 
++                                   const sal_Int32 			/*nLen*/)
++            {
++                sal_Unicode aChar( rStr[io_rPos] );
++                ::rtl::OUStringBuffer sNumberString;
++
++                if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
++                {
++                    sNumberString.append(rStr[io_rPos]);
++                    aChar = rStr[++io_rPos];
++                }
++
++                while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
++                      || sal_Unicode('.') == aChar)
++                {
++                    sNumberString.append(rStr[io_rPos]);
++                    aChar = rStr[++io_rPos];
++                }
++
++                if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
++                {
++                    sNumberString.append(rStr[io_rPos]);
++                    aChar = rStr[++io_rPos];
++	
++                    if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
++                    {
++                        sNumberString.append(rStr[io_rPos]);
++                        aChar = rStr[++io_rPos];
++                    }
++
++                    while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
++                    {
++                        sNumberString.append(rStr[io_rPos]);
++                        aChar = rStr[++io_rPos];
++                    }
++                }
++
++                if(sNumberString.getLength())
++                {
++                    rtl_math_ConversionStatus eStatus;
++                    o_fRetval = ::rtl::math::stringToDouble( sNumberString.makeStringAndClear(), 
++                                                             (sal_Unicode)('.'), 
++                                                             (sal_Unicode)(','), 
++                                                             &eStatus, 
++                                                             NULL );
++                    return ( eStatus == rtl_math_ConversionStatus_Ok );
++                }
++
++                return false;
++            }
++
++            bool lcl_importDoubleAndSpaces( double& 				o_fRetval, 
++                                            sal_Int32& 				io_rPos, 
++                                            const ::rtl::OUString& 	rStr, 
++                                            const sal_Int32 		nLen )
++            {
++                if( !lcl_getDoubleChar(o_fRetval, io_rPos, rStr, nLen) )
++                    return false;
++
++                lcl_skipSpacesAndCommas(io_rPos, rStr, nLen);
++
++                return true;
++            }
++
++            void lcl_skipNumber(sal_Int32& 				io_rPos, 
++                                const ::rtl::OUString& 	rStr, 
++                                const sal_Int32 		nLen)
++            {
++                bool bSignAllowed(true);
++
++                while(io_rPos < nLen && lcl_isOnNumberChar(rStr, io_rPos, bSignAllowed))
++                {
++                    bSignAllowed = false;
++                    ++io_rPos;
++                }
++            }
++
++            void lcl_skipDouble(sal_Int32& 				io_rPos, 
++                                const ::rtl::OUString& 	rStr, 
++                                const sal_Int32 		/*nLen*/)
++            {
++                sal_Unicode aChar( rStr[io_rPos] );
++
++                if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
++                    aChar = rStr[++io_rPos];
++
++                while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
++                      || sal_Unicode('.') == aChar)
++                {
++                    aChar = rStr[++io_rPos];
++                }
++
++                if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
++                {
++                    aChar = rStr[++io_rPos];
++	
++                    if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
++                        aChar = rStr[++io_rPos];
++
++                    while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
++                    {
++                        aChar = rStr[++io_rPos];
++                    }
++                }
++            }
++            void lcl_skipNumberAndSpacesAndCommas(sal_Int32& 				io_rPos, 
++                                                  const ::rtl::OUString& 	rStr, 
++                                                  const sal_Int32 			nLen)
++            {
++                lcl_skipNumber(io_rPos, rStr, nLen);
++                lcl_skipSpacesAndCommas(io_rPos, rStr, nLen);
++            }
++
++			// #100617# Allow to skip doubles, too.
++            void lcl_skipDoubleAndSpacesAndCommas(sal_Int32& 				io_rPos, 
++                                                  const ::rtl::OUString& 	rStr, 
++                                                  const sal_Int32 			nLen)
++            {
++                lcl_skipDouble(io_rPos, rStr, nLen);
++                lcl_skipSpacesAndCommas(io_rPos, rStr, nLen);
++            }
++
++            void lcl_putNumberChar( ::rtl::OUString& rStr, 
++                                    double 		 	 fValue )
++            {
++                rStr += ::rtl::OUString::valueOf( fValue );
++            }
++
++            void lcl_putNumberCharWithSpace( ::rtl::OUString& rStr, 
++                                             double 		  fValue,
++                                             double 		  fOldValue,
++                                             bool 			  bUseRelativeCoordinates )
++            {
++                if( bUseRelativeCoordinates )
++                    fValue -= fOldValue;
++
++                const sal_Int32 aLen( rStr.getLength() );
++                if(aLen)
++                {
++                    if( lcl_isOnNumberChar(rStr, aLen - 1, false) && 
++                        fValue >= 0.0 )
++                    {
++                        rStr += ::rtl::OUString::valueOf( 
++                            sal_Unicode(' ') );
++                    }
++                }
++
++                lcl_putNumberChar(rStr, fValue);
++            }
++
++            inline sal_Unicode lcl_getCommand( sal_Char cUpperCaseCommand,
++                                               sal_Char cLowerCaseCommand,
++                                               bool 	bUseRelativeCoordinates )
++            {
++                return bUseRelativeCoordinates ? cLowerCaseCommand : cUpperCaseCommand;
++            }
++        }
++
++        bool importFromSvgD(B2DPolyPolygon& o_rPolyPolygon, const ::rtl::OUString& 	rSvgDStatement)
++        {
++            o_rPolyPolygon.clear();
++            const sal_Int32 nLen(rSvgDStatement.getLength());
++            sal_Int32 nPos(0);
++            bool bIsClosed(false);
++            double nLastX( 0.0 );
++            double nLastY( 0.0 );
++			B2DPolygon aCurrPoly;
++
++			// skip initial whitespace
++            lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++            while(nPos < nLen)
++            {
++                bool bRelative(false);
++                bool bMoveTo(false);
++                const sal_Unicode aCurrChar(rSvgDStatement[nPos]);
++
++                switch(aCurrChar)
++                {
++                    case 'z' :
++                    case 'Z' :
++                    {
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        // remember closed state of current polygon
++                        bIsClosed = true;
++                        break;
++                    }
++				
++                    case 'm' :
++                    case 'M' :
++                    {
++                        bMoveTo = true;
++                        // FALLTHROUGH intended
++                    }
++                    case 'l' :
++                    case 'L' :
++                    {
++                        if('m' == aCurrChar || 'l' == aCurrChar)
++						{
++                            bRelative = true;
++						}
++
++                        if(bMoveTo)
++                        {
++							// new polygon start, finish old one
++                            if(aCurrPoly.count())
++                            {
++                                aCurrPoly.setClosed(bIsClosed);
++                                bIsClosed = false;
++                                o_rPolyPolygon.append(aCurrPoly);
++                                aCurrPoly.clear();
++                            }
++                        }
++
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            double nX, nY;
++
++                            if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
++
++                            if(bRelative)
++                            {
++                                nX += nLastX;
++                                nY += nLastY;
++                            }
++
++                            // set last position
++                            nLastX = nX;
++                            nLastY = nY;
++						
++                            // add point
++                            aCurrPoly.append(B2DPoint(nX, nY));
++                        }
++                        break;
++                    }
++
++                    case 'h' :
++                    {
++                        bRelative = true;
++                        // FALLTHROUGH intended
++                    }
++                    case 'H' :
++                    {
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            double nX, nY(nLastY);
++
++                            if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
++
++                            if(bRelative)
++							{
++                                nX += nLastX;
++							}
++
++                            // set last position
++                            nLastX = nX;
++						
++                            // add point
++                            aCurrPoly.append(B2DPoint(nX, nY));
++                        }
++                        break;
++                    }
++				
++                    case 'v' :
++                    {
++                        bRelative = true;
++                        // FALLTHROUGH intended
++                    }
++                    case 'V' :
++                    {
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            double nX(nLastX), nY;
++
++                            if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
++
++                            if(bRelative)
++							{
++                                nY += nLastY;
++							}
++
++                            // set last position
++                            nLastY = nY;
++						
++                            // add point
++                            aCurrPoly.append(B2DPoint(nX, nY));
++                        }
++                        break;
++                    }
++				
++                    case 's' :
++                    {
++                        bRelative = true;
++                        // FALLTHROUGH intended
++                    }
++                    case 'S' :
++                    {
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            double nX, nY;
++                            double nX2, nY2;
++
++                            if(!lcl_importDoubleAndSpaces(nX2, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY2, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
++
++                            if(bRelative)
++                            {
++                                nX2 += nLastX;
++                                nY2 += nLastY;
++                                nX += nLastX;
++                                nY += nLastY;
++                            }
++
++							// ensure existance of start point
++							if(!aCurrPoly.count())
++							{
++                                aCurrPoly.append(B2DPoint(nLastX, nLastY));
++							}
++
++							// get first control point. It's the reflection of the PrevControlPoint
++							// of the last point. If not existent, use current point (see SVG)
++							B2DPoint aPrevControl(B2DPoint(nLastX, nLastY));
++							const sal_uInt32 nIndex(aCurrPoly.count() - 1);
++
++							if(aCurrPoly.areControlPointsUsed() && aCurrPoly.isPrevControlPointUsed(nIndex))
++							{
++								const B2DPoint aPrevPoint(aCurrPoly.getB2DPoint(nIndex));
++								const B2DPoint aPrevControlPoint(aCurrPoly.getPrevControlPoint(nIndex));
++
++								// use mirrored previous control point
++								aPrevControl.setX((2.0 * aPrevPoint.getX()) - aPrevControlPoint.getX());
++								aPrevControl.setY((2.0 * aPrevPoint.getY()) - aPrevControlPoint.getY());
++							}
++
++							// append curved edge
++							aCurrPoly.appendBezierSegment(aPrevControl, B2DPoint(nX2, nY2), B2DPoint(nX, nY));
++
++                            // set last position
++                            nLastX = nX;
++                            nLastY = nY;
++                        }
++                        break;
++                    }
++				
++                    case 'c' :
++                    {
++                        bRelative = true;
++                        // FALLTHROUGH intended
++                    }
++                    case 'C' :
++                    {
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            double nX, nY;
++                            double nX1, nY1;
++                            double nX2, nY2;
++
++                            if(!lcl_importDoubleAndSpaces(nX1, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY1, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nX2, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY2, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
++
++                            if(bRelative)
++                            {
++                                nX1 += nLastX;
++                                nY1 += nLastY;
++                                nX2 += nLastX;
++                                nY2 += nLastY;
++                                nX += nLastX;
++                                nY += nLastY;
++                            }
++
++							// ensure existance of start point
++							if(!aCurrPoly.count())
++							{
++                                aCurrPoly.append(B2DPoint(nLastX, nLastY));
++							}
++
++							// append curved edge
++							aCurrPoly.appendBezierSegment(B2DPoint(nX1, nY1), B2DPoint(nX2, nY2), B2DPoint(nX, nY));
++
++                            // set last position
++                            nLastX = nX;
++                            nLastY = nY;
++                        }
++                        break;
++                    }
++				
++                    // #100617# quadratic beziers are imported as cubic ones
++                    case 'q' :
++                    {
++                        bRelative = true;
++                        // FALLTHROUGH intended
++                    }
++                    case 'Q' :
++                    {
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            double nX, nY;
++                            double nX1, nY1;
++
++                            if(!lcl_importDoubleAndSpaces(nX1, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY1, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
++
++                            if(bRelative)
++                            {
++                                nX1 += nLastX;
++                                nY1 += nLastY;
++                                nX += nLastX;
++                                nY += nLastY;
++                            }
++
++                            // calculate the cubic bezier coefficients from the quadratic ones
++                            const double nX1Prime((nX1 * 2.0 + nLastX) / 3.0);
++                            const double nY1Prime((nY1 * 2.0 + nLastY) / 3.0);
++                            const double nX2Prime((nX1 * 2.0 + nX) / 3.0);
++                            const double nY2Prime((nY1 * 2.0 + nY) / 3.0);
++
++							// ensure existance of start point
++							if(!aCurrPoly.count())
++							{
++                                aCurrPoly.append(B2DPoint(nLastX, nLastY));
++							}
++
++							// append curved edge
++							aCurrPoly.appendBezierSegment(B2DPoint(nX1Prime, nY1Prime), B2DPoint(nX2Prime, nY2Prime), B2DPoint(nX, nY));
++
++                            // set last position
++                            nLastX = nX;
++                            nLastY = nY;
++                        }
++                        break;
++                    }
++				
++                    // #100617# relative quadratic beziers are imported as cubic
++                    case 't' :
++                    {
++                        bRelative = true;
++                        // FALLTHROUGH intended
++                    }
++                    case 'T' :
++                    {
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            double nX, nY;
++
++                            if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
++
++                            if(bRelative)
++                            {
++                                nX += nLastX;
++                                nY += nLastY;
++                            }
++
++							// ensure existance of start point
++							if(!aCurrPoly.count())
++							{
++                                aCurrPoly.append(B2DPoint(nLastX, nLastY));
++							}
++
++							// get first control point. It's the reflection of the PrevControlPoint
++							// of the last point. If not existent, use current point (see SVG)
++							B2DPoint aPrevControl(B2DPoint(nLastX, nLastY));
++							const sal_uInt32 nIndex(aCurrPoly.count() - 1);
++							const B2DPoint aPrevPoint(aCurrPoly.getB2DPoint(nIndex));
++
++							if(aCurrPoly.areControlPointsUsed() && aCurrPoly.isPrevControlPointUsed(nIndex))
++							{
++								const B2DPoint aPrevControlPoint(aCurrPoly.getPrevControlPoint(nIndex));
++
++								// use mirrored previous control point
++								aPrevControl.setX((2.0 * aPrevPoint.getX()) - aPrevControlPoint.getX());
++								aPrevControl.setY((2.0 * aPrevPoint.getY()) - aPrevControlPoint.getY());
++							}
++
++							if(!aPrevControl.equal(aPrevPoint))
++							{
++								// there is a prev control point, and we have the already mirrored one
++								// in aPrevControl. We also need the quadratic control point for this
++								// new quadratic segment to calculate the 2nd cubic control point
++								const B2DPoint aQuadControlPoint(
++									((3.0 * aPrevControl.getX()) - aPrevPoint.getX()) / 2.0,
++									((3.0 * aPrevControl.getY()) - aPrevPoint.getY()) / 2.0);
++								
++								// calculate the cubic bezier coefficients from the quadratic ones.
++								const double nX2Prime((aQuadControlPoint.getX() * 2.0 + nX) / 3.0);
++								const double nY2Prime((aQuadControlPoint.getY() * 2.0 + nY) / 3.0);
++								
++								// append curved edge, use mirrored cubic control point directly
++								aCurrPoly.appendBezierSegment(aPrevControl, B2DPoint(nX2Prime, nY2Prime), B2DPoint(nX, nY));
++							}
++							else
++							{
++								// when no previous control, SVG says to use current point -> straight line.
++								// Just add end point
++								aCurrPoly.append(B2DPoint(nX, nY));
++							}
++
++                            // set last position
++                            nLastX = nX;
++                            nLastY = nY;
++                        }
++                        break;
++                    }
++
++                    // #100617# not yet supported: elliptical arc
++                    case 'A' :
++                        // FALLTHROUGH intended
++                    case 'a' :
++                    {
++                        OSL_ENSURE(false, "importFromSvgD(): non-interpreted tags in svg:d element (elliptical arc)!");
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            lcl_skipDoubleAndSpacesAndCommas(nPos, rSvgDStatement, nLen);
++                            lcl_skipDoubleAndSpacesAndCommas(nPos, rSvgDStatement, nLen);
++                            lcl_skipDoubleAndSpacesAndCommas(nPos, rSvgDStatement, nLen);
++                            lcl_skipNumberAndSpacesAndCommas(nPos, rSvgDStatement, nLen);
++                            lcl_skipNumberAndSpacesAndCommas(nPos, rSvgDStatement, nLen);
++                            lcl_skipDoubleAndSpacesAndCommas(nPos, rSvgDStatement, nLen);
++                            lcl_skipDoubleAndSpacesAndCommas(nPos, rSvgDStatement, nLen);
++                        }
++                        break;
++                    }
++
++                    default:
++                    {
++                        OSL_ENSURE(false, "importFromSvgD(): skipping tags in svg:d element (unknown)!");
++                        OSL_TRACE("importFromSvgD(): skipping tags in svg:d element (unknown: \"%c\")!", aCurrChar);
++                        ++nPos;
++                        break;
++                    }
++                }
++            }
++
++            if(aCurrPoly.count())
++            {
++                // end-process last poly
++                aCurrPoly.setClosed(bIsClosed);
++                o_rPolyPolygon.append(aCurrPoly);
++            }
++
++            return true;
++        }
 +
- 
- 		// create 3d PolyPolygon from given 2d PolyPolygon. The given fZCoordinate is used to expand the
- 		// third coordinate.
-diff --git a/basegfx/source/polygon/b2dsvgpolypolygon.cxx b/basegfx/source/polygon/b2dsvgpolypolygon.cxx
-index 8965007..170d453 100644
---- basegfx/source/polygon/b2dsvgpolypolygon.cxx
-+++ basegfx/source/polygon/b2dsvgpolypolygon.cxx
-@@ -665,6 +665,32 @@ namespace basegfx
-             return true;
-         }
- 
 +        bool importFromSvgPoints( B2DPolygon&            o_rPoly,
 +                                  const ::rtl::OUString& rSvgPointsAttribute )
 +        {
@@ -79,6 +794,197 @@
 +            return true;
 +        }
 +
-         ::rtl::OUString exportToSvgD(
- 			const B2DPolyPolygon& rPolyPolygon,
- 			bool bUseRelativeCoordinates, 
++        ::rtl::OUString exportToSvgD(
++			const B2DPolyPolygon& rPolyPolygon,
++			bool bUseRelativeCoordinates, 
++			bool bDetectQuadraticBeziers)
++        {
++            const sal_uInt32 nCount(rPolyPolygon.count());
++            ::rtl::OUString aResult;
++            B2DPoint aLastPoint(0.0, 0.0); // SVG assumes (0,0) as the initial current point
++
++            for(sal_uInt32 i(0); i < nCount; i++)
++            {
++                const B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(i));
++                const sal_uInt32 nPointCount(aPolygon.count());
++                const bool bPolyUsesControlPoints(aPolygon.areControlPointsUsed());
++                sal_Unicode aLastSVGCommand(' '); // last SVG command char
++				B2DPoint aLeft, aRight; // for quadratic bezier test
++
++                for(sal_uInt32 j(0); j < nPointCount; j++)
++                {
++                    const B2DPoint aCurrent(aPolygon.getB2DPoint(j));
++
++                    if(0 == j)
++                    {
++						// handle first polygon point
++                        aResult += ::rtl::OUString::valueOf(lcl_getCommand('M', 'm', bUseRelativeCoordinates));
++                        lcl_putNumberCharWithSpace(aResult, aCurrent.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                        lcl_putNumberCharWithSpace(aResult, aCurrent.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                        aLastSVGCommand =  lcl_getCommand('L', 'l', bUseRelativeCoordinates);
++                    }
++                    else
++                    {
++						// handle edge from j-1 to j
++						const bool bEdgeIsBezier(bPolyUsesControlPoints
++							&& (aPolygon.isNextControlPointUsed(j - 1) || aPolygon.isPrevControlPointUsed(j)));
++
++                        if(bEdgeIsBezier)
++                        {
++                            // handle bezier edge
++                            const B2DPoint aControl0(aPolygon.getNextControlPoint(j - 1));
++                            const B2DPoint aControl1(aPolygon.getPrevControlPoint(j));
++							const B2VectorContinuity aPrevCont(aPolygon.getContinuityInPoint(j - 1));
++							const bool bSymmetricControlVector(CONTINUITY_C2 == aPrevCont);
++							bool bIsQuadraticBezier(false);
++
++							if(bDetectQuadraticBeziers)
++							{
++								// check for quadratic beziers - that's
++								// the case if both control points are in
++								// the same place when they are prolonged
++								// to the common quadratic control point
++								//
++								// Left: P = (3P1 - P0) / 2 
++								// Right: P = (3P2 - P3) / 2
++								aLeft = B2DPoint((3.0 * aControl0 - aLastPoint) / 2.0);
++								aRight= B2DPoint((3.0 * aControl1 - aCurrent) / 2.0);
++								bIsQuadraticBezier = aLeft.equal(aRight);
++							}
++
++							if(bIsQuadraticBezier)
++							{
++                                // approximately equal, export as quadratic bezier
++                                if(bSymmetricControlVector)
++                                {
++                                    const sal_Unicode aCommand(lcl_getCommand('T', 't', bUseRelativeCoordinates));
++
++                                    if(aLastSVGCommand != aCommand)
++                                    {
++                                        aResult += ::rtl::OUString::valueOf(aCommand);
++                                        aLastSVGCommand = aCommand;
++                                    }
++                                    
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    aLastSVGCommand = aCommand;
++                                }
++                                else
++                                {
++                                    const sal_Unicode aCommand(lcl_getCommand('Q', 'q', bUseRelativeCoordinates));
++
++                                    if(aLastSVGCommand != aCommand)
++                                    {
++                                        aResult += ::rtl::OUString::valueOf(aCommand);
++                                        aLastSVGCommand = aCommand;
++                                    }
++                                    
++                                    lcl_putNumberCharWithSpace(aResult, aLeft.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aLeft.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    aLastSVGCommand = aCommand;
++                                }
++                            }
++                            else
++                            {
++                                // export as cubic bezier
++                                if(bSymmetricControlVector)
++                                {
++                                    const sal_Unicode aCommand(lcl_getCommand('S', 's', bUseRelativeCoordinates));
++
++                                    if(aLastSVGCommand != aCommand)
++                                    {
++                                        aResult += ::rtl::OUString::valueOf(aCommand);
++                                        aLastSVGCommand = aCommand;
++                                    }
++                                    
++                                    lcl_putNumberCharWithSpace(aResult, aControl1.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aControl1.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    aLastSVGCommand = aCommand;
++                                }
++                                else
++                                {
++                                    const sal_Unicode aCommand(lcl_getCommand('C', 'c', bUseRelativeCoordinates));
++
++                                    if(aLastSVGCommand != aCommand)
++                                    {
++                                        aResult += ::rtl::OUString::valueOf(aCommand);
++                                        aLastSVGCommand = aCommand;
++                                    }
++                                    
++                                    lcl_putNumberCharWithSpace(aResult, aControl0.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aControl0.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aControl1.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aControl1.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    aLastSVGCommand = aCommand;
++                                }
++                            }                            
++                        }
++                        else
++                        {
++                            // normal straight line points
++                            if(aLastPoint.getX() == aCurrent.getX())
++                            {
++								// export as vertical line
++                                const sal_Unicode aCommand(lcl_getCommand('V', 'v', bUseRelativeCoordinates));
++
++								if(aLastSVGCommand != aCommand)
++                                {
++									aResult += ::rtl::OUString::valueOf(aCommand);
++                                    aLastSVGCommand = aCommand;
++                                }
++
++								lcl_putNumberCharWithSpace(aResult, aCurrent.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                            }
++                            else if(aLastPoint.getY() == aCurrent.getY())
++                            {
++								// export as horizontal line
++                                const sal_Unicode aCommand(lcl_getCommand('H', 'h', bUseRelativeCoordinates));
++
++								if(aLastSVGCommand != aCommand)
++                                {
++									aResult += ::rtl::OUString::valueOf(aCommand);
++                                    aLastSVGCommand = aCommand;
++                                }
++
++								lcl_putNumberCharWithSpace(aResult, aCurrent.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                            }
++                            else
++                            {
++								// export as line
++                                const sal_Unicode aCommand(lcl_getCommand('L', 'l', bUseRelativeCoordinates));
++
++								if(aLastSVGCommand != aCommand)
++                                {
++									aResult += ::rtl::OUString::valueOf(aCommand);
++                                    aLastSVGCommand = aCommand;
++                                }
++
++								lcl_putNumberCharWithSpace(aResult, aCurrent.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++								lcl_putNumberCharWithSpace(aResult, aCurrent.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                            }
++                        }
++                    }
++
++                    aLastPoint = aCurrent;
++                }
++
++                // close path if closed poly (Z and z are equivalent here, but looks nicer
++				// when case is matched)
++                if(aPolygon.isClosed())
++				{
++                    aResult += ::rtl::OUString::valueOf(lcl_getCommand('Z', 'z', bUseRelativeCoordinates));
++				}
++            }
++
++            return aResult;
++        }
++    }
++}
++
++// eof

Modified: trunk/patches/svgimport/svg-import-basegfx.diff
==============================================================================
--- trunk/patches/svgimport/svg-import-basegfx.diff	(original)
+++ trunk/patches/svgimport/svg-import-basegfx.diff	Sun Feb 24 10:34:43 2008
@@ -1,58 +1,773 @@
-diff --git a/basegfx/inc/basegfx/polygon/b2dpolypolygontools.hxx b/basegfx/inc/basegfx/polygon/b2dpolypolygontools.hxx
-index a84ad15..14ac14f 100644
---- basegfx/inc/basegfx/polygon/b2dpolypolygontools.hxx
-+++ basegfx/inc/basegfx/polygon/b2dpolypolygontools.hxx
-@@ -127,19 +127,37 @@ namespace basegfx
-         /** Read poly-polygon from SVG.
+--- basegfx/source/polygon/b2dsvgpolypolygon.cxx	2008-02-24 11:25:04.000000000 +0100
++++ basegfx/source/polygon/b2dsvgpolypolygon.cxx	2008-02-24 11:24:13.000000000 +0100
+@@ -665,6 +665,32 @@
+             return true;
+         }
  
-         	This function imports a poly-polygon from an SVG-D
--        	statement. Currently, elliptical arc elements are not yet
-+        	attribute. Currently, elliptical arc elements are not yet
-         	supported (and ignored during parsing).
++        bool importFromSvgPoints( B2DPolygon&            o_rPoly,
++                                  const ::rtl::OUString& rSvgPointsAttribute )
++        {
++            o_rPoly.clear();
++            const sal_Int32 nLen(rSvgPointsAttribute.getLength());
++            sal_Int32 nPos(0);
++            double nX, nY;
++
++            // skip initial whitespace
++            lcl_skipSpaces(nPos, rSvgPointsAttribute, nLen);
++
++            while(nPos < nLen)
++            {
++                if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgPointsAttribute, nLen)) return false;
++                if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgPointsAttribute, nLen)) return false;
++                
++                // add point        
++                o_rPoly.append(B2DPoint(nX, nY));
++
++                // skip to next number, or finish
++                lcl_skipSpaces(nPos, rSvgPointsAttribute, nLen);
++            }
++
++            return true;
++        }
++
+         ::rtl::OUString exportToSvgD(
+ 			const B2DPolyPolygon& rPolyPolygon,
+ 			bool bUseRelativeCoordinates, 
+@@ -678,13 +704,23 @@
+             {
+                 const B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(i));
+                 const sal_uInt32 nPointCount(aPolygon.count());
++
++                // simply skip empty polygons - avoids special-casing
++                // this below for the n+1 fix for closed polygons
++                if( !aPolygon.count() )
++                    continue;
++
+                 const bool bPolyUsesControlPoints(aPolygon.areControlPointsUsed());
++                // to correctly write out closed curves, need to
++                // output first point twice (so output one additional
++                // point)
++                const sal_uInt32 nExtendedPointCount(nPointCount + aPolygon.isClosed()*bPolyUsesControlPoints);
+                 sal_Unicode aLastSVGCommand(' '); // last SVG command char
+ 				B2DPoint aLeft, aRight; // for quadratic bezier test
  
-             @param o_rPolyPoly
-             The output poly-polygon
+-                for(sal_uInt32 j(0); j < nPointCount; j++)
++                for(sal_uInt32 j(0); j<nExtendedPointCount; j++)
+                 {
+-                    const B2DPoint aCurrent(aPolygon.getB2DPoint(j));
++                    const B2DPoint aCurrent(aPolygon.getB2DPoint(j%nPointCount));
  
--            @param rSvgDStatement
--            A valid SVG-D statement
-+            @param rSvgDAttribute
-+            A valid SVG-D attribute string
+                     if(0 == j)
+                     {
+@@ -697,15 +733,17 @@
+                     else
+                     {
+ 						// handle edge from j-1 to j
+-						const bool bEdgeIsBezier(bPolyUsesControlPoints
+-							&& (aPolygon.isNextControlPointUsed(j - 1) || aPolygon.isPrevControlPointUsed(j)));
+-
++						const bool bEdgeIsBezier(
++                            bPolyUsesControlPoints
++                            && (aPolygon.isNextControlPointUsed((j - 1)%nPointCount) 
++                                || aPolygon.isPrevControlPointUsed(j%nPointCount)));
++                        
+                         if(bEdgeIsBezier)
+                         {
+                             // handle bezier edge
+-                            const B2DPoint aControl0(aPolygon.getNextControlPoint(j - 1));
+-                            const B2DPoint aControl1(aPolygon.getPrevControlPoint(j));
+-							const B2VectorContinuity aPrevCont(aPolygon.getContinuityInPoint(j - 1));
++                            const B2DPoint aControl0(aPolygon.getNextControlPoint((j - 1)%nPointCount));
++                            const B2DPoint aControl1(aPolygon.getPrevControlPoint(j%nPointCount));
++							const B2VectorContinuity aPrevCont(aPolygon.getContinuityInPoint((j - 1)%nPointCount));
+ 							const bool bSymmetricControlVector(CONTINUITY_C2 == aPrevCont);
+ 							bool bIsQuadraticBezier(false);
  
-             @return true, if the string was successfully parsed
-          */
--        bool importFromSvgD( B2DPolyPolygon& o_rPolyPoly,
--                             const ::rtl::OUString& 	rSvgDStatement );
-+        bool importFromSvgD( B2DPolyPolygon&        o_rPolyPoly,
-+                             const ::rtl::OUString& rSvgDAttribute );
-+
-+        /** Read poly-polygon from SVG.
-+
-+        	This function imports a poly-polygon from an SVG points
-+        	attribute (a plain list of coordinate pairs).
-+
-+            @param o_rPoly
-+            The output polygon. Note that svg:points can only define a
-+            single polygon
+@@ -798,7 +836,13 @@
+                         }
+                         else
+                         {
+-                            // normal straight line points
++                            // normal straight line points - no need
++                            // to write extra segments for closed
++                            // polygons here (see n+1 fix above for
++                            // reasoning)
++                            if( j==nPointCount )
++                                continue;
++
+                             if(aLastPoint.getX() == aCurrent.getX())
+                             {
+ 								// export as vertical line
+--- basegfx/source/polygon/b2dsvgpolypolygon.cxx.orig	1970-01-01 01:00:00.000000000 +0100
++++ basegfx/source/polygon/b2dsvgpolypolygon.cxx.orig	2008-02-23 23:29:27.000000000 +0100
+@@ -0,0 +1,887 @@
++/*************************************************************************
++ *
++ *  OpenOffice.org - a multi-platform office productivity suite
++ *
++ *  $RCSfile: b2dsvgpolypolygon.cxx,v $
++ *
++ *  $Revision: 1.7 $
++ *
++ *  last change: $Author: obo $ $Date: 2007/07/18 11:07:24 $
++ *
++ *  The Contents of this file are made available subject to
++ *  the terms of GNU Lesser General Public License Version 2.1.
++ *
++ *
++ *    GNU Lesser General Public License Version 2.1
++ *    =============================================
++ *    Copyright 2005 by Sun Microsystems, Inc.
++ *    901 San Antonio Road, Palo Alto, CA 94303, USA
++ *
++ *    This library is free software; you can redistribute it and/or
++ *    modify it under the terms of the GNU Lesser General Public
++ *    License version 2.1, as published by the Free Software Foundation.
++ *
++ *    This library is distributed in the hope that it will be useful,
++ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ *    Lesser General Public License for more details.
++ *
++ *    You should have received a copy of the GNU Lesser General Public
++ *    License along with this library; if not, write to the Free Software
++ *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ *    MA  02111-1307  USA
++ *
++ ************************************************************************/
++
++// MARKER(update_precomp.py): autogen include statement, do not remove
++#include "precompiled_basegfx.hxx"
++
++#include <basegfx/polygon/b2dpolypolygontools.hxx>
++#include <basegfx/polygon/b2dpolypolygon.hxx>
++
++#ifndef _RTL_USTRING_
++#include <rtl/ustring.hxx>
++#endif
++#ifndef INCLUDED_RTL_MATH_HXX
++#include <rtl/math.hxx>
++#endif
++
++namespace basegfx
++{
++	namespace tools
++	{
++        namespace
++        {
++            void lcl_skipSpaces(sal_Int32& 				io_rPos, 
++                                const ::rtl::OUString& 	rStr, 
++                                const sal_Int32 		nLen)
++            {
++                while( io_rPos < nLen &&
++                       sal_Unicode(' ') == rStr[io_rPos] )
++                {
++                    ++io_rPos;
++                }
++            }
 +
-+            @param rSvgPointsAttribute
-+            A valid SVG points attribute string
++            void lcl_skipSpacesAndCommas(sal_Int32& 			io_rPos, 
++                                         const ::rtl::OUString& rStr, 
++                                         const sal_Int32 		nLen)
++            {
++                while(io_rPos < nLen 
++                      && (sal_Unicode(' ') == rStr[io_rPos] || sal_Unicode(',') == rStr[io_rPos]))
++                {
++                    ++io_rPos;
++                }
++            }
 +
-+            @return true, if the string was successfully parsed
-+         */
-+        bool importFromSvgPoints( B2DPolygon&            o_rPoly,
-+                                  const ::rtl::OUString& rSvgPointsAttribute );
++            bool lcl_isOnNumberChar(const ::rtl::OUString& rStr, const sal_Int32 nPos, bool bSignAllowed = true)
++            {
++                const sal_Unicode aChar(rStr[nPos]);
++
++                const bool bPredicate( (sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
++                                       || (bSignAllowed && sal_Unicode('+') == aChar)
++                                       || (bSignAllowed && sal_Unicode('-') == aChar) );
++
++                return bPredicate;
++            }
++
++            bool lcl_getDoubleChar(double& 					o_fRetval,
++                                   sal_Int32& 				io_rPos, 
++                                   const ::rtl::OUString& 	rStr, 
++                                   const sal_Int32 			/*nLen*/)
++            {
++                sal_Unicode aChar( rStr[io_rPos] );
++                ::rtl::OUStringBuffer sNumberString;
++
++                if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
++                {
++                    sNumberString.append(rStr[io_rPos]);
++                    aChar = rStr[++io_rPos];
++                }
++
++                while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
++                      || sal_Unicode('.') == aChar)
++                {
++                    sNumberString.append(rStr[io_rPos]);
++                    aChar = rStr[++io_rPos];
++                }
++
++                if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
++                {
++                    sNumberString.append(rStr[io_rPos]);
++                    aChar = rStr[++io_rPos];
++	
++                    if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
++                    {
++                        sNumberString.append(rStr[io_rPos]);
++                        aChar = rStr[++io_rPos];
++                    }
++
++                    while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
++                    {
++                        sNumberString.append(rStr[io_rPos]);
++                        aChar = rStr[++io_rPos];
++                    }
++                }
++
++                if(sNumberString.getLength())
++                {
++                    rtl_math_ConversionStatus eStatus;
++                    o_fRetval = ::rtl::math::stringToDouble( sNumberString.makeStringAndClear(), 
++                                                             (sal_Unicode)('.'), 
++                                                             (sal_Unicode)(','), 
++                                                             &eStatus, 
++                                                             NULL );
++                    return ( eStatus == rtl_math_ConversionStatus_Ok );
++                }
++
++                return false;
++            }
++
++            bool lcl_importDoubleAndSpaces( double& 				o_fRetval, 
++                                            sal_Int32& 				io_rPos, 
++                                            const ::rtl::OUString& 	rStr, 
++                                            const sal_Int32 		nLen )
++            {
++                if( !lcl_getDoubleChar(o_fRetval, io_rPos, rStr, nLen) )
++                    return false;
++
++                lcl_skipSpacesAndCommas(io_rPos, rStr, nLen);
++
++                return true;
++            }
++
++            void lcl_skipNumber(sal_Int32& 				io_rPos, 
++                                const ::rtl::OUString& 	rStr, 
++                                const sal_Int32 		nLen)
++            {
++                bool bSignAllowed(true);
++
++                while(io_rPos < nLen && lcl_isOnNumberChar(rStr, io_rPos, bSignAllowed))
++                {
++                    bSignAllowed = false;
++                    ++io_rPos;
++                }
++            }
++
++            void lcl_skipDouble(sal_Int32& 				io_rPos, 
++                                const ::rtl::OUString& 	rStr, 
++                                const sal_Int32 		/*nLen*/)
++            {
++                sal_Unicode aChar( rStr[io_rPos] );
++
++                if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
++                    aChar = rStr[++io_rPos];
++
++                while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
++                      || sal_Unicode('.') == aChar)
++                {
++                    aChar = rStr[++io_rPos];
++                }
++
++                if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
++                {
++                    aChar = rStr[++io_rPos];
++	
++                    if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
++                        aChar = rStr[++io_rPos];
++
++                    while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
++                    {
++                        aChar = rStr[++io_rPos];
++                    }
++                }
++            }
++            void lcl_skipNumberAndSpacesAndCommas(sal_Int32& 				io_rPos, 
++                                                  const ::rtl::OUString& 	rStr, 
++                                                  const sal_Int32 			nLen)
++            {
++                lcl_skipNumber(io_rPos, rStr, nLen);
++                lcl_skipSpacesAndCommas(io_rPos, rStr, nLen);
++            }
++
++			// #100617# Allow to skip doubles, too.
++            void lcl_skipDoubleAndSpacesAndCommas(sal_Int32& 				io_rPos, 
++                                                  const ::rtl::OUString& 	rStr, 
++                                                  const sal_Int32 			nLen)
++            {
++                lcl_skipDouble(io_rPos, rStr, nLen);
++                lcl_skipSpacesAndCommas(io_rPos, rStr, nLen);
++            }
++
++            void lcl_putNumberChar( ::rtl::OUString& rStr, 
++                                    double 		 	 fValue )
++            {
++                rStr += ::rtl::OUString::valueOf( fValue );
++            }
++
++            void lcl_putNumberCharWithSpace( ::rtl::OUString& rStr, 
++                                             double 		  fValue,
++                                             double 		  fOldValue,
++                                             bool 			  bUseRelativeCoordinates )
++            {
++                if( bUseRelativeCoordinates )
++                    fValue -= fOldValue;
++
++                const sal_Int32 aLen( rStr.getLength() );
++                if(aLen)
++                {
++                    if( lcl_isOnNumberChar(rStr, aLen - 1, false) && 
++                        fValue >= 0.0 )
++                    {
++                        rStr += ::rtl::OUString::valueOf( 
++                            sal_Unicode(' ') );
++                    }
++                }
++
++                lcl_putNumberChar(rStr, fValue);
++            }
++
++            inline sal_Unicode lcl_getCommand( sal_Char cUpperCaseCommand,
++                                               sal_Char cLowerCaseCommand,
++                                               bool 	bUseRelativeCoordinates )
++            {
++                return bUseRelativeCoordinates ? cLowerCaseCommand : cUpperCaseCommand;
++            }
++        }
++
++        bool importFromSvgD(B2DPolyPolygon& o_rPolyPolygon, const ::rtl::OUString& 	rSvgDStatement)
++        {
++            o_rPolyPolygon.clear();
++            const sal_Int32 nLen(rSvgDStatement.getLength());
++            sal_Int32 nPos(0);
++            bool bIsClosed(false);
++            double nLastX( 0.0 );
++            double nLastY( 0.0 );
++			B2DPolygon aCurrPoly;
++
++			// skip initial whitespace
++            lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++            while(nPos < nLen)
++            {
++                bool bRelative(false);
++                bool bMoveTo(false);
++                const sal_Unicode aCurrChar(rSvgDStatement[nPos]);
++
++                switch(aCurrChar)
++                {
++                    case 'z' :
++                    case 'Z' :
++                    {
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        // remember closed state of current polygon
++                        bIsClosed = true;
++                        break;
++                    }
++				
++                    case 'm' :
++                    case 'M' :
++                    {
++                        bMoveTo = true;
++                        // FALLTHROUGH intended
++                    }
++                    case 'l' :
++                    case 'L' :
++                    {
++                        if('m' == aCurrChar || 'l' == aCurrChar)
++						{
++                            bRelative = true;
++						}
++
++                        if(bMoveTo)
++                        {
++							// new polygon start, finish old one
++                            if(aCurrPoly.count())
++                            {
++                                aCurrPoly.setClosed(bIsClosed);
++                                bIsClosed = false;
++                                o_rPolyPolygon.append(aCurrPoly);
++                                aCurrPoly.clear();
++                            }
++                        }
++
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            double nX, nY;
++
++                            if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
++
++                            if(bRelative)
++                            {
++                                nX += nLastX;
++                                nY += nLastY;
++                            }
++
++                            // set last position
++                            nLastX = nX;
++                            nLastY = nY;
++						
++                            // add point
++                            aCurrPoly.append(B2DPoint(nX, nY));
++                        }
++                        break;
++                    }
++
++                    case 'h' :
++                    {
++                        bRelative = true;
++                        // FALLTHROUGH intended
++                    }
++                    case 'H' :
++                    {
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            double nX, nY(nLastY);
++
++                            if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
++
++                            if(bRelative)
++							{
++                                nX += nLastX;
++							}
++
++                            // set last position
++                            nLastX = nX;
++						
++                            // add point
++                            aCurrPoly.append(B2DPoint(nX, nY));
++                        }
++                        break;
++                    }
++				
++                    case 'v' :
++                    {
++                        bRelative = true;
++                        // FALLTHROUGH intended
++                    }
++                    case 'V' :
++                    {
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            double nX(nLastX), nY;
++
++                            if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
++
++                            if(bRelative)
++							{
++                                nY += nLastY;
++							}
++
++                            // set last position
++                            nLastY = nY;
++						
++                            // add point
++                            aCurrPoly.append(B2DPoint(nX, nY));
++                        }
++                        break;
++                    }
++				
++                    case 's' :
++                    {
++                        bRelative = true;
++                        // FALLTHROUGH intended
++                    }
++                    case 'S' :
++                    {
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            double nX, nY;
++                            double nX2, nY2;
++
++                            if(!lcl_importDoubleAndSpaces(nX2, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY2, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
++
++                            if(bRelative)
++                            {
++                                nX2 += nLastX;
++                                nY2 += nLastY;
++                                nX += nLastX;
++                                nY += nLastY;
++                            }
++
++							// ensure existance of start point
++							if(!aCurrPoly.count())
++							{
++                                aCurrPoly.append(B2DPoint(nLastX, nLastY));
++							}
++
++							// get first control point. It's the reflection of the PrevControlPoint
++							// of the last point. If not existent, use current point (see SVG)
++							B2DPoint aPrevControl(B2DPoint(nLastX, nLastY));
++							const sal_uInt32 nIndex(aCurrPoly.count() - 1);
++
++							if(aCurrPoly.areControlPointsUsed() && aCurrPoly.isPrevControlPointUsed(nIndex))
++							{
++								const B2DPoint aPrevPoint(aCurrPoly.getB2DPoint(nIndex));
++								const B2DPoint aPrevControlPoint(aCurrPoly.getPrevControlPoint(nIndex));
++
++								// use mirrored previous control point
++								aPrevControl.setX((2.0 * aPrevPoint.getX()) - aPrevControlPoint.getX());
++								aPrevControl.setY((2.0 * aPrevPoint.getY()) - aPrevControlPoint.getY());
++							}
++
++							// append curved edge
++							aCurrPoly.appendBezierSegment(aPrevControl, B2DPoint(nX2, nY2), B2DPoint(nX, nY));
++
++                            // set last position
++                            nLastX = nX;
++                            nLastY = nY;
++                        }
++                        break;
++                    }
++				
++                    case 'c' :
++                    {
++                        bRelative = true;
++                        // FALLTHROUGH intended
++                    }
++                    case 'C' :
++                    {
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            double nX, nY;
++                            double nX1, nY1;
++                            double nX2, nY2;
++
++                            if(!lcl_importDoubleAndSpaces(nX1, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY1, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nX2, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY2, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
++
++                            if(bRelative)
++                            {
++                                nX1 += nLastX;
++                                nY1 += nLastY;
++                                nX2 += nLastX;
++                                nY2 += nLastY;
++                                nX += nLastX;
++                                nY += nLastY;
++                            }
++
++							// ensure existance of start point
++							if(!aCurrPoly.count())
++							{
++                                aCurrPoly.append(B2DPoint(nLastX, nLastY));
++							}
++
++							// append curved edge
++							aCurrPoly.appendBezierSegment(B2DPoint(nX1, nY1), B2DPoint(nX2, nY2), B2DPoint(nX, nY));
++
++                            // set last position
++                            nLastX = nX;
++                            nLastY = nY;
++                        }
++                        break;
++                    }
++				
++                    // #100617# quadratic beziers are imported as cubic ones
++                    case 'q' :
++                    {
++                        bRelative = true;
++                        // FALLTHROUGH intended
++                    }
++                    case 'Q' :
++                    {
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            double nX, nY;
++                            double nX1, nY1;
++
++                            if(!lcl_importDoubleAndSpaces(nX1, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY1, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
++
++                            if(bRelative)
++                            {
++                                nX1 += nLastX;
++                                nY1 += nLastY;
++                                nX += nLastX;
++                                nY += nLastY;
++                            }
++
++                            // calculate the cubic bezier coefficients from the quadratic ones
++                            const double nX1Prime((nX1 * 2.0 + nLastX) / 3.0);
++                            const double nY1Prime((nY1 * 2.0 + nLastY) / 3.0);
++                            const double nX2Prime((nX1 * 2.0 + nX) / 3.0);
++                            const double nY2Prime((nY1 * 2.0 + nY) / 3.0);
++
++							// ensure existance of start point
++							if(!aCurrPoly.count())
++							{
++                                aCurrPoly.append(B2DPoint(nLastX, nLastY));
++							}
++
++							// append curved edge
++							aCurrPoly.appendBezierSegment(B2DPoint(nX1Prime, nY1Prime), B2DPoint(nX2Prime, nY2Prime), B2DPoint(nX, nY));
++
++                            // set last position
++                            nLastX = nX;
++                            nLastY = nY;
++                        }
++                        break;
++                    }
++				
++                    // #100617# relative quadratic beziers are imported as cubic
++                    case 't' :
++                    {
++                        bRelative = true;
++                        // FALLTHROUGH intended
++                    }
++                    case 'T' :
++                    {
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            double nX, nY;
++
++                            if(!lcl_importDoubleAndSpaces(nX, nPos, rSvgDStatement, nLen)) return false;
++                            if(!lcl_importDoubleAndSpaces(nY, nPos, rSvgDStatement, nLen)) return false;
++
++                            if(bRelative)
++                            {
++                                nX += nLastX;
++                                nY += nLastY;
++                            }
++
++							// ensure existance of start point
++							if(!aCurrPoly.count())
++							{
++                                aCurrPoly.append(B2DPoint(nLastX, nLastY));
++							}
++
++							// get first control point. It's the reflection of the PrevControlPoint
++							// of the last point. If not existent, use current point (see SVG)
++							B2DPoint aPrevControl(B2DPoint(nLastX, nLastY));
++							const sal_uInt32 nIndex(aCurrPoly.count() - 1);
++							const B2DPoint aPrevPoint(aCurrPoly.getB2DPoint(nIndex));
++
++							if(aCurrPoly.areControlPointsUsed() && aCurrPoly.isPrevControlPointUsed(nIndex))
++							{
++								const B2DPoint aPrevControlPoint(aCurrPoly.getPrevControlPoint(nIndex));
++
++								// use mirrored previous control point
++								aPrevControl.setX((2.0 * aPrevPoint.getX()) - aPrevControlPoint.getX());
++								aPrevControl.setY((2.0 * aPrevPoint.getY()) - aPrevControlPoint.getY());
++							}
++
++							if(!aPrevControl.equal(aPrevPoint))
++							{
++								// there is a prev control point, and we have the already mirrored one
++								// in aPrevControl. We also need the quadratic control point for this
++								// new quadratic segment to calculate the 2nd cubic control point
++								const B2DPoint aQuadControlPoint(
++									((3.0 * aPrevControl.getX()) - aPrevPoint.getX()) / 2.0,
++									((3.0 * aPrevControl.getY()) - aPrevPoint.getY()) / 2.0);
++								
++								// calculate the cubic bezier coefficients from the quadratic ones.
++								const double nX2Prime((aQuadControlPoint.getX() * 2.0 + nX) / 3.0);
++								const double nY2Prime((aQuadControlPoint.getY() * 2.0 + nY) / 3.0);
++								
++								// append curved edge, use mirrored cubic control point directly
++								aCurrPoly.appendBezierSegment(aPrevControl, B2DPoint(nX2Prime, nY2Prime), B2DPoint(nX, nY));
++							}
++							else
++							{
++								// when no previous control, SVG says to use current point -> straight line.
++								// Just add end point
++								aCurrPoly.append(B2DPoint(nX, nY));
++							}
++
++                            // set last position
++                            nLastX = nX;
++                            nLastY = nY;
++                        }
++                        break;
++                    }
++
++                    // #100617# not yet supported: elliptical arc
++                    case 'A' :
++                        // FALLTHROUGH intended
++                    case 'a' :
++                    {
++                        OSL_ENSURE(false, "importFromSvgD(): non-interpreted tags in svg:d element (elliptical arc)!");
++                        nPos++;
++                        lcl_skipSpaces(nPos, rSvgDStatement, nLen);
++
++                        while(nPos < nLen && lcl_isOnNumberChar(rSvgDStatement, nPos))
++                        {
++                            lcl_skipDoubleAndSpacesAndCommas(nPos, rSvgDStatement, nLen);
++                            lcl_skipDoubleAndSpacesAndCommas(nPos, rSvgDStatement, nLen);
++                            lcl_skipDoubleAndSpacesAndCommas(nPos, rSvgDStatement, nLen);
++                            lcl_skipNumberAndSpacesAndCommas(nPos, rSvgDStatement, nLen);
++                            lcl_skipNumberAndSpacesAndCommas(nPos, rSvgDStatement, nLen);
++                            lcl_skipDoubleAndSpacesAndCommas(nPos, rSvgDStatement, nLen);
++                            lcl_skipDoubleAndSpacesAndCommas(nPos, rSvgDStatement, nLen);
++                        }
++                        break;
++                    }
++
++                    default:
++                    {
++                        OSL_ENSURE(false, "importFromSvgD(): skipping tags in svg:d element (unknown)!");
++                        OSL_TRACE("importFromSvgD(): skipping tags in svg:d element (unknown: \"%c\")!", aCurrChar);
++                        ++nPos;
++                        break;
++                    }
++                }
++            }
++
++            if(aCurrPoly.count())
++            {
++                // end-process last poly
++                aCurrPoly.setClosed(bIsClosed);
++                o_rPolyPolygon.append(aCurrPoly);
++            }
++
++            return true;
++        }
 +
- 
- 		// create 3d PolyPolygon from given 2d PolyPolygon. The given fZCoordinate is used to expand the
- 		// third coordinate.
-diff --git a/basegfx/source/polygon/b2dsvgpolypolygon.cxx b/basegfx/source/polygon/b2dsvgpolypolygon.cxx
-index 8965007..170d453 100644
---- basegfx/source/polygon/b2dsvgpolypolygon.cxx
-+++ basegfx/source/polygon/b2dsvgpolypolygon.cxx
-@@ -665,6 +665,32 @@ namespace basegfx
-             return true;
-         }
- 
 +        bool importFromSvgPoints( B2DPolygon&            o_rPoly,
 +                                  const ::rtl::OUString& rSvgPointsAttribute )
 +        {
@@ -79,6 +794,197 @@
 +            return true;
 +        }
 +
-         ::rtl::OUString exportToSvgD(
- 			const B2DPolyPolygon& rPolyPolygon,
- 			bool bUseRelativeCoordinates, 
++        ::rtl::OUString exportToSvgD(
++			const B2DPolyPolygon& rPolyPolygon,
++			bool bUseRelativeCoordinates, 
++			bool bDetectQuadraticBeziers)
++        {
++            const sal_uInt32 nCount(rPolyPolygon.count());
++            ::rtl::OUString aResult;
++            B2DPoint aLastPoint(0.0, 0.0); // SVG assumes (0,0) as the initial current point
++
++            for(sal_uInt32 i(0); i < nCount; i++)
++            {
++                const B2DPolygon aPolygon(rPolyPolygon.getB2DPolygon(i));
++                const sal_uInt32 nPointCount(aPolygon.count());
++                const bool bPolyUsesControlPoints(aPolygon.areControlPointsUsed());
++                sal_Unicode aLastSVGCommand(' '); // last SVG command char
++				B2DPoint aLeft, aRight; // for quadratic bezier test
++
++                for(sal_uInt32 j(0); j < nPointCount; j++)
++                {
++                    const B2DPoint aCurrent(aPolygon.getB2DPoint(j));
++
++                    if(0 == j)
++                    {
++						// handle first polygon point
++                        aResult += ::rtl::OUString::valueOf(lcl_getCommand('M', 'm', bUseRelativeCoordinates));
++                        lcl_putNumberCharWithSpace(aResult, aCurrent.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                        lcl_putNumberCharWithSpace(aResult, aCurrent.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                        aLastSVGCommand =  lcl_getCommand('L', 'l', bUseRelativeCoordinates);
++                    }
++                    else
++                    {
++						// handle edge from j-1 to j
++						const bool bEdgeIsBezier(bPolyUsesControlPoints
++							&& (aPolygon.isNextControlPointUsed(j - 1) || aPolygon.isPrevControlPointUsed(j)));
++
++                        if(bEdgeIsBezier)
++                        {
++                            // handle bezier edge
++                            const B2DPoint aControl0(aPolygon.getNextControlPoint(j - 1));
++                            const B2DPoint aControl1(aPolygon.getPrevControlPoint(j));
++							const B2VectorContinuity aPrevCont(aPolygon.getContinuityInPoint(j - 1));
++							const bool bSymmetricControlVector(CONTINUITY_C2 == aPrevCont);
++							bool bIsQuadraticBezier(false);
++
++							if(bDetectQuadraticBeziers)
++							{
++								// check for quadratic beziers - that's
++								// the case if both control points are in
++								// the same place when they are prolonged
++								// to the common quadratic control point
++								//
++								// Left: P = (3P1 - P0) / 2 
++								// Right: P = (3P2 - P3) / 2
++								aLeft = B2DPoint((3.0 * aControl0 - aLastPoint) / 2.0);
++								aRight= B2DPoint((3.0 * aControl1 - aCurrent) / 2.0);
++								bIsQuadraticBezier = aLeft.equal(aRight);
++							}
++
++							if(bIsQuadraticBezier)
++							{
++                                // approximately equal, export as quadratic bezier
++                                if(bSymmetricControlVector)
++                                {
++                                    const sal_Unicode aCommand(lcl_getCommand('T', 't', bUseRelativeCoordinates));
++
++                                    if(aLastSVGCommand != aCommand)
++                                    {
++                                        aResult += ::rtl::OUString::valueOf(aCommand);
++                                        aLastSVGCommand = aCommand;
++                                    }
++                                    
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    aLastSVGCommand = aCommand;
++                                }
++                                else
++                                {
++                                    const sal_Unicode aCommand(lcl_getCommand('Q', 'q', bUseRelativeCoordinates));
++
++                                    if(aLastSVGCommand != aCommand)
++                                    {
++                                        aResult += ::rtl::OUString::valueOf(aCommand);
++                                        aLastSVGCommand = aCommand;
++                                    }
++                                    
++                                    lcl_putNumberCharWithSpace(aResult, aLeft.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aLeft.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    aLastSVGCommand = aCommand;
++                                }
++                            }
++                            else
++                            {
++                                // export as cubic bezier
++                                if(bSymmetricControlVector)
++                                {
++                                    const sal_Unicode aCommand(lcl_getCommand('S', 's', bUseRelativeCoordinates));
++
++                                    if(aLastSVGCommand != aCommand)
++                                    {
++                                        aResult += ::rtl::OUString::valueOf(aCommand);
++                                        aLastSVGCommand = aCommand;
++                                    }
++                                    
++                                    lcl_putNumberCharWithSpace(aResult, aControl1.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aControl1.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    aLastSVGCommand = aCommand;
++                                }
++                                else
++                                {
++                                    const sal_Unicode aCommand(lcl_getCommand('C', 'c', bUseRelativeCoordinates));
++
++                                    if(aLastSVGCommand != aCommand)
++                                    {
++                                        aResult += ::rtl::OUString::valueOf(aCommand);
++                                        aLastSVGCommand = aCommand;
++                                    }
++                                    
++                                    lcl_putNumberCharWithSpace(aResult, aControl0.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aControl0.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aControl1.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aControl1.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                                    lcl_putNumberCharWithSpace(aResult, aCurrent.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                                    aLastSVGCommand = aCommand;
++                                }
++                            }                            
++                        }
++                        else
++                        {
++                            // normal straight line points
++                            if(aLastPoint.getX() == aCurrent.getX())
++                            {
++								// export as vertical line
++                                const sal_Unicode aCommand(lcl_getCommand('V', 'v', bUseRelativeCoordinates));
++
++								if(aLastSVGCommand != aCommand)
++                                {
++									aResult += ::rtl::OUString::valueOf(aCommand);
++                                    aLastSVGCommand = aCommand;
++                                }
++
++								lcl_putNumberCharWithSpace(aResult, aCurrent.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                            }
++                            else if(aLastPoint.getY() == aCurrent.getY())
++                            {
++								// export as horizontal line
++                                const sal_Unicode aCommand(lcl_getCommand('H', 'h', bUseRelativeCoordinates));
++
++								if(aLastSVGCommand != aCommand)
++                                {
++									aResult += ::rtl::OUString::valueOf(aCommand);
++                                    aLastSVGCommand = aCommand;
++                                }
++
++								lcl_putNumberCharWithSpace(aResult, aCurrent.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++                            }
++                            else
++                            {
++								// export as line
++                                const sal_Unicode aCommand(lcl_getCommand('L', 'l', bUseRelativeCoordinates));
++
++								if(aLastSVGCommand != aCommand)
++                                {
++									aResult += ::rtl::OUString::valueOf(aCommand);
++                                    aLastSVGCommand = aCommand;
++                                }
++
++								lcl_putNumberCharWithSpace(aResult, aCurrent.getX(), aLastPoint.getX(), bUseRelativeCoordinates);
++								lcl_putNumberCharWithSpace(aResult, aCurrent.getY(), aLastPoint.getY(), bUseRelativeCoordinates);
++                            }
++                        }
++                    }
++
++                    aLastPoint = aCurrent;
++                }
++
++                // close path if closed poly (Z and z are equivalent here, but looks nicer
++				// when case is matched)
++                if(aPolygon.isClosed())
++				{
++                    aResult += ::rtl::OUString::valueOf(lcl_getCommand('Z', 'z', bUseRelativeCoordinates));
++				}
++            }
++
++            return aResult;
++        }
++    }
++}
++
++// eof



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]