ooo-build r12668 - in branches/ooo-build-2-4-1: . patches/src680



Author: thorstenb
Date: Mon May 26 14:25:11 2008
New Revision: 12668
URL: http://svn.gnome.org/viewvc/ooo-build?rev=12668&view=rev

Log:
	* patches/src680/svg-import-filter.diff: made text import actually
	work with auto-width/height, added gradient support (currently
	mapping more-than-two color gradients to ODF's two colors). Added
	standalone svg2svm conversion tool, and a unit test for the spirit
	attribute parsers



Modified:
   branches/ooo-build-2-4-1/ChangeLog
   branches/ooo-build-2-4-1/patches/src680/svg-import-filter.diff

Modified: branches/ooo-build-2-4-1/patches/src680/svg-import-filter.diff
==============================================================================
--- branches/ooo-build-2-4-1/patches/src680/svg-import-filter.diff	(original)
+++ branches/ooo-build-2-4-1/patches/src680/svg-import-filter.diff	Mon May 26 14:25:11 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
@@ -499,10 +538,10 @@
 +        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
@@ -1794,7 +1849,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,1888 @@
 +/*************************************************************************
 + *
 + *    OpenOffice.org - a multi-platform office productivity suite
@@ -1900,6 +1955,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,
@@ -1911,9 +1982,8 @@
 +        mrStates(rStatePool),
 +        mrStateMap(rStateMap),
 +        mxDocumentHandler(xDocumentHandler),
-+		mpCurrentGradient(NULL),
-+		mpCurrentGradientStop(NULL),
-+		mxGradientVector()
++		maGradientVector(),
++        maGradientStopVector()
 +    {
 +        State aState;
 +        aState.maCTM = aState.maTransform;
@@ -1926,31 +1996,95 @@
 +    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;
++
++				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;
++
 +				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;
 +			}
@@ -2016,6 +2150,84 @@
 +        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.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
@@ -2047,7 +2259,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() );
@@ -2064,8 +2276,87 @@
 +        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:start" ), 
++                                      rtl::OUString::valueOf(
++                                          maGradientStopVector[
++                                              rState.maFillGradient.maStops[0]].maStopColor.a*
++                                          maCurrState.mnFillOpacity*100.0)+USTR("%" ) );
++                xAttrs->AddAttribute( USTR( "draw:end" ), 
++                                      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"), 
@@ -2074,10 +2365,29 @@
 +        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));
++            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"));
@@ -2085,20 +2395,16 @@
 +        if( rState.meStrokeType != NONE )
 +        {
 +            xAttrs->AddAttribute( USTR( "draw:stroke" ), USTR("solid"));
-+            xAttrs->AddAttribute( USTR( "svg:stroke-color" ), getOdfColor(rState.maStrokeColor));
++            xAttrs->AddAttribute( USTR( "draw: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"));
@@ -2107,16 +2413,18 @@
 +        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));
++            xAttrs->AddAttribute( USTR("svg:stroke-opacity"), 
++                                  rtl::OUString::valueOf(100.0*maCurrState.mnStrokeOpacity)+USTR("%"));
 +
 +        // beef up text box style with some auto-magic
 +        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"));
@@ -2131,7 +2439,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() && 
@@ -2150,14 +2458,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;
@@ -2180,53 +2488,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 );
@@ -2280,6 +2650,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" )
@@ -2339,10 +2715,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,
@@ -2354,7 +2737,8 @@
 +            case XML_STROKE:
 +            {
 +                const State& rParent( maParentStates.back() );
-+                parsePaint( aValueUtf8.getStr(),
++                parsePaint( sValue,
++                            aValueUtf8.getStr(),
 +                            maCurrState.meStrokeType,
 +                            maCurrState.maStrokeColor,
 +                            maCurrState.maStrokeGradient,
@@ -2389,10 +2773,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));
@@ -2426,7 +2820,8 @@
 +        while( nIndex != -1 );
 +    }
 +
-+    void parsePaint( const char*      sValue, 
++    void parsePaint( const rtl::OUString& rValue,
++                     const char*      sValue, 
 +                     PaintType&       rType,
 +                     ARGBColor&       rColor,
 +                     Gradient&        rGradient,
@@ -2447,8 +2842,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
 +        { 
@@ -2457,15 +2863,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
@@ -2813,15 +3220,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);
@@ -3357,6 +3784,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 @@
@@ -3459,7 +4533,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)
@@ -3584,7 +4658,6 @@
 +dur
 +editable
 +end
-+ev:event
 +event
 +externalResourcesRequired
 +fill
@@ -3596,9 +4669,12 @@
 +font-variant
 +font-weight
 +from
++fx
++fy
 +g1
 +g2
 +glyph-name
++gradientTransform
 +gradientUnits
 +handler
 +hanging
@@ -3691,17 +4767,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]