Hi,

Here are some patches to improve SVG export filter.

0001: Make filter export Gradients and Hatches as SVG <pattern>s.
This tend not to change a visual look but improve semantic structure of a file.
# Actually,hatches go outside of a shape sometimes without this patch.

0003: Make filter export linear and axial gradients as SVG <linearGradient>s.
Use SVG's native gradient instead of polygon fallback.
With this patch, gradient steps of linear and axial gradient are ignored.
In other words, linear and axial gradients are always exported as
"smooth" gradients.
However, as far as I know, the manual steps function is for printing.
So I suppose ignoring gradient steps is safe.

To support native gradients, I need to calculate a bounding box of a gradient.
Currently it is done in OutputDevice::ImplDrawLinearGradient and
OutputDevice::ImplDrawComplexGradient.
So I moved that to Gradient class (0002 patch) to use it in filter code.


0004: Make filter export transparencies as SVG <mask>s.
SVG export filter supports only solid transparency of solid fill (i.e.
color) until now.
The patch extends support to support solid and gradient transparency
of all fill styles.
# Some SVG viewers including WebKit don't support <mask> yet :-(.


The patches are under the LGPLv3+ / MPL.

Cheers,
--
KUROSAWA Takeshi <taken....@gmail.com>
From 6254c025823c829e56fe6b5775c91c014eb2b87c Mon Sep 17 00:00:00 2001
From: Takeshi Kurosawa <taken....@gmail.com>
Date: Wed, 2 Feb 2011 14:31:59 +0900
Subject: [PATCH 1/3] Export hatches and gradients as SVG <pattern>s

This tend not to change a visual look, but improve semantic structure of a file.
---
 filter/source/svg/svgwriter.cxx |   85 +++++++++++++++++++++++++++------------
 filter/source/svg/svgwriter.hxx |    3 +
 2 files changed, 62 insertions(+), 26 deletions(-)

diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index 7765ea5..1599cc6 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -39,6 +39,7 @@
 static const char	aXMLElemG[] = "g";
 static const char	aXMLElemDefs[] = "defs";
 static const char	aXMLElemClipPath[] = "clipPath";
+static const char	aXMLElemPattern[] = "pattern";
 static const char	aXMLElemLine[] = "line";
 static const char	aXMLElemRect[] = "rect";
 static const char	aXMLElemEllipse[] = "ellipse";
@@ -66,6 +67,7 @@ static const char	aXMLAttrRY[] = "ry";
 static const char	aXMLAttrWidth[] = "width";
 static const char	aXMLAttrHeight[] = "height";
 static const char	aXMLAttrPoints[] = "points";
+static const char	aXMLAttrPatternUnits[] = "patternUnits";
 static const char	aXMLAttrXLinkHRef[] = "xlink:href";
 
 static const sal_Unicode pBase64[] = 
@@ -483,7 +485,8 @@ SVGActionWriter::SVGActionWriter( SvXMLExport& rExport, SVGFontExport& rFontExpo
     mrFontExport( rFontExport ),
     mpContext( NULL ),
     mbClipAttrChanged( sal_False ),
-    mnCurClipId( 1 )
+    mnCurClipId( 1 ),
+    mnCurPatternId( 1 )
 {
     mpVDev = new VirtualDevice;
     mpVDev->EnableOutput( sal_False );
@@ -763,48 +766,81 @@ void SVGActionWriter::ImplWritePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bo
 
 // -----------------------------------------------------------------------------
 
-void SVGActionWriter::ImplWriteGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient,
-                                           const NMSP_RTL::OUString* pStyle, sal_uInt32 nWriteFlags )
+void SVGActionWriter::ImplWritePattern( const PolyPolygon& rPolyPoly,
+                                        const Hatch* pHatch,
+                                        const Gradient* pGradient,
+                                        const NMSP_RTL::OUString* pStyle,
+                                        sal_uInt32 nWriteFlags )
 {
     if( rPolyPoly.Count() )
     {
-        SvXMLElementExport	aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, TRUE, TRUE );
-        FastString			aClipId;
-        FastString			aClipStyle;
+        SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, TRUE, TRUE );
 
-        aClipId += B2UCONST( "clip" );
-        aClipId += NMSP_RTL::OUString::valueOf( ImplGetNextClipId() );
+        FastString aPatternId;
+        aPatternId += B2UCONST( "pattern" );
+        aPatternId += GetValueString( ImplGetNextPatternId() );
 
         {
             SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, TRUE, TRUE );
 
-            mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aClipId.GetString() );
+            mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aPatternId.GetString() );
+
+            Rectangle aRect( ImplMap( rPolyPoly.GetBoundRect() ) );
+            mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, GetValueString( aRect.Left() ) );
+            mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, GetValueString( aRect.Top() ) );
+            mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrWidth, GetValueString( aRect.GetWidth() ) );
+            mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrHeight, GetValueString( aRect.GetHeight() ) );
+
+            mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrPatternUnits, NMSP_RTL::OUString( RTL_CONSTASCII_USTRINGPARAM( "userSpaceOnUse") ) );
 
             {
-                SvXMLElementExport aElemClipPath( mrExport, XML_NAMESPACE_NONE, aXMLElemClipPath, TRUE, TRUE );
-                ImplWritePolyPolygon( rPolyPoly, sal_False );
+                SvXMLElementExport aElemPattern( mrExport, XML_NAMESPACE_NONE, aXMLElemPattern, TRUE, TRUE );
+
+                // The origion of a pattern is positioned at (aRect.Left(), aRect.Top())
+                // We need to translate a pattern to (aRect.Left(), aRect.Top())
+                FastString aTransform;
+                aTransform += B2UCONST( "translate" );
+                aTransform += B2UCONST( "(" );
+                aTransform += GetValueString( -aRect.Left() );
+                aTransform += B2UCONST( "," );
+                aTransform += GetValueString( -aRect.Top() );
+                aTransform += B2UCONST( ")" );
+                mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTransform, aTransform.GetString() );
+
+                {
+                    SvXMLElementExport aElemG2( mrExport, XML_NAMESPACE_NONE, aXMLElemG, TRUE, TRUE );
+
+                    GDIMetaFile aTmpMtf;
+                    if( pHatch )
+                        mpVDev->AddHatchActions( rPolyPoly, *pHatch, aTmpMtf );
+                    else if ( pGradient )
+                        mpVDev->AddGradientActions( rPolyPoly.GetBoundRect(), *pGradient, aTmpMtf );
+                    ImplWriteActions( aTmpMtf, pStyle, nWriteFlags );
+                }
             }
         }
 
-        // create new context with clippath set
-        aClipStyle += B2UCONST( "clip-path:URL(#" );
-        aClipStyle += aClipId.GetString();
-        aClipStyle += B2UCONST( ")" );
-
-        mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aClipStyle.GetString() );
+        FastString aPatternStyle;
+        aPatternStyle += B2UCONST( "fill:url(#" );
+        aPatternStyle += aPatternId.GetString();
+        aPatternStyle += B2UCONST( ")" );
 
         {
-            GDIMetaFile			aTmpMtf;
-            SvXMLElementExport	aElemG2( mrExport, XML_NAMESPACE_NONE, aXMLElemG, TRUE, TRUE );
-
-            mpVDev->AddGradientActions( rPolyPoly.GetBoundRect(), rGradient, aTmpMtf );
-            ImplWriteActions( aTmpMtf, pStyle, nWriteFlags );
+            ImplWritePolyPolygon( rPolyPoly, sal_False, &aPatternStyle.GetString() );
         }
     }
 }
 
 // -----------------------------------------------------------------------------
 
+void SVGActionWriter::ImplWriteGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient,
+                                           const NMSP_RTL::OUString* pStyle, sal_uInt32 nWriteFlags )
+{
+    ImplWritePattern( rPolyPoly, NULL, &rGradient, pStyle, nWriteFlags );
+}
+
+// -----------------------------------------------------------------------------
+
 void SVGActionWriter::ImplWriteText( const Point& rPos, const String& rText, 
                                      const sal_Int32* pDXArray, long nWidth,
                                      const NMSP_RTL::OUString* pStyle )
@@ -1409,10 +1445,7 @@ void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
                 if( nWriteFlags & SVGWRITER_WRITE_FILL )
                 {
                     const MetaHatchAction*	pA = (const MetaHatchAction*) pAction;
-                    GDIMetaFile				aTmpMtf;
-
-                    mpVDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
-                    ImplWriteActions( aTmpMtf, pStyle, nWriteFlags );
+                    ImplWritePattern( pA->GetPolyPolygon(), &pA->GetHatch(), NULL, pStyle, nWriteFlags );
                 }
             }
             break;
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index e1467c3..65bb067 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -165,6 +165,7 @@ private:
     SVGAttributeWriter*		mpContext;
     sal_Bool				mbClipAttrChanged;
     sal_Int32				mnCurClipId;
+    sal_Int32				mnCurPatternId;
     Stack					maContextStack;
     VirtualDevice*			mpVDev;
     MapMode					maTargetMapMode;
@@ -185,6 +186,7 @@ private:
     void					ImplWriteRect( const Rectangle& rRect, long nRadX = 0, long nRadY = 0, const ::rtl::OUString* pStyle = NULL );
     void					ImplWriteEllipse( const Point& rCenter, long nRadX, long nRadY, const ::rtl::OUString* pStyle = NULL );
     void					ImplWritePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bool bLineOnly, const ::rtl::OUString* pStyle = NULL );
+    void					ImplWritePattern( const PolyPolygon& rPolyPoly, const Hatch* pHatch, const Gradient* pGradient, const ::rtl::OUString* pStyle, sal_uInt32 nWriteFlags );
     void					ImplWriteGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient, const ::rtl::OUString* pStyle, sal_uInt32 nWriteFlags );
     void					ImplWriteText( const Point& rPos, const String& rText, const sal_Int32* pDXArray, long nWidth, const ::rtl::OUString* pStyle = NULL );
     void                ImplWriteText( const Point& rPos, const String& rText, const sal_Int32* pDXArray, long nWidth, const ::rtl::OUString* pStyle, Color aTextColor );
@@ -195,6 +197,7 @@ private:
     
     void					ImplWriteActions( const GDIMetaFile& rMtf, const ::rtl::OUString* pStyle, sal_uInt32 nWriteFlags );
     sal_Int32				ImplGetNextClipId() { return mnCurClipId++; }
+    sal_Int32				ImplGetNextPatternId() { return mnCurPatternId++; }
 
 public:
 
-- 
1.7.1

From b3ea2556903c07658e748d2bcb80cfd082b9ad7c Mon Sep 17 00:00:00 2001
From: Takeshi Kurosawa <taken....@gmail.com>
Date: Tue, 1 Feb 2011 14:40:58 +0900
Subject: [PATCH] Encapsulate calculation of gradient bounding box to Gradient::GetBoundRect

Export filters need to get gradient bounding box.
---
 vcl/inc/vcl/gradient.hxx    |    3 +
 vcl/source/gdi/gradient.cxx |   93 +++++++++++++++++++++++++++++++++++++++++++
 vcl/source/gdi/outdev4.cxx  |   91 +++++-------------------------------------
 3 files changed, 107 insertions(+), 80 deletions(-)

diff --git a/vcl/inc/vcl/gradient.hxx b/vcl/inc/vcl/gradient.hxx
index 46abd8d..f24ec95 100644
--- a/vcl/inc/vcl/gradient.hxx
+++ b/vcl/inc/vcl/gradient.hxx
@@ -31,6 +31,7 @@
 
 #include <vcl/dllapi.h>
 #include <tools/color.hxx>
+#include <tools/gen.hxx>
 
 #include <vcl/vclenum.hxx>
 
@@ -119,6 +120,8 @@ public:
     void            SetSteps( USHORT nSteps );
     USHORT          GetSteps() const { return mpImplGradient->mnStepCount; }
 
+    void            GetBoundRect( const Rectangle& rRect, Rectangle &rBoundRect, Point& rCenter ) const;
+
     Gradient&       operator=( const Gradient& rGradient );
     BOOL            operator==( const Gradient& rGradient ) const;
     BOOL            operator!=( const Gradient& rGradient ) const
diff --git a/vcl/source/gdi/gradient.cxx b/vcl/source/gdi/gradient.cxx
index d11d62e..297f30d 100644
--- a/vcl/source/gdi/gradient.cxx
+++ b/vcl/source/gdi/gradient.cxx
@@ -245,6 +245,99 @@ void Gradient::SetSteps( USHORT nSteps )
 
 // -----------------------------------------------------------------------
 
+void Gradient::GetBoundRect( const Rectangle& rRect, Rectangle& rBoundRect, Point& rCenter ) const
+{
+    Rectangle aRect( rRect );
+    USHORT nAngle = GetAngle() % 3600;
+
+    if( GetStyle() == GRADIENT_LINEAR || GetStyle() == GRADIENT_AXIAL )
+    {
+        aRect.Left()--;
+        aRect.Top()--;
+        aRect.Right()++;
+        aRect.Bottom()++;
+
+        const double    fAngle = nAngle * F_PI1800;
+        const double    fWidth = aRect.GetWidth();
+        const double    fHeight = aRect.GetHeight();
+        double          fDX = fWidth  * fabs( cos( fAngle ) ) + fHeight * fabs( sin( fAngle ) );
+        double          fDY = fHeight * fabs( cos( fAngle ) ) + fWidth  * fabs( sin( fAngle ) );
+
+        fDX = ( fDX - fWidth  ) * 0.5 + 0.5;
+        fDY = ( fDY - fHeight ) * 0.5 + 0.5;
+
+        aRect.Left()   -= (long) fDX;
+        aRect.Right()  += (long) fDX;
+        aRect.Top()    -= (long) fDY;
+        aRect.Bottom() += (long) fDY;
+
+        rBoundRect = aRect;
+        rCenter = rRect.Center();
+    }
+    else
+    {
+
+        if( GetStyle() == GRADIENT_SQUARE || GetStyle() == GRADIENT_RECT )
+        {
+            const double    fAngle = nAngle * F_PI1800;
+            const double    fWidth = aRect.GetWidth();
+            const double    fHeight = aRect.GetHeight();
+            double          fDX = fWidth  * fabs( cos( fAngle ) ) + fHeight * fabs( sin( fAngle ) );
+            double          fDY = fHeight * fabs( cos( fAngle ) ) + fWidth  * fabs( sin( fAngle ) );
+
+            fDX = ( fDX - fWidth  ) * 0.5 + 0.5;
+            fDY = ( fDY - fHeight ) * 0.5 + 0.5;
+
+            aRect.Left()   -= (long) fDX;
+            aRect.Right()  += (long) fDX;
+            aRect.Top()    -= (long) fDY;
+            aRect.Bottom() += (long) fDY;
+        }
+
+        Size aSize( aRect.GetSize() );
+
+        if( GetStyle() == GRADIENT_RADIAL )
+        {
+            // Radien-Berechnung fuer Kreis
+            aSize.Width() = (long)(0.5 + sqrt((double)aSize.Width()*(double)aSize.Width() + (double)aSize.Height()*(double)aSize.Height()));
+            aSize.Height() = aSize.Width();
+        }
+        else if( GetStyle() == GRADIENT_ELLIPTICAL )
+        {
+            // Radien-Berechnung fuer Ellipse
+            aSize.Width() = (long)( 0.5 + (double) aSize.Width()  * 1.4142 );
+            aSize.Height() = (long)( 0.5 + (double) aSize.Height() * 1.4142 );
+        }
+        else if( GetStyle() == GRADIENT_SQUARE )
+        {
+            if ( aSize.Width() > aSize.Height() )
+                aSize.Height() = aSize.Width();
+            else
+                aSize.Width() = aSize.Height();
+        }
+
+        // neue Mittelpunkte berechnen
+        long    nZWidth = aRect.GetWidth() * (long) GetOfsX() / 100;
+        long    nZHeight = aRect.GetHeight() * (long) GetOfsY() / 100;
+        long    nBorderX = (long) GetBorder() * aSize.Width()  / 100;
+        long    nBorderY = (long) GetBorder() * aSize.Height() / 100;
+        rCenter = Point( aRect.Left() + nZWidth, aRect.Top() + nZHeight );
+
+        // Rand beruecksichtigen
+        aSize.Width() -= nBorderX;
+        aSize.Height() -= nBorderY;
+
+        // Ausgaberechteck neu setzen
+        aRect.Left() = rCenter.X() - ( aSize.Width() >> 1 );
+        aRect.Top() = rCenter.Y() - ( aSize.Height() >> 1 );
+
+        aRect.SetSize( aSize );
+        rBoundRect = rRect;
+    }
+}
+
+// -----------------------------------------------------------------------
+
 Gradient& Gradient::operator=( const Gradient& rGradient )
 {
     DBG_CHKTHIS( Gradient, NULL );
diff --git a/vcl/source/gdi/outdev4.cxx b/vcl/source/gdi/outdev4.cxx
index e550225..cc6facf 100644
--- a/vcl/source/gdi/outdev4.cxx
+++ b/vcl/source/gdi/outdev4.cxx
@@ -175,42 +175,25 @@ void OutputDevice::ImplDrawLinearGradient( const Rectangle& rRect,
                                            BOOL bMtf, const PolyPolygon* pClipPolyPoly )
 {
     // rotiertes BoundRect ausrechnen
-    Rectangle aRect = rRect;
-    aRect.Left()--;
-    aRect.Top()--;
-    aRect.Right()++;
-    aRect.Bottom()++;
-    USHORT	nAngle = rGradient.GetAngle() % 3600;
-    double	fAngle	= nAngle * F_PI1800;
-    double	fWidth	= aRect.GetWidth();
-    double	fHeight = aRect.GetHeight();
-    double	fDX 	= fWidth  * fabs( cos( fAngle ) ) +
-                      fHeight * fabs( sin( fAngle ) );
-    double	fDY 	= fHeight * fabs( cos( fAngle ) ) +
-                      fWidth  * fabs( sin( fAngle ) );
-            fDX 	= (fDX - fWidth)  * 0.5 + 0.5;
-            fDY 	= (fDY - fHeight) * 0.5 + 0.5;
-    aRect.Left()   -= (long)fDX;
-    aRect.Right()  += (long)fDX;
-    aRect.Top()    -= (long)fDY;
-    aRect.Bottom() += (long)fDY;
+    Rectangle aRect;
+    Point     aCenter;
+    USHORT    nAngle = rGradient.GetAngle() % 3600;
+
+    rGradient.GetBoundRect( rRect, aRect, aCenter );
 
     // Rand berechnen und Rechteck neu setzen
-    Point		aCenter = rRect.Center();
     Rectangle	aFullRect = aRect;
     long		nBorder = (long)rGradient.GetBorder() * aRect.GetHeight() / 100;
-    BOOL		bLinear;
 
     // Rand berechnen und Rechteck neu setzen fuer linearen Farbverlauf
-    if ( rGradient.GetStyle() == GRADIENT_LINEAR )
+    bool bLinear = (rGradient.GetStyle() == GRADIENT_LINEAR);
+    if ( bLinear )
     {
-        bLinear = TRUE;
         aRect.Top() += nBorder;
     }
     // Rand berechnen und Rechteck neu setzen fuer axiale Farbverlauf
     else
     {
-        bLinear = FALSE;
         nBorder >>= 1;
 
         aRect.Top()    += nBorder;
@@ -430,7 +413,8 @@ void OutputDevice::ImplDrawComplexGradient( const Rectangle& rRect,
     // Virtuelle Device werden auch ausgeklammert, da einige Treiber
     // ansonsten zu langsam sind
     PolyPolygon*    pPolyPoly;
-    Rectangle	    aRect( rRect );
+    Rectangle       aRect;
+    Point           aCenter;
     Color			aStartCol( rGradient.GetStartColor() );
     Color			aEndCol( rGradient.GetEndColor() );
     long			nStartRed = ( (long) aStartCol.GetRed() * rGradient.GetStartIntensity() ) / 100;
@@ -444,67 +428,14 @@ void OutputDevice::ImplDrawComplexGradient( const Rectangle& rRect,
     long			nBlueSteps = nEndBlue	- nStartBlue;
     long            nStepCount = rGradient.GetSteps();
     USHORT	        nAngle = rGradient.GetAngle() % 3600;
+
+    rGradient.GetBoundRect( rRect, aRect, aCenter );
     
     if( (meRasterOp != ROP_OVERPAINT) || (meOutDevType != OUTDEV_WINDOW) || bMtf )
         pPolyPoly = new PolyPolygon( 2 );
     else
         pPolyPoly = NULL;
 
-    if( rGradient.GetStyle() == GRADIENT_SQUARE || rGradient.GetStyle() == GRADIENT_RECT )
-    {
-        const double    fAngle	= nAngle * F_PI1800;
-        const double    fWidth	= aRect.GetWidth();
-        const double    fHeight = aRect.GetHeight();
-        double          fDX = fWidth  * fabs( cos( fAngle ) ) + fHeight * fabs( sin( fAngle ) ); 
-        double          fDY = fHeight * fabs( cos( fAngle ) ) + fWidth  * fabs( sin( fAngle ) ); 
-
-        fDX = ( fDX - fWidth ) * 0.5 + 0.5;
-        fDY = ( fDY - fHeight ) * 0.5 + 0.5;
-    
-        aRect.Left() -= (long) fDX;
-        aRect.Right() += (long) fDX;
-        aRect.Top() -= (long) fDY;
-        aRect.Bottom() += (long) fDY;
-    }
-    
-    Size aSize( aRect.GetSize() );
-    
-    if( rGradient.GetStyle() == GRADIENT_RADIAL )
-    {
-        // Radien-Berechnung fuer Kreis
-        aSize.Width() = (long)(0.5 + sqrt((double)aSize.Width()*(double)aSize.Width() + (double)aSize.Height()*(double)aSize.Height()));
-        aSize.Height() = aSize.Width();
-    }
-    else if( rGradient.GetStyle() == GRADIENT_ELLIPTICAL )
-    {
-        // Radien-Berechnung fuer Ellipse
-        aSize.Width() = (long)( 0.5 + (double) aSize.Width()  * 1.4142 );
-        aSize.Height() = (long)( 0.5 + (double) aSize.Height() * 1.4142 );
-    }
-    else if( rGradient.GetStyle() == GRADIENT_SQUARE )
-    {
-        if ( aSize.Width() > aSize.Height() )
-            aSize.Height() = aSize.Width();
-        else
-            aSize.Width() = aSize.Height();
-    }
-
-    // neue Mittelpunkte berechnen
-    long	nZWidth = aRect.GetWidth()	* (long) rGradient.GetOfsX() / 100;
-    long	nZHeight = aRect.GetHeight() * (long) rGradient.GetOfsY() / 100;
-    long	nBorderX = (long) rGradient.GetBorder() * aSize.Width()  / 100;
-    long	nBorderY = (long) rGradient.GetBorder() * aSize.Height() / 100;
-    Point	aCenter( aRect.Left() + nZWidth, aRect.Top() + nZHeight );
-
-    // Rand beruecksichtigen
-    aSize.Width() -= nBorderX;
-    aSize.Height() -= nBorderY;
-
-    // Ausgaberechteck neu setzen
-    aRect.Left() = aCenter.X() - ( aSize.Width() >> 1 );
-    aRect.Top() = aCenter.Y() - ( aSize.Height() >> 1 );
-    
-    aRect.SetSize( aSize );
     long nMinRect = Min( aRect.GetWidth(), aRect.GetHeight() );
 
     // Anzahl der Schritte berechnen, falls nichts uebergeben wurde
-- 
1.7.1

From 9ef0b3c56099a6c58a1347574115d803c2071ee6 Mon Sep 17 00:00:00 2001
From: Takeshi Kurosawa <taken....@gmail.com>
Date: Wed, 2 Feb 2011 14:35:20 +0900
Subject: [PATCH 2/3] Export linear and axial gradient as SVG <linearGradient>

With this patch, gradient steps of linear and axial are ignored.
In other words, theose gradients are always exported as "smooth" gradients.
---
 filter/source/svg/svgwriter.cxx |  141 ++++++++++++++++++++++++++++++++++-----
 filter/source/svg/svgwriter.hxx |    5 ++
 2 files changed, 130 insertions(+), 16 deletions(-)

diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index 1599cc6..ab5bd3b 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -40,6 +40,8 @@ static const char	aXMLElemG[] = "g";
 static const char	aXMLElemDefs[] = "defs";
 static const char	aXMLElemClipPath[] = "clipPath";
 static const char	aXMLElemPattern[] = "pattern";
+static const char	aXMLElemLinearGradient[] = "linearGradient";
+static const char	aXMLElemStop[] = "stop";
 static const char	aXMLElemLine[] = "line";
 static const char	aXMLElemRect[] = "rect";
 static const char	aXMLElemEllipse[] = "ellipse";
@@ -68,6 +70,8 @@ static const char	aXMLAttrWidth[] = "width";
 static const char	aXMLAttrHeight[] = "height";
 static const char	aXMLAttrPoints[] = "points";
 static const char	aXMLAttrPatternUnits[] = "patternUnits";
+static const char	aXMLAttrGradientUnits[] = "gradientUnits";
+static const char	aXMLAttrOffset[] = "offset";
 static const char	aXMLAttrXLinkHRef[] = "xlink:href";
 
 static const sal_Unicode pBase64[] = 
@@ -331,6 +335,22 @@ NMSP_RTL::OUString SVGAttributeWriter::GetFontStyle( const Font& rFont )
 
 // -----------------------------------------------------------------------------
 
+NMSP_RTL::OUString SVGAttributeWriter::GetColorStyle( const Color& rColor,
+                                                      USHORT nIntensity )
+{
+    FastString aStyle;
+    aStyle += B2UCONST( "rgb(" );
+    aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rColor.GetRed() * nIntensity / 100L );
+    aStyle += B2UCONST( "," );
+    aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rColor.GetGreen() * nIntensity / 100L );
+    aStyle += B2UCONST( "," );
+    aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rColor.GetBlue()  * nIntensity / 100L );
+    aStyle += B2UCONST( ")" );
+    return aStyle.GetString();
+}
+
+// -----------------------------------------------------------------------------
+
 NMSP_RTL::OUString SVGAttributeWriter::GetPaintStyle( const Color& rLineColor, const Color& rFillColor, const LineInfo* pLineInfo )
 {
     FastString aStyle;
@@ -343,13 +363,7 @@ NMSP_RTL::OUString SVGAttributeWriter::GetPaintStyle( const Color& rLineColor, c
     else
     {
         // line color value in rgb
-        aStyle += B2UCONST( "rgb(" );
-        aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rLineColor.GetRed() );
-        aStyle += B2UCONST( "," );
-        aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rLineColor.GetGreen() );
-        aStyle += B2UCONST( "," );
-        aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rLineColor.GetBlue() );
-        aStyle += B2UCONST( ")" );
+        aStyle += GetColorStyle( rLineColor );
 
         // line color opacity in percent if neccessary
         if( rLineColor.GetTransparency() )
@@ -431,13 +445,7 @@ NMSP_RTL::OUString SVGAttributeWriter::GetPaintStyle( const Color& rLineColor, c
     else
     {
         // fill color value in rgb
-        aStyle += B2UCONST( "rgb(" );
-        aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rFillColor.GetRed() );
-        aStyle += B2UCONST( "," );
-        aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rFillColor.GetGreen() );
-        aStyle += B2UCONST( "," );
-        aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rFillColor.GetBlue() );
-        aStyle += B2UCONST( ")" );
+        aStyle += GetColorStyle( rFillColor );
 
         // fill color opacity in percent if neccessary
         if( rFillColor.GetTransparency() )
@@ -486,7 +494,8 @@ SVGActionWriter::SVGActionWriter( SvXMLExport& rExport, SVGFontExport& rFontExpo
     mpContext( NULL ),
     mbClipAttrChanged( sal_False ),
     mnCurClipId( 1 ),
-    mnCurPatternId( 1 )
+    mnCurPatternId( 1 ),
+    mnCurGradientId( 1 )
 {
     mpVDev = new VirtualDevice;
     mpVDev->EnableOutput( sal_False );
@@ -836,7 +845,107 @@ void SVGActionWriter::ImplWritePattern( const PolyPolygon& rPolyPoly,
 void SVGActionWriter::ImplWriteGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient,
                                            const NMSP_RTL::OUString* pStyle, sal_uInt32 nWriteFlags )
 {
-    ImplWritePattern( rPolyPoly, NULL, &rGradient, pStyle, nWriteFlags );
+    if ( rGradient.GetStyle() == GRADIENT_LINEAR ||
+         rGradient.GetStyle() == GRADIENT_AXIAL )
+    {
+        ImplWriteGradientLinear( rPolyPoly, rGradient );
+    }
+    else
+    {
+        ImplWritePattern( rPolyPoly, NULL, &rGradient, pStyle, nWriteFlags );
+    }
+}
+
+void SVGActionWriter::ImplWriteGradientLinear( const PolyPolygon& rPolyPoly,
+                                               const Gradient& rGradient )
+{
+    if( rPolyPoly.Count() )
+    {
+        SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, TRUE, TRUE );
+
+        FastString aGradientId;
+        aGradientId += B2UCONST( "gradient" );
+        aGradientId += GetValueString( ImplGetNextGradientId() );
+
+        {
+            SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, TRUE, TRUE );
+
+            mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aGradientId.GetString() );
+            {
+                Rectangle aTmpRect;
+                Point aTmpCenter;
+                rGradient.GetBoundRect( rPolyPoly.GetBoundRect(), aTmpRect, aTmpCenter );
+                const Rectangle aRect( ImplMap( aTmpRect) );
+                const Point aCenter( ImplMap( aTmpCenter) );
+                const USHORT nAngle = rGradient.GetAngle() % 3600;
+
+                Polygon aPoly( 2 );
+                aPoly[ 0 ].X() = aPoly[ 1 ].X() = aRect.Left();
+                aPoly[ 0 ].Y() = aRect.Top();
+                aPoly[ 1 ].Y() = aRect.Bottom();
+                aPoly.Rotate( aCenter, nAngle );
+
+                mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, GetValueString( aPoly[ 0 ].X() ) );
+                mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, GetValueString( aPoly[ 0 ].Y() ) );
+                mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, GetValueString( aPoly[ 1 ].X() ) );
+                mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, GetValueString( aPoly[ 1 ].Y() ) );
+
+                mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits, NMSP_RTL::OUString( RTL_CONSTASCII_USTRINGPARAM( "userSpaceOnUse" ) ) );
+            }
+
+            {
+                SvXMLElementExport aElemLinearGradient( mrExport, XML_NAMESPACE_NONE, aXMLElemLinearGradient, TRUE, TRUE );
+
+                if( rGradient.GetStyle() == GRADIENT_LINEAR )
+                {
+                    ImplWriteGradientStop( rGradient.GetStartColor(),
+                                           rGradient.GetStartIntensity(),
+                                           rGradient.GetBorder() / 100.0 );
+                    ImplWriteGradientStop( rGradient.GetEndColor(),
+                                           rGradient.GetEndIntensity(),
+                                           1.0 );
+                }
+                else
+                {
+                    ImplWriteGradientStop( rGradient.GetEndColor(),
+                                           rGradient.GetEndIntensity(),
+                                           rGradient.GetBorder() / 200.0 );
+                    ImplWriteGradientStop( rGradient.GetStartColor(),
+                                           rGradient.GetStartIntensity(),
+                                           0.5 );
+                    ImplWriteGradientStop( rGradient.GetEndColor(),
+                                           rGradient.GetEndIntensity(),
+                                           1.0 - rGradient.GetBorder() / 200.0 );
+                }
+            }
+        }
+
+        FastString aGradientStyle;
+        aGradientStyle += B2UCONST( "fill:" );
+        aGradientStyle += B2UCONST( "url(#" );
+        aGradientStyle += aGradientId.GetString();
+        aGradientStyle += B2UCONST( ")" );
+
+        {
+            ImplWritePolyPolygon( rPolyPoly, sal_False, &aGradientStyle.GetString() );
+        }
+    }
+}
+
+void SVGActionWriter::ImplWriteGradientStop( const Color& rColor,
+                                             USHORT nIntensity,
+                                             double fOffset )
+{
+    mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, NMSP_RTL::OUString::valueOf( fOffset ) );
+
+    FastString aStyle;
+    aStyle += B2UCONST( "stop-color:" );
+    aStyle += mpContext->GetColorStyle ( rColor, nIntensity );
+
+    mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aStyle.GetString() );
+    {
+        SvXMLElementExport aElemStartStop( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, TRUE, TRUE );
+    }
 }
 
 // -----------------------------------------------------------------------------
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index 65bb067..103bdee 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -142,6 +142,7 @@ public:
     virtual					~SVGAttributeWriter();
 
     ::rtl::OUString			GetFontStyle( const Font& rFont );
+    ::rtl::OUString			GetColorStyle( const Color& rColor, USHORT nItensity = 100 );
     ::rtl::OUString			GetPaintStyle( const Color& rLineColor, const Color& rFillColor, const LineInfo* pLineInfo );
 
     void					SetFontAttr( const Font& rFont );
@@ -166,6 +167,7 @@ private:
     sal_Bool				mbClipAttrChanged;
     sal_Int32				mnCurClipId;
     sal_Int32				mnCurPatternId;
+    sal_Int32				mnCurGradientId;
     Stack					maContextStack;
     VirtualDevice*			mpVDev;
     MapMode					maTargetMapMode;
@@ -188,6 +190,8 @@ private:
     void					ImplWritePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bool bLineOnly, const ::rtl::OUString* pStyle = NULL );
     void					ImplWritePattern( const PolyPolygon& rPolyPoly, const Hatch* pHatch, const Gradient* pGradient, const ::rtl::OUString* pStyle, sal_uInt32 nWriteFlags );
     void					ImplWriteGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient, const ::rtl::OUString* pStyle, sal_uInt32 nWriteFlags );
+    void					ImplWriteGradientLinear( const PolyPolygon& rPolyPoly, const Gradient& rGradient );
+    void					ImplWriteGradientStop( const Color& rColor, USHORT nIntensity, double fOffset );
     void					ImplWriteText( const Point& rPos, const String& rText, const sal_Int32* pDXArray, long nWidth, const ::rtl::OUString* pStyle = NULL );
     void                ImplWriteText( const Point& rPos, const String& rText, const sal_Int32* pDXArray, long nWidth, const ::rtl::OUString* pStyle, Color aTextColor );
     void					ImplWriteBmp( const BitmapEx& rBmpEx, const Point& rPt, const Size& rSz, const Point& rSrcPt, const Size& rSrcSz, const ::rtl::OUString* pStyle = NULL );
@@ -198,6 +202,7 @@ private:
     void					ImplWriteActions( const GDIMetaFile& rMtf, const ::rtl::OUString* pStyle, sal_uInt32 nWriteFlags );
     sal_Int32				ImplGetNextClipId() { return mnCurClipId++; }
     sal_Int32				ImplGetNextPatternId() { return mnCurPatternId++; }
+    sal_Int32				ImplGetNextGradientId() { return mnCurGradientId++; }
 
 public:
 
-- 
1.7.1

From 84ae44fd034700fb9c55000bf85ca893c06edd67 Mon Sep 17 00:00:00 2001
From: Takeshi Kurosawa <taken....@gmail.com>
Date: Wed, 2 Feb 2011 14:38:31 +0900
Subject: [PATCH 3/3] Export transparencies as SVg <mask>s

SVG export filter supports only solid transparency of solid fill (i.e. color) until now.
This patch extends support to solid and gradient transparency of all fill styles.
---
 filter/source/svg/svgwriter.cxx |   94 +++++++++++++++++++++++++++++---------
 filter/source/svg/svgwriter.hxx |    3 +
 2 files changed, 74 insertions(+), 23 deletions(-)

diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index ab5bd3b..f88c36c 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -39,6 +39,7 @@
 static const char	aXMLElemG[] = "g";
 static const char	aXMLElemDefs[] = "defs";
 static const char	aXMLElemClipPath[] = "clipPath";
+static const char	aXMLElemMask[] = "mask";
 static const char	aXMLElemPattern[] = "pattern";
 static const char	aXMLElemLinearGradient[] = "linearGradient";
 static const char	aXMLElemStop[] = "stop";
@@ -495,7 +496,8 @@ SVGActionWriter::SVGActionWriter( SvXMLExport& rExport, SVGFontExport& rFontExpo
     mbClipAttrChanged( sal_False ),
     mnCurClipId( 1 ),
     mnCurPatternId( 1 ),
-    mnCurGradientId( 1 )
+    mnCurGradientId( 1 ),
+    mnCurMaskId( 1 )
 {
     mpVDev = new VirtualDevice;
     mpVDev->EnableOutput( sal_False );
@@ -949,6 +951,72 @@ void SVGActionWriter::ImplWriteGradientStop( const Color& rColor,
 }
 
 // -----------------------------------------------------------------------------
+void SVGActionWriter::ImplWriteMask( GDIMetaFile& rMtf,
+                                     const Point& rDestPt,
+                                     const Size& rDestSize,
+                                     const Gradient& rGradient,
+                                     const NMSP_RTL::OUString* pStyle,
+                                     sal_uInt32 nWriteFlags )
+{
+    Point          aSrcPt( rMtf.GetPrefMapMode().GetOrigin() );
+    const Size     aSrcSize( rMtf.GetPrefSize() );
+    const double   fScaleX = aSrcSize.Width() ? (double) rDestSize.Width() / aSrcSize.Width() : 1.0;
+    const double   fScaleY = aSrcSize.Height() ? (double) rDestSize.Height() / aSrcSize.Height() : 1.0;
+    long           nMoveX, nMoveY;
+
+    if( fScaleX != 1.0 || fScaleY != 1.0 )
+    {
+        rMtf.Scale( fScaleX, fScaleY );
+        aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
+    }
+
+    nMoveX = rDestPt.X() - aSrcPt.X(), nMoveY = rDestPt.Y() - aSrcPt.Y();
+
+    if( nMoveX || nMoveY )
+        rMtf.Move( nMoveX, nMoveY );
+
+    FastString aMaskId;
+    aMaskId += B2UCONST( "mask" );
+    aMaskId += GetValueString( ImplGetNextMaskId() );
+
+    {
+        SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, TRUE, TRUE );
+
+        mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aMaskId.GetString() );
+        {
+            SvXMLElementExport aElemMask( mrExport, XML_NAMESPACE_NONE, aXMLElemMask, TRUE, TRUE );
+
+            PolyPolygon aPolyPolygon( PolyPolygon( Rectangle( rDestPt, rDestSize ) ) );
+            Gradient aGradient( rGradient );
+
+            // swap gradient stops to adopt SVG mask
+            Color tmpColor( aGradient.GetStartColor() );
+            USHORT tmpIntensity( aGradient.GetStartIntensity() );
+            aGradient.SetStartColor( aGradient.GetEndColor() );
+            aGradient.SetStartIntensity( aGradient.GetEndIntensity()) ;
+            aGradient.SetEndColor( tmpColor );
+            aGradient.SetEndIntensity( tmpIntensity );
+
+            ImplWriteGradientEx( aPolyPolygon, aGradient, pStyle, nWriteFlags );
+        }
+    }
+
+    FastString aMaskStyle;
+    aMaskStyle += B2UCONST( "mask:url(#" );
+    aMaskStyle += aMaskId.GetString();
+    aMaskStyle += B2UCONST( ")" );
+    mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aMaskStyle.GetString() );
+
+    {
+        SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, TRUE, TRUE );
+
+        mpVDev->Push();
+        ImplWriteActions( rMtf, pStyle, nWriteFlags );
+        mpVDev->Pop();
+    }
+}
+
+// -----------------------------------------------------------------------------
 
 void SVGActionWriter::ImplWriteText( const Point& rPos, const String& rText, 
                                      const sal_Int32* pDXArray, long nWidth,
@@ -1588,28 +1656,8 @@ void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
                 {
                     const MetaFloatTransparentAction*	pA = (const MetaFloatTransparentAction*) pAction;
                     GDIMetaFile							aTmpMtf( pA->GetGDIMetaFile() );
-                    Point								aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
-                    const Size							aSrcSize( aTmpMtf.GetPrefSize() );
-                    const Point							aDestPt( pA->GetPoint() );
-                    const Size							aDestSize( pA->GetSize() );
-                    const double						fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0;
-                    const double						fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0;
-                    long								nMoveX, nMoveY;
-
-                    if( fScaleX != 1.0 || fScaleY != 1.0 )
-                    {
-                        aTmpMtf.Scale( fScaleX, fScaleY );
-                        aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
-                    }
-
-                    nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y();
-
-                    if( nMoveX || nMoveY )
-                        aTmpMtf.Move( nMoveX, nMoveY );
-
-                    mpVDev->Push();
-                    ImplWriteActions( aTmpMtf, pStyle, nWriteFlags );
-                    mpVDev->Pop();
+                    ImplWriteMask( aTmpMtf, pA->GetPoint(), pA->GetSize(),
+                                   pA->GetGradient(), pStyle, nWriteFlags  );
                 }
             }
             break;
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index 103bdee..90fae3d 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -168,6 +168,7 @@ private:
     sal_Int32				mnCurClipId;
     sal_Int32				mnCurPatternId;
     sal_Int32				mnCurGradientId;
+    sal_Int32				mnCurMaskId;
     Stack					maContextStack;
     VirtualDevice*			mpVDev;
     MapMode					maTargetMapMode;
@@ -192,6 +193,7 @@ private:
     void					ImplWriteGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient, const ::rtl::OUString* pStyle, sal_uInt32 nWriteFlags );
     void					ImplWriteGradientLinear( const PolyPolygon& rPolyPoly, const Gradient& rGradient );
     void					ImplWriteGradientStop( const Color& rColor, USHORT nIntensity, double fOffset );
+    void					ImplWriteMask( GDIMetaFile& rMtf, const Point& rDestPt, const Size& rDestSize, const Gradient& rGradient, const ::rtl::OUString* pStyle, sal_uInt32 nWriteFlags );
     void					ImplWriteText( const Point& rPos, const String& rText, const sal_Int32* pDXArray, long nWidth, const ::rtl::OUString* pStyle = NULL );
     void                ImplWriteText( const Point& rPos, const String& rText, const sal_Int32* pDXArray, long nWidth, const ::rtl::OUString* pStyle, Color aTextColor );
     void					ImplWriteBmp( const BitmapEx& rBmpEx, const Point& rPt, const Size& rSz, const Point& rSrcPt, const Size& rSrcSz, const ::rtl::OUString* pStyle = NULL );
@@ -203,6 +205,7 @@ private:
     sal_Int32				ImplGetNextClipId() { return mnCurClipId++; }
     sal_Int32				ImplGetNextPatternId() { return mnCurPatternId++; }
     sal_Int32				ImplGetNextGradientId() { return mnCurGradientId++; }
+    sal_Int32				ImplGetNextMaskId() { return mnCurMaskId++; }
 
 public:
 
-- 
1.7.1

_______________________________________________
LibreOffice mailing list
LibreOffice@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libreoffice

Reply via email to