ooo-build r12703 - in trunk: . patches/dev300



Author: thorstenb
Date: Thu May 29 14:33:40 2008
New Revision: 12703
URL: http://svn.gnome.org/viewvc/ooo-build?rev=12703&view=rev

Log:
	* patches/dev300/svg-import-basegfx-m10.diff
	* patches/dev300/svg-import-basegfx.diff: fix wrong bracket
	  placement, leading to incorrect elliptical arc import
	* patches/dev300/svg-import-filter.diff: added gradient & text
	  support, fixed a bunch of parser bugs 
	* patches/dev300/svg-import-filter-gfxfilter.diff
	* patches/dev300/apply: added a graphic filter for svg with
	  similar capabilities as the doc import above



Added:
   trunk/patches/dev300/svg-import-filter-gfxfilter.diff
Modified:
   trunk/ChangeLog
   trunk/patches/dev300/apply
   trunk/patches/dev300/svg-import-basegfx-m10.diff
   trunk/patches/dev300/svg-import-basegfx.diff
   trunk/patches/dev300/svg-import-filter.diff

Modified: trunk/patches/dev300/apply
==============================================================================
--- trunk/patches/dev300/apply	(original)
+++ trunk/patches/dev300/apply	Thu May 29 14:33:40 2008
@@ -1950,6 +1950,8 @@
 # Marco Cecchetti's work on importing text
 #svg-import-text.diff, jholesov
 
+# A bit less partial implementation of SVG import
+# Work in progress, but fairly usable already
 svg-import-filter.diff, thorsten
 
 [ SVGImport < dev300-m11 ]
@@ -1958,6 +1960,9 @@
 [ SVGImport >= dev300-m11 ]
 svg-import-basegfx.diff, thorsten
 
+# like svg-import-filter.diff, but adds a graphic filter for SVG
+svg-import-filter-gfxfilter.diff, thorsten
+
 [ CalcDataPilotDrillDown < dev300-m14 ]
 # Implements DataPilot cache table, result drill-down, and some extra UNO API.
 SectionOwner => kohei

Modified: trunk/patches/dev300/svg-import-basegfx-m10.diff
==============================================================================
--- trunk/patches/dev300/svg-import-basegfx-m10.diff	(original)
+++ trunk/patches/dev300/svg-import-basegfx-m10.diff	Thu May 29 14:33:40 2008
@@ -225,7 +225,7 @@
 +
 +
 +                                    const double fFactor(
-+                                        (bLargeArcFlag==bSweepFlag) ? -1.0 : 1.0 *
++                                        (bLargeArcFlag==bSweepFlag ? -1.0 : 1.0) *
 +                                        sqrt((fRX*fRX*fRY*fRY - fRX*fRX*p1_prime.getY()*p1_prime.getY() - fRY*fRY*p1_prime.getX()*p1_prime.getX())/
 +                                             (fRX*fRX*p1_prime.getY()*p1_prime.getY() + fRY*fRY*p1_prime.getX()*p1_prime.getX())));
 +

Modified: trunk/patches/dev300/svg-import-basegfx.diff
==============================================================================
--- trunk/patches/dev300/svg-import-basegfx.diff	(original)
+++ trunk/patches/dev300/svg-import-basegfx.diff	Thu May 29 14:33:40 2008
@@ -103,7 +103,7 @@
              void lcl_skipNumber(sal_Int32& 				io_rPos, 
                                  const ::rtl::OUString& 	rStr, 
                                  const sal_Int32 		nLen)
-@@ -621,24 +654,185 @@ namespace basegfx
+@@ -623,24 +656,185 @@
                          break;
                      }
  
@@ -226,7 +226,7 @@
 +
 +
 +                                    const double fFactor(
-+                                        (bLargeArcFlag==bSweepFlag) ? -1.0 : 1.0 *
++                                        (bLargeArcFlag==bSweepFlag ? -1.0 : 1.0) *
 +                                        sqrt((fRX*fRX*fRY*fRY - fRX*fRX*p1_prime.getY()*p1_prime.getY() - fRY*fRY*p1_prime.getX()*p1_prime.getX())/
 +                                             (fRX*fRX*p1_prime.getY()*p1_prime.getY() + fRY*fRY*p1_prime.getX()*p1_prime.getX())));
 +
@@ -300,7 +300,7 @@
                          }
                          break;
                      }
-@@ -667,7 +861,33 @@ namespace basegfx
+@@ -667,6 +861,32 @@ namespace basegfx
              return true;
          }
  

Added: trunk/patches/dev300/svg-import-filter-gfxfilter.diff
==============================================================================
--- (empty file)
+++ trunk/patches/dev300/svg-import-filter-gfxfilter.diff	Thu May 29 14:33:40 2008
@@ -0,0 +1,872 @@
+diff -ur filter_orig/source/config/fragments/internalgraphicfilters/svg_Export.xcu filter/source/config/fragments/internalgraphicfilters/svg_Export.xcu
+--- filter_orig/source/config/fragments/internalgraphicfilters/svg_Export.xcu	2008-05-28 02:34:02.000000000 +0200
++++ filter/source/config/fragments/internalgraphicfilters/svg_Export.xcu	2008-05-28 02:30:15.000000000 +0200
+@@ -8,3 +8,13 @@
+ 		</prop>
+ 		<prop oor:name="Flags"><value>EXPORT</value></prop>
+ 	</node>
++	<node oor:name="svg_Import" oor:op="replace"  >
++		<prop oor:name="Type"><value>svg_Scalable_Vector_Graphics</value></prop>
++        <prop oor:name="FormatName"><value>svgfilter</value></prop>
++        <prop oor:name="RealFilterName"/>
++		<prop oor:name="UIComponent"/>
++		<prop oor:name="UIName">
++			<value xml:lang="en-US">SVG - Scalable Vector Graphics</value>
++		</prop>
++		<prop oor:name="Flags"><value>IMPORT</value></prop>
++	</node>
+diff -ur filter_orig/source/svg/exports.map filter/source/svg/exports.map
+--- filter_orig/source/svg/exports.map	2008-05-28 02:34:02.000000000 +0200
++++ filter/source/svg/exports.map	2008-05-27 23:32:34.000000000 +0200
+@@ -3,6 +3,7 @@
+                 component_getImplementationEnvironment;
+                 component_getFactory;
+                 component_writeInfo;
++                GraphicImport;
+ 
+         local:
+                 *;
+diff -ur filter_orig/source/svg/makefile.mk filter/source/svg/makefile.mk
+--- filter_orig/source/svg/makefile.mk	2008-05-28 02:34:02.000000000 +0200
++++ filter/source/svg/makefile.mk	2008-05-28 02:16:23.000000000 +0200
+@@ -78,6 +78,7 @@
+ 	$(UNOTOOLSLIB)		\
+ 	$(TOOLSLIB)			\
+ 	$(COMPHELPERLIB)	\
++	$(SVTOOLLIB)	    \
+ 	$(CPPUHELPERLIB)	\
+ 	$(CPPULIB)			\
+ 	$(SALLIB)			\
+diff -ur filter_orig/source/svg/svgfilter.cxx filter/source/svg/svgfilter.cxx
+--- filter_orig/source/svg/svgfilter.cxx	2008-05-28 02:34:02.000000000 +0200
++++ filter/source/svg/svgfilter.cxx	2008-05-27 23:32:59.000000000 +0200
+@@ -243,3 +243,11 @@
+ {
+     return SVGFilter_getSupportedServiceNames();
+ }
++
++// -----------------------------------------------------------------------------
++
++class FilterConfigItem;
++extern "C" BOOL __LOADONCALLAPI GraphicImport(SvStream & rStream, Graphic & rGraphic, FilterConfigItem*, BOOL )
++{
++	return importSvg( rStream, rGraphic );
++}
+diff -ur filter_orig/source/svg/svgfilter.hxx filter/source/svg/svgfilter.hxx
+--- filter_orig/source/svg/svgfilter.hxx	2008-05-28 02:34:02.000000000 +0200
++++ filter/source/svg/svgfilter.hxx	2008-05-27 23:03:42.000000000 +0200
+@@ -328,4 +328,11 @@
+ SAL_CALL SVGFilter_createInstance( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & rSMgr)
+ 	throw ( ::com::sun::star::uno::Exception );
+ 
++// -----------------------------------------------------------------------------
++
++class SvStream;
++class Graphic;
++
++bool importSvg(SvStream & rStream, Graphic & rGraphic );
++
+ #endif // SVGFILTER_HXX
+diff -ur filter_orig/source/svg/svgreader.cxx filter/source/svg/svgreader.cxx
+--- filter_orig/source/svg/svgreader.cxx	2008-05-28 02:34:02.000000000 +0200
++++ filter/source/svg/svgreader.cxx	2008-05-28 22:12:21.000000000 +0200
+@@ -7,6 +7,7 @@
+  *      Thorsten Behrens <tbehrens novell com>	   	
+  *
+  *      Copyright (C) 2008, Novell Inc.
++ *      Parts copyright 2005 by Sun Microsystems, Inc.
+  *
+  *   The Contents of this file are made available subject to
+  *   the terms of GNU Lesser General Public License Version 2.1.
+@@ -41,6 +42,17 @@
+ #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
+ #include <com/sun/star/xml/dom/NodeType.hpp>
+ 
++#include <comphelper/processfactory.hxx>
++#include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
++#include <basegfx/polygon/b2dpolypolygontools.hxx>
++#include <unotools/streamwrap.hxx>
++#include <xmloff/xmluconv.hxx>
++#include <vcl/graph.hxx>
++#include <vcl/virdev.hxx>
++#include <vcl/gradient.hxx>
++#include <svx/impgrf.hxx>
++#include <tools/zcodec.hxx>
++
+ #include <boost/bind.hpp>
+ #include <hash_set>
+ #include <map>
+@@ -432,6 +444,9 @@
+         // start&end color)
+         optimizeGradientStops(rState.maFillGradient);
+ 
++        if( !mxDocumentHandler.is() )
++            return true; // cannot write style, svm import case
++
+         // do we have a gradient fill? then write out gradient as well
+         if( rState.meFillType == GRADIENT && rState.maFillGradient.maStops.size() > 1 )
+         {
+@@ -1541,10 +1556,13 @@
+             for( sal_uInt32 i=0; i<rPoly.count(); ++i )
+             {                
+                 aPolys.push_back(
+-                    basegfx::tools::createAreaGeometryForPolygon(
+-                        rPoly.getB2DPolygon(i),
+-                        aState.mnStrokeWidth/2.0,
+-                        aState.meLineJoin));
++                    basegfx::tools::removeNeutralPolygons(
++                        basegfx::tools::removeAllIntersections(
++                            basegfx::tools::createAreaGeometryForPolygon(
++                                rPoly.getB2DPolygon(i),
++                                aState.mnStrokeWidth/2.0,
++                                aState.meLineJoin)),
++                            true));
+                 // TODO(F2): line ends
+             }
+ 
+@@ -1896,4 +1914,734 @@
+     return sal_True;
+ }
+ 
++///////////////////////////////////////////////////////////////
++
++struct ShapeRenderingVisitor
++{
++    ShapeRenderingVisitor(StatePool&    rStatePool,
++                          StateMap&     rStateMap,
++                          OutputDevice& rOutDev,
++                          const std::vector< Gradient >& rGradientVector,
++                          const std::vector< GradientStop >& rGradientStopVector) :
++        mrStates(rStatePool),
++        mrStateMap(rStateMap),
++        mrOutDev(rOutDev),
++        mrGradientVector(rGradientVector),
++        mrGradientStopVector(rGradientStopVector)
++    {}
++
++    void operator()( const uno::Reference<xml::dom::XElement>& )
++    {
++    }
++
++    void operator()( const uno::Reference<xml::dom::XElement>&      xElem,
++                     const uno::Reference<xml::dom::XNamedNodeMap>& xAttributes )
++    {
++        sal_Int32 nDummyIndex(0);
++        rtl::OUString sStyleId(
++            xElem->getAttribute(
++                USTR("internal-style-ref")).getToken(
++                    0,'$',nDummyIndex));
++        StateMap::iterator pOrigState=mrStateMap.find(
++            sStyleId.toInt32());
++        maCurrState = pOrigState != mrStateMap.end() ? pOrigState->second : maParentStates.back();
++
++        OSL_TRACE("the CTM is now #2: %f %f %f %f %f %f", 
++                  maCurrState.maCTM.get(0,0),
++                  maCurrState.maCTM.get(0,1),
++                  maCurrState.maCTM.get(0,2),
++                  maCurrState.maCTM.get(1,0),
++                  maCurrState.maCTM.get(1,1),
++                  maCurrState.maCTM.get(1,2));
++        
++        const sal_Int32 nTokenId(getTokenId(xElem->getNodeName()));
++        switch(nTokenId)
++        {
++		    case XML_LINE:
++			{
++                // collect attributes
++                const sal_Int32 nNumAttrs( xAttributes->getLength() );
++                rtl::OUString sAttributeValue;
++                double x1=0.0,y1=0.0,x2=0.0,y2=0.0;
++                for( sal_Int32 i=0; i<nNumAttrs; ++i )
++                {
++                    sAttributeValue = xAttributes->item(i)->getNodeValue();
++                    const sal_Int32 nAttribId( 
++                        getTokenId(xAttributes->item(i)->getNodeName()));
++                    switch(nAttribId)
++                    {
++                        case XML_X1:
++                            x1= convLength(sAttributeValue);
++                            break;
++                        case XML_X2:
++                            x2 = convLength(sAttributeValue);
++                            break;
++                        case XML_Y1:
++                            y1 = convLength(sAttributeValue);
++                            break;
++                        case XML_Y2:
++                            y2 = convLength(sAttributeValue);
++                            break;
++                        default:
++                            // skip
++                            break;
++                    }
++                }
++
++                basegfx::B2DPolygon aPoly;
++                aPoly.append(basegfx::B2DPoint(x1,y1));
++                aPoly.append(basegfx::B2DPoint(x2,y2));
++
++                renderPathShape(basegfx::B2DPolyPolygon(aPoly));
++                break;
++			}
++            case XML_POLYGON:
++            case XML_POLYLINE:
++            {
++                rtl::OUString sPoints = xElem->hasAttribute(USTR("points")) ? xElem->getAttribute(USTR("points")) : USTR("");
++                basegfx::B2DPolygon aPoly;
++                basegfx::tools::importFromSvgPoints(aPoly, sPoints);
++                // if( nTokenId == XML_POLYGON )
++                    aPoly.setClosed(true);
++
++				// assuming the coordinates are in pts since they are interpreted as such by different renderers
++				basegfx::B2DHomMatrix aScale;
++				aScale.scale(2540.0f/72.0f,2540.0f/72.0f);
++				aPoly.transform(aScale);
++
++                renderPathShape(basegfx::B2DPolyPolygon(aPoly));
++                break;
++            }
++            case XML_RECT:
++            {
++                // collect attributes
++                const sal_Int32 nNumAttrs( xAttributes->getLength() );
++                rtl::OUString sAttributeValue;
++                bool bRxSeen=false, bRySeen=false;
++                double x=0.0,y=0.0,width=0.0,height=0.0,rx=0.0,ry=0.0;
++                for( sal_Int32 i=0; i<nNumAttrs; ++i )
++                {
++                    sAttributeValue = xAttributes->item(i)->getNodeValue();
++                    const sal_Int32 nAttribId( 
++                        getTokenId(xAttributes->item(i)->getNodeName()));
++                    switch(nAttribId)
++                    {
++                        case XML_X:
++                            x = convLength(sAttributeValue);
++                            break;
++                        case XML_Y:
++                            y = convLength(sAttributeValue);
++                            break;
++                        case XML_WIDTH:
++                            width = convLength(sAttributeValue);
++                            break;
++                        case XML_HEIGHT:
++                            height = convLength(sAttributeValue);
++                            break;
++                        case XML_RX:
++                            rx = convLength(sAttributeValue);
++                            bRxSeen=true;
++                            break;
++                        case XML_RY:
++                            ry = convLength(sAttributeValue);
++                            bRySeen=true;
++                            break;
++                        default:
++                            // skip
++                            break;
++                    }
++                }
++
++                if( bRxSeen && !bRySeen )
++                    ry = rx;
++                else if( bRySeen && !bRxSeen )
++                    rx = ry;
++
++                basegfx::B2DPolygon aPoly;
++                aPoly = basegfx::tools::createPolygonFromRect(
++                    basegfx::B2DRange(x,y,x+width,y+height),
++                    rx, ry );
++
++                renderPathShape(basegfx::B2DPolyPolygon(aPoly));
++                break;
++            }
++            case XML_PATH:
++            {
++                rtl::OUString sPath = xElem->hasAttribute(USTR("d")) ? xElem->getAttribute(USTR("d")) : USTR("");
++                basegfx::B2DPolyPolygon aPoly;
++                basegfx::tools::importFromSvgD(aPoly, sPath);
++
++				// assuming the coordinates are in pts since they are interpreted as such by different renderers
++				basegfx::B2DHomMatrix aScale;
++				aScale.scale(2540.0f/72.0f,2540.0f/72.0f);
++				aPoly.transform(aScale);
++				
++                renderPathShape(aPoly);
++                break;
++            }
++			case XML_CIRCLE:
++			{
++                // collect attributes
++                const sal_Int32 nNumAttrs( xAttributes->getLength() );
++                rtl::OUString sAttributeValue;
++                double cx=0.0,cy=0.0,r=0.0;
++                for( sal_Int32 i=0; i<nNumAttrs; ++i )
++                {
++                    sAttributeValue = xAttributes->item(i)->getNodeValue();
++                    const sal_Int32 nAttribId( 
++                        getTokenId(xAttributes->item(i)->getNodeName()));
++                    switch(nAttribId)
++                    {
++                        case XML_CX:
++                            cx = convLength(sAttributeValue);
++                            break;
++                        case XML_CY:
++                            cy = convLength(sAttributeValue);
++                            break;
++                        case XML_R:
++                            r = convLength(sAttributeValue);
++                        default:
++                            // skip
++                            break;
++                    }
++                }
++
++                basegfx::B2DEllipse aEllipse(basegfx::B2DPoint(cx, cy), basegfx::B2DTuple(r,r));
++                basegfx::B2DPolygon aPoly = basegfx::tools::createPolygonFromEllipse(
++                    aEllipse.getB2DEllipseCenter(),
++                    aEllipse.getB2DEllipseRadius().getX(), 
++                    aEllipse.getB2DEllipseRadius().getY());
++
++                renderPathShape(basegfx::B2DPolyPolygon(aPoly));
++				break;
++			}
++			case XML_ELLIPSE:
++			{
++                // collect attributes
++                const sal_Int32 nNumAttrs( xAttributes->getLength() );
++                rtl::OUString sAttributeValue;
++                double cx=0.0,cy=0.0,rx=0.0, ry=0.0;
++                for( sal_Int32 i=0; i<nNumAttrs; ++i )
++                {
++                    sAttributeValue = xAttributes->item(i)->getNodeValue();
++                    const sal_Int32 nAttribId( 
++                        getTokenId(xAttributes->item(i)->getNodeName()));
++                    switch(nAttribId)
++                    {
++                        case XML_CX:
++                            cx = convLength(sAttributeValue);
++                            break;
++                        case XML_CY:
++                            cy = convLength(sAttributeValue);
++                            break;
++                        case XML_RX:
++                            rx = convLength(sAttributeValue);
++							break;
++						case XML_RY:
++							ry = convLength(sAttributeValue);
++                        default:
++                            // skip
++                            break;
++                    }
++                }
++
++                basegfx::B2DEllipse aEllipse(basegfx::B2DPoint(cx, cy), basegfx::B2DTuple(rx,ry));
++                basegfx::B2DPolygon aPoly = basegfx::tools::createPolygonFromEllipse(
++                    aEllipse.getB2DEllipseCenter(),
++                    aEllipse.getB2DEllipseRadius().getX(), 
++                    aEllipse.getB2DEllipseRadius().getY());
++
++                renderPathShape(basegfx::B2DPolyPolygon(aPoly));
++				break;
++			}
++            case XML_IMAGE:
++            {
++                // collect attributes
++                const sal_Int32 nNumAttrs( xAttributes->getLength() );
++                rtl::OUString sAttributeValue;
++                double x=0.0,y=0.0,width=0.0,height=0.0;
++                for( sal_Int32 i=0; i<nNumAttrs; ++i )
++                {
++                    sAttributeValue = xAttributes->item(i)->getNodeValue();
++                    const sal_Int32 nAttribId( 
++                        getTokenId(xAttributes->item(i)->getNodeName()));
++                    switch(nAttribId)
++                    {
++                        case XML_X:
++                            x = convLength(sAttributeValue);
++                            break;
++                        case XML_Y:
++                            y = convLength(sAttributeValue);
++                            break;
++                        case XML_WIDTH:
++                            width = convLength(sAttributeValue);
++                            break;
++                        case XML_HEIGHT:
++                            height = convLength(sAttributeValue);
++                            break;
++                        default:
++                            // skip
++                            break;
++                    }
++                }
++
++                rtl::OUString sValue = xElem->hasAttribute(USTR("href")) ? xElem->getAttribute(USTR("href")) : USTR("");
++        		rtl::OString aValueUtf8( sValue.getStr(), sValue.getLength(), RTL_TEXTENCODING_UTF8 );
++				std::string sLinkValue;
++				parseXlinkHref(aValueUtf8.getStr(), sLinkValue);
++
++				if (!sLinkValue.empty())
++                {
++                    // <- blatant copy from svx/source/xml/xmlgrhlp.cxx
++                    Graphic aGraphic;
++
++                    uno::Sequence<sal_Int8> aData;
++                    SvXMLUnitConverter::decodeBase64(aData, 
++                                                     rtl::OUString::createFromAscii(sLinkValue.c_str()));
++                    SvMemoryStream aSrc(aData.getArray(), 
++                                        aData.getLength(), 
++                                        STREAM_READ);
++                    USHORT nFormat = GRFILTER_FORMAT_DONTKNOW;
++                    USHORT pDeterminedFormat = GRFILTER_FORMAT_DONTKNOW;
++                    GetGrfFilter()->ImportGraphic( aGraphic, String(), aSrc ,nFormat,&pDeterminedFormat );
++
++                    if (pDeterminedFormat == GRFILTER_FORMAT_DONTKNOW)
++                    {
++                        //Read the first two byte to check whether it is a gzipped stream, is so it may be in wmz or emz format 
++                        //unzip them and try again
++
++                        BYTE    sFirstBytes[ 2 ];
++
++                        aSrc.Seek( STREAM_SEEK_TO_END );
++                        ULONG nStreamLen = aSrc.Tell();
++                        aSrc.Seek( 0 );
++
++                        if ( !nStreamLen )
++                        {
++                            SvLockBytes* pLockBytes = aSrc.GetLockBytes();
++                            if ( pLockBytes  )
++                                pLockBytes->SetSynchronMode( TRUE );
++
++                            aSrc.Seek( STREAM_SEEK_TO_END );
++                            nStreamLen = aSrc.Tell();
++                            aSrc.Seek( 0 );
++                        }
++                        if( nStreamLen >= 2 )
++                        {
++                            //read two byte
++                            aSrc.Read( sFirstBytes, 2 );
++
++                            if( sFirstBytes[0] == 0x1f && sFirstBytes[1] == 0x8b )
++                            {
++                                SvMemoryStream* pDest = new SvMemoryStream;
++                                ZCodec aZCodec( 0x8000, 0x8000 );
++                                aZCodec.BeginCompression(ZCODEC_GZ_LIB);
++                                aSrc.Seek( 0 );
++                                aZCodec.Decompress( aSrc, *pDest );
++					
++                                if (aZCodec.EndCompression() && pDest )
++                                {
++                                    pDest->Seek( STREAM_SEEK_TO_END );
++                                    ULONG nStreamLen_ = pDest->Tell();
++                                    if (nStreamLen_)
++                                    {
++                                        pDest->Seek(0L);
++                                        GetGrfFilter()->ImportGraphic( aGraphic, String(), *pDest ,nFormat,&pDeterminedFormat );
++                                    }
++                                }
++                                delete pDest;
++                            }
++                        }
++                    }
++                    // -> blatant copy from svx/source/xml/xmlgrhlp.cxx
++
++                    const Rectangle aBounds(
++                        Point(basegfx::fround(x),
++                              basegfx::fround(y)),
++                        Size(basegfx::fround(width),
++                             basegfx::fround(height)));
++                    aGraphic.Draw(&mrOutDev,
++                                  aBounds.TopLeft(),
++                                  aBounds.GetSize());
++                    maBounds.Union(aBounds);
++                }
++                break;
++            }
++            case XML_TEXT:
++            {
++                // collect text from all TEXT_NODE children into sText
++                rtl::OUStringBuffer sText;
++                visitChildren(boost::bind(
++                                  (rtl::OUStringBuffer& (rtl::OUStringBuffer::*)(const sal_Unicode* str))&rtl::OUStringBuffer::append,
++                                  boost::ref(sText),
++                                  boost::bind(&xml::dom::XNode::getNodeValue,
++                                              _1)),
++                              xElem,
++                              xml::dom::NodeType_TEXT_NODE);
++
++                // collect attributes
++                const sal_Int32 nNumAttrs( xAttributes->getLength() );
++                rtl::OUString sAttributeValue;
++                double x=0.0,y=0.0,width=0.0,height=0.0;
++                for( sal_Int32 i=0; i<nNumAttrs; ++i )
++                {
++                    sAttributeValue = xAttributes->item(i)->getNodeValue();
++                    const sal_Int32 nAttribId( 
++                        getTokenId(xAttributes->item(i)->getNodeName()));
++                    switch(nAttribId)
++                    {
++                        case XML_X:
++                            x = convLength(sAttributeValue);
++                            break;
++                        case XML_Y:
++                            y = convLength(sAttributeValue);
++                            break;
++                        case XML_WIDTH:
++                            width = convLength(sAttributeValue);
++                            break;
++                        case XML_HEIGHT:
++                            height = convLength(sAttributeValue);
++                            break;
++                        default:
++                            // skip
++                            break;
++                    }
++                }
++
++                // actually export text
++                Font aFont(maCurrState.maFontFamily, 
++                           Size(0,
++                                basegfx::fround(maCurrState.mnFontSize)));
++
++                // extract basic transformations out of CTM
++                basegfx::B2DTuple aScale, aTranslate;
++                double fRotate, fShearX;
++                ::rtl::OUString sTransformValue;
++                if (maCurrState.maCTM.decompose(aScale, aTranslate, fRotate, fShearX))
++                {
++                    rtl::OUString sTransform;
++                    x += aTranslate.getX();
++                    y += aTranslate.getY();
++
++                    aFont.SetSize(
++                        Size(basegfx::fround(aFont.GetWidth()*aScale.getX()),
++                             basegfx::fround(aFont.GetHeight()*aScale.getY())));
++
++                    if( fRotate )
++                        aFont.SetOrientation(basegfx::fround(fRotate*1800.0/M_PI));
++                }
++
++                // TODO(F2): update bounds
++                mrOutDev.SetFont(aFont);
++                mrOutDev.DrawText(Point(basegfx::fround(x),
++                                        basegfx::fround(y)),
++                                  sText.makeStringAndClear());
++                break;
++            }
++        }
++    }
++
++    void push()
++    {
++        maParentStates.push_back(maCurrState);
++    }
++
++    void pop()
++    {
++        maParentStates.pop_back();
++    }
++	
++    bool hasGradientOpacity( const Gradient& rGradient )
++    {
++        return 
++            mrGradientStopVector[
++                rGradient.maStops[0]].maStopColor.a != 1.0 ||
++            mrGradientStopVector[
++                rGradient.maStops[1]].maStopColor.a != 1.0;
++    }
++
++    sal_Int8 toByteColor( double val )
++    {
++        // TODO(Q3): duplicated from vcl::unotools
++        return sal::static_int_cast<sal_Int8>(
++            basegfx::fround(val*255.0));
++    }
++
++    ::Color getVclColor( const ARGBColor& rColor )
++    {
++        const sal_uInt8 nRed  ( toByteColor(rColor.r)   );
++        const sal_uInt8 nGreen( toByteColor(rColor.g) );
++        const sal_uInt8 nBlue ( toByteColor(rColor.b)  );
++
++        return ::Color(nRed,nGreen,nBlue);
++    }
++
++    void renderPathShape(const basegfx::B2DPolyPolygon& rPoly)
++    {
++        // we might need to split up polypolygon into multiple path
++        // shapes (e.g. when emulating line stroking)
++        State aState = maCurrState;
++		
++        basegfx::B2DPolyPolygon aPoly(rPoly);
++        aPoly.transform(aState.maCTM);
++
++        OSL_TRACE("the CTM is now #2: %f %f %f %f %f %f", 
++                  maCurrState.maCTM.get(0,0),
++                  maCurrState.maCTM.get(0,1),
++                  maCurrState.maCTM.get(0,2),
++                  maCurrState.maCTM.get(1,0),
++                  maCurrState.maCTM.get(1,1),
++                  maCurrState.maCTM.get(1,2));        
++
++        const basegfx::B2DRange aBounds=basegfx::tools::getRange(aPoly);
++        maBounds.Union(
++            Rectangle(
++                basegfx::fround(aBounds.getMinX()),
++                basegfx::fround(aBounds.getMinY()),
++                basegfx::fround(aBounds.getMaxX()),
++                basegfx::fround(aBounds.getMaxY())));
++
++        // fill first
++        mrOutDev.SetLineColor();
++
++        // do we have a gradient fill?
++        if( aState.meFillType == GRADIENT && aState.maFillGradient.maStops.size() > 1 )
++        {
++            ::Gradient aGradient;
++
++            if( aState.maFillGradient.meType == Gradient::LINEAR )
++            {
++                // should the optimizeGradientStops method decide that
++                // this is a three-color gradient, it prolly wanted us
++                // to take axial instead
++                aGradient = ::Gradient( aState.maFillGradient.maStops.size() == 3 ?
++                                        GRADIENT_AXIAL :
++                                        GRADIENT_LINEAR );
++            }
++            else
++            {
++                aGradient = ::Gradient( GRADIENT_ELLIPTICAL );
++            }
++
++            basegfx::B2DTuple rScale, rTranslate;
++            double rRotate, rShearX;
++            if( aState.maFillGradient.maTransform.decompose(rScale, rTranslate, rRotate, rShearX) )
++                aGradient.SetAngle( basegfx::fround(rRotate*1800.0/M_PI) );
++            aGradient.SetStartColor( getVclColor(
++                                         mrGradientStopVector[
++                                             aState.maFillGradient.maStops[0]].maStopColor) );
++            aGradient.SetEndColor( getVclColor(
++                                       mrGradientStopVector[
++                                           aState.maFillGradient.maStops[1]].maStopColor) );
++
++            if( hasGradientOpacity(aState.maFillGradient) )
++            {
++                ::Gradient aTransparencyGradient=aGradient;
++
++                const BYTE	cTransStart( 255-
++                    basegfx::fround(mrGradientStopVector[
++                                        aState.maFillGradient.maStops[1]].maStopColor.a*
++                                    aState.mnFillOpacity*255.0));
++                const Color aTransStart( cTransStart, cTransStart, cTransStart );
++
++                const BYTE	cTransEnd( 255-
++                    basegfx::fround(mrGradientStopVector[
++                                        aState.maFillGradient.maStops[0]].maStopColor.a*
++                                    aState.mnFillOpacity*255.0));
++                const Color aTransEnd( cTransEnd, cTransEnd, cTransEnd );
++
++                // modulate gradient opacity with overall fill opacity
++                aTransparencyGradient.SetStartColor(aTransStart);
++                aTransparencyGradient.SetEndColor(aTransEnd);
++
++                VirtualDevice	aVDev;
++                GDIMetaFile		aMtf;
++
++                aVDev.EnableOutput( FALSE );
++                aMtf.Record( &aVDev );
++                aVDev.DrawGradient(::PolyPolygon(aPoly),aGradient);
++
++                aMtf.Stop();
++                aMtf.WindStart();
++                aMtf.SetPrefMapMode( MAP_100TH_MM );
++                aMtf.SetPrefSize( Size(basegfx::fround(aBounds.getMaxX()),
++                                       basegfx::fround(aBounds.getMaxY())) );
++
++                mrOutDev.DrawTransparent(aMtf,
++                                         Point(),
++                                         aMtf.GetPrefSize(),
++                                         aTransparencyGradient);
++            }
++            else
++            {
++                mrOutDev.DrawGradient(::PolyPolygon(aPoly),aGradient);
++            }
++        }
++        else
++        {
++            if( aState.meFillType == NONE )
++                mrOutDev.SetFillColor();
++            else
++                mrOutDev.SetFillColor(getVclColor(aState.maFillColor));
++
++            if( aState.mnFillOpacity != 1.0 )
++                mrOutDev.DrawTransparent(::PolyPolygon(aPoly),
++                                         basegfx::fround(
++                                             (1.0-aState.mnFillOpacity)*100.0));
++            else
++                mrOutDev.DrawPolyPolygon(::PolyPolygon(aPoly));
++        }
++
++        // Stroking now
++        mrOutDev.SetFillColor();
++
++        if( aState.meStrokeType != NONE &&
++            (aState.maDashArray.size() ||
++             aState.mnStrokeWidth != 1.0) )
++        {
++            // vcl thick lines are severly borked - generate filled
++            // polygon instead
++            std::vector<basegfx::B2DPolyPolygon> aPolys;
++            aPoly=basegfx::tools::adaptiveSubdivideByAngle(aPoly);
++            if( !aState.maDashArray.empty() )
++                aPoly=basegfx::tools::applyLineDashing(aPoly,
++                                                       aState.maDashArray);
++            for( sal_uInt32 i=0; i<aPoly.count(); ++i )
++            {                
++                // ugly. convert to integer-based tools polygon
++                // first, and only _then_ remove intersections (we
++                // might get new ones from the rounding)
++                aPolys.push_back(
++                    basegfx::tools::removeNeutralPolygons(
++                        basegfx::tools::removeAllIntersections(
++                            ::PolyPolygon(
++                                basegfx::tools::createAreaGeometryForPolygon(
++                                    aPoly.getB2DPolygon(i),
++                                    aState.mnStrokeWidth/2.0,
++                                    aState.meLineJoin)).getB2DPolyPolygon()),
++                        true));
++                // TODO(F2): line ends
++            }
++
++            mrOutDev.SetLineColor();
++            mrOutDev.SetFillColor(getVclColor(aState.maStrokeColor));
++
++            for( sal_uInt32 i=0; i<aPolys.size(); ++i )
++            {
++                if( aState.mnStrokeOpacity != 1.0 )
++                    mrOutDev.DrawTransparent(::PolyPolygon(aPolys[i]),
++                                             basegfx::fround(
++                                                 (1.0-aState.mnStrokeOpacity)*100.0));
++                else
++                    mrOutDev.DrawPolyPolygon(::PolyPolygon(aPolys[i]));
++
++                const basegfx::B2DRange aStrokeBounds=basegfx::tools::getRange(aPolys[i]);
++                maBounds.Union(
++                    Rectangle(
++                        basegfx::fround(aStrokeBounds.getMinX()),
++                        basegfx::fround(aStrokeBounds.getMinY()),
++                        basegfx::fround(aStrokeBounds.getMaxX()),
++                        basegfx::fround(aStrokeBounds.getMaxY())));
++            }
++        }
++        else
++        {
++            if( aState.meStrokeType == NONE )
++                mrOutDev.SetLineColor();
++            else
++                mrOutDev.SetLineColor(getVclColor(aState.maStrokeColor));
++
++            if( aState.mnStrokeOpacity != 1.0 )
++                mrOutDev.DrawTransparent(::PolyPolygon(aPoly),
++                                         basegfx::fround(
++                                             (1.0-aState.mnStrokeOpacity)*100.0));
++            else
++                mrOutDev.DrawPolyPolygon(::PolyPolygon(aPoly));
++        }
++    }
++
++    State                                      maCurrState;
++    std::vector<State>                         maParentStates;
++    StatePool&                                 mrStates;
++    StateMap&                                  mrStateMap;
++    OutputDevice&                               mrOutDev;
++    const std::vector< Gradient >&             mrGradientVector;
++    const std::vector< GradientStop >&         mrGradientStopVector;
++    Rectangle                                   maBounds;
++};
++
+ } // namespace svgi
++
++bool importSvg(SvStream & rStream, Graphic & rGraphic )
++{
++    const uno::Reference<lang::XMultiServiceFactory> xServiceFactory(
++        ::comphelper::getProcessServiceFactory());    
++
++	uno::Reference<xml::dom::XDocumentBuilder> xDomBuilder( 
++        xServiceFactory->createInstance( 
++            rtl::OUString::createFromAscii("com.sun.star.xml.dom.DocumentBuilder")), 
++        uno::UNO_QUERY );
++
++    uno::Reference<io::XInputStream> xStream(
++        new utl::OInputStreamWrapper(rStream) );
++
++    uno::Reference<xml::dom::XDocument> xDom(
++        xDomBuilder->parse(xStream),
++        uno::UNO_QUERY_THROW );
++
++    uno::Reference<xml::dom::XElement> xDocElem( xDom->getDocumentElement(),
++                                                 uno::UNO_QUERY_THROW );
++    
++    VirtualDevice	aVDev;
++    GDIMetaFile		aMtf;
++
++    aVDev.EnableOutput( FALSE );
++    aMtf.Record( &aVDev );
++
++    // parse styles and fill state stack
++    svgi::StatePool aStatePool;
++    svgi::StateMap  aStateMap;
++    svgi::AnnotatingVisitor aVisitor(aStatePool,
++                                     aStateMap,
++                                     uno::Reference<xml::sax::XDocumentHandler>());
++    svgi::visitElements(aVisitor, xDocElem);
++
++#ifdef VERBOSE
++    dumpTree(xDocElem);
++#endif
++
++    // render all shapes to mtf
++    svgi::ShapeRenderingVisitor aRenderer(aStatePool,aStateMap,aVDev,
++                                         aVisitor.maGradientVector,
++                                         aVisitor.maGradientStopVector);
++    svgi::visitElements(aRenderer, xDocElem);
++
++    aMtf.Stop();
++
++    aMtf.WindStart();
++    aMtf.SetPrefMapMode( MAP_100TH_MM );
++
++    // get the document dimensions
++
++    // if the "width" and "height" attributes are missing, inkscape fakes
++    // A4 portrait for. Let's do the same.
++	if (!xDocElem->hasAttribute(USTR("width")))
++		xDocElem->setAttribute(USTR("width"), USTR("210mm"));
++	if (!xDocElem->hasAttribute(USTR("height")))
++		xDocElem->setAttribute(USTR("height"), USTR("297mm"));
++		
++    aMtf.SetPrefSize( 
++        Size( 
++            std::max(
++                sal_Int32(aRenderer.maBounds.Right()),
++                basegfx::fround(svgi::convLength(xDocElem->getAttribute(USTR("width"))))), 
++            std::max(
++                sal_Int32(aRenderer.maBounds.Bottom()),
++                basegfx::fround(svgi::convLength(xDocElem->getAttribute(USTR("height"))))) ));
++
++    rGraphic = aMtf;
++    
++    return sal_True;
++}
++
++
+diff -ur filter_orig/source/svg/test/makefile.mk filter/source/svg/test/makefile.mk
+--- filter_orig/source/svg/test/makefile.mk	2008-05-28 02:34:02.000000000 +0200
++++ filter/source/svg/test/makefile.mk	2008-05-28 02:18:07.000000000 +0200
+@@ -40,6 +40,7 @@
+ 	$(UNOTOOLSLIB)		\
+ 	$(TOOLSLIB)			\
+ 	$(COMPHELPERLIB)	\
++	$(SVTOOLLIB)	    \
+ 	$(CPPUHELPERLIB)	\
+ 	$(CPPULIB)			\
+ 	$(SALLIB)			\

Modified: trunk/patches/dev300/svg-import-filter.diff
==============================================================================
--- trunk/patches/dev300/svg-import-filter.diff	(original)
+++ trunk/patches/dev300/svg-import-filter.diff	Thu May 29 14:33:40 2008
@@ -343,7 +343,7 @@
 +close ( GPERF );
 --- filter/source/svg/gfxtypes.hxx	1970-01-01 01:00:00.000000000 +0100
 +++ filter/source/svg/gfxtypes.hxx	2008-04-11 00:09:55.000000000 +0200
-@@ -0,0 +1,317 @@
+@@ -0,0 +1,356 @@
 +/*************************************************************************
 + *
 + *    OpenOffice.org - a multi-platform office productivity suite
@@ -377,7 +377,7 @@
 +{
 +    double toDoubleColor( sal_uInt8 val ) { return val/255.0; }
 +
-+    ARGBColor() : a(0.0), r(0.0), g(0.0), b(0.0)
++    ARGBColor() : a(1.0), r(0.0), g(0.0), b(0.0)
 +    {}
 +    explicit ARGBColor(double fGrey) : a(1.0), r(fGrey), g(fGrey), b(fGrey)
 +    {}
@@ -406,33 +406,72 @@
 +};
 +inline bool operator==( const ARGBColor& rLHS, const ARGBColor& rRHS )
 +{ return rLHS.a==rRHS.a && rLHS.r==rRHS.r && rLHS.g==rRHS.g && rLHS.b==rRHS.b; }
++inline bool operator!=( const ARGBColor& rLHS, const ARGBColor& rRHS )
++{ return !(rLHS==rRHS); }
 +
 +struct GradientStop
 +{
-+    GradientStop() : maStopColor(), mnStopPosition(0.0), msId()
++    GradientStop() : maStopColor(), mnStopPosition(0.0)
 +    {}
 +    ARGBColor     maStopColor;
 +    double        mnStopPosition;
-+	rtl::OUString msId;
 +};
 +inline bool operator==( const GradientStop& rLHS, const GradientStop& rRHS )
 +{ return rLHS.mnStopPosition==rRHS.mnStopPosition && rLHS.maStopColor==rRHS.maStopColor; }
 +
 +struct Gradient
 +{
-+    Gradient() : maStops(), mbBoundingBoxUnits(false), msId(), msLinkedTo(), mfX1(0.0f), mfX2(0.0f), mfY1(0.0f), mfY2(0.0f) 
-+    {}
-+    std::vector<GradientStop> maStops;
-+    bool                      mbBoundingBoxUnits;
-+	rtl::OUString			  msId, msLinkedTo;
-+	double					  mfX1, mfX2, mfY1, mfY2;
++    enum GradientType { LINEAR, RADIAL};
++    std::vector<sal_Size> maStops;
++    basegfx::B2DHomMatrix maTransform;
++    GradientType          meType;
++    union
++    {
++        double test;
++        struct
++        {
++            double                mfX1;
++            double                mfX2;
++            double                mfY1;
++            double                mfY2;
++        } linear;
++        struct
++        {
++            double                mfCX;
++            double                mfCY;
++            double                mfFX;
++            double                mfFY;
++            double                mfR;
++        } radial;
++    } maCoords;
++    sal_Int32             mnId;
++    bool                  mbBoundingBoxUnits;
++    bool                  mbLinearBoundingBoxUnits;
++
++//    explicit Gradient(GradientType eType) : maStops(), maTransform(), meType(eType), maCoords.mfCX(0.0), maCoords.mfCY(0.0), maCoords.mfFX(0.0), maCoords.mfFY(0.0), maCoords.mfR(0.0), mnId(0), mbBoundingBoxUnits(false) 
++    explicit Gradient(GradientType eType) : maStops(), maTransform(), meType(eType), mnId(0), mbBoundingBoxUnits(false) 
++    {
++        maCoords.radial.mfCX = 0.0;
++        maCoords.radial.mfCY = 0.0;
++        maCoords.radial.mfFX = 0.0;
++        maCoords.radial.mfFY = 0.0;
++        maCoords.radial.mfR  = 0.0;
++    }
 +};
 +
 +inline bool operator==( const Gradient& rLHS, const Gradient& rRHS )
 +{
-+	return rLHS.mbBoundingBoxUnits==rRHS.mbBoundingBoxUnits && rLHS.maStops==rRHS.maStops &&
-+	rLHS.msId.equals(rRHS.msId) && rLHS.msLinkedTo.equals(rRHS.msLinkedTo) &&
-+	rLHS.mfX1 == rRHS.mfX1 && rLHS.mfX2 == rRHS.mfX2 && rLHS.mfY1 == rRHS.mfY1 && rLHS.mfY2 == rRHS.mfY2;
++    if( rLHS.meType != rRHS.meType )
++        return false;
++    if( rLHS.meType == Gradient::LINEAR )
++        return rLHS.mbBoundingBoxUnits==rRHS.mbBoundingBoxUnits && rLHS.maStops==rRHS.maStops &&
++            rLHS.maCoords.linear.mfX1 == rRHS.maCoords.linear.mfX1 && rLHS.maCoords.linear.mfX2 == rRHS.maCoords.linear.mfX2 && 
++            rLHS.maCoords.linear.mfY1 == rRHS.maCoords.linear.mfY1 && rLHS.maCoords.linear.mfY2 == rRHS.maCoords.linear.mfY2;
++    else
++        return rLHS.mbBoundingBoxUnits==rRHS.mbBoundingBoxUnits && rLHS.maStops==rRHS.maStops &&
++            rLHS.maCoords.radial.mfCX == rRHS.maCoords.radial.mfCX && rLHS.maCoords.radial.mfCY == rRHS.maCoords.radial.mfCY && 
++            rLHS.maCoords.radial.mfFX == rRHS.maCoords.radial.mfFX && rLHS.maCoords.radial.mfFY == rRHS.maCoords.radial.mfFY && 
++            rLHS.maCoords.radial.mfR == rRHS.maCoords.radial.mfR;
 +}
 +
 +enum PaintType
@@ -492,17 +531,17 @@
 +        mnTextLineIncrement(0.0),
 +        maCurrentColor(1.0),
 +        mbVisibility(true),
-+        meFillType(NONE),
++        meFillType(SOLID),
 +        mnFillOpacity(1.0),
 +        meStrokeType(NONE),
 +        mnStrokeOpacity(1.0),
 +        meViewportFillType(NONE),
 +        mnViewportFillOpacity(1.0),
 +        maFillColor(0.0),
-+        maFillGradient(),
++        maFillGradient(Gradient::LINEAR),
 +        meFillRule(NON_ZERO),
 +        maStrokeColor(0.0),
-+        maStrokeGradient(),
++        maStrokeGradient(Gradient::LINEAR),
 +        maDashArray(),
 +        mnDashOffset(0.0),
 +        meLineCap(BUTT),
@@ -510,7 +549,7 @@
 +        mnMiterLimit(4.0),
 +        mnStrokeWidth(1.0),
 +        maViewportFillColor(1.0),
-+        maViewportFillGradient(),
++        maViewportFillGradient(Gradient::LINEAR),
 +        mnStyleId(0)
 +    {}
 +
@@ -733,7 +772,7 @@
  
  SHL1DEPN=
  SHL1IMPLIB=	i$(SHL1TARGET)
-@@ -87,3 +94,17 @@
+@@ -87,3 +94,16 @@
  # --- Targets ----------------------------------
  
  .INCLUDE : target.mk
@@ -750,10 +789,9 @@
 +$(SLO)$/parserfragments.obj : $(INCCOM)$/tokens.cxx $(INCCOM)$/tokens.hxx
 +
 +$(SLO)$/svgreader.obj : $(INCCOM)$/tokens.cxx $(INCCOM)$/tokens.hxx
-+
 --- filter/source/svg/parserfragments.cxx	1970-01-01 01:00:00.000000000 +0100
 +++ filter/source/svg/parserfragments.cxx	2008-04-11 00:09:55.000000000 +0200
-@@ -0,0 +1,536 @@
+@@ -0,0 +1,553 @@
 +/*************************************************************************
 + *
 + *    OpenOffice.org - a multi-platform office productivity suite
@@ -841,18 +879,23 @@
 +               double                                 fSkewAngle)
 +{
 +    geometry::AffineMatrix2D aMat(1.0,0.0,0.0,
-+                                  tan(fSkewAngle),1.0,0.0);
++                                  tan(fSkewAngle*M_PI/180),1.0,0.0);
 +    rTransforms.push_back(aMat);
 +}
 +
 +void calcSkewY(std::vector<geometry::AffineMatrix2D>& rTransforms,
 +               double                                 fSkewAngle)
 +{
-+    geometry::AffineMatrix2D aMat(1.0,tan(fSkewAngle),0.0,
++    geometry::AffineMatrix2D aMat(1.0,tan(fSkewAngle*M_PI/180),0.0,
 +                                  0.0,1.0,0.0);
 +    rTransforms.push_back(aMat);
 +}
 +
++void assign_twice(double& r_oVal1, double& r_oVal2, const double& rInVal )
++{
++    r_oVal1 = r_oVal2 = rInVal;
++}
++
 +geometry::AffineMatrix2D multiplyMatrix( const geometry::AffineMatrix2D& rLHS,
 +                                         const geometry::AffineMatrix2D& rRHS )
 +{
@@ -896,6 +939,7 @@
 +    	        // rgb() form
 +        	    (str_p("rgb") 
 +            	 >> '(' >>
++                     (
 +                	         // rgb(int,int,int)
 +                    	     (byte_p[boost::bind(&setIntColor,
 +                        	                     boost::ref(rColor.r),_1)] >> ',' >>
@@ -908,6 +952,7 @@
 +                        	 (real_p[assign_a(rColor.r)] >> ',' >>
 +	                          real_p[assign_a(rColor.g)] >> ',' >>
 +    	                      real_p[assign_a(rColor.b)])
++                     )
 +        	     >> ')')
 +	        ) >> end_p,
 +    	    //  End grammar
@@ -918,7 +963,16 @@
 +    }
 +
 +    // no free-form color - maybe a color name?
-+	switch (getTokenId(sColor, strlen(sColor)))
++    // trim white space before 
++    while( *sColor && 
++           (*sColor==' ' || *sColor=='\t' || *sColor=='\r' || *sColor=='\n') )
++        ++sColor;
++    // trim white space after 
++    int nLen=strlen(sColor)-1;
++    while( nLen && 
++           (sColor[nLen]==' ' || sColor[nLen]=='\t' || sColor[nLen]=='\r' || sColor[nLen]=='\n') )
++        --nLen;
++	switch (getTokenId(sColor, nLen+1))
 +	{
 +        case XML_ALICEBLUE: rColor = ARGBColor(240,248,255); return true;
 +        case XML_ANTIQUEWHITE: rColor = ARGBColor(250,235,215); return true;
@@ -1077,14 +1131,13 @@
 +{
 +	using namespace ::boost::spirit;
 +	
-+	
 +	if( parse(sOpacity,
-+			// Begin grammar
-+			(
-+				real_p[assign_a(rColor.a)] 
-+			) >> end_p,
-+			// End grammar
-+			space_p).full )
++              // Begin grammar  
++              (
++                  real_p[assign_a(rColor.a)] 
++                  ) >> end_p,
++              // End grammar  
++              space_p).full )
 +	{
 +		return true;
 +	}
@@ -1119,7 +1172,7 @@
 +            (str_p("ref")
 +             >> '('
 +             >> str_p("svg")[assign_a(bRefTransform,true)] 
-+             >> !(real_p[assign_a(fRefOffsetX)] >> ',' >>
++             >> !(real_p[assign_a(fRefOffsetX)] >> (',' | eps_p) >>
 +                  real_p[assign_a(fRefOffsetY)])
 +             >> ')')
 +          |
@@ -1129,35 +1182,42 @@
 +                 // matrix(a,b,c,d,e,f)  
 +                 (str_p("matrix") 
 +                  >> '('
-+                  >> real_p[assign_a(aCurrTransform.m00)] >> ',' 
-+                  >> real_p[assign_a(aCurrTransform.m10)] >> ',' 
-+                  >> real_p[assign_a(aCurrTransform.m01)] >> ',' 
-+                  >> real_p[assign_a(aCurrTransform.m11)] >> ',' 
-+                  >> real_p[assign_a(aCurrTransform.m02)] >> ',' 
++                  >> real_p[assign_a(aCurrTransform.m00)] >> (',' | eps_p)
++                  >> real_p[assign_a(aCurrTransform.m10)] >> (',' | eps_p) 
++                  >> real_p[assign_a(aCurrTransform.m01)] >> (',' | eps_p)
++                  >> real_p[assign_a(aCurrTransform.m11)] >> (',' | eps_p)
++                  >> real_p[assign_a(aCurrTransform.m02)] >> (',' | eps_p)
 +                  >> real_p[assign_a(aCurrTransform.m12)]
 +                  >> ')')[push_back_a(aTransforms,aCurrTransform)]
 +               |  
 +                 // translate(x,[y])
 +                 (str_p("translate") 
 +                  >> '('
-+                  >> real_p[assign_a(aCurrTransform.m02)]
-+                  >> !(',' >> real_p[assign_a(aCurrTransform.m12)])
++                  >> real_p[boost::bind(&assign_twice,
++                                        boost::ref(aCurrTransform.m02),
++                                        boost::ref(aCurrTransform.m12),_1)]
++                  >> !((',' | eps_p) >> real_p[assign_a(aCurrTransform.m12)])
 +                  >> ')')[push_back_a(aTransforms,aCurrTransform)]
 +               |  
 +                 // scale(x,[y])
 +                 (str_p("scale") 
 +                  >> '('
-+                  >> real_p[assign_a(aCurrTransform.m00)]
-+                  >> !(',' >> real_p[assign_a(aCurrTransform.m11)])
++                  >> real_p[boost::bind(&assign_twice,
++                                        boost::ref(aCurrTransform.m00),
++                                        boost::ref(aCurrTransform.m11),_1)]
++                  >> !((',' | eps_p) >> real_p[assign_a(aCurrTransform.m11)])
 +                  >> ')')[push_back_a(aTransforms,aCurrTransform)]
 +               |  
 +                 // rotate(phi,[cx, cy])
 +                 (str_p("rotate") 
 +                  >> '('
-+                  >> real_p[assign_a(fRotationAngle)] >> ')')[boost::bind(&calcRotation,
-+                                                  boost::ref(aTransforms),
-+                                                  boost::ref(aCurrTransform),
-+                                                  boost::cref(fRotationAngle))]
++                  >> real_p[assign_a(fRotationAngle)]
++                  >> !((',' | eps_p) >> real_p[assign_a(aCurrTransform.m02)]
++                       >> real_p[assign_a(aCurrTransform.m12)])
++                  >> ')')[boost::bind(&calcRotation,
++                                      boost::ref(aTransforms),
++                                      boost::ref(aCurrTransform),
++                                      boost::cref(fRotationAngle))]
 +               |  
 +                 // skewX(phi)
 +                 (str_p("skewX") 
@@ -1211,17 +1271,12 @@
 +    const bool bRes = parse(sViewbox,
 +        //  Begin grammar
 +        (
-+            // either comma- or space-delimited list of four doubles
-+            (real_p[assign_a(x)] >> ',' >>
-+             real_p[assign_a(y)] >> ',' >>
-+             real_p[assign_a(w)] >> ',' >>
-+             real_p[assign_a(h)])
-+           | 
-+            (real_p[assign_a(x)] >>
-+             real_p[assign_a(y)] >>
-+             real_p[assign_a(w)] >>
-+             real_p[assign_a(h)])
-+        ) >> end_p,
++            // either comma- or space-delimited list of four doubles    
++            real_p[assign_a(x)] >> (',' | eps_p) >>
++            real_p[assign_a(y)] >> (',' | eps_p) >>
++            real_p[assign_a(w)] >> (',' | eps_p) >>
++            real_p[assign_a(h)] >> end_p
++        ),
 +        //  End grammar
 +        space_p).full;
 +
@@ -1243,8 +1298,14 @@
 +    return parse(sDashArray,
 +        //  Begin grammar
 +        (
-+            // parse comma-delimited list of doubles
-+            list_p(real_p[push_back_a(rOutputVector)])
++            // parse comma-delimited list of doubles (have to use the
++            // 'direct' variant, as otherwise spirit refactors our
++            // parser to push both real num and comma to push_back_a)
++            list_p.direct
++            (
++                real_p[push_back_a(rOutputVector)], 
++                ','
++            )
 +        ) >> end_p,
 +        //  End grammar
 +        space_p).full;
@@ -1281,12 +1342,6 @@
 +    }
 +
 +    return false;
-+#if 0
-+    // the "normal" outplace uri
-+    (repeat_p(1, more)[anychar_p[boost::bind(&appendChar,
-+                                             boost::ref(data),
-+                                             _1)]]) 
-+#endif
 +}
 +
 +} // namespace svgi
@@ -1392,7 +1447,7 @@
 +        return assigner<Target,Value>(rTarget,aValue);
 +    }
 +
-+    template<typename Target> inline assign_actor<Target>
++    template <typename Target> inline assign_actor<Target>
 +    assign_a(Target& rTarget)
 +    {
 +        return assign_actor<Target>(rTarget);
@@ -1507,7 +1562,7 @@
  
 --- filter/source/svg/svgfilter.hxx	2008-04-11 08:49:31.000000000 +0200
 +++ filter/source/svg/svgfilter.hxx	2008-04-11 00:09:55.000000000 +0200
-@@ -57,9 +57,7 @@
+@@ -38,20 +38,14 @@
  #include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
  #include <com/sun/star/presentation/XPresentationSupplier.hpp>
  #include <com/sun/star/document/XFilter.hpp>
@@ -1517,7 +1572,6 @@
  #include <com/sun/star/document/XExporter.hpp>
  #include <com/sun/star/lang/XInitialization.hpp>
  #include <com/sun/star/lang/XServiceInfo.hpp>
-@@ -80,11 +78,7 @@
  #include <com/sun/star/beans/XPropertySet.hpp>
  #include <com/sun/star/lang/XComponent.hpp>
  #include <cppuhelper/implbase1.hxx>
@@ -1788,7 +1842,7 @@
      
 --- filter/source/svg/svgreader.cxx	1970-01-01 01:00:00.000000000 +0100
 +++ filter/source/svg/svgreader.cxx	2008-04-11 09:33:30.000000000 +0200
-@@ -0,0 +1,1516 @@
+@@ -0,0 +1,1899 @@
 +/*************************************************************************
 + *
 + *    OpenOffice.org - a multi-platform office productivity suite
@@ -1894,6 +1948,22 @@
 +    rFunc.pop();
 +}
 +
++template<typename value_type> value_type square(value_type v)
++{
++    return v*v;
++}
++
++double colorDiffSquared(const ARGBColor& rCol1, const ARGBColor& rCol2)
++{
++    return 
++        square(rCol1.a-rCol2.a) 
++        + square(rCol1.r-rCol2.r)
++        + square(rCol1.g-rCol2.g)
++        + square(rCol1.b-rCol2.b);
++}
++
++typedef std::map<rtl::OUString,sal_Size> ElementRefMapType;
++
 +struct AnnotatingVisitor
 +{
 +    AnnotatingVisitor(StatePool&                                        rStatePool,
@@ -1905,9 +1975,8 @@
 +        mrStates(rStatePool),
 +        mrStateMap(rStateMap),
 +        mxDocumentHandler(xDocumentHandler),
-+		mpCurrentGradient(NULL),
-+		mpCurrentGradientStop(NULL),
-+		mxGradientVector()
++		maGradientVector(),
++        maGradientStopVector()
 +    {
 +        State aState;
 +        aState.maCTM = aState.maTransform;
@@ -1920,31 +1989,97 @@
 +    void operator()( const uno::Reference<xml::dom::XElement>&      xElem,
 +                     const uno::Reference<xml::dom::XNamedNodeMap>& xAttributes )
 +    {
-+		sal_Int32 nTagId(getTokenId(xElem->getTagName()));
++		const sal_Int32 nTagId(getTokenId(xElem->getTagName()));
 +		switch (nTagId)
 +		{
 +			case XML_LINEARGRADIENT:
 +			{
 +				const sal_Int32 nNumAttrs( xAttributes->getLength() );
 +				rtl::OUString sAttributeValue;
-+				mxGradientVector.push_back(Gradient()); 
-+				mpCurrentGradient = &(mxGradientVector.back());
++				maGradientVector.push_back(Gradient(Gradient::LINEAR)); 
++                
++                // do we have a reference to a parent gradient? parse
++                // that first, as it sets our defaults here (manually
++                // tracking default state on each Gradient variable is
++                // much more overhead)
++                uno::Reference<xml::dom::XNode> xNode(xAttributes->getNamedItem(USTR("href")));
++                if(xNode.is())
++                {
++                    const rtl::OUString sValue(xNode->getNodeValue());
++                    ElementRefMapType::iterator aFound=maGradientIdMap.end();
++                    if (sValue.copy(0,1).equalsAscii("#"))
++                        aFound = maGradientIdMap.find(sValue.copy(1));
++                    else
++                        aFound = maGradientIdMap.find(sValue);;
++
++                    if( aFound != maGradientIdMap.end() )
++                        maGradientVector.back() = maGradientVector[aFound->second];
++                }
++
++                // do that after dereferencing, to prevent hyperlinked
++                // gradient to clobber our Id again
++                maGradientVector.back().mnId = maGradientVector.size()-1;
++                maGradientVector.back().meType = Gradient::LINEAR; // has been clobbered as well
++
++				for( sal_Int32 i=0; i<nNumAttrs; ++i )
++				{
++					parseLinearGradientData( maGradientVector.back(),
++                                             maGradientVector.size()-1,
++                                             getTokenId(xAttributes->item(i)->getNodeName()), 
++                                             xAttributes->item(i)->getNodeValue() );
++				}
++				break;
++			}
++            case XML_RADIALGRADIENT:
++			{
++				const sal_Int32 nNumAttrs( xAttributes->getLength() );
++				rtl::OUString sAttributeValue;
++				maGradientVector.push_back(Gradient(Gradient::RADIAL)); 
++
++                // do we have a reference to a parent gradient? parse
++                // that first, as it sets our defaults here (manually
++                // tracking default state on each Gradient variable is
++                // much more overhead)
++                uno::Reference<xml::dom::XNode> xNode(xAttributes->getNamedItem(USTR("href")));
++                if(xNode.is())
++                {
++                    const rtl::OUString sValue(xNode->getNodeValue());
++                    ElementRefMapType::iterator aFound=maGradientIdMap.end();
++                    if (sValue.copy(0,1).equalsAscii("#"))
++                        aFound = maGradientIdMap.find(sValue.copy(1));
++                    else
++                        aFound = maGradientIdMap.find(sValue);;
++
++                    if( aFound != maGradientIdMap.end() )
++                        maGradientVector.back() = maGradientVector[aFound->second];
++                }
++
++                // do that after dereferencing, to prevent hyperlinked
++                // gradient to clobber our Id again
++                maGradientVector.back().mnId = maGradientVector.size()-1;
++                maGradientVector.back().meType = Gradient::RADIAL; // has been clobbered as well
++
 +				for( sal_Int32 i=0; i<nNumAttrs; ++i )
 +				{
-+					parseGradientData( getTokenId(xAttributes->item(i)->getNodeName()), xAttributes->item(i)->getNodeValue() );
++					parseRadialGradientData( maGradientVector.back(),
++                                             maGradientVector.size()-1,
++                                             getTokenId(xAttributes->item(i)->getNodeName()), 
++                                             xAttributes->item(i)->getNodeValue() );
 +				}
 +				break;
 +			}
 +			case XML_STOP:
 +			{
-+				
 +				const sal_Int32 nNumAttrs( xAttributes->getLength() );
 +				rtl::OUString sAttributeValue;
-+				mpCurrentGradient->maStops.push_back(GradientStop());
-+				mpCurrentGradientStop = &(mpCurrentGradient->maStops.back());
++				maGradientStopVector.push_back(GradientStop());
++				maGradientVector.back().maStops.push_back(maGradientStopVector.size()-1);
 +				for( sal_Int32 i=0; i<nNumAttrs; ++i )
 +				{
-+					parseGradientStop( getTokenId(xAttributes->item(i)->getNodeName()), xAttributes->item(i)->getNodeValue() );
++					parseGradientStop( maGradientStopVector.back(),
++                                       maGradientStopVector.size()-1,
++                                       getTokenId(xAttributes->item(i)->getNodeName()), 
++                                       xAttributes->item(i)->getNodeValue() );
 +				}
 +				break;
 +			}
@@ -2010,6 +2145,85 @@
 +        return rtl::OUString::createFromAscii(sPrefix)+rtl::OUString::valueOf(nId);
 +    }
 +
++    bool hasGradientOpacity( const Gradient& rGradient )
++    {
++        return 
++            maGradientStopVector[
++                rGradient.maStops[0]].maStopColor.a != 1.0 ||
++            maGradientStopVector[
++                rGradient.maStops[1]].maStopColor.a != 1.0;
++    }
++
++    struct StopSorter
++    {
++        explicit StopSorter( const std::vector< GradientStop >& rStopVec ) :
++            mrStopVec(rStopVec)
++        {}
++
++        bool operator()( sal_Size rLHS, sal_Size rRHS )
++        {
++            return mrStopVec[rLHS].mnStopPosition < mrStopVec[rRHS].mnStopPosition;
++        }
++        
++        const std::vector< GradientStop >& mrStopVec;
++    };
++
++    void optimizeGradientStops( Gradient& rGradient )
++    {
++        // sort for increasing stop position
++        std::sort(rGradient.maStops.begin(),rGradient.maStops.end(),
++                  StopSorter(maGradientStopVector));
++
++        if( rGradient.maStops.size() < 3 )
++            return; //easy! :-)
++        
++        // join similar colors
++        std::vector<sal_Size> aNewStops(rGradient.maStops.front());
++        for( sal_Size i=1; i<rGradient.maStops.size(); ++i )
++        {
++            if( maGradientStopVector[rGradient.maStops[i]].maStopColor != 
++                maGradientStopVector[aNewStops.back()].maStopColor )
++                aNewStops.push_back(rGradient.maStops[i]);
++        }
++
++        rGradient.maStops = aNewStops;
++
++        // axial gradient, maybe?
++        if( rGradient.meType == Gradient::LINEAR &&
++            rGradient.maStops.size() == 3 && 
++            maGradientStopVector[rGradient.maStops.front()].maStopColor ==
++            maGradientStopVector[rGradient.maStops.back()].maStopColor )
++        {
++            // yep - keep it at that
++            return;
++        }
++
++        // find out most significant color difference, and limit to
++        // those two stops around this border (metric is
++        // super-simplistic: take euclidean distance of colors, weigh
++        // with stop distance)
++        sal_Size nMaxIndex=0;
++        double    fMaxDistance=0.0;
++        for( sal_Size i=1; i<rGradient.maStops.size(); ++i )
++        {
++            const double fCurrDistance( 
++                colorDiffSquared(
++                    maGradientStopVector[rGradient.maStops[i-1]].maStopColor,
++                    maGradientStopVector[rGradient.maStops[i]].maStopColor) *
++                (square(maGradientStopVector[rGradient.maStops[i-1]].mnStopPosition) +
++                 square(maGradientStopVector[rGradient.maStops[i]].mnStopPosition)) );
++
++            if( fCurrDistance > fMaxDistance )
++            {
++                nMaxIndex = i-1;
++                fMaxDistance = fCurrDistance;
++            }
++        }
++        rGradient.maStops[0] = rGradient.maStops[nMaxIndex];
++        rGradient.maStops[1] = rGradient.maStops[nMaxIndex+1];
++        rGradient.maStops.erase(rGradient.maStops.begin()+2,rGradient.maStops.end());
++    }
++
 +    sal_Int8 toByteColor( double val )
 +    {
 +        // TODO(Q3): duplicated from vcl::unotools
@@ -2041,7 +2255,7 @@
 +        return aBuf.makeStringAndClear();
 +    }
 +
-+    bool writeStyle(const State& rState, sal_Int32 nTagId)
++    bool writeStyle(State& rState, const sal_Int32 nTagId)
 +    {
 +        rtl::Reference<SvXMLAttributeList> xAttrs( new SvXMLAttributeList() );
 +        uno::Reference<xml::sax::XAttributeList> xUnoAttrs( xAttrs.get() );
@@ -2058,63 +2272,167 @@
 +        mrStateMap.insert(std::make_pair(
 +                              mnCurrStateId,
 +                              rState));
-+        
++
++        // find two representative stop colors (as odf only support
++        // start&end color)
++        optimizeGradientStops(rState.maFillGradient);
++
++        // do we have a gradient fill? then write out gradient as well
++        if( rState.meFillType == GRADIENT && rState.maFillGradient.maStops.size() > 1 )
++        {
++            // TODO(F3): ODF12 supposedly also groks svg:linear/radialGradient 
++            xAttrs->AddAttribute( USTR( "draw:name" ), getStyleName("svggradient", rState.maFillGradient.mnId) );
++            if( rState.maFillGradient.meType == Gradient::LINEAR )
++            {
++                // should the optimizeGradientStops method decide that
++                // this is a three-color gradient, it prolly wanted us
++                // to take axial instead
++                xAttrs->AddAttribute( USTR( "draw:style" ), 
++                                      rState.maFillGradient.maStops.size() == 3 ?
++                                      USTR("axial") :
++                                      USTR("linear") );
++            }
++            else
++            {
++                xAttrs->AddAttribute( USTR( "draw:style" ), USTR("ellipsoid") );
++                xAttrs->AddAttribute( USTR( "draw:cx" ), USTR("50%") );
++                xAttrs->AddAttribute( USTR( "draw:cy" ), USTR("50%") );
++            }
++
++            basegfx::B2DTuple rScale, rTranslate;
++            double rRotate, rShearX;
++            if( rState.maFillGradient.maTransform.decompose(rScale, rTranslate, rRotate, rShearX) )
++                xAttrs->AddAttribute( USTR( "draw:angle" ), 
++                                      rtl::OUString::valueOf(rRotate*1800.0/M_PI ) );
++            xAttrs->AddAttribute( USTR( "draw:start-color" ), 
++                                  getOdfColor(
++                                      maGradientStopVector[
++                                          rState.maFillGradient.maStops[0]].maStopColor) );
++            xAttrs->AddAttribute( USTR( "draw:end-color" ), 
++                                  getOdfColor(
++                                      maGradientStopVector[
++                                          rState.maFillGradient.maStops[1]].maStopColor) );
++            xAttrs->AddAttribute( USTR( "draw:border" ), USTR("0%") );
++            mxDocumentHandler->startElement( USTR("draw:gradient"), 
++                                             xUnoAttrs );
++            mxDocumentHandler->endElement( USTR("draw:gradient") );
++
++            if( hasGradientOpacity(rState.maFillGradient) )
++            {
++                // need to write out opacity style as well
++                xAttrs->Clear();
++                xAttrs->AddAttribute( USTR( "draw:name" ), getStyleName("svgopacity", rState.maFillGradient.mnId) );
++                if( rState.maFillGradient.meType == Gradient::LINEAR )
++                {
++                    xAttrs->AddAttribute( USTR( "draw:style" ), USTR("linear") );
++                }
++                else
++                {
++                    xAttrs->AddAttribute( USTR( "draw:style" ), USTR("ellipsoid") );
++                    xAttrs->AddAttribute( USTR( "draw:cx" ), USTR("50%") );
++                    xAttrs->AddAttribute( USTR( "draw:cy" ), USTR("50%") );
++                }
++
++                // modulate gradient opacity with overall fill opacity
++                xAttrs->AddAttribute( USTR( "draw:end" ), 
++                                      rtl::OUString::valueOf(
++                                          maGradientStopVector[
++                                              rState.maFillGradient.maStops[0]].maStopColor.a*
++                                          maCurrState.mnFillOpacity*100.0)+USTR("%" ) );
++                xAttrs->AddAttribute( USTR( "draw:start" ), 
++                                      rtl::OUString::valueOf(
++                                          maGradientStopVector[
++                                              rState.maFillGradient.maStops[1]].maStopColor.a*
++                                          maCurrState.mnFillOpacity*100.0)+USTR("%" ) );
++                xAttrs->AddAttribute( USTR( "draw:border" ), USTR("0%") );
++                mxDocumentHandler->startElement( USTR("draw:opacity"), 
++                                                 xUnoAttrs );
++                mxDocumentHandler->endElement( USTR("draw:opacity") );
++            }
++        }
++
 +        // serialize to automatic-style section
++        xAttrs->Clear();
 +		xAttrs->AddAttribute( USTR( "style:name" ), getStyleName("svggraphicstyle", mnCurrStateId) );
 +		xAttrs->AddAttribute( USTR( "style:family" ), USTR("graphic") );
 +        mxDocumentHandler->startElement( USTR("style:style"), 
 +                                         xUnoAttrs );
 +        
 +        xAttrs->Clear();
-+        if( rState.meFillType != NONE )
-+        {
-+            xAttrs->AddAttribute( USTR( "draw:fill" ), USTR("solid"));
-+            xAttrs->AddAttribute( USTR( "draw:fill-color" ), getOdfColor(rState.maFillColor));
-+            if( maCurrState.mnFillOpacity != 1.0 )
-+                xAttrs->AddAttribute( USTR( "draw:fill-opacity" ), rtl::OUString::valueOf(maCurrState.mnFillOpacity));
-+        }
-+        else
-+            xAttrs->AddAttribute( USTR( "draw:fill" ), USTR("none"));
-+
-+        if( rState.meStrokeType != NONE )
-+        {
-+            xAttrs->AddAttribute( USTR( "draw:stroke" ), USTR("solid"));
-+            xAttrs->AddAttribute( USTR( "svg:stroke-color" ), getOdfColor(rState.maStrokeColor));
-+        }
-+        else
-+            xAttrs->AddAttribute( USTR( "draw:stroke" ), USTR("none"));
-+
-+        if( maCurrState.mnStrokeWidth != 0.0 )
-+        {
-+#if 1
-+            ::basegfx::B2DVector aVec(maCurrState.mnStrokeWidth,0);
-+            aVec *= maCurrState.maCTM;
-+            xAttrs->AddAttribute( USTR("svg:stroke-width"), rtl::OUString::valueOf( aVec.getLength()/1000.0 )+USTR("mm"));
-+#else
-+			xAttrs->AddAttribute( USTR("svg:stroke-width"), rtl::OUString::valueOf(maCurrState.mnStrokeWidth/100.0)+USTR("mm"));
-+#endif
-+        }
-+        if( maCurrState.meLineJoin == basegfx::tools::B2DLINEJOIN_MITER )
-+            xAttrs->AddAttribute( USTR( "draw:stroke-linejoin"), USTR("miter"));
-+        else if( maCurrState.meLineJoin == basegfx::tools::B2DLINEJOIN_ROUND )
-+            xAttrs->AddAttribute( USTR( "draw:stroke-linejoin"), USTR("round"));
-+        else if( maCurrState.meLineJoin == basegfx::tools::B2DLINEJOIN_BEVEL )
-+            xAttrs->AddAttribute( USTR( "draw:stroke-linejoin"), USTR("bevel"));
-+        if( maCurrState.mnStrokeOpacity != 1.0 )
-+            xAttrs->AddAttribute( USTR("svg:stroke-opacity"), rtl::OUString::valueOf(maCurrState.mnStrokeOpacity));
-+
-+        // beef up text box style with some auto-magic
++        // text or shape? if the former, no use in processing any
++        // graphic attributes except stroke color, ODF can do ~nothing
++        // with text shapes
 +        if( nTagId == XML_TEXT )
 +        {
-+            xAttrs->AddAttribute( USTR( "draw:auto-grow-height"), USTR("true"));
++            //xAttrs->AddAttribute( USTR( "draw:auto-grow-height"), USTR("true"));
 +            xAttrs->AddAttribute( USTR( "draw:auto-grow-width"), USTR("true"));
 +            xAttrs->AddAttribute( USTR( "draw:textarea-horizontal-align"), USTR("left"));
-+            xAttrs->AddAttribute( USTR( "textarea-vertical-align"), USTR("top"));
-+            xAttrs->AddAttribute( USTR( "fo:padding-top"), USTR("0cm"));
++            //xAttrs->AddAttribute( USTR( "draw:textarea-vertical-align"), USTR("top"));
++            xAttrs->AddAttribute( USTR( "fo:min-height"), USTR("0cm"));
++
 +            xAttrs->AddAttribute( USTR( "fo:padding-top"), USTR("0cm"));
 +            xAttrs->AddAttribute( USTR( "fo:padding-left"), USTR("0cm"));
 +            xAttrs->AddAttribute( USTR( "fo:padding-right"), USTR("0cm"));
 +            xAttrs->AddAttribute( USTR( "fo:padding-bottom"), USTR("0cm"));
++
++            // disable any background shape
++            xAttrs->AddAttribute( USTR( "draw:stroke" ), USTR("none"));
++            xAttrs->AddAttribute( USTR( "draw:fill" ), USTR("none"));
++        }
++        else
++        {
++            if( rState.meFillType != NONE )
++            {
++                if( rState.meFillType == GRADIENT )
++                {
++                    xAttrs->AddAttribute( USTR( "draw:fill" ), USTR("gradient"));
++                    xAttrs->AddAttribute( USTR( "draw:fill-gradient-name" ), 
++                                          getStyleName("svggradient", rState.maFillGradient.mnId) );
++                    if( hasGradientOpacity(rState.maFillGradient) )
++                    {
++                        // needs transparency gradient as well
++                        xAttrs->AddAttribute( USTR( "draw:opacity-name" ), 
++                                              getStyleName("svgopacity", rState.maFillGradient.mnId) );
++                    }
++                    else if( maCurrState.mnFillOpacity != 1.0 )
++                        xAttrs->AddAttribute( USTR( "draw:opacity" ), 
++                                              rtl::OUString::valueOf(100.0*maCurrState.mnFillOpacity)+USTR("%") );
++                }
++                else
++                {
++                    xAttrs->AddAttribute( USTR( "draw:fill" ), USTR("solid"));
++                    xAttrs->AddAttribute( USTR( "draw:fill-color" ), getOdfColor(rState.maFillColor));
++                    if( maCurrState.mnFillOpacity != 1.0 )
++                        xAttrs->AddAttribute( USTR( "draw:opacity" ), 
++                                              rtl::OUString::valueOf(100.0*maCurrState.mnFillOpacity)+USTR("%") );
++                }
++            }
++            else
++                xAttrs->AddAttribute( USTR( "draw:fill" ), USTR("none"));
++
++            if( rState.meStrokeType != NONE )
++            {
++                xAttrs->AddAttribute( USTR( "draw:stroke" ), USTR("solid"));
++                xAttrs->AddAttribute( USTR( "svg:stroke-color" ), getOdfColor(rState.maStrokeColor));
++            }
++            else
++                xAttrs->AddAttribute( USTR( "draw:stroke" ), USTR("none"));
++
++            if( maCurrState.mnStrokeWidth != 0.0 )
++            {
++                ::basegfx::B2DVector aVec(maCurrState.mnStrokeWidth,0);
++                aVec *= maCurrState.maCTM;
++                xAttrs->AddAttribute( USTR("svg:stroke-width"), rtl::OUString::valueOf( aVec.getLength()/100.0 )+USTR("mm"));
++            }
++            if( maCurrState.meLineJoin == basegfx::tools::B2DLINEJOIN_MITER )
++                xAttrs->AddAttribute( USTR( "draw:stroke-linejoin"), USTR("miter"));
++            else if( maCurrState.meLineJoin == basegfx::tools::B2DLINEJOIN_ROUND )
++                xAttrs->AddAttribute( USTR( "draw:stroke-linejoin"), USTR("round"));
++            else if( maCurrState.meLineJoin == basegfx::tools::B2DLINEJOIN_BEVEL )
++                xAttrs->AddAttribute( USTR( "draw:stroke-linejoin"), USTR("bevel"));
++            if( maCurrState.mnStrokeOpacity != 1.0 )
++                xAttrs->AddAttribute( USTR("svg:stroke-opacity"), 
++                                      rtl::OUString::valueOf(100.0*maCurrState.mnStrokeOpacity)+USTR("%"));
 +        }
 +
 +        mxDocumentHandler->startElement( USTR("style:graphic-properties"), 
@@ -2125,7 +2443,7 @@
 +        return true; // newly written
 +    }
 +
-+    void writeStyle(const uno::Reference<xml::dom::XElement>& xElem, sal_Int32 nTagId)
++    void writeStyle(const uno::Reference<xml::dom::XElement>& xElem, const sal_Int32 nTagId)
 +    {
 +        sal_Int32 nEmulatedStyleId=0;
 +        if( maCurrState.maDashArray.size() && 
@@ -2144,14 +2462,14 @@
 +            aEmulatedStrokeState.meFillRule = EVEN_ODD;
 +            aEmulatedStrokeState.meStrokeType = NONE;
 +
-+            if( writeStyle(aEmulatedStrokeState,nTagId) )
++            if( writeStyle(aEmulatedStrokeState, nTagId) )
 +                nEmulatedStyleId = mnCurrStateId;
 +            else
 +                nEmulatedStyleId = mrStates.find(aEmulatedStrokeState)->mnStyleId;
 +        }
 +
 +        sal_Int32 nStyleId=0;
-+        if( writeStyle(maCurrState,nTagId) )
++        if( writeStyle(maCurrState, nTagId) )
 +            nStyleId = mnCurrStateId;
 +        else
 +            nStyleId = mrStates.find(maCurrState)->mnStyleId;
@@ -2174,53 +2492,115 @@
 +        maParentStates.pop_back();
 +    }
 +	
-+	void parseGradientData( const sal_Int32			nTokenId,
-+							const rtl::OUString&	sValue )
++	void parseLinearGradientData( Gradient& io_rCurrGradient,
++                                  const sal_Int32 nGradientNumber,
++                                  const sal_Int32 nTokenId,
++                                  const rtl::OUString& sValue )
 +	{
 +		switch(nTokenId)
 +		{
++            case XML_GRADIENTTRANSFORM:
++            {
++                rtl::OString aValueUtf8( sValue.getStr(), 
++                                         sValue.getLength(), 
++                                         RTL_TEXTENCODING_UTF8 );
++                parseTransform(aValueUtf8.getStr(),io_rCurrGradient.maTransform);
++                break;
++            }
 +			case XML_X1:
-+				mpCurrentGradient->mfX1 = convLength(sValue);
++				io_rCurrGradient.maCoords.linear.mfX1 = convLength(sValue);
 +				break;
 +			case XML_X2:
-+				mpCurrentGradient->mfX2 = convLength(sValue);
++				io_rCurrGradient.maCoords.linear.mfX2 = convLength(sValue);
 +				break;
 +			case XML_Y1:
-+				mpCurrentGradient->mfY1 = convLength(sValue);
++				io_rCurrGradient.maCoords.linear.mfY1 = convLength(sValue);
 +				break;
 +			case XML_Y2:
-+				mpCurrentGradient->mfY2 = convLength(sValue);
++				io_rCurrGradient.maCoords.linear.mfY2 = convLength(sValue);
 +				break;
 +			case XML_ID:
-+				mpCurrentGradient->msId = sValue;
++                maGradientIdMap.insert(std::make_pair(sValue,nGradientNumber));
 +				break;
 +			case XML_GRADIENTUNITS:
 +				if (getTokenId(sValue) == XML_OBJECTBOUNDINGBOX)
-+					mpCurrentGradient->mbBoundingBoxUnits = true;
++					io_rCurrGradient.mbBoundingBoxUnits = true;
 +				else
-+					mpCurrentGradient->mbBoundingBoxUnits = false;
++					io_rCurrGradient.mbBoundingBoxUnits = false;
 +				break;
-+			case XML_XLINK_HREF:
-+				if (sValue.copy(0,1).equalsAscii("#"))
-+					mpCurrentGradient->msLinkedTo = sValue.copy(1);
++			default:
++				break;
++		}
++	}
++	
++	void parseRadialGradientData( Gradient& io_rCurrGradient,
++                                  const sal_Int32 nGradientNumber,
++                                  const sal_Int32 nTokenId,
++                                  const rtl::OUString& sValue )
++	{
++		switch(nTokenId)
++		{
++            case XML_GRADIENTTRANSFORM:
++            {
++                rtl::OString aValueUtf8( sValue.getStr(), 
++                                         sValue.getLength(), 
++                                         RTL_TEXTENCODING_UTF8 );
++                parseTransform(aValueUtf8.getStr(),io_rCurrGradient.maTransform);
++                break;
++            }
++			case XML_CX:
++				io_rCurrGradient.maCoords.radial.mfCX = convLength(sValue);
++				break;
++			case XML_CY:
++				io_rCurrGradient.maCoords.radial.mfCY = convLength(sValue);
++				break;
++			case XML_FX:
++				io_rCurrGradient.maCoords.radial.mfFX = convLength(sValue);
++				break;
++			case XML_FY:
++				io_rCurrGradient.maCoords.radial.mfFY = convLength(sValue);
++				break;
++			case XML_R:
++				io_rCurrGradient.maCoords.radial.mfR = convLength(sValue);
++				break;
++			case XML_ID:
++                maGradientIdMap.insert(std::make_pair(sValue,nGradientNumber));
++				break;
++			case XML_GRADIENTUNITS:
++				if (getTokenId(sValue) == XML_OBJECTBOUNDINGBOX)
++					io_rCurrGradient.mbBoundingBoxUnits = true;
 +				else
-+					mpCurrentGradient->msLinkedTo = sValue;
++					io_rCurrGradient.mbBoundingBoxUnits = false;
 +				break;
 +			default:
 +				break;
 +		}
 +	}
 +	
-+	void parseGradientStop( const sal_Int32      nTokenId, 
++	void parseGradientStop( GradientStop& io_rGradientStop,
++                            const sal_Int32 nStopNumber,
++                            const sal_Int32 nTokenId, 
 +							const rtl::OUString& sValue )
 +	{
 +		switch(nTokenId)
 +		{
++			case XML_HREF:
++            {
++                ElementRefMapType::iterator aFound=maStopIdMap.end();
++				if (sValue.copy(0,1).equalsAscii("#"))
++					aFound = maStopIdMap.find(sValue.copy(1));
++				else
++					aFound = maStopIdMap.find(sValue);;
++
++                if( aFound != maStopIdMap.end() )
++                    io_rGradientStop =  maGradientStopVector[aFound->second];
++				break;
++            }
 +			case XML_ID:
-+				mpCurrentGradientStop->msId = sValue;
++                maStopIdMap.insert(std::make_pair(sValue,nStopNumber));
 +				break;
 +			case XML_OFFSET:
-+				mpCurrentGradientStop->mnStopPosition = sValue.toDouble();
++				io_rGradientStop.mnStopPosition = sValue.toDouble();
 +				break;
 +			case XML_STYLE:
 +				parseStyle( sValue );
@@ -2274,6 +2654,12 @@
 +                    maCurrState.meFillRule = maParentStates.back().meFillRule;
 +                break;
 +            }
++            case XML_FILL_OPACITY:
++                if( aValueUtf8 == "inherit" )
++                    maCurrState.mnFillOpacity = maParentStates.back().mnFillOpacity;
++                else
++                    maCurrState.mnFillOpacity = aValueUtf8.toDouble();
++                break;
 +            case XML_STROKE_WIDTH:
 +            {
 +                if( aValueUtf8 == "inherit" )
@@ -2333,10 +2719,17 @@
 +                                   maCurrState.maDashArray);
 +                break;
 +            }
++            case XML_STROKE_OPACITY:
++                if( aValueUtf8 == "inherit" )
++                    maCurrState.mnStrokeOpacity = maParentStates.back().mnStrokeOpacity;
++                else
++                    maCurrState.mnStrokeOpacity = aValueUtf8.toDouble();
++                break;
 +            case XML_FILL:
 +            {
 +                const State& rParent( maParentStates.back() );
-+                parsePaint( aValueUtf8.getStr(),
++                parsePaint( sValue,
++                            aValueUtf8.getStr(),
 +                            maCurrState.meFillType,
 +                            maCurrState.maFillColor,
 +                            maCurrState.maFillGradient,
@@ -2348,7 +2741,8 @@
 +            case XML_STROKE:
 +            {
 +                const State& rParent( maParentStates.back() );
-+                parsePaint( aValueUtf8.getStr(),
++                parsePaint( sValue,
++                            aValueUtf8.getStr(),
 +                            maCurrState.meStrokeType,
 +                            maCurrState.maStrokeColor,
 +                            maCurrState.maStrokeGradient,
@@ -2383,10 +2777,20 @@
 +                maCurrState.meFontVariant=VARIANT_SMALLCAPS; // TODO: sValue.toDouble();
 +                break;
 +			case XML_STOP_COLOR:
-+				parseColor( aValueUtf8, mpCurrentGradientStop->maStopColor );
++                if( maGradientVector.empty() ||
++                    maGradientVector.back().maStops.empty() )
++                    break;
++				parseColor( aValueUtf8, 
++                            maGradientStopVector[
++                                maGradientVector.back().maStops.back()].maStopColor );
 +				break;
 +			case XML_STOP_OPACITY:
-+				parseOpacity( aValueUtf8, mpCurrentGradientStop->maStopColor );
++                if( maGradientVector.empty() ||
++                    maGradientVector.back().maStops.empty() )
++                    break;
++				parseOpacity( aValueUtf8, 
++                              maGradientStopVector[
++                                  maGradientVector.back().maStops.back()].maStopColor );
 +				break;
 +            default:
 +                OSL_TRACE("unhandled token %s", getTokenName(nTokenId));
@@ -2420,7 +2824,8 @@
 +        while( nIndex != -1 );
 +    }
 +
-+    void parsePaint( const char*      sValue, 
++    void parsePaint( const rtl::OUString& rValue,
++                     const char*      sValue, 
 +                     PaintType&       rType,
 +                     ARGBColor&       rColor,
 +                     Gradient&        rGradient,
@@ -2441,8 +2846,19 @@
 +            rColor = rInheritColor;
 +            rGradient = rInheritGradient;
 +        }
-+		else if( strncmp(sValue,"url",3) == 0)
++		else if( strncmp(sValue,"url(#",5) == 0 )
 +		{
++            // assuming gradient. assumption does not hold generally
++            if( rValue.getLength() > 5 )
++            {
++                ElementRefMapType::iterator aRes;
++                if( (aRes=maGradientIdMap.find(rValue.copy(5,
++                                                           rValue.getLength()-6))) != maGradientIdMap.end() )
++                {
++                    rGradient = maGradientVector[aRes->second];
++                    rType = GRADIENT;
++                }
++            }
 +		}
 +        else
 +        { 
@@ -2451,15 +2867,16 @@
 +        }
 +    }
 +
-+    sal_Int32                                   mnCurrStateId;
-+    State                                       maCurrState;
-+    std::vector<State>                          maParentStates;
-+    StatePool&                                  mrStates;
-+    StateMap&                                   mrStateMap;
-+    uno::Reference<xml::sax::XDocumentHandler>  mxDocumentHandler;
-+	Gradient*									mpCurrentGradient;
-+	GradientStop*		                		mpCurrentGradientStop;
-+	std::vector< Gradient >						mxGradientVector;
++    sal_Int32                                  mnCurrStateId;
++    State                                      maCurrState;
++    std::vector<State>                         maParentStates;
++    StatePool&                                 mrStates;
++    StateMap&                                  mrStateMap;
++    uno::Reference<xml::sax::XDocumentHandler> mxDocumentHandler;
++    std::vector< Gradient >                    maGradientVector;
++    std::vector< GradientStop >                maGradientStopVector;
++    ElementRefMapType                          maGradientIdMap;
++    ElementRefMapType                          maStopIdMap;
 +};
 +
 +/// Annotate svg styles with unique references to state pool
@@ -2807,15 +3224,35 @@
 +
 +                // actually export text
 +                xAttrs->Clear();
++
++                // extract basic transformations out of CTM
++                basegfx::B2DTuple aScale, aTranslate;
++                double fRotate, fShearX;
++                ::rtl::OUString sTransformValue;
++                if (maCurrState.maCTM.decompose(aScale, aTranslate, fRotate, fShearX))
++                {
++                    rtl::OUString sTransform;
++                    x += aTranslate.getX();
++                    y += aTranslate.getY();
++
++                    sTransform += 
++                        USTR("scale(") + 
++                        rtl::OUString::valueOf(aScale.getX()) + 
++                        USTR(", ") +
++                        rtl::OUString::valueOf(aScale.getX()) + 
++                        USTR(")");
++
++                    if( fRotate )
++                        sTransform += USTR(" rotate(") + rtl::OUString::valueOf(fRotate*180.0/M_PI) + USTR(")");
++
++                    if( fShearX )
++                        sTransform += USTR(" skewX(") + rtl::OUString::valueOf(fShearX*180.0/M_PI) + USTR(")");
++                }
++
 +                xAttrs->AddAttribute( USTR( "svg:x" ), rtl::OUString::valueOf(x/100.0)+USTR("mm"));
 +                xAttrs->AddAttribute( USTR( "svg:y" ), rtl::OUString::valueOf(y/100.0)+USTR("mm"));
-+#if 0
-+                xAttrs->AddAttribute( USTR( "svg:width" ), rtl::OUString::valueOf(std::max(10.0,width/100.0))+USTR("mm"));
-+                xAttrs->AddAttribute( USTR( "svg:height" ), rtl::OUString::valueOf(std::max(10.0,height/100.0))+USTR("mm"));
-+#else
-+                xAttrs->AddAttribute( USTR( "svg:width" ), USTR("100mm"));
-+                xAttrs->AddAttribute( USTR( "svg:height" ), USTR("100mm"));
-+#endif
++                //xAttrs->AddAttribute( USTR( "svg:width" ), rtl::OUString::valueOf(width/100.0)+USTR("mm"));
++                //xAttrs->AddAttribute( USTR( "svg:height" ), rtl::OUString::valueOf(height/100.0)+USTR("mm"));
 +                xAttrs->AddAttribute( USTR( "draw:style-name" ), USTR("svggraphicstyle")+sStyleId );
 +
 +                mxDocumentHandler->startElement(USTR("draw:frame"),xUnoAttrs);
@@ -3351,6 +3788,653 @@
 +} // namespace svgi
 +
 +#endif
+--- filter/source/svg/test/makefile.mk	1970-01-01 01:00:00.000000000 +0100
++++ filter/source/svg/test/makefile.mk	2008-05-23 11:23:50.000000000 +0200
+@@ -0,0 +1,123 @@
++#*************************************************************************
++#
++#    OpenOffice.org - a multi-platform office productivity suite
++#
++#    Author:
++#      Fridrich Strba  <fridrich strba bluewin ch>
++#      Thorsten Behrens <tbehrens novell com>	   	
++#
++#      Copyright (C) 2008, Novell Inc.
++#      Parts copyright 2005 by Sun Microsystems, Inc.
++#
++#   The Contents of this file are made available subject to
++#   the terms of GNU Lesser General Public License Version 2.1.
++#
++#*************************************************************************
++
++PRJ=..$/..$/..
++PRJNAME=filter
++TARGET=tests
++TARGETTYPE=CUI
++ENABLE_EXCEPTIONS=TRUE
++
++# --- Settings -----------------------------------------------------
++
++.INCLUDE: settings.mk
++
++# --- unit tests ---------------------------------------------------
++
++SHL1OBJS=  \
++	$(SLO)$/parsertest.obj
++
++SHL1TARGET= tests
++SHL1LIBS= $(SLB)$/svgfilter.lib
++SHL1STDLIBS= 	        \
++	$(BASEGFXLIB)		\
++	$(SVXLIB)			\
++	$(XMLOFFLIB)		\
++	$(BASEGFXLIB)		\
++	$(VCLLIB)			\
++	$(UNOTOOLSLIB)		\
++	$(TOOLSLIB)			\
++	$(COMPHELPERLIB)	\
++	$(CPPUHELPERLIB)	\
++	$(CPPULIB)			\
++	$(SALLIB)			\
++	$(LIBXML)			\
++	$(CPPUNITLIB)
++
++# --- svg2xml binary ------------------------------------------------------
++
++TARGET2=svg2odf
++
++APP1TARGET=$(TARGET2)
++APP1LIBSALCPPRT=
++APP1OBJS= \
++	$(SLO)$/odfserializer.obj	\
++    $(SLO)$/svg2odf.obj
++
++APP1LIBS=\
++	$(SLB)$/svgfilter.lib
++
++APP1STDLIBS=\
++	$(BASEGFXLIB)		\
++	$(SVXLIB)			\
++	$(XMLOFFLIB)		\
++	$(BASEGFXLIB)		\
++	$(VCLLIB)			\
++	$(UNOTOOLSLIB)		\
++	$(TOOLSLIB)			\
++	$(COMPHELPERLIB)	\
++	$(CPPUHELPERLIB)	\
++	$(CPPULIB)			\
++	$(SALLIB)			\
++	$(LIBXML)
++
++# --- Targets ------------------------------------------------------
++
++.INCLUDE : target.mk
++.INCLUDE : _cppunit.mk 
++
++# --- Special ------------------------------------------------------
++
++TESTFILES=\
++	anarchist.svg \
++	andorra.svg \
++	butterfly.svg \
++	daisies.svg \
++	ellipticarcs.svg \
++	firewall_denco_01.svg \
++	mediatrice.svg \
++	mouse_the_structorr.svg \
++	network_could_nicolas_cl.svg \
++	otto_01.svg \
++	roundingerrors.svg \
++	test.svg \
++	tiger.svg
++
++$(MISC)$/%_svgi_unittest_succeeded : $(BIN)$/svg2odf
++    rm -f $(MISC)$/$(@:s/_succeeded/.xml/:f)
++	$(BIN)$/svg2odf $(@:s/_svgi_unittest_succeeded/.svg/:f) $(MISC)$/$(@:s/_succeeded/.xml/:f) $(BIN)$/svgi_unittest_test.ini
++	$(TOUCH) $@
++
++.IF "$(GUI)" == "WNT"
++SAXPARSERLIB=$(SOLARBINDIR)$/sax.uno$(DLLPOST)
++UNOXMLLIB=$(SOLARBINDIR)$/$(DLLPRE)unoxml$(OFFICEUPD)$(DLLPOSTFIX)$(DLLPOST)
++.ELSE
++SAXPARSERLIB=$(SOLARLIBDIR)$/sax.uno$(DLLPOST)
++UNOXMLLIB=$(SOLARLIBDIR)$/$(DLLPRE)unoxml$(OFFICEUPD)$(DLLPOSTFIX)$(DLLPOST)
++.ENDIF
++
++$(BIN)$/unittestservices.rdb : makefile.mk $(SAXPARSERLIB) $(UNOXMLLIB)
++    rm -f $@
++	$(REGCOMP) -register -r $@ -c $(SAXPARSERLIB)
++	$(REGCOMP) -register -r $@ -c $(UNOXMLLIB)
++
++$(BIN)$/svgi_unittest_test.ini : makefile.mk
++	rm -f $@
++	@echo UNO_SERVICES=$(BIN)$/unittestservices.rdb > $@
++	@echo UNO_TYPES=$(UNOUCRRDB:s/\/\\/) >> $@
++
++#ALLTAR : $(BIN)$/svgi_unittest_test.ini \
++#		 $(BIN)$/unittestservices.rdb \
++#         $(foreach,i,$(TESTFILES:s/.svg/_svgi_unittest_succeeded/:f) $(MISC)$/$i)
+diff -urN /tmp/svgfilter/filter/source/svg/test/odfserializer.cxx /builds/oobuild/ooo-build-2.4/build/current/filter/source/svg/test/odfserializer.cxx
+--- filter/source/svg/test/odfserializer.cxx	1970-01-01 01:00:00.000000000 +0100
++++ filter/source/svg/test/odfserializer.cxx	2008-05-23 10:23:53.000000000 +0200
+@@ -0,0 +1,140 @@
++/*************************************************************************
++ *
++ *    OpenOffice.org - a multi-platform office productivity suite
++ *
++ *    Author:
++ *      Fridrich Strba  <fridrich strba bluewin ch>
++ *      Thorsten Behrens <tbehrens novell com>	   	
++ *
++ *      Copyright (C) 2008, Novell Inc.
++ *      Parts copyright 2005 by Sun Microsystems, Inc.
++ *
++ *   The Contents of this file are made available subject to
++ *   the terms of GNU Lesser General Public License Version 2.1.
++ *
++ ************************************************************************/
++
++// MARKER(update_precomp.py): autogen include statement, do not remove
++#include "precompiled_filter.hxx"
++
++#include "odfserializer.hxx"
++#include <osl/diagnose.h>
++#include <rtl/ustrbuf.hxx>
++#include <cppuhelper/compbase1.hxx>
++#include <cppuhelper/basemutex.hxx>
++#include <com/sun/star/uno/Sequence.hxx>
++#include <boost/noncopyable.hpp>
++
++using namespace ::com::sun::star;
++
++namespace svgi
++{
++
++typedef ::cppu::WeakComponentImplHelper1< 
++    com::sun::star::xml::sax::XDocumentHandler> ODFSerializerBase;
++
++class ODFSerializer : private cppu::BaseMutex,
++                public ODFSerializerBase,
++                boost::noncopyable
++{
++public:
++    explicit ODFSerializer(const uno::Reference<io::XOutputStream>& xOut) :
++        ODFSerializerBase(m_aMutex),
++        m_xOutStream(xOut),
++        m_aLineFeed(1),
++        m_aBuf()
++    {
++        m_aLineFeed[0] = '\n';
++    }
++
++    virtual void SAL_CALL startDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException);
++    virtual void SAL_CALL endDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException);
++    virtual void SAL_CALL startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException);
++    virtual void SAL_CALL endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException);
++    virtual void SAL_CALL characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException);
++    virtual void SAL_CALL ignorableWhitespace( const ::rtl::OUString& aWhitespaces ) throw (xml::sax::SAXException, uno::RuntimeException);
++    virtual void SAL_CALL processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData ) throw (xml::sax::SAXException, uno::RuntimeException);
++    virtual void SAL_CALL setDocumentLocator( const uno::Reference< xml::sax::XLocator >& xLocator ) throw (xml::sax::SAXException, uno::RuntimeException);
++
++private:
++    uno::Reference<io::XOutputStream> m_xOutStream;
++    uno::Sequence<sal_Int8>           m_aLineFeed;
++    uno::Sequence<sal_Int8>           m_aBuf;
++};
++
++void SAL_CALL ODFSerializer::startDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException)
++{
++    OSL_PRECOND(m_xOutStream.is(), "ODFSerializer(): invalid output stream");
++
++    rtl::OUStringBuffer aElement;
++    aElement.appendAscii("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
++    characters(aElement.makeStringAndClear());
++}
++
++void SAL_CALL ODFSerializer::endDocument() throw (xml::sax::SAXException, uno::RuntimeException)
++{}
++
++void SAL_CALL ODFSerializer::startElement( const ::rtl::OUString& aName, 
++                                           const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException)
++{
++    rtl::OUStringBuffer aElement;
++    aElement.appendAscii("<");
++    aElement.append(aName);
++    aElement.appendAscii(" ");
++
++    const sal_Int16 nLen=xAttribs->getLength();
++    for( sal_Int16 i=0; i<nLen; ++i )
++    {
++        rtl::OUStringBuffer aAttribute;
++        aElement.append(xAttribs->getNameByIndex(i));
++        aElement.appendAscii("=\"");
++        aElement.append(xAttribs->getValueByIndex(i));
++        aElement.appendAscii("\" ");
++    }
++
++    aElement.appendAscii(">");
++    characters(aElement.makeStringAndClear());
++}
++
++void SAL_CALL ODFSerializer::endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException)
++{
++    rtl::OUStringBuffer aElement;
++    aElement.appendAscii("</");
++    aElement.append(aName);
++    aElement.appendAscii(">");
++    characters(aElement.makeStringAndClear());
++}
++
++void SAL_CALL ODFSerializer::characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException)
++{
++    const rtl::OString aStr = rtl::OUStringToOString(aChars,
++                                                     RTL_TEXTENCODING_UTF8);
++    const sal_Int32 nLen( aStr.getLength() );
++    m_aBuf.realloc( nLen );
++    const sal_Char* pStr = aStr.getStr();
++    std::copy(pStr,pStr+nLen,m_aBuf.getArray());
++
++    m_xOutStream->writeBytes(m_aBuf);
++    // TODO(F1): Make pretty printing configurable
++    m_xOutStream->writeBytes(m_aLineFeed);
++}
++
++void SAL_CALL ODFSerializer::ignorableWhitespace( const ::rtl::OUString& aWhitespaces ) throw (xml::sax::SAXException, uno::RuntimeException)
++{
++    // TODO(F1): Make pretty printing configurable
++    characters(aWhitespaces);
++}
++
++void SAL_CALL ODFSerializer::processingInstruction( const ::rtl::OUString&, 
++                                                    const ::rtl::OUString& ) throw (xml::sax::SAXException, uno::RuntimeException)
++{}
++
++void SAL_CALL ODFSerializer::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& ) throw (xml::sax::SAXException, uno::RuntimeException)
++{}
++
++uno::Reference< xml::sax::XDocumentHandler> createSerializer(const uno::Reference<io::XOutputStream>& xOut )
++{
++    return uno::Reference<xml::sax::XDocumentHandler>(new ODFSerializer(xOut));
++}
++
++}
+diff -urN /tmp/svgfilter/filter/source/svg/test/odfserializer.hxx /builds/oobuild/ooo-build-2.4/build/current/filter/source/svg/test/odfserializer.hxx
+--- filter/source/svg/test/odfserializer.hxx	1970-01-01 01:00:00.000000000 +0100
++++ filter/source/svg/test/odfserializer.hxx	2008-05-23 10:23:53.000000000 +0200
+@@ -0,0 +1,31 @@
++/*************************************************************************
++ *
++ *    OpenOffice.org - a multi-platform office productivity suite
++ *
++ *    Author:
++ *      Fridrich Strba  <fridrich strba bluewin ch>
++ *      Thorsten Behrens <tbehrens novell com>	   	
++ *
++ *      Copyright (C) 2008, Novell Inc.
++ *      Parts copyright 2005 by Sun Microsystems, Inc.
++ *
++ *   The Contents of this file are made available subject to
++ *   the terms of GNU Lesser General Public License Version 2.1.
++ *
++ ************************************************************************/
++
++#ifndef INCLUDED_SVG_ODFSERIALIZER_HXX
++#define INCLUDED_SVG_ODFSERIALIZER_HXX
++
++#include <com/sun/star/uno/Reference.hxx>
++#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
++#include <com/sun/star/io/XOutputStream.hpp>
++
++namespace svgi
++{
++    /// Creates a XDocumentHandler that serializes directly to an XOutputStream
++    ::com::sun::star::uno::Reference< com::sun::star::xml::sax::XDocumentHandler>
++        createSerializer(const ::com::sun::star::uno::Reference<com::sun::star::io::XOutputStream>& );
++}
++
++#endif // _COM_SUN_STAR_XML_SAX_XDOCUMENTHANDLER_HDL_
+diff -urN /tmp/svgfilter/filter/source/svg/test/parsertest.cxx /builds/oobuild/ooo-build-2.4/build/current/filter/source/svg/test/parsertest.cxx
+--- filter/source/svg/test/parsertest.cxx	1970-01-01 01:00:00.000000000 +0100
++++ filter/source/svg/test/parsertest.cxx	2008-05-23 15:52:49.000000000 +0200
+@@ -0,0 +1,210 @@
++/*************************************************************************
++ *
++ *    OpenOffice.org - a multi-platform office productivity suite
++ *
++ *    Author:
++ *      Fridrich Strba  <fridrich strba bluewin ch>
++ *      Thorsten Behrens <tbehrens novell com>	   	
++ *
++ *      Copyright (C) 2008, Novell Inc.
++ *
++ *   The Contents of this file are made available subject to
++ *   the terms of GNU Lesser General Public License Version 2.1.
++ *
++ ************************************************************************/
++
++// MARKER(update_precomp.py): autogen include statement, do not remove
++#include "precompiled_filter.hxx"
++
++#include <cppunit/simpleheader.hxx>
++
++#include "../gfxtypes.hxx"
++#include "../parserfragments.hxx"
++
++using namespace svgi;
++
++class TestParser : public CppUnit::TestFixture
++{
++public:
++    void setUp()
++    {}
++
++    void tearDown()
++    {}
++
++    void testParseColor()
++    {
++        ARGBColor aTmp;
++
++        const char* sIn="#102030  ";
++        ARGBColor aOut(16, 32, 48);
++        CPPUNIT_ASSERT_MESSAGE( "Consuming color #112233",
++                                parseColor( sIn, aTmp ) );
++        OSL_TRACE("color is: a:%f r:%f g:%f b:%f", aTmp.a, aTmp.r, aTmp.g, aTmp.b);
++        CPPUNIT_ASSERT_MESSAGE( "Parsing color #112233",
++                                aOut==aTmp );
++
++        sIn="  #321";
++        aOut=ARGBColor(51, 34, 17);
++        CPPUNIT_ASSERT_MESSAGE( "Consuming color #321",
++                                parseColor( sIn, aTmp ) );
++        OSL_TRACE("color is: a:%f r:%f g:%f b:%f", aTmp.a, aTmp.r, aTmp.g, aTmp.b);
++        CPPUNIT_ASSERT_MESSAGE( "Parsing color #321",
++                                aOut==aTmp );
++
++        sIn="rgb(100,200,\t 50)";
++        aOut=ARGBColor(100, 200, 50);
++        CPPUNIT_ASSERT_MESSAGE( "Consuming color rgb(100,200,50)",
++                                parseColor( sIn, aTmp ) );
++        OSL_TRACE("color is: a:%f r:%f g:%f b:%f", aTmp.a, aTmp.r, aTmp.g, aTmp.b);
++        CPPUNIT_ASSERT_MESSAGE( "Parsing color rgb(100,200,50)",
++                                aOut==aTmp );
++
++        sIn="rgb(0.1, \t0.2,0.9)";
++        aOut=ARGBColor(0.1, 0.2, 0.9);
++        CPPUNIT_ASSERT_MESSAGE( "Consuming color rgb(0.1,0.2,0.9)",
++                                parseColor( sIn, aTmp ) );
++        OSL_TRACE("color is: a:%f r:%f g:%f b:%f", aTmp.a, aTmp.r, aTmp.g, aTmp.b);
++        CPPUNIT_ASSERT_MESSAGE( "Parsing color rgb(0.1,0.2,0.9)",
++                                aOut==aTmp );
++
++        sIn=" burlywood ";
++        aOut=ARGBColor(222,184,135);
++        CPPUNIT_ASSERT_MESSAGE( "Consuming color burlywood",
++                                parseColor( sIn, aTmp ) );
++        OSL_TRACE("color is: a:%f r:%f g:%f b:%f", aTmp.a, aTmp.r, aTmp.g, aTmp.b);
++        CPPUNIT_ASSERT_MESSAGE( "Parsing color burlywood",
++                                aOut==aTmp );
++    }
++
++    void testParseOpacity()
++    {
++        ARGBColor aTmp;
++
++        const char* sIn=" 0.123  ";
++        ARGBColor aOut(0.123, 0.0, 0.0, 0.0);
++        CPPUNIT_ASSERT_MESSAGE( "Consuming opacity 0.123",
++                                parseOpacity( sIn, aTmp ) );
++        OSL_TRACE("color is: a:%f r:%f g:%f b:%f", aTmp.a, aTmp.r, aTmp.g, aTmp.b);
++        CPPUNIT_ASSERT_MESSAGE( "Parsing opacity 0.123",
++                                aOut==aTmp );
++    }
++
++    void testParseTransform()
++    {
++        basegfx::B2DHomMatrix aOut;
++
++        const char* sIn=" none  ";
++        basegfx::B2DHomMatrix aTmp;
++        CPPUNIT_ASSERT_MESSAGE( "Consuming transformation none",
++                                parseTransform( sIn, aTmp ) );
++        OSL_TRACE("transformation is: m00:%f m01:%f m02:%f m10:%f m11:%f m12:%f", 
++                  aTmp.get(0,0), aTmp.get(0,1), aTmp.get(0,2), aTmp.get(1,0), aTmp.get(1,1), aTmp.get(1,2) );
++        CPPUNIT_ASSERT_MESSAGE( "Parsing transformation none",
++                                aOut==aTmp );
++
++        sIn=" scale( 10 )  ";
++        aOut.identity();
++        aOut.scale(10.0,10.0);
++        CPPUNIT_ASSERT_MESSAGE( "Consuming transformation scale(10)",
++                                parseTransform( sIn, aTmp ) );
++        OSL_TRACE("transformation is: m00:%f m01:%f m02:%f m10:%f m11:%f m12:%f", 
++                  aTmp.get(0,0), aTmp.get(0,1), aTmp.get(0,2), aTmp.get(1,0), aTmp.get(1,1), aTmp.get(1,2) );
++        CPPUNIT_ASSERT_MESSAGE( "Parsing transformation scale(10)",
++                                aOut==aTmp );
++
++        sIn=" scale( 10 20.12 )  ";
++        aOut.identity();
++        aOut.scale(10.0,20.12);
++        CPPUNIT_ASSERT_MESSAGE( "Consuming transformation scale(10 20.12)",
++                                parseTransform( sIn, aTmp ) );
++        OSL_TRACE("transformation is: m00:%f m01:%f m02:%f m10:%f m11:%f m12:%f", 
++                  aTmp.get(0,0), aTmp.get(0,1), aTmp.get(0,2), aTmp.get(1,0), aTmp.get(1,1), aTmp.get(1,2) );
++        CPPUNIT_ASSERT_MESSAGE( "Parsing transformation scale(10 20.12)",
++                                aOut==aTmp );
++
++        sIn="matrix( 1,2 3,4,5 6 )";
++        aOut.identity();
++        aOut.set(0,0,1.0); aOut.set(1,0,2.0); aOut.set(0,1,3.0); aOut.set(1,1,4.0); aOut.set(0,2,5.0); aOut.set(1,2,6.0);
++        CPPUNIT_ASSERT_MESSAGE( "Consuming transformation matrix(1,2,3,4,5,6)",
++                                parseTransform( sIn, aTmp ) );
++        OSL_TRACE("transformation is: m00:%f m01:%f m02:%f m10:%f m11:%f m12:%f", 
++                  aTmp.get(0,0), aTmp.get(0,1), aTmp.get(0,2), aTmp.get(1,0), aTmp.get(1,1), aTmp.get(1,2) );
++        CPPUNIT_ASSERT_MESSAGE( "Parsing transformation matrix(1,2,3,4,5,6)",
++                                aOut==aTmp );
++
++        sIn="matrix( 1 0 0 1 -10 -10 ) translate(10) scale(10), rotate(90)";
++        aOut.identity();
++        aOut.set(0,0,0.0); aOut.set(1,0,10.0); aOut.set(0,1,-10.0); aOut.set(1,1,0.0); aOut.set(0,2,0.0); aOut.set(1,2,0.0);
++        CPPUNIT_ASSERT_MESSAGE( "Consuming transformation matrix(1,2,3,4,5,6)",
++                                parseTransform( sIn, aTmp ) );
++        OSL_TRACE("transformation is: m00:%f m01:%f m02:%f m10:%f m11:%f m12:%f", 
++                  aTmp.get(0,0), aTmp.get(0,1), aTmp.get(0,2), aTmp.get(1,0), aTmp.get(1,1), aTmp.get(1,2) );
++        CPPUNIT_ASSERT_MESSAGE( "Parsing transformation matrix(1,2,3,4,5,6)",
++                                aOut==aTmp );
++
++        sIn="skewX(45)";
++        aOut.identity();
++        aOut.set(0,0,1.0); aOut.set(1,0,1.0); aOut.set(0,1,0.0); aOut.set(1,1,1.0); aOut.set(0,2,0.0); aOut.set(1,2,0.0);
++        CPPUNIT_ASSERT_MESSAGE( "Consuming transformation skewX(45)",
++                                parseTransform( sIn, aTmp ) );
++        OSL_TRACE("transformation is: m00:%f m01:%f m02:%f m10:%f m11:%f m12:%f", 
++                  aTmp.get(0,0), aTmp.get(0,1), aTmp.get(0,2), aTmp.get(1,0), aTmp.get(1,1), aTmp.get(1,2) );
++        CPPUNIT_ASSERT_MESSAGE( "Parsing transformation skewX(45)",
++                                aOut==aTmp );
++
++        sIn="skewY(45)";
++        aOut.identity();
++        aOut.set(0,0,1.0); aOut.set(1,0,0.0); aOut.set(0,1,1.0); aOut.set(1,1,1.0); aOut.set(0,2,0.0); aOut.set(1,2,0.0);
++        CPPUNIT_ASSERT_MESSAGE( "Consuming transformation skewY(45)",
++                                parseTransform( sIn, aTmp ) );
++        OSL_TRACE("transformation is: m00:%f m01:%f m02:%f m10:%f m11:%f m12:%f", 
++                  aTmp.get(0,0), aTmp.get(0,1), aTmp.get(0,2), aTmp.get(1,0), aTmp.get(1,1), aTmp.get(1,2) );
++        CPPUNIT_ASSERT_MESSAGE( "Parsing transformation skewY(45)",
++                                aOut==aTmp );
++    }
++
++    void testParseViewBox()
++    {
++        basegfx::B2DRange aTmp;
++
++        const char* sIn=" 10 20, 30.5,5  ";
++        basegfx::B2DRange aOut(10,20,40.5,25);
++        CPPUNIT_ASSERT_MESSAGE( "Consuming 10,20,30.5,5",
++                                parseViewBox( sIn, aTmp ) );
++        OSL_TRACE("viewbox is: x1:%f y1:%f x2:%f y2:%f", aTmp.getMinX(), aTmp.getMinY(), aTmp.getMaxX(), aTmp.getMaxY());
++        CPPUNIT_ASSERT_MESSAGE( "Parsing 10,20,30.5,5",
++                                aOut==aTmp );
++    }
++
++    void testParseDashArray()
++    {
++        std::vector<double> aTmp;
++
++        const char* sIn=" 10,20, -10.00  ";
++        std::vector<double> aOut; aOut.push_back(10.0); aOut.push_back(20.0); aOut.push_back(-10.0);
++        CPPUNIT_ASSERT_MESSAGE( "Consuming 10,20,-10.00",
++                                parseDashArray( sIn, aTmp ) );
++        OSL_TRACE("dash array is: len %d, %f %f %f", aTmp.size(), aTmp[0], aTmp[1], aTmp[2] );
++        CPPUNIT_ASSERT_MESSAGE( "Parsing 10,20,-10.00",
++                                aOut==aTmp );
++    }
++
++    CPPUNIT_TEST_SUITE(TestParser);
++    CPPUNIT_TEST(testParseColor);
++    CPPUNIT_TEST(testParseOpacity);
++    CPPUNIT_TEST(testParseTransform);
++    CPPUNIT_TEST(testParseViewBox);
++    CPPUNIT_TEST(testParseDashArray);
++    // TODO: CPPUNIT_TEST(testParseXlinkHref);
++    CPPUNIT_TEST_SUITE_END();
++};
++
++// -----------------------------------------------------------------------------
++
++CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(TestParser, "test svg parser fragments");
++
++// this macro creates an empty function, which will called by the RegisterAllFunctions()
++// to let the user the possibility to also register some functions by hand.
++NOADDITIONAL;
++
+diff -urN /tmp/svgfilter/filter/source/svg/test/svg2odf.cxx /builds/oobuild/ooo-build-2.4/build/current/filter/source/svg/test/svg2odf.cxx
+--- filter/source/svg/test/svg2odf.cxx	1970-01-01 01:00:00.000000000 +0100
++++ filter/source/svg/test/svg2odf.cxx	2008-05-23 11:23:07.000000000 +0200
+@@ -0,0 +1,124 @@
++/*************************************************************************
++ *
++ *    OpenOffice.org - a multi-platform office productivity suite
++ *
++ *    Author:
++ *      Fridrich Strba  <fridrich strba bluewin ch>
++ *      Thorsten Behrens <tbehrens novell com>	   	
++ *
++ *      Copyright (C) 2008, Novell Inc.
++ *      Parts copyright 2005 by Sun Microsystems, Inc.
++ *
++ *   The Contents of this file are made available subject to
++ *   the terms of GNU Lesser General Public License Version 2.1.
++ *
++ ************************************************************************/
++
++// MARKER(update_precomp.py): autogen include statement, do not remove
++#include "precompiled_filter.hxx"
++
++#include "../svgreader.hxx" 
++#include "odfserializer.hxx" 
++
++#include <sal/main.h>
++#include <osl/file.hxx>
++#include <osl/process.h>
++#include <rtl/bootstrap.hxx>
++
++#include <cppuhelper/implbase1.hxx>
++#include <cppuhelper/bootstrap.hxx>
++#include <cppuhelper/servicefactory.hxx>
++#include <comphelper/processfactory.hxx>
++#include <comphelper/oslfile2streamwrap.hxx>
++
++using namespace ::com::sun::star;
++
++namespace
++{
++    class OutputWrap : public cppu::WeakImplHelper1<
++        io::XOutputStream>
++    {
++        osl::File maFile;
++
++    public:
++
++        explicit OutputWrap( const rtl::OUString& rURL ) : maFile(rURL) 
++        {
++            maFile.open(osl_File_OpenFlag_Create|OpenFlag_Write);
++        }
++
++		virtual void SAL_CALL writeBytes( const com::sun::star::uno::Sequence< ::sal_Int8 >& aData ) throw (com::sun::star::io::NotConnectedException,com::sun::star::io::BufferSizeExceededException, com::sun::star::io::IOException, com::sun::star::uno::RuntimeException)
++
++        {
++            sal_uInt64 nBytesWritten(0);
++            maFile.write(aData.getConstArray(),aData.getLength(),nBytesWritten);
++        }
++
++        virtual void SAL_CALL flush() throw (com::sun::star::io::NotConnectedException, com::sun::star::io::BufferSizeExceededException, com::sun::star::io::IOException, com::sun::star::uno::RuntimeException)
++        {
++        }
++
++        virtual void SAL_CALL closeOutput() throw (com::sun::star::io::NotConnectedException, com::sun::star::io::BufferSizeExceededException, com::sun::star::io::IOException, com::sun::star::uno::RuntimeException)
++        {
++            maFile.close();
++        }
++    };
++}
++
++SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
++{
++	if( argc != 4 )
++    {
++        OSL_TRACE( "Invocation: svg2odf <base_url> <dst_url> <ini_file>. Exiting" );
++		return 1;
++    }
++
++	::rtl::OUString aBaseURL, aTmpURL, aSrcURL, aDstURL, aIniUrl;
++    
++    osl_getProcessWorkingDir(&aBaseURL.pData);
++    osl_getFileURLFromSystemPath( rtl::OUString::createFromAscii(argv[1]).pData,
++                                  &aTmpURL.pData );
++    osl_getAbsoluteFileURL(aBaseURL.pData,aTmpURL.pData,&aSrcURL.pData);
++
++    osl_getFileURLFromSystemPath( rtl::OUString::createFromAscii(argv[2]).pData,
++                                  &aTmpURL.pData );
++    osl_getAbsoluteFileURL(aBaseURL.pData,aTmpURL.pData,&aDstURL.pData);
++
++	osl_getFileURLFromSystemPath( rtl::OUString::createFromAscii(argv[3]).pData, 
++								&aTmpURL.pData );
++    osl_getAbsoluteFileURL(aBaseURL.pData,aTmpURL.pData,&aIniUrl.pData);
++
++    // bootstrap UNO
++    uno::Reference< lang::XMultiServiceFactory > xFactory;
++    uno::Reference< uno::XComponentContext > xCtx;
++    try
++    {
++        xCtx = ::cppu::defaultBootstrap_InitialComponentContext(aIniUrl);
++        xFactory = uno::Reference< lang::XMultiServiceFactory >(xCtx->getServiceManager(), 
++                                                                uno::UNO_QUERY);
++        if( xFactory.is() )
++            ::comphelper::setProcessServiceFactory( xFactory );
++    }
++    catch( uno::Exception& )
++    {
++    }
++
++    if( !xFactory.is() )
++    {
++        OSL_TRACE( "Could not bootstrap UNO, installation must be in disorder. Exiting." );
++        return 1;
++    }
++
++    osl::File aInputFile(aSrcURL);
++    if( osl::FileBase::E_None!=aInputFile.open(OpenFlag_Read) )
++    {
++        OSL_TRACE( "Cannot open input file" );
++        return 1;
++    }
++
++    svgi::SVGReader aReader(xFactory, 
++                            uno::Reference<io::XInputStream>(
++                                new comphelper::OSLInputStreamWrapper(aInputFile)),
++                            svgi::createSerializer(new OutputWrap(aDstURL)));
++    return aReader.parseAndConvert() ? 0 : 1;
++}
 --- filter/source/svg/tokenmap.cxx	1970-01-01 01:00:00.000000000 +0100
 +++ filter/source/svg/tokenmap.cxx	2008-04-11 00:09:55.000000000 +0200
 @@ -0,0 +1,62 @@
@@ -3453,7 +4537,7 @@
 +#endif
 --- filter/source/svg/tokens.txt	1970-01-01 01:00:00.000000000 +0100
 +++ filter/source/svg/tokens.txt	2008-04-11 00:09:55.000000000 +0200
-@@ -0,0 +1,405 @@
+@@ -0,0 +1,403 @@
 +#######################################
 +#
 +# elements (SVG Tiny 1.2)
@@ -3578,7 +4662,6 @@
 +dur
 +editable
 +end
-+ev:event
 +event
 +externalResourcesRequired
 +fill
@@ -3590,9 +4673,12 @@
 +font-variant
 +font-weight
 +from
++fx
++fy
 +g1
 +g2
 +glyph-name
++gradientTransform
 +gradientUnits
 +handler
 +hanging
@@ -3685,17 +4771,13 @@
 +x-height
 +x1
 +x2
-+xlink:actuate
-+xlink:arcrole
-+xlink:href
-+xlink:role
-+xlink:show
-+xlink:title
-+xlink:type
-+xml:base
-+xml:id
-+xml:lang
-+xml:space
++actuate
++arcrole
++href
++role
++show
++base
++space
 +y
 +y1
 +y2



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