Date: prev next · Thread: first prev next last
2011 Archives by date, by thread · List index


Hi, Throsten,

I express thanks for your review.
I was bit busy with school work. But here are updated patches.
0001 and 0003 are almost same as previous.

2011/2/2 Thorsten Behrens <thb@documentfoundation.org>:
Nope, this is still in use, especially in legacy binary documents
(soon to be axed I guess), and more importantly, for all those svm
metafiles. Could you keep both code paths - i.e. falling back to the
old code, should there be a step count (with 0 meaning smooth
gradient, and maybe you can even cut off at something like 100 or so
steps)?

I found the way to reproduce the stepping gradients with native gradients.
# Simply adding gradient stops as needed.
So 0002 patch uses native gradients for both smooth and non-smooth gradients.


A bit orthogonal to this great improvement, let me point you to
https://github.com/knobo/OOo-svg-Export.git - this is an early stage
of a slightly different attempt, using the new drawing layer
primitives (that contain more high-level geometry information, like
stroking etc.). I attach two changes I had lying around locally -
maybe you're also interested in looking into that.

It's very interesting and has a potential to resolve many long standing issues.
While it's really attractive, I would like to continue to improve the
current filter.
LibreOffice and its predecessors have never produced an SVG
preserving, at least, visual appearances.
Improving the current filter is the shortest path to make LibreOffice
export visual identical SVG files in a short term.
# I know the structure of an SVG produced by the current filter is mess.

Cheers,

--
Kurosawa Takeshi <taken.spc@gmail.com>
From ba06cca17ff6fd112d8fd4ee9a16176c34de5205 Mon Sep 17 00:00:00 2001
From: Kurosawa Takeshi <taken.spc@gmail.com>
Date: Fri, 11 Feb 2011 18:55:42 +0900
Subject: [PATCH 1/3] Export hatches and gradients as SVG <pattern>s

This patch tends not to improve a visual look, but improve semantic
structure of an exported 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 b33e84a..b0e2a0f 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";
 
 // --------------
@@ -379,7 +381,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 );
@@ -659,48 +662,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 origin of a pattern is positioned at (aRect.Left(), aRect.Top()).
+                // So we need to adjust the pattern coordinate.
+                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 )
@@ -1267,10 +1303,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 dfdc559..6ec2452 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -163,6 +163,7 @@ private:
     SVGAttributeWriter*                mpContext;
     sal_Bool                           mbClipAttrChanged;
     sal_Int32                          mnCurClipId;
+    sal_Int32                          mnCurPatternId;
     Stack                                      maContextStack;
     VirtualDevice*                     mpVDev;
     MapMode                                    maTargetMapMode;
@@ -183,6 +184,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 );
@@ -193,6 +195,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 a22a8ba96005850eeb4d44dd64d727e34b2e3c4f Mon Sep 17 00:00:00 2001
From: Kurosawa Takeshi <taken.spc@gmail.com>
Date: Fri, 11 Feb 2011 19:23:10 +0900
Subject: [PATCH 2/3] Export linear and axial gradients as SVG <linearGraidents>s

---
 filter/source/svg/svgwriter.cxx |  203 +++++++++++++++++++++++++++++++++++---
 filter/source/svg/svgwriter.hxx |    7 ++
 2 files changed, 194 insertions(+), 16 deletions(-)

diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index b0e2a0f..15a61e7 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";
 
 // --------------
@@ -227,6 +231,21 @@ NMSP_RTL::OUString SVGAttributeWriter::GetFontStyle( const Font& rFont )
 
 // -----------------------------------------------------------------------------
 
+NMSP_RTL::OUString SVGAttributeWriter::GetColorStyle( const Color& rColor )
+{
+    FastString aStyle;
+    aStyle += B2UCONST( "rgb(" );
+    aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rColor.GetRed() );
+    aStyle += B2UCONST( "," );
+    aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rColor.GetGreen() );
+    aStyle += B2UCONST( "," );
+    aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rColor.GetBlue() );
+    aStyle += B2UCONST( ")" );
+    return aStyle.GetString();
+}
+
+// -----------------------------------------------------------------------------
+
 NMSP_RTL::OUString SVGAttributeWriter::GetPaintStyle( const Color& rLineColor, const Color& 
rFillColor, const LineInfo* pLineInfo )
 {
     FastString aStyle;
@@ -239,13 +258,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() )
@@ -327,13 +340,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() )
@@ -382,7 +389,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 );
@@ -732,7 +740,170 @@ 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 sal_uInt16 nAngle = rGradient.GetAngle() % 3600;
+
+                Polygon aPoly( 2 );
+                // Setting x value of a gradient vector to rotation center to
+                // place a gradient vector in a target polygon.
+                // This would help editing it in SVG editors like inkscape.
+                aPoly[ 0 ].X() = aPoly[ 1 ].X() = aCenter.X();
+                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 );
+
+                const Color aStartColor = ImplGetColorWithIntensity( rGradient.GetStartColor(), 
rGradient.GetStartIntensity() );
+                const Color aEndColor = ImplGetColorWithIntensity( rGradient.GetEndColor(), 
rGradient.GetEndIntensity() );
+                double fBorderOffset = rGradient.GetBorder() / 100.0;
+                const sal_uInt16 nSteps = rGradient.GetSteps();
+                if( rGradient.GetStyle() == GRADIENT_LINEAR )
+                {
+                    // Emulate non-smooth gradient
+                    if( 0 < nSteps && nSteps < 100 )
+                    {
+                        double fOffsetStep = ( 1.0 - fBorderOffset ) / (double)nSteps;
+                        for( sal_uInt16 i = 0; i < nSteps; i++ ) {
+                            Color aColor = ImplGetGradientColor( aStartColor, aEndColor, i / 
(double) nSteps );
+                            ImplWriteGradientStop( aColor, fBorderOffset + ( i + 1 ) * fOffsetStep 
);
+                            aColor = ImplGetGradientColor( aStartColor, aEndColor, ( i + 1 ) / 
(double) nSteps );
+                            ImplWriteGradientStop( aColor, fBorderOffset + ( i + 1 ) * fOffsetStep 
);
+                        }
+                    }
+                    else
+                    {
+                        ImplWriteGradientStop( aStartColor, fBorderOffset );
+                        ImplWriteGradientStop( aEndColor, 1.0 );
+                    }
+                }
+                else
+                {
+                    fBorderOffset /= 2;
+                    // Emulate non-smooth gradient
+                    if( 0 < nSteps && nSteps < 100 )
+                    {
+                        double fOffsetStep = ( 0.5 - fBorderOffset ) / (double)nSteps;
+                        // Upper half
+                        for( sal_uInt16 i = 0; i < nSteps; i++ )
+                        {
+                            Color aColor = ImplGetGradientColor( aEndColor, aStartColor, i / 
(double) nSteps );
+                            ImplWriteGradientStop( aColor, fBorderOffset + i * fOffsetStep );
+                            aColor = ImplGetGradientColor( aEndColor, aStartColor, (i + 1 ) / 
(double) nSteps );
+                            ImplWriteGradientStop( aColor, fBorderOffset + i * fOffsetStep );
+                        }
+                        // Lower half
+                        for( sal_uInt16 i = 0; i < nSteps; i++ )
+                        {
+                            Color aColor = ImplGetGradientColor( aStartColor, aEndColor, i / 
(double) nSteps );
+                            ImplWriteGradientStop( aColor, 0.5 + (i + 1) * fOffsetStep );
+                            aColor = ImplGetGradientColor( aStartColor, aEndColor, (i + 1 ) / 
(double) nSteps );
+                            ImplWriteGradientStop( aColor, 0.5 + (i + 1) * fOffsetStep );
+                        }
+                    }
+                    else
+                    {
+                        ImplWriteGradientStop( aEndColor, fBorderOffset );
+                        ImplWriteGradientStop( aStartColor, 0.5 );
+                        ImplWriteGradientStop( aEndColor, 1.0 - fBorderOffset );
+                    }
+                }
+            }
+        }
+
+        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, double fOffset )
+{
+    mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, NMSP_RTL::OUString::valueOf( 
fOffset ) );
+
+    FastString aStyle;
+    aStyle += B2UCONST( "stop-color:" );
+    aStyle += mpContext->GetColorStyle ( rColor );
+
+    mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aStyle.GetString() );
+    {
+        SvXMLElementExport aElemStartStop( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, TRUE, TRUE 
);
+    }
+}
+
+Color SVGActionWriter::ImplGetColorWithIntensity( const Color& rColor,
+                                                  sal_uInt16 nIntensity )
+{
+     sal_uInt8 nNewRed = (sal_uInt8)( (long)rColor.GetRed() * nIntensity / 100L );
+     sal_uInt8 nNewGreen = (sal_uInt8)( (long)rColor.GetGreen() * nIntensity / 100L );
+     sal_uInt8 nNewBlue = (sal_uInt8)( (long)rColor.GetBlue() * nIntensity / 100L );
+     return Color( nNewRed, nNewGreen, nNewBlue);
+}
+
+Color SVGActionWriter::ImplGetGradientColor( const Color& rStartColor,
+                                             const Color& rEndColor,
+                                             double fOffset )
+{
+    long nRedStep = rEndColor.GetRed() - rStartColor.GetRed();
+    long nNewRed = rStartColor.GetRed() + (long)( nRedStep * fOffset );
+    nNewRed = ( nNewRed < 0 ) ? 0 : ( nNewRed > 0xFF) ? 0xFF : nNewRed;
+
+    long nGreenStep = rEndColor.GetGreen() - rStartColor.GetGreen();
+    long nNewGreen = rStartColor.GetGreen() + (long)( nGreenStep * fOffset );
+    nNewGreen = ( nNewGreen < 0 ) ? 0 : ( nNewGreen > 0xFF) ? 0xFF : nNewGreen;
+
+    long nBlueStep = rEndColor.GetBlue() - rStartColor.GetBlue();
+    long nNewBlue = rStartColor.GetBlue() + (long)( nBlueStep * fOffset );
+    nNewBlue = ( nNewBlue < 0 ) ? 0 : ( nNewBlue > 0xFF) ? 0xFF : nNewBlue;
+
+    return Color( (sal_uInt8)nNewRed, (sal_uInt8)nNewGreen, (sal_uInt8)nNewBlue );
 }
 
 // -----------------------------------------------------------------------------
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index 6ec2452..f5928d1 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -140,6 +140,7 @@ public:
     virtual                                    ~SVGAttributeWriter();
 
     ::rtl::OUString                    GetFontStyle( const Font& rFont );
+    ::rtl::OUString                    GetColorStyle( const Color& rColor );
     ::rtl::OUString                    GetPaintStyle( const Color& rLineColor, const Color& 
rFillColor, const LineInfo* pLineInfo );
 
     void                                       SetFontAttr( const Font& rFont );
@@ -164,6 +165,7 @@ private:
     sal_Bool                           mbClipAttrChanged;
     sal_Int32                          mnCurClipId;
     sal_Int32                          mnCurPatternId;
+    sal_Int32                          mnCurGradientId;
     Stack                                      maContextStack;
     VirtualDevice*                     mpVDev;
     MapMode                                    maTargetMapMode;
@@ -186,6 +188,10 @@ 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, double 
fOffset );
+    Color                                      ImplGetColorWithIntensity( const Color& rColor, 
USHORT nIntensity );
+    Color                                      ImplGetGradientColor( const Color& rStartColor, 
const Color& rEndColor, 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 
);
@@ -196,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 fc8d029f88c2f7ec67db8122249f23f889a4f707 Mon Sep 17 00:00:00 2001
From: Kurosawa Takeshi <taken.spc@gmail.com>
Date: Fri, 11 Feb 2011 19:29:41 +0900
Subject: [PATCH 3/3] Export transparencies as SVG <mask>s

With this patch, SVG export filter supports solid and gradient tranparencies in all sill styles.
---
 filter/source/svg/svgwriter.cxx |   95 +++++++++++++++++++++++++++++---------
 filter/source/svg/svgwriter.hxx |    3 +
 2 files changed, 75 insertions(+), 23 deletions(-)

diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index 15a61e7..c3f459b 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";
@@ -390,7 +391,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 );
@@ -908,6 +910,73 @@ Color SVGActionWriter::ImplGetGradientColor( const Color& rStartColor,
 
 // -----------------------------------------------------------------------------
 
+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 );
+
+            const PolyPolygon aPolyPolygon( PolyPolygon( Rectangle( rDestPt, rDestSize ) ) );
+            Gradient aGradient( rGradient );
+
+            // swap gradient stops to adopt SVG mask
+            Color aTmpColor( aGradient.GetStartColor() );
+            sal_uInt16 nTmpIntensity( aGradient.GetStartIntensity() );
+            aGradient.SetStartColor( aGradient.GetEndColor() );
+            aGradient.SetStartIntensity( aGradient.GetEndIntensity() ) ;
+            aGradient.SetEndColor( aTmpColor );
+            aGradient.SetEndIntensity( nTmpIntensity );
+
+            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,
                                      const NMSP_RTL::OUString* pStyle )
@@ -1508,28 +1577,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 f5928d1..26470af 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -166,6 +166,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                                       ImplWriteGradientStop( const Color& rColor, double 
fOffset );
     Color                                      ImplGetColorWithIntensity( const Color& rColor, 
USHORT nIntensity );
     Color                                      ImplGetGradientColor( const Color& rStartColor, 
const Color& rEndColor, 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


Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.