summaryrefslogtreecommitdiff
path: root/filter
diff options
context:
space:
mode:
authorFridrich Štrba <fridrich.strba@bluewin.ch>2010-09-14 09:36:14 +0200
committerFridrich Štrba <fridrich.strba@bluewin.ch>2010-09-14 09:36:14 +0200
commit90f5ce36231551e226d4b3e2fefaa8493af692ac (patch)
treef8df50349969a0b2b6d9f1d526fce48661507fd7 /filter
parent24dd42f316e5cb16ba726c05ba486d53e033052d (diff)
svg-import-filter.diff: SVG Import Filter implementation in filter module
Diffstat (limited to 'filter')
-rw-r--r--filter/source/config/fragments/fcfg_drawgraphics.mk1
-rw-r--r--filter/source/config/fragments/filters/SVG___Scalable_Vector_Graphics.xcu13
-rw-r--r--filter/source/config/fragments/types/svg_Scalable_Vector_Graphics.xcu6
-rw-r--r--filter/source/svg/b2dellipse.cxx139
-rw-r--r--filter/source/svg/b2dellipse.hxx77
-rw-r--r--filter/source/svg/gentoken.pl58
-rw-r--r--filter/source/svg/gfxtypes.hxx356
-rw-r--r--filter/source/svg/makefile.mk52
-rw-r--r--filter/source/svg/parserfragments.cxx553
-rw-r--r--filter/source/svg/parserfragments.hxx50
-rw-r--r--filter/source/svg/spirit_supplements.hxx115
-rw-r--r--filter/source/svg/svgfilter.cxx107
-rw-r--r--filter/source/svg/svgfilter.hxx39
-rw-r--r--filter/source/svg/svgimport.cxx191
-rw-r--r--filter/source/svg/svgreader.cxx1876
-rw-r--r--filter/source/svg/svgreader.hxx43
-rw-r--r--filter/source/svg/test/makefile.mk114
-rw-r--r--filter/source/svg/test/odfserializer.cxx140
-rw-r--r--filter/source/svg/test/odfserializer.hxx31
-rw-r--r--filter/source/svg/test/parsertest.cxx209
-rw-r--r--filter/source/svg/test/svg2odf.cxx124
-rw-r--r--filter/source/svg/tokenmap.cxx62
-rw-r--r--filter/source/svg/tokenmap.hxx32
-rw-r--r--filter/source/svg/tokens.txt403
-rw-r--r--filter/source/svg/units.cxx99
-rw-r--r--filter/source/svg/units.hxx60
26 files changed, 4695 insertions, 255 deletions
diff --git a/filter/source/config/fragments/fcfg_drawgraphics.mk b/filter/source/config/fragments/fcfg_drawgraphics.mk
index 7038e27e8ae4..41a46254b871 100644
--- a/filter/source/config/fragments/fcfg_drawgraphics.mk
+++ b/filter/source/config/fragments/fcfg_drawgraphics.mk
@@ -54,6 +54,7 @@ F4_DRAWGRAPHICS = \
SGF___StarOffice_Writer_SGF \
SGV___StarDraw_2_0 \
SVM___StarView_Metafile \
+ SVG___Scalable_Vector_Graphics \
TGA___Truevision_TARGA \
TIF___Tag_Image_File \
WMF___MS_Windows_Metafile \
diff --git a/filter/source/config/fragments/filters/SVG___Scalable_Vector_Graphics.xcu b/filter/source/config/fragments/filters/SVG___Scalable_Vector_Graphics.xcu
new file mode 100644
index 000000000000..1212e056762e
--- /dev/null
+++ b/filter/source/config/fragments/filters/SVG___Scalable_Vector_Graphics.xcu
@@ -0,0 +1,13 @@
+ <node oor:name="SVG - Scalable Vector Graphics" oor:op="replace">
+ <prop oor:name="Flags"><value>IMPORT ALIEN USESOPTIONS 3RDPARTYFILTER PREFERRED</value></prop>
+ <prop oor:name="UIComponent"/>
+ <prop oor:name="FilterService"><value>com.sun.star.comp.Draw.SVGFilter</value></prop>
+ <prop oor:name="UserData"><value></value></prop>
+ <prop oor:name="UIName">
+ <value xml:lang="x-default">SVG - Scalable Vector Graphics</value>
+ </prop>
+ <prop oor:name="FileFormatVersion"><value>0</value></prop>
+ <prop oor:name="Type"><value>svg_Scalable_Vector_Graphics</value></prop>
+ <prop oor:name="TemplateName"/>
+ <prop oor:name="DocumentService"><value>com.sun.star.drawing.DrawingDocument</value></prop>
+ </node>
diff --git a/filter/source/config/fragments/types/svg_Scalable_Vector_Graphics.xcu b/filter/source/config/fragments/types/svg_Scalable_Vector_Graphics.xcu
index 37643df4c7ec..8865dee4a831 100644
--- a/filter/source/config/fragments/types/svg_Scalable_Vector_Graphics.xcu
+++ b/filter/source/config/fragments/types/svg_Scalable_Vector_Graphics.xcu
@@ -1,10 +1,10 @@
<node oor:name="svg_Scalable_Vector_Graphics" oor:op="replace" >
- <prop oor:name="DetectService"/>
+ <prop oor:name="DetectService"><value>com.sun.star.comp.Draw.SVGFilter</value></prop>
<prop oor:name="URLPattern"/>
<prop oor:name="Extensions"><value>svg</value></prop>
<prop oor:name="MediaType"><value>image/svg+xml</value></prop>
- <prop oor:name="Preferred"><value>false</value></prop>
- <prop oor:name="PreferredFilter"/>
+ <prop oor:name="Preferred"><value>true</value></prop>
+ <prop oor:name="PreferredFilter"><value>SVG - Scalable Vector Graphics</value></prop>
<prop oor:name="UIName">
<value>SVG - Scalable Vector Graphics</value>
</prop>
diff --git a/filter/source/svg/b2dellipse.cxx b/filter/source/svg/b2dellipse.cxx
new file mode 100644
index 000000000000..8ae97c6bcdb3
--- /dev/null
+++ b/filter/source/svg/b2dellipse.cxx
@@ -0,0 +1,139 @@
+/*************************************************************************
+ *
+ * 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 3.
+ *
+ ************************************************************************/
+
+#include "b2dellipse.hxx"
+
+#include <osl/diagnose.h>
+
+#include <basegfx/point/b2dpoint.hxx>
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+
+#include <rtl/instance.hxx>
+
+#include <boost/scoped_ptr.hpp>
+#include <vector>
+#include <algorithm>
+
+class ImplB2DEllipse
+{
+ basegfx::B2DPoint maCenter;
+ basegfx::B2DTuple maRadius;
+
+public:
+ ImplB2DEllipse()
+ : maCenter(0.0f, 0.0f),
+ maRadius(0.0f, 0.0f)
+ {}
+
+ ImplB2DEllipse(const ImplB2DEllipse& rToBeCopied)
+ : maCenter(rToBeCopied.maCenter),
+ maRadius(rToBeCopied.maRadius)
+ {}
+
+ ImplB2DEllipse& operator=( const ImplB2DEllipse& rToBeCopied )
+ {
+ maCenter = rToBeCopied.maCenter;
+ maRadius = rToBeCopied.maRadius;
+
+ return *this;
+ }
+
+ bool isEqual(const ImplB2DEllipse& rCandidate) const
+ {
+ return (maCenter == rCandidate.maCenter)
+ && (maRadius == rCandidate.maRadius);
+ }
+
+ basegfx::B2DPoint getCenter() const
+ {
+ return maCenter;
+ }
+
+ void setCenter(const basegfx::B2DPoint& rCenter)
+ {
+ maCenter = rCenter;
+ }
+
+ basegfx::B2DTuple getRadius() const
+ {
+ return maRadius;
+ }
+
+ void setRadius(const basegfx::B2DTuple& rRadius)
+ {
+ maRadius = rRadius;
+ }
+
+
+ void transform(const basegfx::B2DHomMatrix& /* rMatrix */)
+ {
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace basegfx
+{
+
+ B2DEllipse::B2DEllipse()
+ {}
+
+ B2DEllipse::B2DEllipse(const basegfx::B2DPoint& rCenter, const basegfx::B2DTuple& rRadius)
+ : maCenter(rCenter), maRadius(rRadius)
+ {
+ }
+
+ B2DEllipse::~B2DEllipse()
+ {
+ }
+
+ bool B2DEllipse::operator==(const B2DEllipse& rEllipse) const
+ {
+ return (maCenter == rEllipse.maCenter) && (maRadius == rEllipse.maRadius);
+ }
+
+ bool B2DEllipse::operator!=(const B2DEllipse& rEllipse) const
+ {
+ return !(*this == rEllipse);
+ }
+
+ basegfx::B2DPoint B2DEllipse::getB2DEllipseCenter() const
+ {
+ return maCenter;
+ }
+
+ void B2DEllipse::setB2DEllipseCenter(const basegfx::B2DPoint& rCenter)
+ {
+ maCenter = rCenter;
+ }
+
+ basegfx::B2DTuple B2DEllipse::getB2DEllipseRadius() const
+ {
+ return maRadius;
+ }
+
+ void B2DEllipse::setB2DEllipseRadius(const basegfx::B2DTuple& rRadius)
+ {
+ maRadius = rRadius;
+ }
+
+ void B2DEllipse::transform(const basegfx::B2DHomMatrix& /* rMatrix */)
+ {
+ }
+} // end of namespace basegfx
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/filter/source/svg/b2dellipse.hxx b/filter/source/svg/b2dellipse.hxx
new file mode 100644
index 000000000000..a63d83974ec5
--- /dev/null
+++ b/filter/source/svg/b2dellipse.hxx
@@ -0,0 +1,77 @@
+/*************************************************************************
+ *
+ * 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 3.
+ *
+ ************************************************************************/
+
+#ifndef _BASEGFX_B2DELLIPSE_HXX
+#define _BASEGFX_B2DELLIPSE_HXX
+
+#include <sal/types.h>
+
+#include <o3tl/cow_wrapper.hxx>
+
+#include <basegfx/point/b2dpoint.hxx>
+
+#include <basegfx/tuple/b2dtuple.hxx>
+
+#include <basegfx/vector/b2enums.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// predeclarations
+class ImplB2DEllipse;
+
+namespace basegfx
+{
+ class B2DPoint;
+ class B2DVector;
+ class B2DHomMatrix;
+} // end of namespace basegfx
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace basegfx
+{
+ class B2DEllipse
+ {
+ private:
+ basegfx::B2DPoint maCenter;
+ basegfx::B2DTuple maRadius;
+
+ public:
+ B2DEllipse();
+ B2DEllipse(const B2DEllipse& rEllipse);
+ B2DEllipse(const basegfx::B2DPoint& rCenter, const basegfx::B2DTuple& rRadius);
+ ~B2DEllipse();
+
+ // assignment operator
+ B2DEllipse& operator=(const B2DEllipse& rEllipse);
+
+ // compare operators
+ bool operator==(const B2DEllipse& rEllipse) const;
+ bool operator!=(const B2DEllipse& rEllipse) const;
+
+ // Coordinate interface
+ basegfx::B2DPoint getB2DEllipseCenter() const;
+ void setB2DEllipseCenter(const basegfx::B2DPoint& rCenter);
+
+ basegfx::B2DTuple getB2DEllipseRadius() const;
+ void setB2DEllipseRadius(const basegfx::B2DTuple& rRadius);
+
+ // apply transformation given in matrix form to the Ellipse
+ void transform(const basegfx::B2DHomMatrix& rMatrix);
+ };
+} // end of namespace basegfx
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif /* _BASEGFX_B2DELLIPSE_HXX */
diff --git a/filter/source/svg/gentoken.pl b/filter/source/svg/gentoken.pl
new file mode 100644
index 000000000000..75bb1e262aab
--- /dev/null
+++ b/filter/source/svg/gentoken.pl
@@ -0,0 +1,58 @@
+# from oox/source/token - should really put this into solenv
+
+$ARGV0 = shift @ARGV;
+$ARGV1 = shift @ARGV;
+$ARGV2 = shift @ARGV;
+
+open ( TOKENS, $ARGV0 ) || die "can't open token file: $!";
+my %tokens;
+
+while ( defined ($line = <TOKENS>) )
+{
+ if( !($line =~ /^#/) )
+ {
+ chomp($line);
+ @token = split(/\s+/,$line);
+ if ( not defined ($token[1]) )
+ {
+ $token[1] = "XML_".$token[0];
+ $token[1] =~ tr/\-\.\:/___/;
+ $token[1] =~ s/\+/PLUS/g;
+ $token[1] =~ s/\-/MINUS/g;
+ }
+
+ $tokens{$token[0]} = uc($token[1]);
+ }
+}
+close ( TOKENS );
+
+open ( HXX, ">$ARGV1" ) || die "can't open tokens.hxx file: $!";
+open ( GPERF, ">$ARGV2" ) || die "can't open tokens.gperf file: $!";
+
+print ( GPERF "%language=C++\n" );
+print ( GPERF "%global-table\n" );
+print ( GPERF "%null-strings\n" );
+print ( GPERF "%struct-type\n" );
+print ( GPERF "struct xmltoken\n" );
+print ( GPERF "{\n" );
+print ( GPERF " const sal_Char *name; sal_Int32 nToken; \n" );
+print ( GPERF "};\n" );
+print ( GPERF "%%\n" );
+
+print ( HXX "#ifndef INCLUDED_AUTOGEN_TOKEN_HXX\n" );
+print ( HXX "#define INCLUDED_AUTOGEN_TOKEN_HXX\n\n" );
+print ( HXX "#include <sal/types.h>\n\n" );
+
+$i = 0;
+foreach( sort(keys(%tokens)) )
+{
+ print( HXX "const sal_Int32 $tokens{$_} = $i;\n" );
+ print( GPERF "$_,$tokens{$_}\n" );
+ $i = $i + 1;
+}
+print ( GPERF "%%\n" );
+print ( HXX "const sal_Int32 XML_TOKEN_COUNT = $i;\n" );
+print ( HXX "const sal_Int32 XML_TOKEN_INVALID = -1;\n\n" );
+print ( HXX "#endif\n" );
+close ( HXX );
+close ( GPERF );
diff --git a/filter/source/svg/gfxtypes.hxx b/filter/source/svg/gfxtypes.hxx
new file mode 100644
index 000000000000..3675e30e65eb
--- /dev/null
+++ b/filter/source/svg/gfxtypes.hxx
@@ -0,0 +1,356 @@
+/*************************************************************************
+ *
+ * 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 3.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_GFXTYPES_HXX
+#define INCLUDED_GFXTYPES_HXX
+
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dlinegeometry.hxx>
+
+#include <hash_set>
+#include <hash_map>
+#include <rtl/ustring.hxx>
+
+namespace svgi
+{
+
+struct ARGBColor
+{
+ double toDoubleColor( sal_uInt8 val ) { return val/255.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)
+ {}
+ ARGBColor( double r_, double g_, double b_ ) :
+ a(1.0), r(r_), g(g_), b(b_)
+ {}
+ ARGBColor( double a_, double r_, double g_, double b_ ) :
+ a(a_), r(r_), g(g_), b(b_)
+ {}
+ ARGBColor( int r_, int g_, int b_ ) :
+ a(1.0),
+ r(toDoubleColor(sal::static_int_cast<sal_uInt8>(r_))),
+ g(toDoubleColor(sal::static_int_cast<sal_uInt8>(g_))),
+ b(toDoubleColor(sal::static_int_cast<sal_uInt8>(b_)))
+ {}
+ ARGBColor( int a_, int r_, int g_, int b_ ) :
+ a(toDoubleColor(sal::static_int_cast<sal_uInt8>(a_))),
+ r(toDoubleColor(sal::static_int_cast<sal_uInt8>(r_))),
+ g(toDoubleColor(sal::static_int_cast<sal_uInt8>(g_))),
+ b(toDoubleColor(sal::static_int_cast<sal_uInt8>(b_)))
+ {}
+ double a;
+ double r;
+ double g;
+ double b;
+};
+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)
+ {}
+ ARGBColor maStopColor;
+ double mnStopPosition;
+};
+inline bool operator==( const GradientStop& rLHS, const GradientStop& rRHS )
+{ return rLHS.mnStopPosition==rRHS.mnStopPosition && rLHS.maStopColor==rRHS.maStopColor; }
+
+struct Gradient
+{
+ 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 )
+{
+ 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
+{
+ NONE,
+ SOLID,
+ GRADIENT
+};
+
+enum FillRule
+{
+ NON_ZERO,
+ EVEN_ODD
+};
+
+enum TextAlign
+{
+ BEFORE,
+ CENTER,
+ AFTER
+};
+
+enum CapStyle
+{
+ BUTT,
+ RECT,
+ ROUND
+};
+
+enum FontStyle
+{
+ STYLE_NORMAL,
+ STYLE_OBLIQUE,
+ STYLE_ITALIC
+};
+
+enum FontVariant
+{
+ VARIANT_NORMAL,
+ VARIANT_SMALLCAPS
+};
+
+struct State
+{
+ State() :
+ maCTM(),
+ maTransform(),
+ maViewport(),
+ maViewBox(),
+ maFontFamily(), // app-default
+ mnFontSize(12.0),
+ meFontStyle(STYLE_NORMAL),
+ meFontVariant(VARIANT_NORMAL),
+ mnFontWeight(400.0),
+ meTextAnchor(BEFORE),
+ meTextDisplayAlign(BEFORE),
+ mnTextLineIncrement(0.0),
+ maCurrentColor(1.0),
+ mbVisibility(true),
+ meFillType(SOLID),
+ mnFillOpacity(1.0),
+ meStrokeType(NONE),
+ mnStrokeOpacity(1.0),
+ meViewportFillType(NONE),
+ mnViewportFillOpacity(1.0),
+ maFillColor(0.0),
+ maFillGradient(Gradient::LINEAR),
+ meFillRule(NON_ZERO),
+ maStrokeColor(0.0),
+ maStrokeGradient(Gradient::LINEAR),
+ maDashArray(),
+ mnDashOffset(0.0),
+ meLineCap(BUTT),
+ meLineJoin(basegfx::B2DLINEJOIN_MITER),
+ mnMiterLimit(4.0),
+ mnStrokeWidth(1.0),
+ maViewportFillColor(1.0),
+ maViewportFillGradient(Gradient::LINEAR),
+ mnStyleId(0)
+ {}
+
+ basegfx::B2DHomMatrix maCTM;
+ basegfx::B2DHomMatrix maTransform;
+ basegfx::B2DRange maViewport;
+ basegfx::B2DRange maViewBox;
+
+ rtl::OUString maFontFamily;
+ /** Absolute: xx-small=6.94 | x-small=8.33 | small=10 | medium=12 | large=14.4 | x-large=17.28 | xx-large=20.736
+
+ Relative(to parent): larger (enlarge by 1.2)
+ smaller (shrink by 1.2)
+
+ */
+ double mnFontSize;
+ FontStyle meFontStyle;
+ FontVariant meFontVariant;
+ double mnFontWeight;
+
+ TextAlign meTextAnchor; // text-anchor
+ TextAlign meTextDisplayAlign; // display-align
+ double mnTextLineIncrement; // 0.0 means auto
+
+ ARGBColor maCurrentColor;
+ bool mbVisibility;
+
+ PaintType meFillType;
+ double mnFillOpacity;
+ PaintType meStrokeType;
+ double mnStrokeOpacity;
+ PaintType meViewportFillType;
+ double mnViewportFillOpacity;
+
+ ARGBColor maFillColor;
+ Gradient maFillGradient;
+ FillRule meFillRule;
+
+ ARGBColor maStrokeColor;
+ Gradient maStrokeGradient;
+ std::vector<double> maDashArray;
+ double mnDashOffset;
+ CapStyle meLineCap;
+ basegfx::B2DLineJoin meLineJoin;
+ double mnMiterLimit;
+ double mnStrokeWidth;
+
+ ARGBColor maViewportFillColor;
+ Gradient maViewportFillGradient;
+
+ sal_Int32 mnStyleId;
+};
+
+inline bool operator==(const State& rLHS, const State& rRHS )
+{
+ return rLHS.maCTM==rRHS.maCTM &&
+ rLHS.maTransform==rRHS.maTransform &&
+ rLHS.maViewport==rRHS.maViewport &&
+ rLHS.maViewBox==rRHS.maViewBox &&
+ rLHS.maFontFamily==rRHS.maFontFamily &&
+ rLHS.mnFontSize==rRHS.mnFontSize &&
+ rLHS.meFontStyle==rRHS.meFontStyle &&
+ rLHS.meFontVariant==rRHS.meFontVariant &&
+ rLHS.mnFontWeight==rRHS.mnFontWeight &&
+ rLHS.meTextAnchor==rRHS.meTextAnchor &&
+ rLHS.meTextDisplayAlign==rRHS.meTextDisplayAlign &&
+ rLHS.mnTextLineIncrement==rRHS.mnTextLineIncrement &&
+ rLHS.maCurrentColor==rRHS.maCurrentColor &&
+ rLHS.mbVisibility==rRHS.mbVisibility &&
+ rLHS.meFillType==rRHS.meFillType &&
+ rLHS.mnFillOpacity==rRHS.mnFillOpacity &&
+ rLHS.meStrokeType==rRHS.meStrokeType &&
+ rLHS.mnStrokeOpacity==rRHS.mnStrokeOpacity &&
+ rLHS.meViewportFillType==rRHS.meViewportFillType &&
+ rLHS.mnViewportFillOpacity==rRHS.mnViewportFillOpacity &&
+ rLHS.maFillColor==rRHS.maFillColor &&
+ rLHS.maFillGradient==rRHS.maFillGradient &&
+ rLHS.meFillRule==rRHS.meFillRule &&
+ rLHS.maStrokeColor==rRHS.maStrokeColor &&
+ rLHS.maStrokeGradient==rRHS.maStrokeGradient &&
+ rLHS.maDashArray==rRHS.maDashArray &&
+ rLHS.mnDashOffset==rRHS.mnDashOffset &&
+ rLHS.meLineCap==rRHS.meLineCap &&
+ rLHS.meLineJoin==rRHS.meLineJoin &&
+ rLHS.mnMiterLimit==rRHS.mnMiterLimit &&
+ rLHS.mnStrokeWidth==rRHS.mnStrokeWidth &&
+ rLHS.maViewportFillColor==rRHS.maViewportFillColor &&
+ rLHS.maViewportFillGradient==rRHS.maViewportFillGradient;
+}
+
+struct StateHash
+{
+ size_t operator()(const State& rState ) const
+ {
+ return size_t(rState.maCTM.get( 0, 0 ))
+ ^ size_t(rState.maCTM.get( 1, 0 ))
+ ^ size_t(rState.maCTM.get( 0, 1 ))
+ ^ size_t(rState.maCTM.get( 1, 1 ))
+ ^ size_t(rState.maCTM.get( 0, 2 ))
+ ^ size_t(rState.maCTM.get( 1, 2 ))
+ ^ size_t(rState.maViewport.getWidth())
+ ^ size_t(rState.maViewport.getHeight())
+ ^ size_t(rState.maViewBox.getWidth())
+ ^ size_t(rState.maViewBox.getHeight())
+ ^ size_t(rState.maFontFamily.hashCode())
+ ^ size_t(rState.mnFontSize)
+ ^ size_t(rState.meFontStyle)
+ ^ size_t(rState.meFontVariant)
+ ^ size_t(rState.mnFontWeight)
+ ^ size_t(rState.meTextAnchor)
+ ^ size_t(rState.meTextDisplayAlign)
+ ^ size_t(rState.mnTextLineIncrement)
+ ^ size_t(rState.mbVisibility)
+ ^ size_t(rState.meFillType)
+ ^ size_t(rState.mnFillOpacity)
+ ^ size_t(rState.meStrokeType)
+ ^ size_t(rState.mnStrokeOpacity)
+ ^ size_t(rState.meViewportFillType)
+ ^ size_t(rState.mnViewportFillOpacity)
+ ^ size_t(rState.maFillColor.a)
+ ^ size_t(rState.maFillColor.r)
+ ^ size_t(rState.maFillColor.g)
+ ^ size_t(rState.maFillColor.b)
+ ^ size_t(rState.maFillGradient.maStops.size())
+ ^ size_t(rState.meFillRule)
+ ^ size_t(rState.maStrokeColor.a)
+ ^ size_t(rState.maStrokeColor.r)
+ ^ size_t(rState.maStrokeColor.g)
+ ^ size_t(rState.maStrokeColor.b)
+ ^ size_t(rState.maStrokeGradient.maStops.size())
+ ^ size_t(rState.maDashArray.size())
+ ^ size_t(rState.mnDashOffset)
+ ^ size_t(rState.meLineCap)
+ ^ size_t(rState.meLineJoin)
+ ^ size_t(rState.mnMiterLimit)
+ ^ size_t(rState.mnStrokeWidth)
+ ^ size_t(rState.maViewportFillColor.a)
+ ^ size_t(rState.maViewportFillColor.r)
+ ^ size_t(rState.maViewportFillColor.g)
+ ^ size_t(rState.maViewportFillColor.b)
+ ^ size_t(rState.maViewportFillGradient.maStops.size());
+ }
+};
+
+typedef std::hash_set<State, StateHash> StatePool;
+typedef std::hash_map<sal_Int32, State> StateMap;
+
+} // namespace svgi
+
+#endif
diff --git a/filter/source/svg/makefile.mk b/filter/source/svg/makefile.mk
index 12c1210c18c4..c9f8e09c8e22 100644
--- a/filter/source/svg/makefile.mk
+++ b/filter/source/svg/makefile.mk
@@ -26,25 +26,38 @@
#*************************************************************************
PRJ=..$/..
+
PRJNAME=filter
TARGET=svgfilter
-
ENABLE_EXCEPTIONS=TRUE
VISIBILITY_HIDDEN=TRUE
# --- Settings ----------------------------------
-.INCLUDE : settings.mk
+.INCLUDE : settings.mk
+.INCLUDE : libs.mk
# --- Types -------------------------------------
-SLOFILES= $(SLO)$/svguno.obj \
- $(SLO)$/svgfilter.obj \
+SLOFILES= \
+ $(SLO)$/b2dellipse.obj \
+ $(SLO)$/parserfragments.obj \
$(SLO)$/svgexport.obj \
+ $(SLO)$/svgfilter.obj \
$(SLO)$/svgfontexport.obj \
- $(SLO)$/svgwriter.obj
-.IF "$(SOLAR_JAVA)"!=""
-SLOFILES+= $(SLO)$/svgimport.obj
+ $(SLO)$/svgimport.obj \
+ $(SLO)$/svgreader.obj \
+ $(SLO)$/svgwriter.obj \
+ $(SLO)$/tokenmap.obj \
+ $(SLO)$/units.obj
+
+.IF "$(COMID)"=="gcc3"
+.IF "$(CCNUMVER)">="000400000000" || "$(SYSTEM_BOOST)"=="YES"
+CFLAGS+=-DUSE_MODERN_SPIRIT
+.ENDIF
+.ENDIF
+.IF "$(SYSTEM_BOOST)"=="NO"
+CFLAGS+=-DUSE_MODERN_SPIRIT
.ENDIF
# --- Library -----------------------------------
@@ -54,21 +67,17 @@ SHL1TARGET=$(TARGET)$(DLLPOSTFIX)
SHL1STDLIBS=\
$(EDITENGLIB) \
$(SVXCORELIB) \
+ $(BASEGFXLIB) \
$(XMLOFFLIB) \
- $(SVTOOLLIB) \
+ $(SVTOOLLIB) \
$(VCLLIB) \
$(UNOTOOLSLIB) \
$(TOOLSLIB) \
$(COMPHELPERLIB) \
$(CPPUHELPERLIB) \
$(CPPULIB) \
- $(SALLIB)
-
-.IF "$(SOLAR_JAVA)"!=""
-SHL1STDLIBS+=\
- $(JVMACCESSLIB)
-.ENDIF
-
+ $(SALLIB) \
+ $(LIBXML)
SHL1DEPN=
SHL1IMPLIB= i$(SHL1TARGET)
@@ -81,3 +90,16 @@ DEF1NAME=$(SHL1TARGET)
# --- Targets ----------------------------------
.INCLUDE : target.mk
+
+# Generate gperf files - from oox/source/token
+$(INCCOM)$/tokens.hxx $(MISC)$/tokens.gperf : tokens.txt gentoken.pl
+ $(PERL) gentoken.pl tokens.txt $(INCCOM)$/tokens.hxx $(MISC)$/tokens.gperf
+
+$(INCCOM)$/tokens.cxx : $(MISC)$/tokens.gperf makefile.mk
+ gperf --compare-strncmp -C -m 20 $(MISC)$/tokens.gperf | $(SED) -e "s/(char\*)0/(char\*)0, 0/g" >$(INCCOM)$/tokens.cxx
+
+$(SLO)$/tokenmap.obj : $(INCCOM)$/tokens.cxx $(INCCOM)$/tokens.hxx
+
+$(SLO)$/parserfragments.obj : $(INCCOM)$/tokens.cxx $(INCCOM)$/tokens.hxx
+
+$(SLO)$/svgreader.obj : $(INCCOM)$/tokens.cxx $(INCCOM)$/tokens.hxx
diff --git a/filter/source/svg/parserfragments.cxx b/filter/source/svg/parserfragments.cxx
new file mode 100644
index 000000000000..d11ceca02d70
--- /dev/null
+++ b/filter/source/svg/parserfragments.cxx
@@ -0,0 +1,553 @@
+/*************************************************************************
+ *
+ * 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 3.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_filter.hxx"
+
+#include "parserfragments.hxx"
+#include "spirit_supplements.hxx"
+#include "gfxtypes.hxx"
+
+#include <basegfx/tools/canvastools.hxx>
+#include <com/sun/star/geometry/AffineMatrix2D.hpp>
+
+#include <string.h>
+#include <limits.h>
+#include <boost/bind.hpp>
+#include <boost/spirit.hpp>
+#include <boost/spirit/dynamic/while.hpp>
+#include <numeric>
+#include <algorithm>
+
+#include "units.hxx"
+#include "tokenmap.hxx"
+
+using namespace ::com::sun::star;
+
+namespace svgi
+{
+
+inline sal_uInt8 hex2int( char val )
+{
+ return val <= '9' ? val-'0' : (val < 'a' ? val+10-'A' : val+10-'a');
+}
+
+void setFourBitColor( double& rChannel, char nChar )
+{
+ const sal_uInt8 nVal(hex2int(nChar));
+ OSL_TRACE( "setFourBitCOlor %d color", nVal );
+ rChannel = (nVal*16+nVal)/255.0;
+}
+
+void setEightBitColor( double& rChannel, const char* pStart, const char* )
+{
+ const sal_uInt8 nVal0(hex2int(pStart[0]));
+ const sal_uInt8 nVal1(hex2int(pStart[1]));
+ OSL_TRACE( "setEightbitCOlor %d, %d color", nVal0, nVal1 );
+ rChannel = (nVal0*16+nVal1)/255.0;
+}
+
+void setIntColor( double& rChannel, sal_uInt8 nVal )
+{
+ OSL_TRACE( "setIntColor %d color", nVal );
+ rChannel = nVal/255.0;
+}
+
+void calcRotation(std::vector<geometry::AffineMatrix2D>& rTransforms,
+ geometry::AffineMatrix2D& rCurrTransform,
+ double fRotationAngle)
+{
+ ::basegfx::B2DHomMatrix aCurr;
+ aCurr.translate(-rCurrTransform.m02,-rCurrTransform.m12);
+ aCurr.rotate(fRotationAngle*M_PI/180);
+ aCurr.translate(rCurrTransform.m02,rCurrTransform.m12);
+
+ OSL_TRACE("calcRotation - fRotationAngle - %f", fRotationAngle);
+ rTransforms.push_back(
+ basegfx::unotools::affineMatrixFromHomMatrix(
+ rCurrTransform,
+ aCurr));
+}
+
+void calcSkewX(std::vector<geometry::AffineMatrix2D>& rTransforms,
+ double fSkewAngle)
+{
+ geometry::AffineMatrix2D aMat(1.0,0.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*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 )
+{
+ basegfx::B2DHomMatrix aLHS;
+ basegfx::B2DHomMatrix aRHS;
+
+ basegfx::unotools::homMatrixFromAffineMatrix(aLHS,rLHS);
+ basegfx::unotools::homMatrixFromAffineMatrix(aRHS,rRHS);
+
+ aRHS*=aLHS;
+
+ geometry::AffineMatrix2D aRet;
+ return basegfx::unotools::affineMatrixFromHomMatrix(aRet,aRHS);
+}
+
+bool parseColor( const char* sColor, ARGBColor& rColor )
+{
+ using namespace ::boost::spirit;
+
+ int_parser<sal_uInt8,10,1,3> byte_p;
+
+ if( parse(sColor,
+ // Begin grammar
+ (
+ // the #rrggbb form
+ ('#' >> (xdigit_p >> xdigit_p)[boost::bind(&setEightBitColor,
+ boost::ref(rColor.r),_1,_2)]
+ >> (xdigit_p >> xdigit_p)[boost::bind(&setEightBitColor,
+ boost::ref(rColor.g),_1,_2)]
+ >> (xdigit_p >> xdigit_p)[boost::bind(&setEightBitColor,
+ boost::ref(rColor.b),_1,_2)])
+ |
+ // the #rgb form
+ ('#' >> xdigit_p[boost::bind(&setFourBitColor,
+ boost::ref(rColor.r),_1)]
+ >> xdigit_p[boost::bind(&setFourBitColor,
+ boost::ref(rColor.g),_1)]
+ >> xdigit_p[boost::bind(&setFourBitColor,
+ boost::ref(rColor.b),_1)])
+ |
+ // rgb() form
+ (str_p("rgb")
+ >> '(' >>
+ (
+ // rgb(int,int,int)
+ (byte_p[boost::bind(&setIntColor,
+ boost::ref(rColor.r),_1)] >> ',' >>
+ byte_p[boost::bind(&setIntColor,
+ boost::ref(rColor.g),_1)] >> ',' >>
+ byte_p[boost::bind(&setIntColor,
+ boost::ref(rColor.b),_1)])
+ |
+ // rgb(double,double,double)
+ (real_p[assign_a(rColor.r)] >> ',' >>
+ real_p[assign_a(rColor.g)] >> ',' >>
+ real_p[assign_a(rColor.b)])
+ )
+ >> ')')
+ ) >> end_p,
+ // End grammar
+ space_p).full )
+ {
+ // free-form color found & parsed
+ return true;
+ }
+
+ // no free-form color - maybe a color name?
+ // 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;
+ case XML_AQUA: rColor = ARGBColor(0,255,255); return true;
+ case XML_AQUAMARINE: rColor = ARGBColor(127,255,212); return true;
+ case XML_AZURE: rColor = ARGBColor(240,255,255); return true;
+ case XML_BEIGE: rColor = ARGBColor(245,245,220); return true;
+ case XML_BISQUE: rColor = ARGBColor(255,228,196); return true;
+ case XML_BLACK: rColor = ARGBColor(0,0,0); return true;
+ case XML_BLANCHEDALMOND: rColor = ARGBColor(255,235,205); return true;
+ case XML_BLUE: rColor = ARGBColor(0,0,255); return true;
+ case XML_BLUEVIOLET: rColor = ARGBColor(138,43,226); return true;
+ case XML_BROWN: rColor = ARGBColor(165,42,42); return true;
+ case XML_BURLYWOOD: rColor = ARGBColor(222,184,135); return true;
+ case XML_CADETBLUE: rColor = ARGBColor(95,158,160); return true;
+ case XML_CHARTREUSE: rColor = ARGBColor(127,255,0); return true;
+ case XML_CHOCOLATE: rColor = ARGBColor(210,105,30); return true;
+ case XML_CORAL: rColor = ARGBColor(255,127,80); return true;
+ case XML_CORNFLOWERBLUE: rColor = ARGBColor(100,149,237); return true;
+ case XML_CORNSILK: rColor = ARGBColor(255,248,220); return true;
+ case XML_CRIMSON: rColor = ARGBColor(220,20,60); return true;
+ case XML_CYAN: rColor = ARGBColor(0,255,255); return true;
+ case XML_DARKBLUE: rColor = ARGBColor(0,0,139); return true;
+ case XML_DARKCYAN: rColor = ARGBColor(0,139,139); return true;
+ case XML_DARKGOLDENROD: rColor = ARGBColor(184,134,11); return true;
+ case XML_DARKGRAY: rColor = ARGBColor(169,169,169); return true;
+ case XML_DARKGREEN: rColor = ARGBColor(0,100,0); return true;
+ case XML_DARKGREY: rColor = ARGBColor(169,169,169); return true;
+ case XML_DARKKHAKI: rColor = ARGBColor(189,183,107); return true;
+ case XML_DARKMAGENTA: rColor = ARGBColor(139,0,139); return true;
+ case XML_DARKOLIVEGREEN: rColor = ARGBColor(85,107,47); return true;
+ case XML_DARKORANGE: rColor = ARGBColor(255,140,0); return true;
+ case XML_DARKORCHID: rColor = ARGBColor(153,50,204); return true;
+ case XML_DARKRED: rColor = ARGBColor(139,0,0); return true;
+ case XML_DARKSALMON: rColor = ARGBColor(233,150,122); return true;
+ case XML_DARKSEAGREEN: rColor = ARGBColor(143,188,143); return true;
+ case XML_DARKSLATEBLUE: rColor = ARGBColor(72,61,139); return true;
+ case XML_DARKSLATEGRAY: rColor = ARGBColor(47,79,79); return true;
+ case XML_DARKSLATEGREY: rColor = ARGBColor(47,79,79); return true;
+ case XML_DARKTURQUOISE: rColor = ARGBColor(0,206,209); return true;
+ case XML_DARKVIOLET: rColor = ARGBColor(148,0,211); return true;
+ case XML_DEEPPINK: rColor = ARGBColor(255,20,147); return true;
+ case XML_DEEPSKYBLUE: rColor = ARGBColor(0,191,255); return true;
+ case XML_DIMGRAY: rColor = ARGBColor(105,105,105); return true;
+ case XML_DIMGREY: rColor = ARGBColor(105,105,105); return true;
+ case XML_DODGERBLUE: rColor = ARGBColor(30,144,255); return true;
+ case XML_FIREBRICK: rColor = ARGBColor(178,34,34); return true;
+ case XML_FLORALWHITE: rColor = ARGBColor(255,250,240); return true;
+ case XML_FORESTGREEN: rColor = ARGBColor(34,139,34); return true;
+ case XML_FUCHSIA: rColor = ARGBColor(255,0,255); return true;
+ case XML_GAINSBORO: rColor = ARGBColor(220,220,220); return true;
+ case XML_GHOSTWHITE: rColor = ARGBColor(248,248,255); return true;
+ case XML_GOLD: rColor = ARGBColor(255,215,0); return true;
+ case XML_GOLDENROD: rColor = ARGBColor(218,165,32); return true;
+ case XML_GRAY: rColor = ARGBColor(128,128,128); return true;
+ case XML_GREY: rColor = ARGBColor(128,128,128); return true;
+ case XML_GREEN: rColor = ARGBColor(0,128,0); return true;
+ case XML_GREENYELLOW: rColor = ARGBColor(173,255,47); return true;
+ case XML_HONEYDEW: rColor = ARGBColor(240,255,240); return true;
+ case XML_HOTPINK: rColor = ARGBColor(255,105,180); return true;
+ case XML_INDIANRED: rColor = ARGBColor(205,92,92); return true;
+ case XML_INDIGO: rColor = ARGBColor(75,0,130); return true;
+ case XML_IVORY: rColor = ARGBColor(255,255,240); return true;
+ case XML_KHAKI: rColor = ARGBColor(240,230,140); return true;
+ case XML_LAVENDER: rColor = ARGBColor(230,230,250); return true;
+ case XML_LAVENDERBLUSH: rColor = ARGBColor(255,240,245); return true;
+ case XML_LAWNGREEN: rColor = ARGBColor(124,252,0); return true;
+ case XML_LEMONCHIFFON: rColor = ARGBColor(255,250,205); return true;
+ case XML_LIGHTBLUE: rColor = ARGBColor(173,216,230); return true;
+ case XML_LIGHTCORAL: rColor = ARGBColor(240,128,128); return true;
+ case XML_LIGHTCYAN: rColor = ARGBColor(224,255,255); return true;
+ case XML_LIGHTGOLDENRODYELLOW: rColor = ARGBColor(250,250,210); return true;
+ case XML_LIGHTGRAY: rColor = ARGBColor(211,211,211); return true;
+ case XML_LIGHTGREEN: rColor = ARGBColor(144,238,144); return true;
+ case XML_LIGHTGREY: rColor = ARGBColor(211,211,211); return true;
+ case XML_LIGHTPINK: rColor = ARGBColor(255,182,193); return true;
+ case XML_LIGHTSALMON: rColor = ARGBColor(255,160,122); return true;
+ case XML_LIGHTSEAGREEN: rColor = ARGBColor(32,178,170); return true;
+ case XML_LIGHTSKYBLUE: rColor = ARGBColor(135,206,250); return true;
+ case XML_LIGHTSLATEGRAY: rColor = ARGBColor(119,136,153); return true;
+ case XML_LIGHTSLATEGREY: rColor = ARGBColor(119,136,153); return true;
+ case XML_LIGHTSTEELBLUE: rColor = ARGBColor(176,196,222); return true;
+ case XML_LIGHTYELLOW: rColor = ARGBColor(255,255,224); return true;
+ case XML_LIME: rColor = ARGBColor(0,255,0); return true;
+ case XML_LIMEGREEN: rColor = ARGBColor(50,205,50); return true;
+ case XML_LINEN: rColor = ARGBColor(250,240,230); return true;
+ case XML_MAGENTA: rColor = ARGBColor(255,0,255); return true;
+ case XML_MAROON: rColor = ARGBColor(128,0,0); return true;
+ case XML_MEDIUMAQUAMARINE: rColor = ARGBColor(102,205,170); return true;
+ case XML_MEDIUMBLUE: rColor = ARGBColor(0,0,205); return true;
+ case XML_MEDIUMORCHID: rColor = ARGBColor(186,85,211); return true;
+ case XML_MEDIUMPURPLE: rColor = ARGBColor(147,112,219); return true;
+ case XML_MEDIUMSEAGREEN: rColor = ARGBColor(60,179,113); return true;
+ case XML_MEDIUMSLATEBLUE: rColor = ARGBColor(123,104,238); return true;
+ case XML_MEDIUMSPRINGGREEN: rColor = ARGBColor(0,250,154); return true;
+ case XML_MEDIUMTURQUOISE: rColor = ARGBColor(72,209,204); return true;
+ case XML_MEDIUMVIOLETRED: rColor = ARGBColor(199,21,133); return true;
+ case XML_MIDNIGHTBLUE: rColor = ARGBColor(25,25,112); return true;
+ case XML_MINTCREAM: rColor = ARGBColor(245,255,250); return true;
+ case XML_MISTYROSE: rColor = ARGBColor(255,228,225); return true;
+ case XML_MOCCASIN: rColor = ARGBColor(255,228,181); return true;
+ case XML_NAVAJOWHITE: rColor = ARGBColor(255,222,173); return true;
+ case XML_NAVY: rColor = ARGBColor(0,0,128); return true;
+ case XML_OLDLACE: rColor = ARGBColor(253,245,230); return true;
+ case XML_OLIVE: rColor = ARGBColor(128,128,0); return true;
+ case XML_OLIVEDRAB: rColor = ARGBColor(107,142,35); return true;
+ case XML_ORANGE: rColor = ARGBColor(255,165,0); return true;
+ case XML_ORANGERED: rColor = ARGBColor(255,69,0); return true;
+ case XML_ORCHID: rColor = ARGBColor(218,112,214); return true;
+ case XML_PALEGOLDENROD: rColor = ARGBColor(238,232,170); return true;
+ case XML_PALEGREEN: rColor = ARGBColor(152,251,152); return true;
+ case XML_PALETURQUOISE: rColor = ARGBColor(175,238,238); return true;
+ case XML_PALEVIOLETRED: rColor = ARGBColor(219,112,147); return true;
+ case XML_PAPAYAWHIP: rColor = ARGBColor(255,239,213); return true;
+ case XML_PEACHPUFF: rColor = ARGBColor(255,218,185); return true;
+ case XML_PERU: rColor = ARGBColor(205,133,63); return true;
+ case XML_PINK: rColor = ARGBColor(255,192,203); return true;
+ case XML_PLUM: rColor = ARGBColor(221,160,221); return true;
+ case XML_POWDERBLUE: rColor = ARGBColor(176,224,230); return true;
+ case XML_PURPLE: rColor = ARGBColor(128,0,128); return true;
+ case XML_RED: rColor = ARGBColor(255,0,0); return true;
+ case XML_ROSYBROWN: rColor = ARGBColor(188,143,143); return true;
+ case XML_ROYALBLUE: rColor = ARGBColor(65,105,225); return true;
+ case XML_SADDLEBROWN: rColor = ARGBColor(139,69,19); return true;
+ case XML_SALMON: rColor = ARGBColor(250,128,114); return true;
+ case XML_SANDYBROWN: rColor = ARGBColor(244,164,96); return true;
+ case XML_SEAGREEN: rColor = ARGBColor(46,139,87); return true;
+ case XML_SEASHELL: rColor = ARGBColor(255,245,238); return true;
+ case XML_SIENNA: rColor = ARGBColor(160,82,45); return true;
+ case XML_SILVER: rColor = ARGBColor(192,192,192); return true;
+ case XML_SKYBLUE: rColor = ARGBColor(135,206,235); return true;
+ case XML_SLATEBLUE: rColor = ARGBColor(106,90,205); return true;
+ case XML_SLATEGRAY: rColor = ARGBColor(112,128,144); return true;
+ case XML_SLATEGREY: rColor = ARGBColor(112,128,144); return true;
+ case XML_SNOW: rColor = ARGBColor(255,250,250); return true;
+ case XML_SPRINGGREEN: rColor = ARGBColor(0,255,127); return true;
+ case XML_STEELBLUE: rColor = ARGBColor(70,130,180); return true;
+ case XML_TAN: rColor = ARGBColor(210,180,140); return true;
+ case XML_TEAL: rColor = ARGBColor(0,128,128); return true;
+ case XML_THISTLE: rColor = ARGBColor(216,191,216); return true;
+ case XML_TOMATO: rColor = ARGBColor(255,99,71); return true;
+ case XML_TURQUOISE: rColor = ARGBColor(64,224,208); return true;
+ case XML_VIOLET: rColor = ARGBColor(238,130,238); return true;
+ case XML_WHEAT: rColor = ARGBColor(245,222,179); return true;
+ case XML_WHITE: rColor = ARGBColor(255,255,255); return true;
+ case XML_WHITESMOKE: rColor = ARGBColor(245,245,245); return true;
+ case XML_YELLOW: rColor = ARGBColor(255,255,0); return true;
+ case XML_YELLOWGREEN: rColor = ARGBColor(154,205,50); return true;
+
+ default:
+ return false; // no color at all, I'd guess.
+ }
+}
+
+bool parseOpacity (const char* sOpacity, ARGBColor& rColor )
+{
+ using namespace ::boost::spirit;
+
+ if( parse(sOpacity,
+ // Begin grammar
+ (
+ real_p[assign_a(rColor.a)]
+ ) >> end_p,
+ // End grammar
+ space_p).full )
+ {
+ return true;
+ }
+ return false;
+}
+
+//////////////////////////////////////////////////////////////
+
+bool parseTransform( const char* sTransform, basegfx::B2DHomMatrix& rTransform )
+{
+ using namespace ::boost::spirit;
+
+ double fRefOffsetX(0.0);
+ double fRefOffsetY(0.0);
+ bool bRefTransform(false);
+
+ double fRotationAngle=0.0;
+ double fSkewAngle=0.0;
+ geometry::AffineMatrix2D aIdentityTransform;
+ geometry::AffineMatrix2D aCurrTransform;
+ std::vector<geometry::AffineMatrix2D> aTransforms;
+ aIdentityTransform.m00 = 1.0; aIdentityTransform.m11 = 1.0;
+ aCurrTransform = aIdentityTransform;
+
+ const bool bRes = parse(sTransform,
+ // Begin grammar
+ (
+ // identity transform
+ str_p("none")
+ |
+ // the ref() form
+ (str_p("ref")
+ >> '('
+ >> str_p("svg")[assign_a(bRefTransform,true)]
+ >> !(real_p[assign_a(fRefOffsetX)] >> (',' | eps_p) >>
+ real_p[assign_a(fRefOffsetY)])
+ >> ')')
+ |
+ // the transform-list form
+ (list_p(
+ (
+ // matrix(a,b,c,d,e,f)
+ (str_p("matrix")
+ >> '('
+ >> 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[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[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)]
+ >> !((',' | 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")
+ >> '('
+ >> real_p[assign_a(fSkewAngle)]
+ >> ')')[boost::bind(&calcSkewX,
+ boost::ref(aTransforms),
+ boost::cref(fSkewAngle))]
+ |
+ // skewY(phi)
+ (str_p("skewY")
+ >> '('
+ >> real_p[assign_a(fSkewAngle)]
+ >> ')')[boost::bind(&calcSkewY,
+ boost::ref(aTransforms),
+ boost::cref(fSkewAngle))]
+ // reset current transform after every push
+ )[assign_a(aCurrTransform,aIdentityTransform)],
+ // list delimiter is either ',' or space
+ ',' | eps_p ))
+ ) >> end_p,
+ // End grammar
+ space_p).full;
+
+ if( !bRes )
+ return false;
+
+ // fold all transformations into one
+ const geometry::AffineMatrix2D aTotalTransform(
+ std::accumulate(aTransforms.begin(),
+ aTransforms.end(),
+ aIdentityTransform,
+ &multiplyMatrix));
+
+ basegfx::unotools::homMatrixFromAffineMatrix(
+ rTransform,
+ aTotalTransform);
+
+ // TODO(F1): handle the ref case
+ return bRes;
+}
+
+//////////////////////////////////////////////////////////////
+
+bool parseViewBox( const char* sViewbox, basegfx::B2DRange& rRect )
+{
+ using namespace ::boost::spirit;
+
+ double x=0.0,y=0.0,w=0.0,h=0.0;
+
+ const bool bRes = parse(sViewbox,
+ // Begin grammar
+ (
+ // 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;
+
+ if( !bRes )
+ return false;
+
+ rRect = basegfx::B2DRange(x,y,x+w,y+h);
+
+ return true;
+}
+
+//////////////////////////////////////////////////////////////
+
+bool parseDashArray( const char* sDashArray, std::vector<double>& rOutputVector )
+{
+ using namespace ::boost::spirit;
+
+ rOutputVector.clear();
+ return parse(sDashArray,
+ // Begin grammar
+ (
+ // 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;
+}
+
+//////////////////////////////////////////////////////////////
+
+namespace
+{
+void appendChar( std::string& str, char character)
+{
+ str.append(1,character);
+}
+}
+
+bool parseXlinkHref( const char* sXlinkHref, std::string& data )
+{
+ using namespace ::boost::spirit;
+
+ data.erase(data.begin(),data.end());
+
+ std::string sLink(sXlinkHref);
+
+ if (!sLink.compare(0,5,"data:"))
+ {
+ // the inplace "data" uri
+ size_t position = sLink.rfind(',');
+ if (position > 0 && position < std::string::npos)
+ {
+ data = sLink.substr(position+1);
+ OSL_TRACE("%s", data.c_str());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace svgi
diff --git a/filter/source/svg/parserfragments.hxx b/filter/source/svg/parserfragments.hxx
new file mode 100644
index 000000000000..bcb6427aa4d8
--- /dev/null
+++ b/filter/source/svg/parserfragments.hxx
@@ -0,0 +1,50 @@
+/*************************************************************************
+ *
+ * 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 3.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_PARSERFRAGMENTS_HXX
+#define INCLUDED_PARSERFRAGMENTS_HXX
+
+#include <sal/config.h>
+#include <vector>
+#include <string>
+
+namespace basegfx
+{
+ class B2DHomMatrix;
+ class B2DRange;
+}
+namespace svgi
+{
+ struct ARGBColor;
+
+ /// Parse given string for one of the SVG color grammars
+ bool parseColor( const char* sColor, ARGBColor& rColor );
+ bool parseOpacity( const char* sOpacity, ARGBColor& rColor );
+
+ /// Parse given string for one of the SVG transformation grammars
+ bool parseTransform( const char* sTransform, basegfx::B2DHomMatrix& rTransform );
+
+ /// Parse given string for the viewBox attribute
+ bool parseViewBox( const char* sViewbox, basegfx::B2DRange& rRect );
+
+ /// Parse given string for a list of double values, comma-delimited
+ bool parseDashArray( const char* sDashArray, std::vector<double>& rOutputVector );
+
+ /// Parse given string for the xlink attribute
+ bool parseXlinkHref( const char* xlink, std::string& data );
+
+} // namespace svgi
+
+#endif
diff --git a/filter/source/svg/spirit_supplements.hxx b/filter/source/svg/spirit_supplements.hxx
new file mode 100644
index 000000000000..6623e6d64f3b
--- /dev/null
+++ b/filter/source/svg/spirit_supplements.hxx
@@ -0,0 +1,115 @@
+/*************************************************************************
+ *
+ * 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 3.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SPIRIT_SUPPLEMENTS_HXX
+#define INCLUDED_SPIRIT_SUPPLEMENTS_HXX
+
+# ifndef USE_MODERN_SPIRIT
+# include <boost/spirit.hpp>
+
+namespace boost { namespace spirit
+{
+ template <>
+ class assign_actor< std::pair<const char*,const char*> >
+ {
+ public:
+ explicit assign_actor(std::pair<const char*,const char*>& ref_)
+ : ref(ref_) {}
+
+ template <typename T2>
+ void operator()(T2 const& val) const
+ { ref = val; }
+
+ template <typename IteratorT>
+ void operator()(IteratorT const& f, IteratorT const& l) const
+ {
+ ref.first = f, ref.second = l;
+ }
+
+ private:
+ std::pair<const char*,const char*>& ref;
+ };
+
+ template<typename Target, typename Value> struct assigner
+ {
+ assigner( Target& rTarget, Value aValue ) :
+ mrTarget(rTarget), maValue(aValue)
+ {}
+
+ void assign() const { mrTarget=maValue; }
+
+ void operator()() const { assign(); }
+ template<typename T1> void operator()(T1) const { assign(); }
+ template<typename T1,typename T2> void operator()(T1,T2) const { assign(); }
+ template<typename T1,typename T2,typename T3> void operator()(T1,T2,T3) const { assign(); }
+
+ Target& mrTarget;
+ const Value maValue;
+ };
+
+ template<typename Target, typename Value> inline assigner<Target,Value>
+ assign_a( Target& rTarget, Value aValue )
+ {
+ return assigner<Target,Value>(rTarget,aValue);
+ }
+
+ template <typename Target> inline assign_actor<Target>
+ assign_a(Target& rTarget)
+ {
+ return assign_actor<Target>(rTarget);
+ }
+
+ template<typename Target, typename Value> struct back_pusher
+ {
+ back_pusher( Target& rTarget, const Value& rValue ) :
+ mrTarget(rTarget), mrValue(rValue)
+ {}
+
+ void push_back() const { mrTarget.push_back(mrValue); }
+
+ void operator()() const { push_back(); }
+ template<typename T1> void operator()(T1) const { push_back(); }
+ template<typename T1,typename T2> void operator()(T1,T2) const { push_back(); }
+ template<typename T1,typename T2,typename T3> void operator()(T1,T2,T3) const { push_back(); }
+
+ Target& mrTarget;
+ const Value& mrValue;
+ };
+
+ template<typename Target, typename Value> inline back_pusher<Target,Value>
+ push_back_a( Target& rTarget, const Value& rValue )
+ {
+ return back_pusher<Target,Value>(rTarget,rValue);
+ }
+
+ template<typename Target> struct value_back_pusher
+ {
+ explicit value_back_pusher( Target& rTarget ) :
+ mrTarget(rTarget)
+ {}
+ template<typename T1> void operator()(T1 val) const { mrTarget.push_back(val); }
+
+ Target& mrTarget;
+ };
+
+ template<typename Target> inline value_back_pusher<Target>
+ push_back_a( Target& rTarget )
+ {
+ return value_back_pusher<Target>(rTarget);
+ }
+} }
+
+# endif
+#endif
diff --git a/filter/source/svg/svgfilter.cxx b/filter/source/svg/svgfilter.cxx
index 118474bbe2b0..2755dfcf45d4 100644
--- a/filter/source/svg/svgfilter.cxx
+++ b/filter/source/svg/svgfilter.cxx
@@ -30,13 +30,16 @@
#include <cstdio>
-#include "svgfilter.hxx"
+#include <comphelper/servicedecl.hxx>
+#include <uno/environment.h>
#include <com/sun/star/drawing/XDrawPage.hpp>
#include <com/sun/star/drawing/XDrawView.hpp>
#include <com/sun/star/frame/XDesktop.hdl>
#include <com/sun/star/frame/XController.hdl>
#include <vos/mutex.hxx>
+#include "svgfilter.hxx"
+
using ::rtl::OUString;
using namespace ::com::sun::star;
@@ -44,8 +47,9 @@ using namespace ::com::sun::star;
// - SVGFilter -
// -------------
-SVGFilter::SVGFilter( const Reference< XMultiServiceFactory > &rxMSF ) :
- mxMSF( rxMSF ),
+SVGFilter::SVGFilter( const Reference< XComponentContext >& rxCtx ) :
+ mxMSF( rxCtx->getServiceManager(),
+ uno::UNO_QUERY_THROW ),
mpSVGDoc( NULL ),
mpSVGExport( NULL ),
mpSVGFontExport( NULL ),
@@ -80,11 +84,9 @@ sal_Bool SAL_CALL SVGFilter::filter( const Sequence< PropertyValue >& rDescripto
if( pFocusWindow )
pFocusWindow->EnterWait();
-#ifdef SOLAR_JAVA
if( mxDstDoc.is() )
bRet = implImport( rDescriptor );
else
-#endif
if( mxSrcDoc.is() )
{
uno::Reference< frame::XDesktop > xDesktop( mxMSF->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.frame.Desktop" ) ),
@@ -153,77 +155,64 @@ void SAL_CALL SVGFilter::setSourceDocument( const Reference< XComponent >& xDoc
// -----------------------------------------------------------------------------
-#ifdef SOLAR_JAVA
void SAL_CALL SVGFilter::setTargetDocument( const Reference< XComponent >& xDoc )
throw (::com::sun::star::lang::IllegalArgumentException, RuntimeException)
{
mxDstDoc = xDoc;
}
-#endif
-
-// -----------------------------------------------------------------------------
-
-void SAL_CALL SVGFilter::initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& /* aArguments */ )
- throw (Exception, RuntimeException)
-{
-}
-
-// -----------------------------------------------------------------------------
-
-OUString SVGFilter_getImplementationName ()
- throw (RuntimeException)
-{
- return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Draw.SVGFilter" ) );
-}
-
-// -----------------------------------------------------------------------------
-
-#define SERVICE_NAME "com.sun.star.document.SVGFilter"
-
-sal_Bool SAL_CALL SVGFilter_supportsService( const OUString& ServiceName )
- throw (RuntimeException)
-{
- return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) );
-}
// -----------------------------------------------------------------------------
-Sequence< OUString > SAL_CALL SVGFilter_getSupportedServiceNames( ) throw (RuntimeException)
+rtl::OUString SAL_CALL SVGFilter::detect( Sequence< PropertyValue >& io_rDescriptor ) throw (RuntimeException)
{
- Sequence < OUString > aRet(1);
- OUString* pArray = aRet.getArray();
- pArray[0] = OUString ( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) );
- return aRet;
-}
+ uno::Reference< io::XInputStream > xInput;
+ rtl::OUString aURL;
-#undef SERVICE_NAME
+ const beans::PropertyValue* pAttribs = io_rDescriptor.getConstArray();
+ const sal_Int32 nAttribs = io_rDescriptor.getLength();
+ for( sal_Int32 i = 0; i < nAttribs; i++ )
+ {
+ if( pAttribs[i].Name.equalsAscii( "InputStream" ) )
+ pAttribs[i].Value >>= xInput;
+ }
-// -----------------------------------------------------------------------------
+ if( !xInput.is() )
+ return rtl::OUString();
-Reference< XInterface > SAL_CALL SVGFilter_createInstance( const Reference< XMultiServiceFactory > & rSMgr) throw( Exception )
-{
- return (cppu::OWeakObject*) new SVGFilter( rSMgr );
-}
+ uno::Reference< io::XSeekable > xSeek( xInput, uno::UNO_QUERY );
+ if( xSeek.is() )
+ xSeek->seek( 0 );
-// -----------------------------------------------------------------------------
+ // read the first 1024 bytes & check a few magic string
+ // constants (heuristically)
+ const sal_Int32 nLookAhead = 1024;
+ uno::Sequence< sal_Int8 > aBuf( nLookAhead );
+ const sal_uInt64 nBytes=xInput->readBytes(aBuf, nLookAhead);
+ const sal_Int8* const pBuf=aBuf.getConstArray();
-OUString SAL_CALL SVGFilter::getImplementationName( )
- throw (RuntimeException)
-{
- return SVGFilter_getImplementationName();
-}
+ sal_Int8 aMagic1[] = {'<', 's', 'v', 'g'};
+ if( std::search(pBuf, pBuf+nBytes,
+ aMagic1, aMagic1+sizeof(aMagic1)/sizeof(*aMagic1)) != pBuf+nBytes )
+ return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("svg_Scalable_Vector_Graphics") );
-// -----------------------------------------------------------------------------
+ sal_Int8 aMagic2[] = {'D', 'O', 'C', 'T', 'Y', 'P', 'E', ' ', 's', 'v', 'g'};
+ if( std::search(pBuf, pBuf+nBytes,
+ aMagic2, aMagic2+sizeof(aMagic2)/sizeof(*aMagic2)) != pBuf+nBytes )
+ return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("svg_Scalable_Vector_Graphics") );
-sal_Bool SAL_CALL SVGFilter::supportsService( const OUString& rServiceName )
- throw (RuntimeException)
-{
- return SVGFilter_supportsService( rServiceName );
+ return rtl::OUString();
}
// -----------------------------------------------------------------------------
-::com::sun::star::uno::Sequence< OUString > SAL_CALL SVGFilter::getSupportedServiceNames( ) throw (RuntimeException)
-{
- return SVGFilter_getSupportedServiceNames();
-}
+namespace sdecl = comphelper::service_decl;
+ sdecl::class_<SVGFilter> serviceImpl;
+ const sdecl::ServiceDecl svgFilter(
+ serviceImpl,
+ "com.sun.star.comp.Draw.SVGFilter",
+ "com.sun.star.document.ImportFilter;"
+ "com.sun.star.document.ExportFilter;"
+ "com.sun.star.document.ExtendedTypeDetection" );
+
+// The C shared lib entry points
+COMPHELPER_SERVICEDECL_EXPORTS1(svgFilter)
diff --git a/filter/source/svg/svgfilter.hxx b/filter/source/svg/svgfilter.hxx
index 0bbc64e2c244..a1582b5e434f 100644
--- a/filter/source/svg/svgfilter.hxx
+++ b/filter/source/svg/svgfilter.hxx
@@ -35,20 +35,14 @@
#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
#include <com/sun/star/presentation/XPresentationSupplier.hpp>
#include <com/sun/star/document/XFilter.hpp>
-#ifdef SOLAR_JAVA
#include <com/sun/star/document/XImporter.hpp>
-#endif // SOLAR_JAVA
#include <com/sun/star/document/XExporter.hpp>
+#include <com/sun/star/document/XExtendedFilterDetection.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/lang/XComponent.hpp>
-#include <cppuhelper/implbase1.hxx>
-#ifdef SOLAR_JAVA
-#include <cppuhelper/implbase5.hxx>
-#else // !SOLAR_JAVA
#include <cppuhelper/implbase4.hxx>
-#endif
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/io/XActiveDataSource.hpp>
#include <com/sun/star/presentation/AnimationEffect.hpp>
@@ -175,18 +169,10 @@ class SVGFontExport;
class SVGActionWriter;
class EditFieldInfo;
-#ifdef SOLAR_JAVA
-class SVGFilter : public cppu::WeakImplHelper5 < XFilter,
- XImporter,
- XExporter,
- XInitialization,
- XServiceInfo >
-#else // !SOLAR_JAVA
class SVGFilter : public cppu::WeakImplHelper4 < XFilter,
+ XImporter,
XExporter,
- XInitialization,
- XServiceInfo >
-#endif
+ XExtendedFilterDetection >
{
typedef ::std::hash_map< Reference< XInterface >, ObjectRepresentation, HashReferenceXInterface > ObjectMap;
@@ -203,15 +189,11 @@ private:
ObjectMap* mpObjects;
Reference< XComponent > mxSrcDoc;
-#ifdef SOLAR_JAVA
Reference< XComponent > mxDstDoc;
-#endif
Reference< XDrawPage > mxDefaultPage;
Link maOldFieldHdl;
-#ifdef SOLAR_JAVA
sal_Bool implImport( const Sequence< PropertyValue >& rDescriptor ) throw (RuntimeException);
-#endif
sal_Bool implExport( const Sequence< PropertyValue >& rDescriptor ) throw (RuntimeException);
Reference< XDocumentHandler > implCreateExportDocumentHandler( const Reference< XOutputStream >& rxOStm );
@@ -250,26 +232,19 @@ protected:
virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& rDescriptor ) throw(RuntimeException);
virtual void SAL_CALL cancel( ) throw (RuntimeException);
-#ifdef SOLAR_JAVA
// XImporter
virtual void SAL_CALL setTargetDocument( const Reference< XComponent >& xDoc ) throw(IllegalArgumentException, RuntimeException);
-#endif
// XExporter
virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) throw(IllegalArgumentException, RuntimeException);
- // XInitialization
- virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw(Exception, RuntimeException);
-
- // XServiceInfo
- virtual ::rtl::OUString SAL_CALL getImplementationName() throw(RuntimeException);
- virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw(RuntimeException);
- virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw(RuntimeException);
+ // XExtendedFilterDetection
+ virtual rtl::OUString SAL_CALL detect( Sequence< PropertyValue >& io_rDescriptor ) throw (RuntimeException);
public:
- SVGFilter( const Reference< XMultiServiceFactory > &rxMSF );
- virtual ~SVGFilter();
+ explicit SVGFilter( const Reference< XComponentContext >& rxCtx );
+ virtual ~SVGFilter();
};
// -----------------------------------------------------------------------------
diff --git a/filter/source/svg/svgimport.cxx b/filter/source/svg/svgimport.cxx
index fd4f711cb085..7f4be27745b6 100644
--- a/filter/source/svg/svgimport.cxx
+++ b/filter/source/svg/svgimport.cxx
@@ -29,160 +29,59 @@
#include "precompiled_filter.hxx"
#include "svgfilter.hxx"
+#include "svgreader.hxx"
+
#include "rtl/ref.hxx"
-#include "jvmaccess/virtualmachine.hxx"
-// -------------
-// - SVGFilter -
-// -------------
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <com/sun/star/lang/XComponent.hpp>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Type.hxx>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <com/sun/star/xml/sax/XParser.hpp>
+#include <com/sun/star/xml/sax/InputSource.hpp>
+#include <com/sun/star/xml/XImportFilter.hpp>
+
+#include <com/sun/star/io/XActiveDataSource.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::svgi;
sal_Bool SVGFilter::implImport( const Sequence< PropertyValue >& rDescriptor )
throw (RuntimeException)
{
- Reference< XMultiServiceFactory > xServiceFactory( ::comphelper::getProcessServiceFactory() ) ;
- rtl::OUString aTmpFileName;
- String aFileName;
- sal_Int32 nLength = rDescriptor.getLength();
- const PropertyValue* pValue = rDescriptor.getConstArray();
- sal_Bool bRet = sal_False;
-
- for( sal_Int32 i = 0 ; ( i < nLength ) && !aTmpFileName.getLength(); i++)
- if( pValue[ i ].Name.equalsAscii( "FileName" ) )
- pValue[ i ].Value >>= aTmpFileName;
-
- if( aTmpFileName.getLength() && xServiceFactory.is() )
+ rtl::OUString aURL;
+ uno::Reference< io::XInputStream > xInputStream;
+ uno::Reference< task::XStatusIndicator > xStatus;
+ const sal_Int32 nLength = rDescriptor.getLength();
+ const beans::PropertyValue* pAttribs = rDescriptor.getConstArray();
+ for ( sal_Int32 i=0 ; i<nLength; ++i, ++pAttribs )
{
-
- Reference< XJavaVM > xJavaVM( xServiceFactory->createInstance( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.java.JavaVirtualMachine") ) ), UNO_QUERY );
- Sequence< sal_Int8 > aProcessID( 17 );
- String aLocalFile;
-
- if( ::utl::LocalFileHelper::ConvertURLToPhysicalName( aTmpFileName, aLocalFile ) && aLocalFile.Len() )
+ if( pAttribs->Name.equalsAscii( "InputStream" ) )
{
- rtl_getGlobalProcessId( (sal_uInt8 *) aProcessID.getArray() );
- aProcessID[16] = 0;
-
- OSL_ENSURE(sizeof (sal_Int64)
- >= sizeof (jvmaccess::VirtualMachine *),
- "Pointer cannot be represented as sal_Int64");
- sal_Int64 nPointer = reinterpret_cast< sal_Int64 >(
- static_cast< jvmaccess::VirtualMachine * >(0));
- xJavaVM->getJavaVM(aProcessID) >>= nPointer;
- rtl::Reference<jvmaccess::VirtualMachine> _virtualMachine =
- reinterpret_cast< jvmaccess::VirtualMachine * >(nPointer);
- if (!_virtualMachine.is())
- return bRet;
-
- jobjectArray aArgs;
- jclass aClass;
- jmethodID aMId;
- jstring aJStr;
-
- try
- {
- jvmaccess::VirtualMachine::AttachGuard vmGuard(_virtualMachine);
-
- JNIEnv * pEnv = vmGuard.getEnvironment();
-
- aClass = pEnv->FindClass( "SOTranscoder" );
-
- if( aClass )
- {
- aMId = pEnv->GetStaticMethodID( aClass, "main", "([Ljava/lang/String;)V" );
- if ( aMId )
- {
-
- ::utl::TempFile aTempFile;
- String aOutputURL( aTempFile.GetURL() );
- String aOutputFile;
-
- aTempFile.EnableKillingFile();
-
- if( ::utl::LocalFileHelper::ConvertURLToPhysicalName( aOutputURL, aOutputFile ) && aOutputFile.Len() )
- {
- aJStr = pEnv->NewStringUTF( ByteString( aLocalFile.GetBuffer(), RTL_TEXTENCODING_UTF8 ).GetBuffer() );
- aArgs = static_cast<jobjectArray>(pEnv->NewObjectArray( 2, pEnv->FindClass( "java/lang/String" ), aJStr ));
- aJStr = pEnv->NewStringUTF( ByteString( aOutputFile.GetBuffer(), RTL_TEXTENCODING_UTF8 ).GetBuffer() );
- pEnv->SetObjectArrayElement( aArgs, 1, aJStr );
- pEnv->CallStaticVoidMethod( aClass, aMId, aArgs );
-
- Graphic aGraphic;
- SvStream* pIStm = ::utl::UcbStreamHelper::CreateStream( aOutputURL, STREAM_READ );
-
- if( pIStm )
- {
- GraphicConverter::Import( *pIStm, aGraphic );
- delete pIStm;
- }
-
- Reference< XDrawPagesSupplier > xDrawPagesSupplier( mxDstDoc, UNO_QUERY );
-
- if( xDrawPagesSupplier.is() && ( aGraphic.GetType() != GRAPHIC_NONE ) )
- {
- Reference< XDrawPages > xDrawPages( xDrawPagesSupplier->getDrawPages() );
-
- if( xDrawPages.is() && xDrawPages->getCount() )
- {
- Reference< XDrawPage > xDrawPage;
-
- if( xDrawPages->getByIndex( 0 ) >>= xDrawPage )
- {
- Reference< XShapes > xShapes( xDrawPage, UNO_QUERY );
- Reference< XPropertySet> xPagePropSet( xDrawPage, UNO_QUERY );
- Reference< XShape > xShape( Reference< XMultiServiceFactory >( mxDstDoc, UNO_QUERY )->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.GraphicObjectShape" ) ) ), UNO_QUERY );
-
- if( xPagePropSet.is() && xShapes.is() && xShape.is() )
- {
- Reference< XPropertySet > xPropSet( xShape, UNO_QUERY );
- sal_Int32 nPageWidth = 0, nPageHeight = 0;
-
- xPagePropSet->getPropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Width" ) ) ) >>= nPageWidth;
- xPagePropSet->getPropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Height" ) ) ) >>= nPageHeight;
-
- if( xPropSet.is() && nPageWidth && nPageHeight )
- {
- xShapes->add( xShape );
-
- ::com::sun::star::awt::Point aPos;
- ::com::sun::star::awt::Size aSize;
- GraphicObject aGraphObj( aGraphic );
- String aGraphURL( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.GraphicObject:" ) );
- Any aValue;
- Size aGraphicSize;
- const MapMode aTargetMapMode( MAP_100TH_MM );
-
- if( aGraphObj.GetPrefMapMode().GetMapUnit() == MAP_PIXEL )
- aGraphicSize = Application::GetDefaultDevice()->PixelToLogic( aGraphObj.GetPrefSize(), aTargetMapMode );
- else
- aGraphicSize = OutputDevice::LogicToLogic( aGraphObj.GetPrefSize(), aGraphObj.GetPrefMapMode(), aTargetMapMode );
-
- aGraphURL += String( aGraphObj.GetUniqueID(), RTL_TEXTENCODING_ASCII_US );
- aValue <<= rtl::OUString( aGraphURL );
- xPropSet->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GraphicURL" ) ), aValue );
-
- aPos.X = ( nPageWidth - aGraphicSize.Width() ) >> 1;
- aPos.Y = ( nPageHeight - aGraphicSize.Height() ) >> 1;
-
- aSize.Width = aGraphicSize.Width();
- aSize.Height = aGraphicSize.Height();
-
- xShape->setPosition( aPos );
- xShape->setSize( aSize );
-
- bRet = sal_True;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &)
- {
- }
+ pAttribs->Value >>= xInputStream;
}
+ else if( pAttribs->Name.equalsAscii( "StatusIndicator" ) )
+ pAttribs->Value >>= xStatus;
}
- return bRet;
+
+ OSL_ASSERT(xInputStream.is());
+ if(!xInputStream.is())
+ return sal_False;
+
+ rtl::OUString sXMLImportService ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Draw.XMLOasisImporter" ) );
+ Reference < XDocumentHandler > xInternalHandler( mxMSF->createInstance( sXMLImportService ), UNO_QUERY );
+
+ // The XImporter sets up an empty target document for XDocumentHandler to write to..
+ uno::Reference < XImporter > xImporter(xInternalHandler, UNO_QUERY);
+ xImporter->setTargetDocument(mxDstDoc);
+
+ SVGReader aReader(mxMSF, xInputStream, xInternalHandler);
+ return aReader.parseAndConvert();
}
diff --git a/filter/source/svg/svgreader.cxx b/filter/source/svg/svgreader.cxx
new file mode 100644
index 000000000000..d24ab7136477
--- /dev/null
+++ b/filter/source/svg/svgreader.cxx
@@ -0,0 +1,1876 @@
+/*************************************************************************
+ *
+ * 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 3.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_filter.hxx"
+
+#include "svgreader.hxx"
+#include <xmloff/attrlist.hxx>
+#include "gfxtypes.hxx"
+#include "units.hxx"
+#include "parserfragments.hxx"
+#include "tokenmap.hxx"
+#include "b2dellipse.hxx"
+
+#include <rtl/math.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <basegfx/vector/b2enums.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dlinegeometry.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dlinegeometry.hxx>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/xml/sax/XParser.hpp>
+#include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
+#include <com/sun/star/xml/dom/NodeType.hpp>
+
+#include <boost/bind.hpp>
+#include <hash_set>
+#include <map>
+#include <string.h>
+
+#define USTR(x) rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( x ) )
+#define OASIS_STR "urn:oasis:names:tc:opendocument:xmlns:"
+
+using namespace ::com::sun::star;
+
+namespace svgi
+{
+namespace
+{
+
+/** visits all children of the specified type with the given functor
+ */
+template<typename Func> void visitChildren(const Func& rFunc,
+ const uno::Reference<xml::dom::XElement> xElem,
+ xml::dom::NodeType eChildType )
+{
+ uno::Reference<xml::dom::XNodeList> xChildren( xElem->getChildNodes() );
+ const sal_Int32 nNumNodes( xChildren->getLength() );
+ for( sal_Int32 i=0; i<nNumNodes; ++i )
+ {
+ if( xChildren->item(i)->getNodeType() == eChildType )
+ rFunc( *xChildren->item(i).get() );
+ }
+}
+
+/** Visit all elements of the given tree (in-order traversal)
+
+ Given functor is called for every element, and passed the
+ element's attributes, if any
+ */
+template<typename Func> void visitElements(Func& rFunc,
+ const uno::Reference<xml::dom::XElement> xElem)
+{
+ if( xElem->hasAttributes() )
+ rFunc(xElem,xElem->getAttributes());
+ else
+ rFunc(xElem);
+
+ // notify children processing
+ rFunc.push();
+
+ // recurse over children
+ uno::Reference<xml::dom::XNodeList> xChildren( xElem->getChildNodes() );
+ const sal_Int32 nNumNodes( xChildren->getLength() );
+ for( sal_Int32 i=0; i<nNumNodes; ++i )
+ {
+ if( xChildren->item(i)->getNodeType() == xml::dom::NodeType_ELEMENT_NODE )
+ visitElements( rFunc,
+ uno::Reference<xml::dom::XElement>(
+ xChildren->item(i),
+ uno::UNO_QUERY_THROW) );
+ }
+
+ // children processing done
+ 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,
+ StateMap& rStateMap,
+ const State& rInitialState,
+ const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler) :
+ mnCurrStateId(0),
+ maCurrState(),
+ maParentStates(),
+ mrStates(rStatePool),
+ mrStateMap(rStateMap),
+ mxDocumentHandler(xDocumentHandler),
+ maGradientVector(),
+ maGradientStopVector()
+ {
+ maParentStates.push_back(rInitialState);
+ }
+
+ void operator()( const uno::Reference<xml::dom::XElement>& )
+ {}
+
+ void operator()( const uno::Reference<xml::dom::XElement>& xElem,
+ const uno::Reference<xml::dom::XNamedNodeMap>& xAttributes )
+ {
+ const sal_Int32 nTagId(getTokenId(xElem->getTagName()));
+ switch (nTagId)
+ {
+ case XML_LINEARGRADIENT:
+ {
+ const sal_Int32 nNumAttrs( xAttributes->getLength() );
+ rtl::OUString sAttributeValue;
+ maGradientVector.push_back(Gradient(Gradient::LINEAR));
+
+ // do we have a reference to a parent gradient? parse
+ // that first, as it sets our defaults here (manually
+ // tracking default state on each Gradient variable is
+ // much more overhead)
+ uno::Reference<xml::dom::XNode> xNode(xAttributes->getNamedItem(USTR("href")));
+ if(xNode.is())
+ {
+ const rtl::OUString sValue(xNode->getNodeValue());
+ ElementRefMapType::iterator aFound=maGradientIdMap.end();
+ if (sValue.copy(0,1).equalsAscii("#"))
+ aFound = maGradientIdMap.find(sValue.copy(1));
+ else
+ aFound = maGradientIdMap.find(sValue);;
+
+ if( aFound != maGradientIdMap.end() )
+ maGradientVector.back() = maGradientVector[aFound->second];
+ }
+
+ // do that after dereferencing, to prevent hyperlinked
+ // gradient to clobber our Id again
+ maGradientVector.back().mnId = maGradientVector.size()-1;
+ maGradientVector.back().meType = Gradient::LINEAR; // has been clobbered as well
+
+ for( sal_Int32 i=0; i<nNumAttrs; ++i )
+ {
+ parseLinearGradientData( maGradientVector.back(),
+ maGradientVector.size()-1,
+ getTokenId(xAttributes->item(i)->getNodeName()),
+ xAttributes->item(i)->getNodeValue() );
+ }
+ break;
+ }
+ case XML_RADIALGRADIENT:
+ {
+ const sal_Int32 nNumAttrs( xAttributes->getLength() );
+ rtl::OUString sAttributeValue;
+ maGradientVector.push_back(Gradient(Gradient::RADIAL));
+
+ // do we have a reference to a parent gradient? parse
+ // that first, as it sets our defaults here (manually
+ // tracking default state on each Gradient variable is
+ // much more overhead)
+ uno::Reference<xml::dom::XNode> xNode(xAttributes->getNamedItem(USTR("href")));
+ if(xNode.is())
+ {
+ const rtl::OUString sValue(xNode->getNodeValue());
+ ElementRefMapType::iterator aFound=maGradientIdMap.end();
+ if (sValue.copy(0,1).equalsAscii("#"))
+ aFound = maGradientIdMap.find(sValue.copy(1));
+ else
+ aFound = maGradientIdMap.find(sValue);;
+
+ if( aFound != maGradientIdMap.end() )
+ maGradientVector.back() = maGradientVector[aFound->second];
+ }
+
+ // do that after dereferencing, to prevent hyperlinked
+ // gradient to clobber our Id again
+ maGradientVector.back().mnId = maGradientVector.size()-1;
+ maGradientVector.back().meType = Gradient::RADIAL; // has been clobbered as well
+
+ for( sal_Int32 i=0; i<nNumAttrs; ++i )
+ {
+ 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;
+ maGradientStopVector.push_back(GradientStop());
+ maGradientVector.back().maStops.push_back(maGradientStopVector.size()-1);
+ for( sal_Int32 i=0; i<nNumAttrs; ++i )
+ {
+ parseGradientStop( maGradientStopVector.back(),
+ maGradientStopVector.size()-1,
+ getTokenId(xAttributes->item(i)->getNodeName()),
+ xAttributes->item(i)->getNodeValue() );
+ }
+ break;
+ }
+ default:
+ {
+ // init state. inherit defaults from parent.
+ maCurrState = maParentStates.back();
+ maCurrState.maTransform.identity();
+
+ // scan for style info
+ const sal_Int32 nNumAttrs( xAttributes->getLength() );
+ rtl::OUString sAttributeValue;
+ for( sal_Int32 i=0; i<nNumAttrs; ++i )
+ {
+ sAttributeValue = xAttributes->item(i)->getNodeValue();
+ const sal_Int32 nTokenId(
+ getTokenId(xAttributes->item(i)->getNodeName()));
+ if( XML_STYLE == nTokenId )
+ parseStyle(sAttributeValue);
+ else
+ parseAttribute(nTokenId,
+ sAttributeValue);
+ }
+
+ // all attributes parsed, can calc total CTM now
+ basegfx::B2DHomMatrix aLocalTransform;
+ if( !maCurrState.maViewBox.isEmpty() &&
+ maCurrState.maViewBox.getWidth() != 0.0 &&
+ maCurrState.maViewBox.getHeight() != 0.0 )
+ {
+ // transform aViewBox into viewport, such that they
+ // coincide
+ aLocalTransform.translate(-maCurrState.maViewBox.getMinX(),
+ -maCurrState.maViewBox.getMinY());
+ aLocalTransform.scale(maCurrState.maViewport.getWidth()/maCurrState.maViewBox.getWidth(),
+ maCurrState.maViewport.getHeight()/maCurrState.maViewBox.getHeight());
+ }
+ maCurrState.maCTM = maCurrState.maCTM*maCurrState.maTransform*aLocalTransform;
+
+ OSL_TRACE("annotateStyle - CTM is: %f %f %f %f %f %f",
+ maCurrState.maCTM.get(0,0),
+ maCurrState.maCTM.get(0,1),
+ maCurrState.maCTM.get(0,2),
+ maCurrState.maCTM.get(1,0),
+ maCurrState.maCTM.get(1,1),
+ maCurrState.maCTM.get(1,2));
+
+ // if necessary, serialize to automatic-style section
+ writeStyle(xElem,nTagId);
+ }
+ }
+ }
+
+ rtl::OUString getStyleName( const char* sPrefix, sal_Int32 nId )
+ {
+ 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(1,rGradient.maStops.front());
+ for( sal_Size i=1; i<rGradient.maStops.size(); ++i )
+ {
+ if( maGradientStopVector[rGradient.maStops[i]].maStopColor !=
+ maGradientStopVector[aNewStops.back()].maStopColor )
+ aNewStops.push_back(rGradient.maStops[i]);
+ }
+
+ rGradient.maStops = aNewStops;
+
+ // axial gradient, maybe?
+ if( rGradient.meType == Gradient::LINEAR &&
+ rGradient.maStops.size() == 3 &&
+ maGradientStopVector[rGradient.maStops.front()].maStopColor ==
+ maGradientStopVector[rGradient.maStops.back()].maStopColor )
+ {
+ // yep - keep it at that
+ return;
+ }
+
+ // find out most significant color difference, and limit to
+ // those two stops around this border (metric is
+ // super-simplistic: take euclidean distance of colors, weigh
+ // with stop distance)
+ sal_Size nMaxIndex=0;
+ double fMaxDistance=0.0;
+ for( sal_Size i=1; i<rGradient.maStops.size(); ++i )
+ {
+ const double fCurrDistance(
+ colorDiffSquared(
+ maGradientStopVector[rGradient.maStops[i-1]].maStopColor,
+ maGradientStopVector[rGradient.maStops[i]].maStopColor) *
+ (square(maGradientStopVector[rGradient.maStops[i-1]].mnStopPosition) +
+ square(maGradientStopVector[rGradient.maStops[i]].mnStopPosition)) );
+
+ if( fCurrDistance > fMaxDistance )
+ {
+ nMaxIndex = i-1;
+ fMaxDistance = fCurrDistance;
+ }
+ }
+ rGradient.maStops[0] = rGradient.maStops[nMaxIndex];
+ rGradient.maStops[1] = rGradient.maStops[nMaxIndex+1];
+ rGradient.maStops.erase(rGradient.maStops.begin()+2,rGradient.maStops.end());
+ }
+
+ sal_Int8 toByteColor( double val )
+ {
+ // TODO(Q3): duplicated from vcl::unotools
+ return sal::static_int_cast<sal_Int8>(
+ basegfx::fround(val*255.0));
+ }
+
+ rtl::OUString getOdfColor( const ARGBColor& rColor )
+ {
+ // TODO(Q3): duplicated from pdfimport
+ rtl::OUStringBuffer aBuf( 7 );
+ const sal_uInt8 nRed ( toByteColor(rColor.r) );
+ const sal_uInt8 nGreen( toByteColor(rColor.g) );
+ const sal_uInt8 nBlue ( toByteColor(rColor.b) );
+ aBuf.append( sal_Unicode('#') );
+ if( nRed < 10 )
+ aBuf.append( sal_Unicode('0') );
+ aBuf.append( sal_Int32(nRed), 16 );
+ if( nGreen < 10 )
+ aBuf.append( sal_Unicode('0') );
+ aBuf.append( sal_Int32(nGreen), 16 );
+ if( nBlue < 10 )
+ aBuf.append( sal_Unicode('0') );
+ aBuf.append( sal_Int32(nBlue), 16 );
+
+ // TODO(F3): respect alpha transparency (polygons etc.)
+ OSL_ASSERT(rColor.a == 1.0);
+
+ return aBuf.makeStringAndClear();
+ }
+
+ bool writeStyle(State& rState, const sal_Int32 nTagId)
+ {
+ rtl::Reference<SvXMLAttributeList> xAttrs( new SvXMLAttributeList() );
+ uno::Reference<xml::sax::XAttributeList> xUnoAttrs( xAttrs.get() );
+
+ std::pair<StatePool::iterator,
+ bool> aRes = mrStates.insert(rState);
+ if( !aRes.second )
+ return false; // not written
+
+ ++mnCurrStateId;
+
+ // mnStyleId does not take part in hashing/comparison
+ const_cast<State&>(*aRes.first).mnStyleId = mnCurrStateId;
+ mrStateMap.insert(std::make_pair(
+ mnCurrStateId,
+ rState));
+
+ // find two representative stop colors (as odf only support
+ // start&end color)
+ optimizeGradientStops(rState.maFillGradient);
+
+ // do we have a gradient fill? then write out gradient as well
+ if( rState.meFillType == GRADIENT && rState.maFillGradient.maStops.size() > 1 )
+ {
+ // TODO(F3): ODF12 supposedly also groks svg:linear/radialGradient
+ xAttrs->AddAttribute( USTR( "draw:name" ), getStyleName("svggradient", rState.maFillGradient.mnId) );
+ if( rState.maFillGradient.meType == Gradient::LINEAR )
+ {
+ // should the optimizeGradientStops method decide that
+ // this is a three-color gradient, it prolly wanted us
+ // to take axial instead
+ xAttrs->AddAttribute( USTR( "draw:style" ),
+ rState.maFillGradient.maStops.size() == 3 ?
+ USTR("axial") :
+ USTR("linear") );
+ }
+ else
+ {
+ xAttrs->AddAttribute( USTR( "draw:style" ), USTR("ellipsoid") );
+ xAttrs->AddAttribute( USTR( "draw:cx" ), USTR("50%") );
+ xAttrs->AddAttribute( USTR( "draw:cy" ), USTR("50%") );
+ }
+
+ basegfx::B2DTuple rScale, rTranslate;
+ double rRotate, rShearX;
+ if( rState.maFillGradient.maTransform.decompose(rScale, rTranslate, rRotate, rShearX) )
+ xAttrs->AddAttribute( USTR( "draw:angle" ),
+ rtl::OUString::valueOf(rRotate*1800.0/M_PI ) );
+ xAttrs->AddAttribute( USTR( "draw:start-color" ),
+ getOdfColor(
+ maGradientStopVector[
+ rState.maFillGradient.maStops[0]].maStopColor) );
+ xAttrs->AddAttribute( USTR( "draw:end-color" ),
+ getOdfColor(
+ maGradientStopVector[
+ rState.maFillGradient.maStops[1]].maStopColor) );
+ xAttrs->AddAttribute( USTR( "draw:border" ), USTR("0%") );
+ mxDocumentHandler->startElement( USTR("draw:gradient"),
+ xUnoAttrs );
+ mxDocumentHandler->endElement( USTR("draw:gradient") );
+
+ if( hasGradientOpacity(rState.maFillGradient) )
+ {
+ // need to write out opacity style as well
+ xAttrs->Clear();
+ xAttrs->AddAttribute( USTR( "draw:name" ), getStyleName("svgopacity", rState.maFillGradient.mnId) );
+ if( rState.maFillGradient.meType == Gradient::LINEAR )
+ {
+ xAttrs->AddAttribute( USTR( "draw:style" ), USTR("linear") );
+ }
+ else
+ {
+ xAttrs->AddAttribute( USTR( "draw:style" ), USTR("ellipsoid") );
+ xAttrs->AddAttribute( USTR( "draw:cx" ), USTR("50%") );
+ xAttrs->AddAttribute( USTR( "draw:cy" ), USTR("50%") );
+ }
+
+ // modulate gradient opacity with overall fill opacity
+ xAttrs->AddAttribute( USTR( "draw:end" ),
+ rtl::OUString::valueOf(
+ maGradientStopVector[
+ rState.maFillGradient.maStops[0]].maStopColor.a*
+ maCurrState.mnFillOpacity*100.0)+USTR("%" ) );
+ xAttrs->AddAttribute( USTR( "draw:start" ),
+ rtl::OUString::valueOf(
+ maGradientStopVector[
+ rState.maFillGradient.maStops[1]].maStopColor.a*
+ maCurrState.mnFillOpacity*100.0)+USTR("%" ) );
+ xAttrs->AddAttribute( USTR( "draw:border" ), USTR("0%") );
+ mxDocumentHandler->startElement( USTR("draw:opacity"),
+ xUnoAttrs );
+ mxDocumentHandler->endElement( USTR("draw:opacity") );
+ }
+ }
+
+ // serialize to automatic-style section
+ xAttrs->Clear();
+ xAttrs->AddAttribute( USTR( "style:name" ), getStyleName("svggraphicstyle", mnCurrStateId) );
+ xAttrs->AddAttribute( USTR( "style:family" ), USTR("graphic") );
+ mxDocumentHandler->startElement( USTR("style:style"),
+ xUnoAttrs );
+
+ xAttrs->Clear();
+ // text or shape? if the former, no use in processing any
+ // graphic attributes except stroke color, ODF can do ~nothing
+ // with text shapes
+ if( nTagId == XML_TEXT )
+ {
+ //xAttrs->AddAttribute( USTR( "draw:auto-grow-height"), USTR("true"));
+ xAttrs->AddAttribute( USTR( "draw:auto-grow-width"), USTR("true"));
+ xAttrs->AddAttribute( USTR( "draw:textarea-horizontal-align"), USTR("left"));
+ //xAttrs->AddAttribute( USTR( "draw:textarea-vertical-align"), USTR("top"));
+ xAttrs->AddAttribute( USTR( "fo:min-height"), USTR("0cm"));
+
+ xAttrs->AddAttribute( USTR( "fo:padding-top"), USTR("0cm"));
+ xAttrs->AddAttribute( USTR( "fo:padding-left"), USTR("0cm"));
+ xAttrs->AddAttribute( USTR( "fo:padding-right"), USTR("0cm"));
+ xAttrs->AddAttribute( USTR( "fo:padding-bottom"), USTR("0cm"));
+
+ // disable any background shape
+ xAttrs->AddAttribute( USTR( "draw:stroke" ), USTR("none"));
+ xAttrs->AddAttribute( USTR( "draw:fill" ), USTR("none"));
+ }
+ else
+ {
+ if( rState.meFillType != NONE )
+ {
+ if( rState.meFillType == GRADIENT )
+ {
+ xAttrs->AddAttribute( USTR( "draw:fill" ), USTR("gradient"));
+ xAttrs->AddAttribute( USTR( "draw:fill-gradient-name" ),
+ getStyleName("svggradient", rState.maFillGradient.mnId) );
+ if( hasGradientOpacity(rState.maFillGradient) )
+ {
+ // needs transparency gradient as well
+ xAttrs->AddAttribute( USTR( "draw:opacity-name" ),
+ getStyleName("svgopacity", rState.maFillGradient.mnId) );
+ }
+ else if( maCurrState.mnFillOpacity != 1.0 )
+ xAttrs->AddAttribute( USTR( "draw:opacity" ),
+ rtl::OUString::valueOf(100.0*maCurrState.mnFillOpacity)+USTR("%") );
+ }
+ else
+ {
+ xAttrs->AddAttribute( USTR( "draw:fill" ), USTR("solid"));
+ xAttrs->AddAttribute( USTR( "draw:fill-color" ), getOdfColor(rState.maFillColor));
+ if( maCurrState.mnFillOpacity != 1.0 )
+ xAttrs->AddAttribute( USTR( "draw:opacity" ),
+ rtl::OUString::valueOf(100.0*maCurrState.mnFillOpacity)+USTR("%") );
+ }
+ }
+ else
+ xAttrs->AddAttribute( USTR( "draw:fill" ), USTR("none"));
+
+ if( rState.meStrokeType != NONE )
+ {
+ xAttrs->AddAttribute( USTR( "draw:stroke" ), USTR("solid"));
+ xAttrs->AddAttribute( USTR( "svg:stroke-color" ), getOdfColor(rState.maStrokeColor));
+ }
+ else
+ xAttrs->AddAttribute( USTR( "draw:stroke" ), USTR("none"));
+
+ if( maCurrState.mnStrokeWidth != 0.0 )
+ {
+ ::basegfx::B2DVector aVec(maCurrState.mnStrokeWidth,0);
+ aVec *= maCurrState.maCTM;
+ xAttrs->AddAttribute( USTR("svg:stroke-width"), rtl::OUString::valueOf( pt2mm(aVec.getLength()) )+USTR("mm"));
+ }
+ if( maCurrState.meLineJoin == basegfx::B2DLINEJOIN_MITER )
+ xAttrs->AddAttribute( USTR( "draw:stroke-linejoin"), USTR("miter"));
+ else if( maCurrState.meLineJoin == basegfx::B2DLINEJOIN_ROUND )
+ xAttrs->AddAttribute( USTR( "draw:stroke-linejoin"), USTR("round"));
+ else if( maCurrState.meLineJoin == basegfx::B2DLINEJOIN_BEVEL )
+ xAttrs->AddAttribute( USTR( "draw:stroke-linejoin"), USTR("bevel"));
+ if( maCurrState.mnStrokeOpacity != 1.0 )
+ xAttrs->AddAttribute( USTR("svg:stroke-opacity"),
+ rtl::OUString::valueOf(100.0*maCurrState.mnStrokeOpacity)+USTR("%"));
+ }
+
+ mxDocumentHandler->startElement( USTR("style:graphic-properties"),
+ xUnoAttrs );
+ mxDocumentHandler->endElement( USTR("style:graphic-properties") );
+ mxDocumentHandler->endElement( USTR("style:style") );
+
+ return true; // newly written
+ }
+
+ void writeStyle(const uno::Reference<xml::dom::XElement>& xElem, const sal_Int32 nTagId)
+ {
+ sal_Int32 nEmulatedStyleId=0;
+ if( maCurrState.maDashArray.size() &&
+ maCurrState.meStrokeType != NONE )
+ {
+ // ODF dashing is severly borked - generate filled shape
+ // instead (further down the road - here, we simply
+ // emulate a filled style with the next id)
+
+ // move all stroke attribs to fill, Clear stroking
+ State aEmulatedStrokeState( maCurrState );
+ aEmulatedStrokeState.meFillType = maCurrState.meStrokeType;
+ aEmulatedStrokeState.mnFillOpacity = maCurrState.mnStrokeOpacity;
+ aEmulatedStrokeState.maFillColor = maCurrState.maStrokeColor;
+ aEmulatedStrokeState.maFillGradient = maCurrState.maStrokeGradient;
+ aEmulatedStrokeState.meFillRule = EVEN_ODD;
+ aEmulatedStrokeState.meStrokeType = NONE;
+
+ if( writeStyle(aEmulatedStrokeState, nTagId) )
+ nEmulatedStyleId = mnCurrStateId;
+ else
+ nEmulatedStyleId = mrStates.find(aEmulatedStrokeState)->mnStyleId;
+ }
+
+ sal_Int32 nStyleId=0;
+ if( writeStyle(maCurrState, nTagId) )
+ nStyleId = mnCurrStateId;
+ else
+ nStyleId = mrStates.find(maCurrState)->mnStyleId;
+
+ xElem->setAttribute(USTR("internal-style-ref"),
+ rtl::OUString::valueOf(
+ nStyleId)
+ +USTR("$")
+ +rtl::OUString::valueOf(
+ nEmulatedStyleId));
+ }
+
+ void push()
+ {
+ maParentStates.push_back(maCurrState);
+ }
+
+ void pop()
+ {
+ maParentStates.pop_back();
+ }
+
+ 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:
+ io_rCurrGradient.maCoords.linear.mfX1 = convLength(sValue,maCurrState,'h');
+ break;
+ case XML_X2:
+ io_rCurrGradient.maCoords.linear.mfX2 = convLength(sValue,maCurrState,'h');
+ break;
+ case XML_Y1:
+ io_rCurrGradient.maCoords.linear.mfY1 = convLength(sValue,maCurrState,'v');
+ break;
+ case XML_Y2:
+ io_rCurrGradient.maCoords.linear.mfY2 = convLength(sValue,maCurrState,'v');
+ 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
+ io_rCurrGradient.mbBoundingBoxUnits = false;
+ break;
+ 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,maCurrState,'h');
+ break;
+ case XML_CY:
+ io_rCurrGradient.maCoords.radial.mfCY = convLength(sValue,maCurrState,'v');
+ break;
+ case XML_FX:
+ io_rCurrGradient.maCoords.radial.mfFX = convLength(sValue,maCurrState,'h');
+ break;
+ case XML_FY:
+ io_rCurrGradient.maCoords.radial.mfFY = convLength(sValue,maCurrState,'v');
+ break;
+ case XML_R:
+ io_rCurrGradient.maCoords.radial.mfR = convLength(sValue,maCurrState,'r');
+ 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
+ io_rCurrGradient.mbBoundingBoxUnits = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ 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:
+ maStopIdMap.insert(std::make_pair(sValue,nStopNumber));
+ break;
+ case XML_OFFSET:
+ io_rGradientStop.mnStopPosition = sValue.toDouble();
+ break;
+ case XML_STYLE:
+ parseStyle( sValue );
+ break;
+ default:
+ break;
+ }
+ }
+
+ void parseAttribute( const sal_Int32 nTokenId,
+ const rtl::OUString& sValue )
+ {
+ rtl::OString aValueUtf8( sValue.getStr(),
+ sValue.getLength(),
+ RTL_TEXTENCODING_UTF8 );
+ switch(nTokenId)
+ {
+ case XML_WIDTH:
+ {
+ const double fViewPortWidth(
+ convLength(sValue,maCurrState,'h'));
+
+ maCurrState.maViewport.expand(
+ basegfx::B2DTuple(fViewPortWidth,0.0));
+ break;
+ }
+ case XML_HEIGHT:
+ {
+ const double fViewPortHeight(
+ convLength(sValue,maCurrState,'v'));
+
+ maCurrState.maViewport.expand(
+ basegfx::B2DTuple(0.0,fViewPortHeight));
+ break;
+ }
+ case XML_VIEWBOX:
+ {
+ // TODO(F1): preserveAspectRatio
+ parseViewBox(
+ aValueUtf8,
+ maCurrState.maViewBox);
+ break;
+ }
+ case XML_FILL_RULE:
+ {
+ if( aValueUtf8 == "evenodd" )
+ maCurrState.meFillRule = EVEN_ODD;
+ else if( aValueUtf8 == "nonzero" )
+ maCurrState.meFillRule = NON_ZERO;
+ else if( aValueUtf8 == "inherit" )
+ 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" )
+ maCurrState.mnStrokeWidth = maParentStates.back().mnStrokeWidth;
+ else
+ maCurrState.mnStrokeWidth = convLength(sValue,maCurrState,'r');
+ break;
+ }
+ case XML_STROKE_LINECAP:
+ {
+ if( aValueUtf8 == "butt" )
+ maCurrState.meLineCap = BUTT;
+ else if( aValueUtf8 == "round" )
+ maCurrState.meLineCap = ROUND;
+ else if( aValueUtf8 == "square" )
+ maCurrState.meLineCap = RECT;
+ else if( aValueUtf8 == "inherit" )
+ maCurrState.meLineCap = maParentStates.back().meLineCap;
+ break;
+ }
+ case XML_STROKE_LINEJOIN:
+ {
+ if( aValueUtf8 == "miter" )
+ maCurrState.meLineJoin = basegfx::B2DLINEJOIN_MITER;
+ else if( aValueUtf8 == "round" )
+ maCurrState.meLineJoin = basegfx::B2DLINEJOIN_ROUND;
+ else if( aValueUtf8 == "bevel" )
+ maCurrState.meLineJoin = basegfx::B2DLINEJOIN_BEVEL;
+ else if( aValueUtf8 == "inherit" )
+ maCurrState.meLineJoin = maParentStates.back().meLineJoin;
+ break;
+ }
+ case XML_STROKE_MITERLIMIT:
+ {
+ if( aValueUtf8 == "inherit" )
+ maCurrState.mnMiterLimit = maParentStates.back().mnMiterLimit;
+ else
+ maCurrState.mnMiterLimit = aValueUtf8.toDouble();
+ break;
+ }
+ case XML_STROKE_DASHOFFSET:
+ {
+ if( aValueUtf8 == "inherit" )
+ maCurrState.mnDashOffset = maParentStates.back().mnDashOffset;
+ else
+ maCurrState.mnDashOffset = convLength(sValue,maCurrState,'r');
+ break;
+ }
+ case XML_STROKE_DASHARRAY:
+ {
+ if( aValueUtf8 == "none" )
+ maCurrState.maDashArray.clear();
+ else if( aValueUtf8 == "inherit" )
+ maCurrState.maDashArray = maParentStates.back().maDashArray;
+ else
+ parseDashArray(aValueUtf8.getStr(),
+ 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( sValue,
+ aValueUtf8.getStr(),
+ maCurrState.meFillType,
+ maCurrState.maFillColor,
+ maCurrState.maFillGradient,
+ rParent.meFillType,
+ rParent.maFillColor,
+ rParent.maFillGradient );
+ break;
+ }
+ case XML_STROKE:
+ {
+ const State& rParent( maParentStates.back() );
+ parsePaint( sValue,
+ aValueUtf8.getStr(),
+ maCurrState.meStrokeType,
+ maCurrState.maStrokeColor,
+ maCurrState.maStrokeGradient,
+ rParent.meStrokeType,
+ rParent.maStrokeColor,
+ rParent.maStrokeGradient );
+ break;
+ }
+ case XML_TRANSFORM:
+ {
+ basegfx::B2DHomMatrix aTransform;
+ parseTransform(aValueUtf8.getStr(),aTransform);
+ maCurrState.maTransform = maCurrState.maTransform*aTransform;
+ break;
+ }
+ case XML_FONT_FAMILY:
+ maCurrState.maFontFamily=sValue;
+ break;
+ case XML_FONT_SIZE:
+ maCurrState.mnFontSize=convLength(sValue,maCurrState,'v');
+ break;
+ case XML_FONT_STYLE:
+ maCurrState.meFontStyle=STYLE_ITALIC; // TODO: sValue.toStyleId();
+ break;
+ case XML_FONT_WEIGHT:
+ maCurrState.mnFontWeight=sValue.toDouble();
+ break;
+ case XML_FONT_VARIANT:
+ maCurrState.meFontVariant=VARIANT_SMALLCAPS; // TODO: sValue.toDouble();
+ break;
+ case XML_STOP_COLOR:
+ if( maGradientVector.empty() ||
+ maGradientVector.back().maStops.empty() )
+ break;
+ parseColor( aValueUtf8,
+ maGradientStopVector[
+ maGradientVector.back().maStops.back()].maStopColor );
+ break;
+ case XML_STOP_OPACITY:
+ 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));
+ break;
+ }
+ }
+
+ void parseStyle( const rtl::OUString& sValue )
+ {
+ // split individual style attributes
+ sal_Int32 nIndex=0, nDummyIndex=0;
+ rtl::OUString aCurrToken;
+ do
+ {
+ aCurrToken=sValue.getToken(0,';',nIndex);
+
+ if( aCurrToken.getLength() )
+ {
+ // split attrib & value
+ nDummyIndex=0;
+ rtl::OUString aCurrAttrib(
+ aCurrToken.getToken(0,':',nDummyIndex).trim());
+ OSL_ASSERT(nDummyIndex!=-1);
+ nDummyIndex=0;
+ rtl::OUString aCurrValue(
+ aCurrToken.getToken(1,':',nDummyIndex).trim());
+ OSL_ASSERT(nDummyIndex==-1);
+
+ // recurse into normal attribute parsing
+ parseAttribute( getTokenId(aCurrAttrib),
+ aCurrValue );
+ }
+ }
+ while( nIndex != -1 );
+ }
+
+ void parsePaint( const rtl::OUString& rValue,
+ const char* sValue,
+ PaintType& rType,
+ ARGBColor& rColor,
+ Gradient& rGradient,
+ const PaintType& rInheritType,
+ const ARGBColor& rInheritColor,
+ const Gradient& rInheritGradient )
+ {
+ if( strcmp(sValue,"none") == 0 )
+ rType = NONE;
+ else if( strcmp(sValue,"currentColor") == 0 )
+ {
+ rType = SOLID;
+ rColor = maCurrState.maCurrentColor;
+ }
+ else if( strcmp(sValue,"inherit") == 0)
+ {
+ rType = rInheritType;
+ rColor = rInheritColor;
+ rGradient = rInheritGradient;
+ }
+ 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
+ {
+ rType = SOLID;
+ parseColor(sValue,rColor);
+ }
+ }
+
+ 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
+static void annotateStyles( StatePool& rStatePool,
+ StateMap& rStateMap,
+ const State& rInitialState,
+ const uno::Reference<xml::dom::XElement> xElem,
+ const uno::Reference<xml::sax::XDocumentHandler>& xDocHdl )
+{
+ AnnotatingVisitor aVisitor(rStatePool,rStateMap,rInitialState,xDocHdl);
+ visitElements(aVisitor, xElem);
+}
+
+struct ShapeWritingVisitor
+{
+ ShapeWritingVisitor(StatePool& /*rStatePool*/,
+ StateMap& rStateMap,
+ const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler) :
+ mrStateMap(rStateMap),
+ mxDocumentHandler(xDocumentHandler),
+ mnShapeNum(0)
+ {}
+
+ void operator()( const uno::Reference<xml::dom::XElement>& )
+ {
+ }
+
+ void operator()( const uno::Reference<xml::dom::XElement>& xElem,
+ const uno::Reference<xml::dom::XNamedNodeMap>& xAttributes )
+ {
+ rtl::Reference<SvXMLAttributeList> xAttrs( new SvXMLAttributeList() );
+ uno::Reference<xml::sax::XAttributeList> xUnoAttrs( xAttrs.get() );
+
+ sal_Int32 nDummyIndex(0);
+ rtl::OUString sStyleId(
+ xElem->getAttribute(
+ USTR("internal-style-ref")).getToken(
+ 0,'$',nDummyIndex));
+ StateMap::iterator pOrigState=mrStateMap.find(
+ sStyleId.toInt32());
+
+ if( pOrigState == mrStateMap.end() )
+ return; // non-exportable element, e.g. linearGradient
+
+ maCurrState = pOrigState->second;
+
+ const sal_Int32 nTokenId(getTokenId(xElem->getNodeName()));
+ switch(nTokenId)
+ {
+ case XML_LINE:
+ {
+ // collect attributes
+ const sal_Int32 nNumAttrs( xAttributes->getLength() );
+ rtl::OUString sAttributeValue;
+ double x1=0.0,y1=0.0,x2=0.0,y2=0.0;
+ for( sal_Int32 i=0; i<nNumAttrs; ++i )
+ {
+ sAttributeValue = xAttributes->item(i)->getNodeValue();
+ const sal_Int32 nAttribId(
+ getTokenId(xAttributes->item(i)->getNodeName()));
+ switch(nAttribId)
+ {
+ case XML_X1:
+ x1= convLength(sAttributeValue,maCurrState,'h');
+ break;
+ case XML_X2:
+ x2 = convLength(sAttributeValue,maCurrState,'h');
+ break;
+ case XML_Y1:
+ y1 = convLength(sAttributeValue,maCurrState,'v');
+ break;
+ case XML_Y2:
+ y2 = convLength(sAttributeValue,maCurrState,'v');
+ break;
+ default:
+ // skip
+ break;
+ }
+ }
+
+ rtl::OUString sLinePath = USTR("M")+rtl::OUString::valueOf(x1)+USTR(",")
+ +rtl::OUString::valueOf(y1)+USTR("L")+rtl::OUString::valueOf(x2)+USTR(",")
+ +rtl::OUString::valueOf(y2);
+ basegfx::B2DPolyPolygon aPoly;
+ basegfx::tools::importFromSvgD(aPoly, sLinePath);
+
+ writePathShape(xAttrs,
+ xUnoAttrs,
+ xElem,
+ sStyleId,
+ basegfx::B2DPolyPolygon(aPoly));
+ break;
+ }
+ case XML_POLYGON:
+ case XML_POLYLINE:
+ {
+ rtl::OUString sPoints = xElem->hasAttribute(USTR("points")) ? xElem->getAttribute(USTR("points")) : USTR("");
+ basegfx::B2DPolygon aPoly;
+ basegfx::tools::importFromSvgPoints(aPoly, sPoints);
+ if( nTokenId == XML_POLYGON || maCurrState.meFillType != NONE )
+ aPoly.setClosed(true);
+
+ writePathShape(xAttrs,
+ xUnoAttrs,
+ xElem,
+ sStyleId,
+ basegfx::B2DPolyPolygon(aPoly));
+ break;
+ }
+ case XML_RECT:
+ {
+ // collect attributes
+ const sal_Int32 nNumAttrs( xAttributes->getLength() );
+ rtl::OUString sAttributeValue;
+ bool bRxSeen=false, bRySeen=false;
+ double x=0.0,y=0.0,width=0.0,height=0.0,rx=0.0,ry=0.0;
+ for( sal_Int32 i=0; i<nNumAttrs; ++i )
+ {
+ sAttributeValue = xAttributes->item(i)->getNodeValue();
+ const sal_Int32 nAttribId(
+ getTokenId(xAttributes->item(i)->getNodeName()));
+ switch(nAttribId)
+ {
+ case XML_X:
+ x = convLength(sAttributeValue,maCurrState,'h');
+ break;
+ case XML_Y:
+ y = convLength(sAttributeValue,maCurrState,'v');
+ break;
+ case XML_WIDTH:
+ width = convLength(sAttributeValue,maCurrState,'h');
+ break;
+ case XML_HEIGHT:
+ height = convLength(sAttributeValue,maCurrState,'v');
+ break;
+ case XML_RX:
+ rx = convLength(sAttributeValue,maCurrState,'h');
+ bRxSeen=true;
+ break;
+ case XML_RY:
+ ry = convLength(sAttributeValue,maCurrState,'v');
+ bRySeen=true;
+ break;
+ default:
+ // skip
+ break;
+ }
+ }
+
+ if( bRxSeen && !bRySeen )
+ ry = rx;
+ else if( bRySeen && !bRxSeen )
+ rx = ry;
+
+ basegfx::B2DPolygon aPoly;
+ aPoly = basegfx::tools::createPolygonFromRect(
+ basegfx::B2DRange(x,y,x+width,y+height),
+ rx/width, ry/height );
+
+ writePathShape(xAttrs,
+ xUnoAttrs,
+ xElem,
+ sStyleId,
+ basegfx::B2DPolyPolygon(aPoly));
+ break;
+ }
+ case XML_PATH:
+ {
+ rtl::OUString sPath = xElem->hasAttribute(USTR("d")) ? xElem->getAttribute(USTR("d")) : USTR("");
+ basegfx::B2DPolyPolygon aPoly;
+ basegfx::tools::importFromSvgD(aPoly, sPath);
+
+ writePathShape(xAttrs,
+ xUnoAttrs,
+ xElem,
+ sStyleId,
+ aPoly);
+ break;
+ }
+ case XML_CIRCLE:
+ {
+ // collect attributes
+ const sal_Int32 nNumAttrs( xAttributes->getLength() );
+ rtl::OUString sAttributeValue;
+ double cx=0.0,cy=0.0,r=0.0;
+ for( sal_Int32 i=0; i<nNumAttrs; ++i )
+ {
+ sAttributeValue = xAttributes->item(i)->getNodeValue();
+ const sal_Int32 nAttribId(
+ getTokenId(xAttributes->item(i)->getNodeName()));
+ switch(nAttribId)
+ {
+ case XML_CX:
+ cx = convLength(sAttributeValue,maCurrState,'h');
+ break;
+ case XML_CY:
+ cy = convLength(sAttributeValue,maCurrState,'v');
+ break;
+ case XML_R:
+ r = convLength(sAttributeValue,maCurrState,'r');
+ default:
+ // skip
+ break;
+ }
+ }
+
+ writeEllipseShape(xAttrs,
+ xUnoAttrs,
+ xElem,
+ sStyleId,
+ basegfx::B2DEllipse(basegfx::B2DPoint(cx, cy), basegfx::B2DTuple(r,r)));
+ break;
+ }
+ case XML_ELLIPSE:
+ {
+ // collect attributes
+ const sal_Int32 nNumAttrs( xAttributes->getLength() );
+ rtl::OUString sAttributeValue;
+ double cx=0.0,cy=0.0,rx=0.0, ry=0.0;
+ for( sal_Int32 i=0; i<nNumAttrs; ++i )
+ {
+ sAttributeValue = xAttributes->item(i)->getNodeValue();
+ const sal_Int32 nAttribId(
+ getTokenId(xAttributes->item(i)->getNodeName()));
+ switch(nAttribId)
+ {
+ case XML_CX:
+ cx = convLength(sAttributeValue,maCurrState,'h');
+ break;
+ case XML_CY:
+ cy = convLength(sAttributeValue,maCurrState,'v');
+ break;
+ case XML_RX:
+ rx = convLength(sAttributeValue,maCurrState,'h');
+ break;
+ case XML_RY:
+ ry = convLength(sAttributeValue,maCurrState,'v');
+ default:
+ // skip
+ break;
+ }
+ }
+
+ writeEllipseShape(xAttrs,
+ xUnoAttrs,
+ xElem,
+ sStyleId,
+ basegfx::B2DEllipse(basegfx::B2DPoint(cx, cy), basegfx::B2DTuple(rx,ry)));
+ break;
+ }
+ case XML_IMAGE:
+ {
+ // collect attributes
+ const sal_Int32 nNumAttrs( xAttributes->getLength() );
+ rtl::OUString sAttributeValue;
+ double x=0.0,y=0.0,width=0.0,height=0.0;
+ for( sal_Int32 i=0; i<nNumAttrs; ++i )
+ {
+ sAttributeValue = xAttributes->item(i)->getNodeValue();
+ const sal_Int32 nAttribId(
+ getTokenId(xAttributes->item(i)->getNodeName()));
+ switch(nAttribId)
+ {
+ case XML_X:
+ x = convLength(sAttributeValue,maCurrState,'h');
+ break;
+ case XML_Y:
+ y = convLength(sAttributeValue,maCurrState,'v');
+ break;
+ case XML_WIDTH:
+ width = convLength(sAttributeValue,maCurrState,'h');
+ break;
+ case XML_HEIGHT:
+ height = convLength(sAttributeValue,maCurrState,'v');
+ break;
+ default:
+ // skip
+ break;
+ }
+ }
+
+ rtl::OUString sValue = xElem->hasAttribute(USTR("href")) ? xElem->getAttribute(USTR("href")) : USTR("");
+ rtl::OString aValueUtf8( sValue.getStr(), sValue.getLength(), RTL_TEXTENCODING_UTF8 );
+ std::string sLinkValue;
+ parseXlinkHref(aValueUtf8.getStr(), sLinkValue);
+
+ if (!sLinkValue.empty())
+ writeBinaryData(xAttrs, xUnoAttrs, xElem, basegfx::B2DRange(x,y,x+width,y+height), sLinkValue);
+ break;
+ }
+ case XML_TEXT:
+ {
+ // collect text from all TEXT_NODE children into sText
+ rtl::OUStringBuffer sText;
+ visitChildren(boost::bind(
+ (rtl::OUStringBuffer& (rtl::OUStringBuffer::*)(const sal_Unicode* str))&rtl::OUStringBuffer::append,
+ boost::ref(sText),
+ boost::bind(&xml::dom::XNode::getNodeValue,
+ _1)),
+ xElem,
+ xml::dom::NodeType_TEXT_NODE);
+
+ // collect attributes
+ const sal_Int32 nNumAttrs( xAttributes->getLength() );
+ rtl::OUString sAttributeValue;
+ double x=0.0,y=0.0,width=0.0,height=0.0;
+ for( sal_Int32 i=0; i<nNumAttrs; ++i )
+ {
+ sAttributeValue = xAttributes->item(i)->getNodeValue();
+ const sal_Int32 nAttribId(
+ getTokenId(xAttributes->item(i)->getNodeName()));
+ switch(nAttribId)
+ {
+ case XML_X:
+ x = convLength(sAttributeValue,maCurrState,'h');
+ break;
+ case XML_Y:
+ y = convLength(sAttributeValue,maCurrState,'v');
+ break;
+ case XML_WIDTH:
+ width = convLength(sAttributeValue,maCurrState,'h');
+ break;
+ case XML_HEIGHT:
+ height = convLength(sAttributeValue,maCurrState,'v');
+ break;
+ default:
+ // skip
+ break;
+ }
+ }
+
+ // 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(pt2mm(x))+USTR("mm"));
+ xAttrs->AddAttribute( USTR( "svg:y" ), rtl::OUString::valueOf(pt2mm(y))+USTR("mm"));
+ xAttrs->AddAttribute( USTR( "draw:style-name" ), USTR("svggraphicstyle")+sStyleId );
+
+ mxDocumentHandler->startElement(USTR("draw:frame"),xUnoAttrs);
+
+ xAttrs->Clear();
+ mxDocumentHandler->startElement(USTR("draw:text-box"),xUnoAttrs);
+ // TODO: put text style in here
+ mxDocumentHandler->startElement(USTR("text:p"),xUnoAttrs);
+ mxDocumentHandler->characters(sText.makeStringAndClear());
+ mxDocumentHandler->endElement(USTR("text:p"));
+ mxDocumentHandler->endElement(USTR("draw:text-box"));
+ mxDocumentHandler->endElement(USTR("draw:frame"));
+ break;
+ }
+ }
+ }
+
+ void push()
+ {}
+
+ void pop()
+ {}
+
+ void writeBinaryData( rtl::Reference<SvXMLAttributeList>& xAttrs,
+ const uno::Reference<xml::sax::XAttributeList>& xUnoAttrs,
+ const uno::Reference<xml::dom::XElement>& /* xElem */,
+ const basegfx::B2DRange& rShapeBounds,
+ const std::string& data)
+ {
+ xAttrs->Clear();
+ xAttrs->AddAttribute( USTR( "svg:x" ), rtl::OUString::valueOf(pt2mm(rShapeBounds.getMinX()))+USTR("mm"));
+ xAttrs->AddAttribute( USTR( "svg:y" ), rtl::OUString::valueOf(pt2mm(rShapeBounds.getMinY()))+USTR("mm"));
+ xAttrs->AddAttribute( USTR( "svg:width" ), rtl::OUString::valueOf(pt2mm(rShapeBounds.getWidth()))+USTR("mm"));
+ xAttrs->AddAttribute( USTR( "svg:height" ), rtl::OUString::valueOf(pt2mm(rShapeBounds.getHeight()))+USTR("mm"));
+
+ mxDocumentHandler->startElement(USTR("draw:frame"),xUnoAttrs);
+
+ xAttrs->Clear();
+ mxDocumentHandler->startElement(USTR("draw:image"),xUnoAttrs);
+
+ mxDocumentHandler->startElement(USTR("office:binary-data"),xUnoAttrs);
+
+ mxDocumentHandler->characters(rtl::OUString::createFromAscii(data.c_str()));
+
+ mxDocumentHandler->endElement(USTR("office:binary-data"));
+
+ mxDocumentHandler->endElement(USTR("draw:image"));
+
+ mxDocumentHandler->endElement(USTR("draw:frame"));
+ }
+
+
+ void writeTransformAttribute(const basegfx::B2DHomMatrix rMatrix, rtl::Reference<SvXMLAttributeList>& xAttrs)
+ {
+ basegfx::B2DTuple rScale, rTranslate;
+ double rRotate, rShearX;
+ ::rtl::OUString sTransformValue;
+ if (!rMatrix.decompose(rScale, rTranslate, rRotate, rShearX))
+ return;
+ if (rScale.getX() != 1.0 || rScale.getY() != 1.0)
+ sTransformValue += USTR("scale(")+::rtl::OUString::valueOf(rScale.getX())+USTR(" ")
+ +::rtl::OUString::valueOf(rScale.getY())+USTR(") ");
+ if (rTranslate.getX() != 0.0f || rTranslate.getY() != 0.0f)
+ sTransformValue += USTR("translate(")+::rtl::OUString::valueOf(rTranslate.getX()/100.0f)+USTR("mm ")
+ +::rtl::OUString::valueOf(rTranslate.getY()/100.0f)+USTR("mm) ");
+ if (rRotate != 0.0f)
+ sTransformValue += USTR("rotate(")+::rtl::OUString::valueOf(rRotate)+USTR(") ");
+
+ if (rShearX != 0.0f)
+ sTransformValue += USTR("skewX(")+::rtl::OUString::valueOf(rShearX)+USTR(") ");
+ if (!sTransformValue.getLength())
+ return;
+ xAttrs->AddAttribute( USTR("draw:transform"), sTransformValue);
+ }
+
+ void writeEllipseShape( rtl::Reference<SvXMLAttributeList>& xAttrs,
+ const uno::Reference<xml::sax::XAttributeList>& xUnoAttrs,
+ const uno::Reference<xml::dom::XElement>& xElem,
+ const rtl::OUString& rStyleId,
+ const basegfx::B2DEllipse& rEllipse)
+ {
+ State aState = maCurrState;
+ rtl::OUString aStyleId(rStyleId);
+
+ xAttrs->Clear();
+
+ basegfx::B2DPolygon aPoly = basegfx::tools::createPolygonFromEllipse(rEllipse.getB2DEllipseCenter(),
+ rEllipse.getB2DEllipseRadius().getX(), rEllipse.getB2DEllipseRadius().getY());
+ writePathShape(xAttrs, xUnoAttrs, xElem, rStyleId, basegfx::B2DPolyPolygon(aPoly));
+
+ }
+
+ void writePathShape( rtl::Reference<SvXMLAttributeList>& xAttrs,
+ const uno::Reference<xml::sax::XAttributeList>& xUnoAttrs,
+ const uno::Reference<xml::dom::XElement>& xElem,
+ const rtl::OUString& rStyleId,
+ const basegfx::B2DPolyPolygon& rPoly )
+ {
+ // we might need to split up polypolygon into multiple path
+ // shapes (e.g. when emulating line stroking)
+ std::vector<basegfx::B2DPolyPolygon> aPolys(1,rPoly);
+ State aState = maCurrState;
+ rtl::OUString aStyleId(rStyleId);
+
+ xAttrs->Clear();
+
+ OSL_TRACE("writePath - the CTM is: %f %f %f %f %f %f",
+ maCurrState.maCTM.get(0,0),
+ maCurrState.maCTM.get(0,1),
+ maCurrState.maCTM.get(0,2),
+ maCurrState.maCTM.get(1,0),
+ maCurrState.maCTM.get(1,1),
+ maCurrState.maCTM.get(1,2));
+
+ if( aState.meStrokeType != NONE && aState.maDashArray.size() )
+ {
+ // ODF dashing is severly borked - generate filled polygon instead
+ aPolys.clear();
+ for( sal_uInt32 i=0; i<rPoly.count(); ++i )
+ {
+ aPolys.push_back(
+ basegfx::tools::createAreaGeometryForPolygon(
+ rPoly.getB2DPolygon(i),
+ aState.mnStrokeWidth/2.0,
+ aState.meLineJoin));
+ // TODO(F2): line ends
+ }
+
+ sal_Int32 nDummyIndex(0);
+ aStyleId = xElem->getAttribute(
+ USTR("internal-style-ref")).getToken(1,'$',nDummyIndex);
+ StateMap::iterator pAlternateState=mrStateMap.find(aStyleId.toInt32());
+ OSL_ASSERT(pAlternateState != mrStateMap.end());
+ aState = pAlternateState->second;
+ OSL_ENSURE( pAlternateState == mrStateMap.end(),
+ "Doh - where's my alternate style entry?!" );
+ }
+
+ // TODO(F2): separate out shear, rotate etc.
+ // apply transformation to polygon, to keep draw
+ // import in 100th mm
+ std::for_each(aPolys.begin(),aPolys.end(),
+ boost::bind(&basegfx::B2DPolyPolygon::transform,
+ _1,boost::cref(aState.maCTM)));
+
+ for( sal_uInt32 i=0; i<aPolys.size(); ++i )
+ {
+ const basegfx::B2DRange aBounds(
+ aPolys[i].areControlPointsUsed() ?
+ basegfx::tools::getRange(
+ basegfx::tools::adaptiveSubdivideByAngle(aPolys[i])) :
+ basegfx::tools::getRange(aPolys[i]));
+ fillShapeProperties(xAttrs,
+ xElem,
+ aBounds,
+ USTR("svggraphicstyle")+aStyleId);
+
+ // force path coordinates to 100th millimeter, after
+ // putting polygon data at origin (odf viewbox
+ // calculations largely untested codepaths, as OOo always
+ // writes "0 0 w h" viewboxes)
+ basegfx::B2DHomMatrix aNormalize;
+ aNormalize.translate(-aBounds.getMinX(),-aBounds.getMinY());
+ aNormalize.scale(2540.0/72.0,2540.0/72.0);
+ aPolys[i].transform(aNormalize);
+
+ xAttrs->AddAttribute( USTR( "svg:d" ), basegfx::tools::exportToSvgD(
+ aPolys[i],
+ false, // no relative coords. causes rounding errors
+ false )); // no quad bezier detection. crashes older versions.
+ mxDocumentHandler->startElement(USTR("draw:path"),
+ xUnoAttrs);
+ mxDocumentHandler->endElement(USTR("draw:path"));
+ }
+ }
+
+ void fillShapeProperties( rtl::Reference<SvXMLAttributeList>& xAttrs,
+ const uno::Reference<xml::dom::XElement>& /* xElem */,
+ const basegfx::B2DRange& rShapeBounds,
+ const rtl::OUString& rStyleName )
+ {
+ xAttrs->AddAttribute( USTR( "draw:z-index" ), rtl::OUString::valueOf( mnShapeNum++ ));
+ xAttrs->AddAttribute( USTR( "draw:style-name" ), rStyleName);
+ xAttrs->AddAttribute( USTR( "svg:width" ), rtl::OUString::valueOf(pt2mm(rShapeBounds.getWidth()))+USTR("mm"));
+ xAttrs->AddAttribute( USTR( "svg:height" ), rtl::OUString::valueOf(pt2mm(rShapeBounds.getHeight()))+USTR("mm"));
+
+ // OOo expects the viewbox to be in 100th of mm
+ xAttrs->AddAttribute( USTR( "svg:viewBox" ),
+ USTR("0 0 ")
+ + rtl::OUString::valueOf(
+ basegfx::fround(pt100thmm(rShapeBounds.getWidth())) )
+ + USTR(" ")
+ + rtl::OUString::valueOf(
+ basegfx::fround(pt100thmm(rShapeBounds.getHeight())) ));
+
+ // TODO(F1): decompose transformation in calling code, and use
+ // transform attribute here
+ // writeTranslate(maCurrState.maCTM, xAttrs);
+ xAttrs->AddAttribute( USTR( "svg:x" ), rtl::OUString::valueOf(pt2mm(rShapeBounds.getMinX()))+USTR("mm"));
+ xAttrs->AddAttribute( USTR( "svg:y" ), rtl::OUString::valueOf(pt2mm(rShapeBounds.getMinY()))+USTR("mm"));
+ }
+
+ State maCurrState;
+ StateMap& mrStateMap;
+ uno::Reference<xml::sax::XDocumentHandler> mxDocumentHandler;
+ sal_Int32 mnShapeNum;
+};
+
+/// Write out shapes from DOM tree
+static void writeShapes( StatePool& rStatePool,
+ StateMap& rStateMap,
+ const uno::Reference<xml::dom::XElement> xElem,
+ const uno::Reference<xml::sax::XDocumentHandler>& xDocHdl )
+{
+ ShapeWritingVisitor aVisitor(rStatePool,rStateMap,xDocHdl);
+ visitElements(aVisitor, xElem);
+}
+
+#ifdef VERBOSE
+struct DumpingVisitor
+{
+ void operator()( const uno::Reference<xml::dom::XElement>& xElem )
+ {
+ OSL_TRACE("name: %s",
+ rtl::OUStringToOString(
+ xElem->getTagName(),
+ RTL_TEXTENCODING_UTF8 ).getStr());
+ }
+
+ void operator()( const uno::Reference<xml::dom::XElement>& xElem,
+ const uno::Reference<xml::dom::XNamedNodeMap>& xAttributes )
+ {
+ OSL_TRACE("name: %s",
+ rtl::OUStringToOString(
+ xElem->getTagName(),
+ RTL_TEXTENCODING_UTF8 ).getStr());
+ const sal_Int32 nNumAttrs( xAttributes->getLength() );
+ for( sal_Int32 i=0; i<nNumAttrs; ++i )
+ {
+ OSL_TRACE(" %s=%s",
+ rtl::OUStringToOString(
+ xAttributes->item(i)->getNodeName(),
+ RTL_TEXTENCODING_UTF8 ).getStr(),
+ rtl::OUStringToOString(
+ xAttributes->item(i)->getNodeValue(),
+ RTL_TEXTENCODING_UTF8 ).getStr());
+ }
+ }
+
+ void push() {}
+ void pop() {}
+};
+
+static void dumpTree( const uno::Reference<xml::dom::XElement> xElem )
+{
+ DumpingVisitor aVisitor;
+ visitElements(aVisitor, xElem);
+}
+#endif
+
+} // namespace
+
+
+SVGReader::SVGReader(const uno::Reference<lang::XMultiServiceFactory>& xServiceFactory,
+ const uno::Reference<io::XInputStream>& xInputStream,
+ const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler) :
+ m_xServiceFactory( xServiceFactory ),
+ m_xInputStream( xInputStream ),
+ m_xDocumentHandler( xDocumentHandler )
+{
+}
+
+sal_Bool SVGReader::parseAndConvert()
+{
+ uno::Reference<xml::dom::XDocumentBuilder> xDomBuilder(
+ m_xServiceFactory->createInstance(
+ rtl::OUString::createFromAscii("com.sun.star.xml.dom.DocumentBuilder")), uno::UNO_QUERY );
+
+ uno::Reference<xml::dom::XDocument> xDom(
+ xDomBuilder->parse(m_xInputStream),
+ uno::UNO_QUERY_THROW );
+
+ uno::Reference<xml::dom::XElement> xDocElem( xDom->getDocumentElement(),
+ uno::UNO_QUERY_THROW );
+
+ // the root state for svg document
+ State aInitialState;
+
+ /////////////////////////////////////////////////////////////////
+ // doc boilerplate
+ /////////////////////////////////////////////////////////////////
+
+ m_xDocumentHandler->startDocument();
+
+ // get the document dimensions
+
+ // if the "width" and "height" attributes are missing, inkscape fakes
+ // A4 portrait for. Let's do the same.
+ if (!xDocElem->hasAttribute(USTR("width")))
+ xDocElem->setAttribute(USTR("width"), USTR("210mm"));
+ if (!xDocElem->hasAttribute(USTR("height")))
+ xDocElem->setAttribute(USTR("height"), USTR("297mm"));
+
+ double fViewPortWidth( pt2mm(convLength(xDocElem->getAttribute(USTR("width")),aInitialState,'h')) );
+ double fViewPortHeight( pt2mm(convLength(xDocElem->getAttribute(USTR("height")),aInitialState,'v')) );
+
+ // document prolog
+ rtl::Reference<SvXMLAttributeList> xAttrs( new SvXMLAttributeList() );
+ uno::Reference<xml::sax::XAttributeList> xUnoAttrs( xAttrs.get() );
+
+ xAttrs->AddAttribute( USTR( "xmlns:office" ), USTR( OASIS_STR "office:1.0" ));
+ xAttrs->AddAttribute( USTR( "xmlns:style" ), USTR( OASIS_STR "style:1.0" ));
+ xAttrs->AddAttribute( USTR( "xmlns:text" ), USTR( OASIS_STR "text:1.0" ));
+ xAttrs->AddAttribute( USTR( "xmlns:svg" ), USTR( OASIS_STR "svg-compatible:1.0" ));
+ xAttrs->AddAttribute( USTR( "xmlns:table" ), USTR( OASIS_STR "table:1.0" ));
+ xAttrs->AddAttribute( USTR( "xmlns:draw" ), USTR( OASIS_STR "drawing:1.0" ));
+ xAttrs->AddAttribute( USTR( "xmlns:fo" ), USTR( OASIS_STR "xsl-fo-compatible:1.0" ));
+ xAttrs->AddAttribute( USTR( "xmlns:xlink" ), USTR( "http://www.w3.org/1999/xlink" ));
+ xAttrs->AddAttribute( USTR( "xmlns:dc" ), USTR( "http://purl.org/dc/elements/1.1/" ));
+ xAttrs->AddAttribute( USTR( "xmlns:number" ), USTR( OASIS_STR "datastyle:1.0" ));
+ xAttrs->AddAttribute( USTR( "xmlns:presentation" ), USTR( OASIS_STR "presentation:1.0" ));
+ xAttrs->AddAttribute( USTR( "xmlns:math" ), USTR( "http://www.w3.org/1998/Math/MathML" ));
+ xAttrs->AddAttribute( USTR( "xmlns:form" ), USTR( OASIS_STR "form:1.0" ));
+ xAttrs->AddAttribute( USTR( "xmlns:script" ), USTR( OASIS_STR "script:1.0" ));
+ xAttrs->AddAttribute( USTR( "xmlns:dom" ), USTR( "http://www.w3.org/2001/xml-events" ));
+ xAttrs->AddAttribute( USTR( "xmlns:xforms" ), USTR( "http://www.w3.org/2002/xforms" ));
+ xAttrs->AddAttribute( USTR( "xmlns:xsd" ), USTR( "http://www.w3.org/2001/XMLSchema" ));
+ xAttrs->AddAttribute( USTR( "xmlns:xsi" ), USTR( "http://www.w3.org/2001/XMLSchema-instance" ));
+ xAttrs->AddAttribute( USTR( "office:version" ), USTR( "1.0" ));
+ xAttrs->AddAttribute( USTR( "office:mimetype" ), USTR( "application/vnd.oasis.opendocument.graphics" ));
+
+ m_xDocumentHandler->startElement( USTR("office:document"), xUnoAttrs );
+
+ xAttrs->Clear();
+
+ m_xDocumentHandler->startElement( USTR("office:settings"), xUnoAttrs);
+
+ xAttrs->AddAttribute( USTR( "config:name" ), USTR( "ooo:view-settings" ));
+ m_xDocumentHandler->startElement( USTR("config:config-item-set"), xUnoAttrs);
+
+ xAttrs->Clear();
+
+ xAttrs->AddAttribute( USTR( "config:name" ), USTR( "VisibleAreaTop" ));
+ xAttrs->AddAttribute( USTR( "config:type" ), USTR( "int" ));
+ m_xDocumentHandler->startElement( USTR( "config:config-item" ), xUnoAttrs);
+
+ m_xDocumentHandler->characters( USTR( "0" ));
+
+ m_xDocumentHandler->endElement( USTR( "config:config-item" ));
+
+ xAttrs->Clear();
+
+ xAttrs->AddAttribute( USTR( "config:name" ), USTR( "VisibleAreaLeft" ));
+ xAttrs->AddAttribute( USTR( "config:type" ), USTR( "int" ));
+ m_xDocumentHandler->startElement( USTR( "config:config-item" ), xUnoAttrs);
+
+ m_xDocumentHandler->characters( USTR( "0" ));
+
+ m_xDocumentHandler->endElement( USTR( "config:config-item" ));
+
+ xAttrs->Clear();
+
+ xAttrs->AddAttribute( USTR( "config:name" ), USTR( "VisibleAreaWidth" ));
+ xAttrs->AddAttribute( USTR( "config:type" ), USTR( "int" ));
+ m_xDocumentHandler->startElement( USTR( "config:config-item" ), xUnoAttrs);
+
+ sal_Int64 iWidth = sal_Int64(fViewPortWidth);
+ m_xDocumentHandler->characters( ::rtl::OUString::valueOf(iWidth) );
+
+ m_xDocumentHandler->endElement( USTR( "config:config-item" ));
+
+ xAttrs->Clear();
+
+ xAttrs->AddAttribute( USTR( "config:name" ), USTR( "VisibleAreaHeight" ));
+ xAttrs->AddAttribute( USTR( "config:type" ), USTR( "int" ));
+ m_xDocumentHandler->startElement( USTR( "config:config-item" ), xUnoAttrs);
+
+ sal_Int64 iHeight = sal_Int64(fViewPortHeight);
+ m_xDocumentHandler->characters( ::rtl::OUString::valueOf(iHeight) );
+
+ m_xDocumentHandler->endElement( USTR( "config:config-item" ));
+
+ m_xDocumentHandler->endElement( USTR( "config:config-item-set" ));
+
+ m_xDocumentHandler->endElement( USTR( "office:settings" ));
+
+ xAttrs->Clear();
+
+ m_xDocumentHandler->startElement( USTR("office:automatic-styles"),
+ xUnoAttrs );
+
+ xAttrs->AddAttribute( USTR( "style:name" ), USTR("pagelayout1"));
+ m_xDocumentHandler->startElement( USTR("style:page-layout"),
+ xUnoAttrs );
+ // TODO(Q3): this is super-ugly. In-place container come to mind.
+ xAttrs->Clear();
+
+ // make page viewport-width times viewport-height mm large - add
+ // 5% border at every side
+ xAttrs->AddAttribute( USTR( "fo:margin-top" ), USTR("0mm"));
+ xAttrs->AddAttribute( USTR( "fo:margin-bottom" ), USTR("0mm"));
+ xAttrs->AddAttribute( USTR( "fo:margin-left" ), USTR("0mm"));
+ xAttrs->AddAttribute( USTR( "fo:margin-right" ), USTR("0mm"));
+ xAttrs->AddAttribute( USTR( "fo:page-width" ), rtl::OUString::valueOf(fViewPortWidth)+USTR("mm"));
+ xAttrs->AddAttribute( USTR( "fo:page-height" ), rtl::OUString::valueOf(fViewPortHeight)+USTR("mm"));
+ xAttrs->AddAttribute( USTR( "style:print-orientation" ),
+ fViewPortWidth > fViewPortHeight ?
+ USTR("landscape") :
+ USTR("portrait"));
+ m_xDocumentHandler->startElement( USTR("style:page-layout-properties"),
+ xUnoAttrs );
+ m_xDocumentHandler->endElement( USTR("style:page-layout-properties") );
+ m_xDocumentHandler->endElement( USTR("style:page-layout") );
+
+ xAttrs->Clear();
+ xAttrs->AddAttribute( USTR( "style:name" ), USTR("pagestyle1"));
+ xAttrs->AddAttribute( USTR( "style:family" ), USTR("drawing-page"));
+ m_xDocumentHandler->startElement( USTR("style:style"),
+ xUnoAttrs );
+
+ xAttrs->Clear();
+ xAttrs->AddAttribute( USTR( "draw:background-size" ), USTR("border"));
+ xAttrs->AddAttribute( USTR( "draw:fill" ), USTR("none"));
+ m_xDocumentHandler->startElement( USTR("style:drawing-page-properties"),
+ xUnoAttrs );
+ m_xDocumentHandler->endElement( USTR("style:drawing-page-properties") );
+ m_xDocumentHandler->endElement( USTR("style:style") );
+
+ StatePool aStatePool;
+ StateMap aStateMap;
+ annotateStyles(aStatePool,aStateMap,aInitialState,
+ xDocElem,m_xDocumentHandler);
+
+#ifdef VERBOSE
+ dumpTree(xDocElem);
+#endif
+
+ m_xDocumentHandler->endElement( USTR("office:automatic-styles") );
+
+ ////////////////////////////////////////////////////////////////////
+
+ xAttrs->Clear();
+ m_xDocumentHandler->startElement( USTR("office:styles"),
+ xUnoAttrs);
+ m_xDocumentHandler->endElement( USTR("office:styles") );
+
+ ////////////////////////////////////////////////////////////////////
+
+ m_xDocumentHandler->startElement( USTR("office:master-styles"),
+ xUnoAttrs );
+ xAttrs->Clear();
+ xAttrs->AddAttribute( USTR( "style:name" ), USTR("Default"));
+ xAttrs->AddAttribute( USTR( "style:page-layout-name" ), USTR("pagelayout1"));
+ xAttrs->AddAttribute( USTR( "draw:style-name" ), USTR("pagestyle1"));
+ m_xDocumentHandler->startElement( USTR("style:master-page"),
+ xUnoAttrs );
+ m_xDocumentHandler->endElement( USTR("style:master-page") );
+
+ m_xDocumentHandler->endElement( USTR("office:master-styles") );
+
+ ////////////////////////////////////////////////////////////////////
+
+ xAttrs->Clear();
+ m_xDocumentHandler->startElement( USTR("office:body"),
+ xUnoAttrs );
+ m_xDocumentHandler->startElement( USTR("office:drawing"),
+ xUnoAttrs );
+
+ xAttrs->Clear();
+ xAttrs->AddAttribute( USTR( "draw:master-page-name" ), USTR("Default"));
+ xAttrs->AddAttribute( USTR( "draw:style-name" ), USTR("pagestyle1"));
+ m_xDocumentHandler->startElement(USTR("draw:page"),
+ xUnoAttrs);
+
+ // write out all shapes
+ writeShapes(aStatePool,
+ aStateMap,
+ xDocElem,
+ m_xDocumentHandler);
+
+ m_xDocumentHandler->endElement( USTR("draw:page") );
+ m_xDocumentHandler->endElement( USTR("office:drawing") );
+ m_xDocumentHandler->endElement( USTR("office:body") );
+ m_xDocumentHandler->endElement( USTR("office:document") );
+ m_xDocumentHandler->endDocument();
+
+ return sal_True;
+}
+
+} // namespace svgi
diff --git a/filter/source/svg/svgreader.hxx b/filter/source/svg/svgreader.hxx
new file mode 100644
index 000000000000..d4b57d31868d
--- /dev/null
+++ b/filter/source/svg/svgreader.hxx
@@ -0,0 +1,43 @@
+/*************************************************************************
+ *
+ * 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 3.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_SVGREADER_HXX
+#define INCLUDED_SVGREADER_HXX
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+
+namespace svgi
+{
+
+class SVGReader
+{
+ const ::com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > m_xServiceFactory;
+ const ::com::sun::star::uno::Reference< com::sun::star::io::XInputStream > m_xInputStream;
+ const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XDocumentHandler > m_xDocumentHandler;
+
+public:
+ SVGReader( const com::sun::star::uno::Reference<com::sun::star::lang::XMultiServiceFactory>& xServiceFactory,
+ const com::sun::star::uno::Reference< com::sun::star::io::XInputStream >& xInputStream,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XDocumentHandler >& xDocumentHandler );
+
+ sal_Bool parseAndConvert();
+};
+
+} // namespace svgi
+
+#endif
diff --git a/filter/source/svg/test/makefile.mk b/filter/source/svg/test/makefile.mk
new file mode 100644
index 000000000000..d51fdda07e68
--- /dev/null
+++ b/filter/source/svg/test/makefile.mk
@@ -0,0 +1,114 @@
+#*************************************************************************
+#
+# 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 3.
+#
+#*************************************************************************
+
+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) \
+ $(SVTOOLLIB) \
+ $(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 \
+ anarchist2.svg \
+ Nested.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 --git a/filter/source/svg/test/odfserializer.cxx b/filter/source/svg/test/odfserializer.cxx
new file mode 100644
index 000000000000..2a8958d02c31
--- /dev/null
+++ b/filter/source/svg/test/odfserializer.cxx
@@ -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 3.
+ *
+ ************************************************************************/
+
+// 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 --git a/filter/source/svg/test/odfserializer.hxx b/filter/source/svg/test/odfserializer.hxx
new file mode 100644
index 000000000000..d9ef2a34cc14
--- /dev/null
+++ b/filter/source/svg/test/odfserializer.hxx
@@ -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 3.
+ *
+ ************************************************************************/
+
+#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 --git a/filter/source/svg/test/parsertest.cxx b/filter/source/svg/test/parsertest.cxx
new file mode 100644
index 000000000000..04695a54f02c
--- /dev/null
+++ b/filter/source/svg/test/parsertest.cxx
@@ -0,0 +1,209 @@
+/*************************************************************************
+ *
+ * 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 31.
+ *
+ ************************************************************************/
+
+// 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 --git a/filter/source/svg/test/svg2odf.cxx b/filter/source/svg/test/svg2odf.cxx
new file mode 100644
index 000000000000..e2235fc4d5ae
--- /dev/null
+++ b/filter/source/svg/test/svg2odf.cxx
@@ -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 3.
+ *
+ ************************************************************************/
+
+// 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;
+}
diff --git a/filter/source/svg/tokenmap.cxx b/filter/source/svg/tokenmap.cxx
new file mode 100644
index 000000000000..18a1de42031e
--- /dev/null
+++ b/filter/source/svg/tokenmap.cxx
@@ -0,0 +1,62 @@
+/*************************************************************************
+ *
+ * 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 3.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_filter.hxx"
+
+#include "tokenmap.hxx"
+#include <string.h>
+
+namespace svgi
+{
+
+#include "tokens.cxx"
+
+sal_Int32 getTokenId( const char* sIdent, sal_Int32 nLen )
+{
+ const struct xmltoken* t = Perfect_Hash::in_word_set( sIdent, nLen );
+ if( t )
+ return t->nToken;
+ else
+ return XML_TOKEN_INVALID;
+}
+
+sal_Int32 getTokenId( const rtl::OUString& sIdent )
+{
+ rtl::OString aUTF8( sIdent.getStr(),
+ sIdent.getLength(),
+ RTL_TEXTENCODING_UTF8 );
+ return getTokenId( aUTF8.getStr(), aUTF8.getLength() );
+}
+
+const char* getTokenName( sal_Int32 nTokenId )
+{
+ if( nTokenId >= XML_TOKEN_COUNT )
+ return NULL;
+
+ const xmltoken* pCurr=wordlist;
+ const xmltoken* pEnd=wordlist+sizeof(wordlist)/sizeof(*wordlist);
+ while( pCurr != pEnd )
+ {
+ if(pCurr->nToken == nTokenId)
+ return pCurr->name;
+ ++pCurr;
+ }
+
+ return NULL;
+}
+
+} // namespace svgi
diff --git a/filter/source/svg/tokenmap.hxx b/filter/source/svg/tokenmap.hxx
new file mode 100644
index 000000000000..475b2b9160eb
--- /dev/null
+++ b/filter/source/svg/tokenmap.hxx
@@ -0,0 +1,32 @@
+/*************************************************************************
+ *
+ * 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 3.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_TOKENMAP_HXX
+#define INCLUDED_TOKENMAP_HXX
+
+#include "tokens.hxx"
+
+#include <rtl/string.hxx>
+#include <rtl/ustring.hxx>
+
+namespace svgi
+{
+ sal_Int32 getTokenId( const char* sIdent, sal_Int32 nLen );
+ sal_Int32 getTokenId( const rtl::OUString& sIdent );
+ const char* getTokenName( sal_Int32 nTokenId );
+
+} // namespace svgi
+
+#endif
diff --git a/filter/source/svg/tokens.txt b/filter/source/svg/tokens.txt
new file mode 100644
index 000000000000..1211e691f627
--- /dev/null
+++ b/filter/source/svg/tokens.txt
@@ -0,0 +1,403 @@
+#######################################
+#
+# elements (SVG Tiny 1.2)
+#
+#######################################
+a
+animate
+animateColor
+animateMotion
+animateTransform
+animation
+audio
+circle
+defs
+desc
+discard
+ellipse
+font
+font-face
+font-face-src
+font-face-uri
+foreignObject
+g
+glyph
+handler
+hkern
+image
+line
+linearGradient
+listener
+metadata
+missing-glyph
+mpath
+path
+polygon
+polyline
+prefetch
+radialGradient
+rect
+script
+set
+solidColor
+stop
+svg
+switch
+tbreak
+text
+textArea
+title
+tspan
+use
+video
+#######################################
+#
+# properties (SVG Tiny 1.2)
+#
+#######################################
+audio-level
+color
+color-rendering
+display
+display-align
+fill
+fill-opacity
+fill-rule
+font-family
+font-size
+font-style
+font-variant
+font-weight
+image-rendering
+line-increment
+opacity
+pointer-events
+shape-rendering
+solid-color
+solid-opacity
+stop-color
+stop-opacity
+stroke
+stroke-dasharray
+stroke-dashoffset
+stroke-linecap
+stroke-linejoin
+stroke-miterlimit
+stroke-opacity
+stroke-width
+text-align
+text-anchor
+text-rendering
+vector-effect
+viewport-fill
+viewport-fill-opacity
+visibility
+#######################################
+#
+# attributes (SVG Tiny 1.2)
+#
+#######################################
+accent-height
+accumulate
+additive
+alphabetic
+arabic-form
+ascent
+attributeName
+attributeType
+bandwidth
+baseProfile
+bbox
+begin
+by
+calcMode
+cap-height
+class
+contentScriptType
+cx
+cy
+d
+defaultAction
+descent
+dur
+editable
+end
+event
+externalResourcesRequired
+fill
+focusHighlight
+focusable
+font-family
+font-stretch
+font-style
+font-variant
+font-weight
+from
+fx
+fy
+g1
+g2
+glyph-name
+gradientTransform
+gradientUnits
+handler
+hanging
+height
+height
+horiz-adv-x
+horiz-origin-x
+id
+ideographic
+initialVisibility
+k
+keyPoints
+keySplines
+keyTimes
+lang
+mathematical
+max
+mediaCharacterEncoding
+mediaContentEncodings
+mediaSize
+mediaTime
+min
+nav-down
+nav-down-left
+nav-down-right
+nav-left
+nav-next
+nav-prev
+nav-right
+nav-up
+nav-up-left
+nav-up-right
+observer
+offset
+origin
+overlay
+overline-position
+overline-thickness
+panose-1
+path
+pathLength
+phase
+playbackOrder
+points
+preserveAspectRatio
+propagate
+r
+repeatCount
+repeatDur
+requiredExtensions
+requiredFeatures
+requiredFonts
+requiredFormats
+restart
+rotate
+rx
+ry
+slope
+snapshotTime
+stemh
+stemv
+strikethrough-position
+strikethrough-thickness
+style
+syncBehavior
+syncBehaviorDefault
+syncMaster
+syncTolerance
+syncToleranceDefault
+systemLanguage
+target
+timelineBegin
+to
+transform
+transformBehavior
+type
+u1
+u2
+underline-position
+underline-thickness
+unicode
+unicode-range
+units-per-em
+values
+version
+viewBox
+width
+widths
+x
+x-height
+x1
+x2
+actuate
+arcrole
+href
+role
+show
+base
+space
+y
+y1
+y2
+zoomAndPan
+#######################################
+#
+# colour values
+#
+#######################################
+aliceblue
+antiquewhite
+aqua
+aquamarine
+azure
+beige
+bisque
+black
+blanchedalmond
+blue
+blueviolet
+brown
+burlywood
+cadetblue
+chartreuse
+chocolate
+coral
+cornflowerblue
+cornsilk
+crimson
+cyan
+darkblue
+darkcyan
+darkgoldenrod
+darkgray
+darkgreen
+darkgrey
+darkkhaki
+darkmagenta
+darkolivegreen
+darkorange
+darkorchid
+darkred
+darksalmon
+darkseagreen
+darkslateblue
+darkslategray
+darkslategrey
+darkturquoise
+darkviolet
+deeppink
+deepskyblue
+dimgray
+dimgrey
+dodgerblue
+firebrick
+floralwhite
+forestgreen
+fuchsia
+gainsboro
+ghostwhite
+gold
+goldenrod
+gray
+grey
+green
+greenyellow
+honeydew
+hotpink
+indianred
+indigo
+ivory
+khaki
+lavender
+lavenderblush
+lawngreen
+lemonchiffon
+lightblue
+lightcoral
+lightcyan
+lightgoldenrodyellow
+lightgray
+lightgreen
+lightgrey
+lightpink
+lightsalmon
+lightseagreen
+lightskyblue
+lightslategray
+lightslategrey
+lightsteelblue
+lightyellow
+lime
+limegreen
+linen
+magenta
+maroon
+mediumaquamarine
+mediumblue
+mediumorchid
+mediumpurple
+mediumseagreen
+mediumslateblue
+mediumspringgreen
+mediumturquoise
+mediumvioletred
+midnightblue
+mintcream
+mistyrose
+moccasin
+navajowhite
+navy
+oldlace
+olive
+olivedrab
+orange
+orangered
+orchid
+palegoldenrod
+palegreen
+paleturquoise
+palevioletred
+papayawhip
+peachpuff
+peru
+pink
+plum
+powderblue
+purple
+red
+rosybrown
+royalblue
+saddlebrown
+salmon
+sandybrown
+seagreen
+seashell
+sienna
+silver
+skyblue
+slateblue
+slategray
+slategrey
+snow
+springgreen
+steelblue
+tan
+teal
+thistle
+tomato
+turquoise
+violet
+wheat
+white
+whitesmoke
+yellow
+yellowgreen
+#######################################
+#
+# Gradient units values
+#
+#######################################
+userSpaceOnUse
+objectBoundingBox
diff --git a/filter/source/svg/units.cxx b/filter/source/svg/units.cxx
new file mode 100644
index 000000000000..b727a42db0fa
--- /dev/null
+++ b/filter/source/svg/units.cxx
@@ -0,0 +1,99 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * Author:
+ * Jan Holesovsky <kendy@suse.cz>
+ * 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 3.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_filter.hxx"
+
+#include "units.hxx"
+#include "gfxtypes.hxx"
+#include "spirit_supplements.hxx"
+
+#include <string.h>
+#include <rtl/ustring.hxx>
+
+#include <boost/bind.hpp>
+// workaround. spirit uses INT_MAX.
+#include <limits.h>
+#include <boost/spirit.hpp>
+
+
+namespace svgi
+{
+
+double convLength( double value, SvgUnit unit, const State& rState, char dir )
+{
+ const double fBoxLen( dir=='h' ? rState.maViewBox.getWidth() :
+ (dir=='v' ? rState.maViewBox.getHeight() :
+ rState.maViewBox.getRange().getLength()));
+
+ // convert svg unit to internal coordinates ("pixel"). Since the
+ // OOo drawing layer is still largely integer-based, the initial
+ // viewport transformation includes a certain scale factor
+ double fRet(value);
+ switch ( unit )
+ {
+ case SVG_LENGTH_UNIT_CM: fRet *= 72.0/2.54; break;
+ case SVG_LENGTH_UNIT_IN: fRet *= 72.0; break;
+ case SVG_LENGTH_UNIT_MM: fRet *= 72.0/25.4; break;
+ case SVG_LENGTH_UNIT_PC: fRet *= 72.0/6.0; break;
+ case SVG_LENGTH_UNIT_USER:
+ case SVG_LENGTH_UNIT_PX: // no unit defaults to PX in svg,
+ // assume display to have 72DPI
+ case SVG_LENGTH_UNIT_PT: break;
+ case SVG_LENGTH_UNIT_EM: fRet *= rState.mnFontSize; break;
+ case SVG_LENGTH_UNIT_EX: fRet *= rState.mnFontSize / 2.0; break;
+ case SVG_LENGTH_UNIT_PERCENTAGE: fRet *= fBoxLen; break;
+ default: OSL_TRACE( "Unknown length type" ); break;
+ }
+
+ return fRet;
+}
+
+double convLength( const rtl::OUString& sValue, const State& rState, char dir )
+{
+ using namespace ::boost::spirit;
+
+ rtl::OString aUTF8 = rtl::OUStringToOString( sValue,
+ RTL_TEXTENCODING_UTF8 );
+
+ double nVal=0.0;
+ SvgUnit eUnit=SVG_LENGTH_UNIT_PX;
+ const bool bRes = parse(aUTF8.getStr(),
+ // Begin grammar
+ (
+ real_p[assign_a(nVal)]
+ >> ( str_p("cm") [assign_a(eUnit,SVG_LENGTH_UNIT_CM)]
+ | str_p("em") [assign_a(eUnit,SVG_LENGTH_UNIT_EM)]
+ | str_p("ex") [assign_a(eUnit,SVG_LENGTH_UNIT_EX)]
+ | str_p("in") [assign_a(eUnit,SVG_LENGTH_UNIT_IN)]
+ | str_p("mm") [assign_a(eUnit,SVG_LENGTH_UNIT_MM)]
+ | str_p("pc") [assign_a(eUnit,SVG_LENGTH_UNIT_PC)]
+ | str_p("pt") [assign_a(eUnit,SVG_LENGTH_UNIT_PT)]
+ | str_p("px") [assign_a(eUnit,SVG_LENGTH_UNIT_PX)]
+ | str_p("%") [assign_a(eUnit,SVG_LENGTH_UNIT_PERCENTAGE)]
+ | str_p("") [assign_a(eUnit,SVG_LENGTH_UNIT_USER)]
+ | end_p)
+ ),
+ // End grammar
+ space_p).full;
+
+ if( !bRes )
+ return 0.0;
+
+ return convLength(nVal,eUnit,rState,dir);
+}
+
+} // namespace svgi
diff --git a/filter/source/svg/units.hxx b/filter/source/svg/units.hxx
new file mode 100644
index 000000000000..7bf764178135
--- /dev/null
+++ b/filter/source/svg/units.hxx
@@ -0,0 +1,60 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * Author:
+ * Jan Holesovsky <kendy@suse.cz>
+ * 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 3.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_UNITS_HXX
+#define INCLUDED_UNITS_HXX
+
+#include <sal/config.h>
+
+namespace rtl{ class OUString; }
+namespace svgi
+{
+ struct State;
+ enum SvgUnit
+ {
+ SVG_LENGTH_UNIT_CM,
+ SVG_LENGTH_UNIT_EM,
+ SVG_LENGTH_UNIT_EX,
+ SVG_LENGTH_UNIT_IN,
+ SVG_LENGTH_UNIT_MM,
+ SVG_LENGTH_UNIT_PC,
+ SVG_LENGTH_UNIT_PT,
+ SVG_LENGTH_UNIT_PX,
+ SVG_LENGTH_UNIT_PERCENTAGE,
+ SVG_LENGTH_UNIT_USER
+ };
+
+ /** return svg_length_t in 100th's of mm
+ @param fVal value to convert
+ @param unit unit the value is in
+ @param rState current state (needed for viewport dimensions etc.)
+ @param dir direction - either 'h' or 'v' for horizonal or vertical, resp.
+ */
+ double convLength( double fVal, SvgUnit unit, const State& rState, char dir );
+
+ /** return svg_length_t in 100th's of mm
+ @param sValue value to convert
+ @param rState current state (needed for viewport dimensions etc.)
+ @param dir direction - either 'h' or 'v' for horizonal or vertical, resp.
+ */
+ double convLength( const rtl::OUString& sValue, const State& rState, char dir );
+
+ inline double pt2mm(double fVal) { return fVal*25.4/72.0; }
+ inline double pt100thmm(double fVal) { return fVal*2540.0/72.0; }
+
+} // namespace svgi
+
+#endif