summaryrefslogtreecommitdiff
path: root/svgio
diff options
context:
space:
mode:
Diffstat (limited to 'svgio')
-rw-r--r--svgio/Library_svgio.mk86
-rw-r--r--svgio/Makefile14
-rw-r--r--svgio/Module_svgio.mk26
-rw-r--r--svgio/Package_inc.mk50
-rw-r--r--svgio/inc/pch/precompiled_svgio.cxx22
-rw-r--r--svgio/inc/pch/precompiled_svgio.hxx25
-rw-r--r--svgio/inc/svgio/svgiodllapi.h33
-rw-r--r--svgio/inc/svgio/svgreader/svgcharacternode.hxx184
-rw-r--r--svgio/inc/svgio/svgreader/svgcirclenode.hxx80
-rw-r--r--svgio/inc/svgio/svgreader/svgclippathnode.hxx73
-rw-r--r--svgio/inc/svgio/svgreader/svgdocument.hxx90
-rw-r--r--svgio/inc/svgio/svgreader/svgdocumenthandler.hxx75
-rw-r--r--svgio/inc/svgio/svgreader/svgellipsenode.hxx85
-rw-r--r--svgio/inc/svgio/svgreader/svggnode.hxx66
-rw-r--r--svgio/inc/svgio/svgreader/svggradientnode.hxx137
-rw-r--r--svgio/inc/svgio/svgreader/svggradientstopnode.hxx64
-rw-r--r--svgio/inc/svgio/svgreader/svgimagenode.hxx99
-rw-r--r--svgio/inc/svgio/svgreader/svglinenode.hxx85
-rw-r--r--svgio/inc/svgio/svgreader/svgmarkernode.hxx123
-rw-r--r--svgio/inc/svgio/svgreader/svgmasknode.hxx98
-rw-r--r--svgio/inc/svgio/svgreader/svgnode.hxx127
-rw-r--r--svgio/inc/svgio/svgreader/svgpaint.hxx65
-rw-r--r--svgio/inc/svgio/svgreader/svgpathnode.hxx75
-rw-r--r--svgio/inc/svgio/svgreader/svgpatternnode.hxx126
-rw-r--r--svgio/inc/svgio/svgreader/svgpolynode.hxx78
-rw-r--r--svgio/inc/svgio/svgreader/svgrectnode.hxx95
-rw-r--r--svgio/inc/svgio/svgreader/svgstyleattributes.hxx411
-rw-r--r--svgio/inc/svgio/svgreader/svgstylenode.hxx64
-rw-r--r--svgio/inc/svgio/svgreader/svgsvgnode.hxx97
-rw-r--r--svgio/inc/svgio/svgreader/svgsymbolnode.hxx68
-rw-r--r--svgio/inc/svgio/svgreader/svgtextnode.hxx80
-rw-r--r--svgio/inc/svgio/svgreader/svgtextpathnode.hxx86
-rw-r--r--svgio/inc/svgio/svgreader/svgtoken.hxx194
-rw-r--r--svgio/inc/svgio/svgreader/svgtools.hxx229
-rw-r--r--svgio/inc/svgio/svgreader/svgtrefnode.hxx65
-rw-r--r--svgio/inc/svgio/svgreader/svgtspannode.hxx64
-rw-r--r--svgio/inc/svgio/svgreader/svgusenode.hxx89
-rw-r--r--svgio/prj/build.lst2
-rw-r--r--svgio/prj/d.lst0
-rw-r--r--svgio/prj/makefile.mk33
-rw-r--r--svgio/source/svgreader/svgcharacternode.cxx740
-rw-r--r--svgio/source/svgreader/svgcirclenode.cxx155
-rw-r--r--svgio/source/svgreader/svgclippathnode.cxx203
-rw-r--r--svgio/source/svgreader/svgdocument.cxx118
-rw-r--r--svgio/source/svgreader/svgdocumenthandler.cxx549
-rw-r--r--svgio/source/svgreader/svgellipsenode.cxx170
-rw-r--r--svgio/source/svgreader/svggnode.cxx115
-rw-r--r--svgio/source/svgreader/svggradientnode.cxx508
-rw-r--r--svgio/source/svgreader/svggradientstopnode.cxx88
-rw-r--r--svgio/source/svgreader/svgimagenode.cxx354
-rw-r--r--svgio/source/svgreader/svglinenode.cxx166
-rw-r--r--svgio/source/svgreader/svgmarkernode.cxx213
-rw-r--r--svgio/source/svgreader/svgmasknode.cxx315
-rw-r--r--svgio/source/svgreader/svgnode.cxx289
-rw-r--r--svgio/source/svgreader/svgpaint.cxx34
-rw-r--r--svgio/source/svgreader/svgpathnode.cxx133
-rw-r--r--svgio/source/svgreader/svgpatternnode.cxx463
-rw-r--r--svgio/source/svgreader/svgpolynode.cxx130
-rw-r--r--svgio/source/svgreader/svgrectnode.cxx227
-rw-r--r--svgio/source/svgreader/svgstyleattributes.cxx2489
-rw-r--r--svgio/source/svgreader/svgstylenode.cxx127
-rw-r--r--svgio/source/svgreader/svgsvgnode.cxx423
-rw-r--r--svgio/source/svgreader/svgsymbolnode.cxx94
-rw-r--r--svgio/source/svgreader/svgtextnode.cxx274
-rw-r--r--svgio/source/svgreader/svgtextpathnode.cxx511
-rw-r--r--svgio/source/svgreader/svgtoken.cxx318
-rw-r--r--svgio/source/svgreader/svgtools.cxx1592
-rw-r--r--svgio/source/svgreader/svgtrefnode.cxx91
-rw-r--r--svgio/source/svgreader/svgtspannode.cxx78
-rw-r--r--svgio/source/svgreader/svgusenode.cxx201
-rw-r--r--svgio/source/svguno/svguno.cxx92
-rw-r--r--svgio/source/svguno/xsvgparser.cxx191
-rw-r--r--svgio/svgio.component25
73 files changed, 15039 insertions, 0 deletions
diff --git a/svgio/Library_svgio.mk b/svgio/Library_svgio.mk
new file mode 100644
index 000000000000..bc4ddb61131f
--- /dev/null
+++ b/svgio/Library_svgio.mk
@@ -0,0 +1,86 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call gb_Library_Library,svgio))
+
+$(eval $(call gb_Library_set_componentfile,svgio,svgio/svgio))
+
+$(eval $(call gb_Library_use_package,svgio))
+
+$(eval $(call gb_Library_add_precompiled_header,svgio,$(SRCDIR)/svgio/inc/pch/precompiled_svgio))
+
+$(eval $(call gb_Library_use_sdk_api,svgio))
+
+$(eval $(call gb_Library_set_include,svgio,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/svgio/inc \
+))
+
+$(eval $(call gb_Library_add_defs,svgio,\
+ -DSVGIO_DLLIMPLEMENTATION \
+))
+
+$(eval $(call gb_Library_use_libraries,svgio,\
+ basegfx \
+ drawinglayer \
+ comphelper \
+ cppu \
+ cppuhelper \
+ sal \
+ tl \
+ sax \
+ vcl \
+ svt \
+))
+
+$(eval $(call gb_Library_add_exception_objects,svgio,\
+ svgio/source/svgreader/svgcharacternode \
+ svgio/source/svgreader/svgcirclenode \
+ svgio/source/svgreader/svgclippathnode \
+ svgio/source/svgreader/svgdocument \
+ svgio/source/svgreader/svgdocumenthandler \
+ svgio/source/svgreader/svgellipsenode \
+ svgio/source/svgreader/svggnode \
+ svgio/source/svgreader/svggradientnode \
+ svgio/source/svgreader/svggradientstopnode \
+ svgio/source/svgreader/svgimagenode \
+ svgio/source/svgreader/svglinenode \
+ svgio/source/svgreader/svgmarkernode \
+ svgio/source/svgreader/svgmasknode \
+ svgio/source/svgreader/svgnode \
+ svgio/source/svgreader/svgpaint \
+ svgio/source/svgreader/svgpathnode \
+ svgio/source/svgreader/svgpatternnode \
+ svgio/source/svgreader/svgpolynode \
+ svgio/source/svgreader/svgrectnode \
+ svgio/source/svgreader/svgstyleattributes \
+ svgio/source/svgreader/svgstylenode \
+ svgio/source/svgreader/svgsvgnode \
+ svgio/source/svgreader/svgsymbolnode \
+ svgio/source/svgreader/svgtextnode \
+ svgio/source/svgreader/svgtoken \
+ svgio/source/svgreader/svgtrefnode \
+ svgio/source/svgreader/svgtools \
+ svgio/source/svgreader/svgtextpathnode \
+ svgio/source/svgreader/svgtspannode \
+ svgio/source/svgreader/svgusenode \
+ svgio/source/svguno/svguno \
+ svgio/source/svguno/xsvgparser \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/svgio/Makefile b/svgio/Makefile
new file mode 100644
index 000000000000..0997e628485b
--- /dev/null
+++ b/svgio/Makefile
@@ -0,0 +1,14 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST))))
+
+include $(module_directory)/../solenv/gbuild/partial_build.mk
+
+# vim: set noet sw=4 ts=4:
diff --git a/svgio/Module_svgio.mk b/svgio/Module_svgio.mk
new file mode 100644
index 000000000000..f1b3b7b88c53
--- /dev/null
+++ b/svgio/Module_svgio.mk
@@ -0,0 +1,26 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call gb_Module_Module,svgio))
+
+$(eval $(call gb_Module_add_targets,svgio,\
+ Library_svgio \
+ Package_inc \
+))
+
+# vim: set noet ts=4 sw=4:
diff --git a/svgio/Package_inc.mk b/svgio/Package_inc.mk
new file mode 100644
index 000000000000..5aed79891b7e
--- /dev/null
+++ b/svgio/Package_inc.mk
@@ -0,0 +1,50 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call gb_Package_Package,svgio_inc,$(SRCDIR)/svgio/inc))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgiodllapi.h,svgio/svgiodllapi.h))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgcharacternode.hxx,svgio/svgreader/svgcharacternode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgcirclenode.hxx,svgio/svgreader/svgcirclenode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgclippathnode.hxx,svgio/svgreader/svgclippathnode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgdocument.hxx,svgio/svgreader/svgdocument.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgdocumenthandler.hxx,svgio/svgreader/svgdocumenthandler.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgellipsenode.hxx,svgio/svgreader/svgellipsenode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svggnode.hxx,svgio/svgreader/svggnode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svggradientnode.hxx,svgio/svgreader/svggradientnode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svggradientstopnode.hxx,svgio/svgreader/svggradientstopnode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgimagenode.hxx,svgio/svgreader/svgimagenode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svglinenode.hxx,svgio/svgreader/svglinenode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgnode.hxx,svgio/svgreader/svgnode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgmarkernode.hxx,svgio/svgreader/svgmarkernode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgmasknode.hxx,svgio/svgreader/svgmasknode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgpaint.hxx,svgio/svgreader/svgpaint.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgpathnode.hxx,svgio/svgreader/svgpathnode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgpatternnode.hxx,svgio/svgreader/svgpatternnode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgpolynode.hxx,svgio/svgreader/svgpolynode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgrectnode.hxx,svgio/svgreader/svgrectnode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgstyleattributes.hxx,svgio/svgreader/svgstyleattributes.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgstylenode.hxx,svgio/svgreader/svgstylenode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgsvgnode.hxx,svgio/svgreader/svgsvgnode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgsymbolnode.hxx,svgio/svgreader/svgsymbolnode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgtextnode.hxx,svgio/svgreader/svgtextnode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgtoken.hxx,svgio/svgreader/svgtoken.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgtrefnode.hxx,svgio/svgreader/svgtrefnode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgtools.hxx,svgio/svgreader/svgtools.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgtextpathnode.hxx,svgio/svgreader/svgtextpathnode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgtspannode.hxx,svgio/svgreader/svgtspannode.hxx))
+$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgusenode.hxx,svgio/svgreader/svgusenode.hxx))
diff --git a/svgio/inc/pch/precompiled_svgio.cxx b/svgio/inc/pch/precompiled_svgio.cxx
new file mode 100644
index 000000000000..db5227c1d1b0
--- /dev/null
+++ b/svgio/inc/pch/precompiled_svgio.cxx
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "precompiled_svgio.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/pch/precompiled_svgio.hxx b/svgio/inc/pch/precompiled_svgio.hxx
new file mode 100644
index 000000000000..e694392e65be
--- /dev/null
+++ b/svgio/inc/pch/precompiled_svgio.hxx
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+// MARKER(update_precomp.py): Generated on 2006-09-01 17:49:30.796084
+
+#ifdef PRECOMPILED_HEADERS
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgiodllapi.h b/svgio/inc/svgio/svgiodllapi.h
new file mode 100644
index 000000000000..c28ff1192427
--- /dev/null
+++ b/svgio/inc/svgio/svgiodllapi.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SVGIODLLAPI_H
+#define INCLUDED_SVGIODLLAPI_H
+
+#include "sal/types.h"
+
+#if defined(SVGIO_DLLIMPLEMENTATION)
+#define SVGIO_DLLPUBLIC SAL_DLLPUBLIC_EXPORT
+#else
+#define SVGIO_DLLPUBLIC SAL_DLLPUBLIC_IMPORT
+#endif
+#define SVGIO_DLLPRIVATE SAL_DLLPRIVATE
+
+#endif /* INCLUDED_SVGIODLLAPI_H */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgcharacternode.hxx b/svgio/inc/svgio/svgreader/svgcharacternode.hxx
new file mode 100644
index 000000000000..55d056aadd52
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgcharacternode.hxx
@@ -0,0 +1,184 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGCHARACTERNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGCHARACTERNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// predefines
+
+namespace drawinglayer { namespace primitive2d { class TextSimplePortionPrimitive2D; }}
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgTextPositions
+ {
+ private:
+ SvgNumberVector maX;
+ SvgNumberVector maY;
+ SvgNumberVector maDx;
+ SvgNumberVector maDy;
+ SvgNumberVector maRotate;
+ SvgNumber maTextLength;
+
+ /// bitfield
+ bool mbLengthAdjust : 1; // true = spacing, false = spacingAndGlyphs
+
+ public:
+ SvgTextPositions();
+
+ void parseTextPositionAttributes(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+
+ /// X content
+ const SvgNumberVector& getX() const { return maX; }
+ void setX(const SvgNumberVector& aX) { maX = aX; }
+
+ /// Y content
+ const SvgNumberVector& getY() const { return maY; }
+ void setY(const SvgNumberVector& aY) { maY = aY; }
+
+ /// Dx content
+ const SvgNumberVector& getDx() const { return maDx; }
+ void setDx(const SvgNumberVector& aDx) { maDx = aDx; }
+
+ /// Dy content
+ const SvgNumberVector& getDy() const { return maDy; }
+ void setDy(const SvgNumberVector& aDy) { maDy = aDy; }
+
+ /// Rotate content
+ const SvgNumberVector& getRotate() const { return maRotate; }
+ void setRotate(const SvgNumberVector& aRotate) { maRotate = aRotate; }
+
+ /// TextLength content
+ const SvgNumber& getTextLength() const { return maTextLength; }
+ void setTextLength(const SvgNumber& rTextLength = SvgNumber()) { maTextLength = rTextLength; }
+
+ /// LengthAdjust content
+ bool getLengthAdjust() const { return mbLengthAdjust; }
+ void setLengthAdjust(bool bNew) { mbLengthAdjust = bNew; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgTextPosition
+ {
+ private:
+ SvgTextPosition* mpParent;
+ ::std::vector< double > maX;
+ ::std::vector< double > maY;
+ ::std::vector< double > maRotate;
+ double mfTextLength;
+
+ // absolute, current, advancing position
+ basegfx::B2DPoint maPosition;
+
+ // advancing rotation index
+ sal_uInt32 mnRotationIndex;
+
+ /// bitfield
+ bool mbLengthAdjust : 1; // true = spacing, false = spacingAndGlyphs
+ bool mbAbsoluteX : 1;
+ bool mbAbsoluteY : 1;
+
+ public:
+ SvgTextPosition(
+ SvgTextPosition* pParent,
+ const InfoProvider& rInfoProvider,
+ const SvgTextPositions& rSvgTextPositions);
+
+ // data read access
+ const SvgTextPosition* getParent() const { return mpParent; }
+ const ::std::vector< double >& getX() const { return maX; }
+ const ::std::vector< double >& getY() const { return maY; }
+ double getTextLength() const { return mfTextLength; }
+ bool getLengthAdjust() const { return mbLengthAdjust; }
+ bool getAbsoluteX() const { return mbAbsoluteX; }
+ bool getAbsoluteY() const { return mbAbsoluteY; }
+
+ // get/set absolute, current, advancing position
+ const basegfx::B2DPoint& getPosition() const { return maPosition; }
+ void setPosition(const basegfx::B2DPoint& rNew) { maPosition = rNew; }
+
+ // rotation handling
+ bool isRotated() const;
+ double consumeRotation();
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgCharacterNode : public SvgNode
+ {
+ private:
+ /// the string data
+ rtl::OUString maText;
+
+ /// local helpers
+ drawinglayer::primitive2d::TextSimplePortionPrimitive2D* createSimpleTextPrimitive(
+ SvgTextPosition& rSvgTextPosition,
+ const SvgStyleAttributes& rSvgStyleAttributes) const;
+ void decomposeTextWithStyle(
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ SvgTextPosition& rSvgTextPosition,
+ const SvgStyleAttributes& rSvgStyleAttributes) const;
+
+ public:
+ SvgCharacterNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent,
+ const rtl::OUString& rText);
+ virtual ~SvgCharacterNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void decomposeText(drawinglayer::primitive2d::Primitive2DSequence& rTarget, SvgTextPosition& rSvgTextPosition) const;
+ void whiteSpaceHandling();
+ void addGap();
+ void concatenate(const rtl::OUString& rText);
+
+ /// Text content
+ const rtl::OUString& getText() const { return maText; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGCHARACTERNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgcirclenode.hxx b/svgio/inc/svgio/svgreader/svgcirclenode.hxx
new file mode 100644
index 000000000000..ddfde9caab00
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgcirclenode.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGCIRCLENODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGCIRCLENODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgCircleNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ SvgNumber maCx;
+ SvgNumber maCy;
+ SvgNumber maR;
+ basegfx::B2DHomMatrix* mpaTransform;
+
+ public:
+ SvgCircleNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgCircleNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const;
+
+ /// Cx content, set if found in current context
+ const SvgNumber& getCx() const { return maCx; }
+ void setCx(const SvgNumber& rCx = SvgNumber()) { maCx = rCx; }
+
+ /// Cy content, set if found in current context
+ const SvgNumber& getCy() const { return maCy; }
+ void setCy(const SvgNumber& rCy = SvgNumber()) { maCy = rCy; }
+
+ /// R content, set if found in current context
+ const SvgNumber& getR() const { return maR; }
+ void setR(const SvgNumber& rR = SvgNumber()) { maR = rR; }
+
+ /// transform content, set if found in current context
+ const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; }
+ void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGCIRCLENODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgclippathnode.hxx b/svgio/inc/svgio/svgreader/svgclippathnode.hxx
new file mode 100644
index 000000000000..95d485ac5dad
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgclippathnode.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGCLIPPATHNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGCLIPPATHNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgClipPathNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ basegfx::B2DHomMatrix* mpaTransform;
+ SvgUnits maClipPathUnits;
+
+ public:
+ SvgClipPathNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgClipPathNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const;
+
+ /// apply contained clipPath to given geometry
+ void apply(drawinglayer::primitive2d::Primitive2DSequence& rTarget) const;
+
+ /// clipPathUnits content
+ SvgUnits getClipPathUnits() const { return maClipPathUnits; }
+ void setClipPathUnits(const SvgUnits aClipPathUnits) { maClipPathUnits = aClipPathUnits; }
+
+ /// transform content
+ const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; }
+ void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGCLIPPATHNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgdocument.hxx b/svgio/inc/svgio/svgreader/svgdocument.hxx
new file mode 100644
index 000000000000..ae30fe40b73d
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgdocument.hxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGDOCUMENT_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGDOCUMENT_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <boost/utility.hpp>
+#include <svgio/svgreader/svgnode.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgDocument : private boost::noncopyable
+ {
+ private:
+ /// the document hierarchy with all root nodes
+ SvgNodeVector maNodes;
+
+ /// the absolute path of the Svg file in progress (if available)
+ const rtl::OUString maAbsolutePath;
+
+ /// hash mapper to find nodes by their id
+ typedef boost::unordered_map< const rtl::OUString, const SvgNode*,
+ rtl::OUStringHash,
+ ::std::equal_to< ::rtl::OUString > > IdTokenMapper;
+ typedef std::pair< const rtl::OUString, const SvgNode* > IdTokenValueType;
+ IdTokenMapper maIdTokenMapperList;
+
+ /// hash mapper to find css styles by their id
+ typedef boost::unordered_map< const rtl::OUString, const SvgStyleAttributes*, rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > > IdStyleTokenMapper;
+ typedef std::pair< const rtl::OUString, const SvgStyleAttributes* > IdStyleTokenValueType;
+ IdStyleTokenMapper maIdStyleTokenMapperList;
+
+ public:
+ SvgDocument(const rtl::OUString& rAbsolutePath);
+ ~SvgDocument();
+
+ /// append anopther root node, ownership changes
+ void appendNode(SvgNode* pNode);
+
+ /// add/remove nodes with Id to mapper
+ void addSvgNodeToMapper(const rtl::OUString& rStr, const SvgNode& rNode);
+ void removeSvgNodeFromMapper(const rtl::OUString& rStr);
+
+ /// find a node by it's Id
+ bool hasSvgNodesById() const { return !maIdTokenMapperList.empty(); }
+ const SvgNode* findSvgNodeById(const rtl::OUString& rStr) const;
+
+ /// add/remove styles to mapper
+ void addSvgStyleAttributesToMapper(const rtl::OUString& rStr, const SvgStyleAttributes& rSvgStyleAttributes);
+ void removeSvgStyleAttributesFromMapper(const rtl::OUString& rStr);
+
+ /// find a style by it's Id
+ bool hasSvgStyleAttributesById() const { return !maIdStyleTokenMapperList.empty(); }
+ const SvgStyleAttributes* findSvgStyleAttributesById(const rtl::OUString& rStr) const;
+
+ /// data read access
+ const SvgNodeVector& getSvgNodeVector() const { return maNodes; }
+ const rtl::OUString& getAbsolutePath() const { return maAbsolutePath; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGDOCUMENT_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgdocumenthandler.hxx b/svgio/inc/svgio/svgreader/svgdocumenthandler.hxx
new file mode 100644
index 000000000000..04ced2ec1cc3
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgdocumenthandler.hxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGDOCUMENTHANDLER_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGDOCUMENTHANDLER_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <svgio/svgreader/svgdocument.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// predefines
+
+namespace svgio { namespace svgreader { class SvgCharacterNode; }}
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgDocHdl : public cppu::WeakImplHelper1< com::sun::star::xml::sax::XDocumentHandler >
+ {
+ private:
+ // the complete SVG Document
+ SvgDocument maDocument;
+
+ // current node for parsing
+ SvgNode* mpTarget;
+
+ // text collector string stack for css styles
+ std::vector< rtl::OUString > maCssContents;
+
+ public:
+ SvgDocHdl(const rtl::OUString& rAbsolutePath);
+ ~SvgDocHdl();
+
+ // Methods XDocumentHandler
+ virtual void SAL_CALL startDocument( ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL endDocument( ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL startElement( const ::rtl::OUString& aName, const com::sun::star::uno::Reference< com::sun::star::xml::sax::XAttributeList >& xAttribs ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL endElement( const ::rtl::OUString& aName ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL characters( const ::rtl::OUString& aChars ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL ignorableWhitespace( const ::rtl::OUString& aWhitespaces ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setDocumentLocator( const com::sun::star::uno::Reference< com::sun::star::xml::sax::XLocator >& xLocator ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException);
+
+ const SvgDocument& getSvgDocument() const { return maDocument; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGDOCUMENTHANDLER_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgellipsenode.hxx b/svgio/inc/svgio/svgreader/svgellipsenode.hxx
new file mode 100644
index 000000000000..5e501c666a87
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgellipsenode.hxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGELLIPSENODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGELLIPSENODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgEllipseNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ SvgNumber maCx;
+ SvgNumber maCy;
+ SvgNumber maRx;
+ SvgNumber maRy;
+ basegfx::B2DHomMatrix* mpaTransform;
+
+ public:
+ SvgEllipseNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgEllipseNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const;
+
+ /// Cx content, set if found in current context
+ const SvgNumber& getCx() const { return maCx; }
+ void setCx(const SvgNumber& rCx = SvgNumber()) { maCx = rCx; }
+
+ /// Cy content, set if found in current context
+ const SvgNumber& getCy() const { return maCy; }
+ void setCy(const SvgNumber& rCy = SvgNumber()) { maCy = rCy; }
+
+ /// Rx content, set if found in current context
+ const SvgNumber& getRx() const { return maRx; }
+ void setRx(const SvgNumber& rRx = SvgNumber()) { maRx = rRx; }
+
+ /// Ry content, set if found in current context
+ const SvgNumber& getRy() const { return maRy; }
+ void setRy(const SvgNumber& rRy = SvgNumber()) { maRy = rRy; }
+
+ /// transform content, set if found in current context
+ const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; }
+ void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGELLIPSENODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svggnode.hxx b/svgio/inc/svgio/svgreader/svggnode.hxx
new file mode 100644
index 000000000000..0bd334dd9257
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svggnode.hxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGGNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGGNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgGNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ basegfx::B2DHomMatrix* mpaTransform;
+
+ public:
+ SvgGNode(
+ SVGToken aType,
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgGNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const;
+
+ /// transform content
+ const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; }
+ void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGGNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svggradientnode.hxx b/svgio/inc/svgio/svgreader/svggradientnode.hxx
new file mode 100644
index 000000000000..7e9e336bf229
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svggradientnode.hxx
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGGRADIENTNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGGRADIENTNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+#include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgGradientNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// linear gradient values
+ SvgNumber maX1;
+ SvgNumber maY1;
+ SvgNumber maX2;
+ SvgNumber maY2;
+
+ /// radial gradient values
+ SvgNumber maCx;
+ SvgNumber maCy;
+ SvgNumber maR;
+ SvgNumber maFx;
+ SvgNumber maFy;
+
+ /// variable scan values, dependent of given XAttributeList
+ SvgUnits maGradientUnits;
+ drawinglayer::primitive2d::SpreadMethod maSpreadMethod;
+ basegfx::B2DHomMatrix* mpaGradientTransform;
+
+ /// link to another gradient used as style. If maXLink
+ /// is set, the node can be fetched on demand by using
+ // tryToFindLink (buffered)
+ rtl::OUString maXLink;
+ const SvgGradientNode* mpXLink;
+
+ /// link on demand
+ void tryToFindLink();
+
+ public:
+ SvgGradientNode(
+ SVGToken aType,
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgGradientNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+
+ /// collect gradient stop entries
+ void collectGradientEntries(drawinglayer::primitive2d::SvgGradientEntryVector& aVector) const;
+
+ /// x1 content
+ const SvgNumber getX1() const;
+ void setX1(const SvgNumber& rX1 = SvgNumber()) { maX1 = rX1; }
+
+ /// y1 content
+ const SvgNumber getY1() const;
+ void setY1(const SvgNumber& rY1 = SvgNumber()) { maY1 = rY1; }
+
+ /// x2 content
+ const SvgNumber getX2() const;
+ void setX2(const SvgNumber& rX2 = SvgNumber()) { maX2 = rX2; }
+
+ /// y2 content
+ const SvgNumber getY2() const;
+ void setY2(const SvgNumber& rY2 = SvgNumber()) { maY2 = rY2; }
+
+ /// Cx content
+ const SvgNumber getCx() const;
+ void setCx(const SvgNumber& rCx = SvgNumber()) { maCx = rCx; }
+
+ /// Cy content
+ const SvgNumber getCy() const;
+ void setCy(const SvgNumber& rCy = SvgNumber()) { maCy = rCy; }
+
+ /// R content
+ const SvgNumber getR() const;
+ void setR(const SvgNumber& rR = SvgNumber()) { maR = rR; }
+
+ /// Fx content
+ const SvgNumber* getFx() const;
+ void setFx(const SvgNumber& rFx = SvgNumber()) { maFx = rFx; }
+
+ /// Fy content
+ const SvgNumber* getFy() const;
+ void setFy(const SvgNumber& rFy = SvgNumber()) { maFy = rFy; }
+
+ /// gradientUnits content
+ SvgUnits getGradientUnits() const { return maGradientUnits; }
+ void setGradientUnits(const SvgUnits aGradientUnits) { maGradientUnits = aGradientUnits; }
+
+ /// SpreadMethod content
+ drawinglayer::primitive2d::SpreadMethod getSpreadMethod() const { return maSpreadMethod; }
+ void setSpreadMethod(const drawinglayer::primitive2d::SpreadMethod aSpreadMethod) { maSpreadMethod = aSpreadMethod; }
+
+ /// transform content, set if found in current context
+ const basegfx::B2DHomMatrix* getGradientTransform() const;
+ void setGradientTransform(const basegfx::B2DHomMatrix* pMatrix = 0);
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGGRADIENTNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svggradientstopnode.hxx b/svgio/inc/svgio/svgreader/svggradientstopnode.hxx
new file mode 100644
index 000000000000..274b25e61891
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svggradientstopnode.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGGRADIENTSTOPNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGGRADIENTSTOPNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgGradientStopNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// local attributes
+ SvgNumber maOffset;
+
+ public:
+ SvgGradientStopNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgGradientStopNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+
+ /// offset content
+ const SvgNumber getOffset() const { return maOffset; }
+ void setOffset(const SvgNumber& rOffset = SvgNumber()) { maOffset = rOffset; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGGRADIENTSTOPNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgimagenode.hxx b/svgio/inc/svgio/svgreader/svgimagenode.hxx
new file mode 100644
index 000000000000..afdf886ab2c3
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgimagenode.hxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGIMAGENODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGIMAGENODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgImageNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ SvgAspectRatio maSvgAspectRatio;
+ basegfx::B2DHomMatrix* mpaTransform;
+ SvgNumber maX;
+ SvgNumber maY;
+ SvgNumber maWidth;
+ SvgNumber maHeight;
+
+ rtl::OUString maXLink; // internal link
+ rtl::OUString maUrl; // external link
+
+ rtl::OUString maMimeType; // mimetype and
+ rtl::OUString maData; // base64 data
+
+ public:
+ SvgImageNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgImageNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const;
+
+ /// SvgAspectRatio content
+ const SvgAspectRatio& getSvgAspectRatio() const { return maSvgAspectRatio; }
+ void setSvgAspectRatio(const SvgAspectRatio& rSvgAspectRatio = SvgAspectRatio()) { maSvgAspectRatio = rSvgAspectRatio; }
+
+ /// transform content, set if found in current context
+ const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; }
+ void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); }
+
+ /// x content, set if found in current context
+ const SvgNumber& getX() const { return maX; }
+ void setX(const SvgNumber& rX = SvgNumber()) { maX = rX; }
+
+ /// y content, set if found in current context
+ const SvgNumber& getY() const { return maY; }
+ void setY(const SvgNumber& rY = SvgNumber()) { maY = rY; }
+
+ /// width content, set if found in current context
+ const SvgNumber& getWidth() const { return maWidth; }
+ void setWidth(const SvgNumber& rWidth = SvgNumber()) { maWidth = rWidth; }
+
+ /// height content, set if found in current context
+ const SvgNumber& getHeight() const { return maHeight; }
+ void setHeight(const SvgNumber& rHeight = SvgNumber()) { maHeight = rHeight; }
+
+ /// XLink access
+ const rtl::OUString& getXLink() const { return maXLink; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGIMAGENODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svglinenode.hxx b/svgio/inc/svgio/svgreader/svglinenode.hxx
new file mode 100644
index 000000000000..4ee18b7bfa32
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svglinenode.hxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGLINENODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGLINENODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgLineNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ SvgNumber maX1;
+ SvgNumber maY1;
+ SvgNumber maX2;
+ SvgNumber maY2;
+ basegfx::B2DHomMatrix* mpaTransform;
+
+ public:
+ SvgLineNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgLineNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const;
+
+ /// X1 content, set if found in current context
+ const SvgNumber& getX1() const { return maX1; }
+ void setX1(const SvgNumber& rX1 = SvgNumber()) { maX1 = rX1; }
+
+ /// Y1 content, set if found in current context
+ const SvgNumber& getY1() const { return maY1; }
+ void setY1(const SvgNumber& rY1 = SvgNumber()) { maY1 = rY1; }
+
+ /// X2 content, set if found in current context
+ const SvgNumber& getX2() const { return maX2; }
+ void setX2(const SvgNumber& rX2 = SvgNumber()) { maX2 = rX2; }
+
+ /// Y2 content, set if found in current context
+ const SvgNumber& getY2() const { return maY2; }
+ void setY2(const SvgNumber& rY2 = SvgNumber()) { maY2 = rY2; }
+
+ /// transform content, set if found in current context
+ const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; }
+ void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGLINENODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgmarkernode.hxx b/svgio/inc/svgio/svgreader/svgmarkernode.hxx
new file mode 100644
index 000000000000..947f5099bd3a
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgmarkernode.hxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGMARKERNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGMARKERNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgMarkerNode : public SvgNode
+ {
+ public:
+ enum MarkerUnits
+ {
+ strokeWidth,
+ userSpaceOnUse
+ };
+
+ private:
+ /// buffered decomposition
+ drawinglayer::primitive2d::Primitive2DSequence aPrimitives;
+
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ basegfx::B2DRange* mpViewBox;
+ SvgAspectRatio maSvgAspectRatio;
+ SvgNumber maRefX;
+ SvgNumber maRefY;
+ MarkerUnits maMarkerUnits;
+ SvgNumber maMarkerWidth;
+ SvgNumber maMarkerHeight;
+ double mfAngle;
+
+ /// bitfield
+ bool mbOrientAuto : 1; // true == on, false == fAngle valid
+
+ public:
+ SvgMarkerNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgMarkerNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+
+ /// get marker primitives buffered, uses decomposeSvgNode internally
+ const drawinglayer::primitive2d::Primitive2DSequence& getMarkerPrimitives() const;
+
+ /// InfoProvider support for % values
+ virtual const basegfx::B2DRange* getCurrentViewPort() const;
+
+ /// viewBox content
+ const basegfx::B2DRange* getViewBox() const { return mpViewBox; }
+ void setViewBox(const basegfx::B2DRange* pViewBox = 0) { if(mpViewBox) delete mpViewBox; mpViewBox = 0; if(pViewBox) mpViewBox = new basegfx::B2DRange(*pViewBox); }
+
+ /// SvgAspectRatio content
+ const SvgAspectRatio& getSvgAspectRatio() const { return maSvgAspectRatio; }
+ void setSvgAspectRatio(const SvgAspectRatio& rSvgAspectRatio = SvgAspectRatio()) { maSvgAspectRatio = rSvgAspectRatio; }
+
+ /// RefX content, set if found in current context
+ const SvgNumber& getRefX() const { return maRefX; }
+ void setRefX(const SvgNumber& rRefX = SvgNumber()) { maRefX = rRefX; }
+
+ /// RefY content, set if found in current context
+ const SvgNumber& getRefY() const { return maRefY; }
+ void setRefY(const SvgNumber& rRefY = SvgNumber()) { maRefY = rRefY; }
+
+ /// MarkerUnits content
+ MarkerUnits getMarkerUnits() const { return maMarkerUnits; }
+ void setMarkerUnits(const MarkerUnits aMarkerUnits) { maMarkerUnits = aMarkerUnits; }
+
+ /// MarkerWidth content, set if found in current context
+ const SvgNumber& getMarkerWidth() const { return maMarkerWidth; }
+ void setMarkerWidth(const SvgNumber& rMarkerWidth = SvgNumber()) { maMarkerWidth = rMarkerWidth; }
+
+ /// MarkerHeight content, set if found in current context
+ const SvgNumber& getMarkerHeight() const { return maMarkerHeight; }
+ void setMarkerHeight(const SvgNumber& rMarkerHeight = SvgNumber()) { maMarkerHeight = rMarkerHeight; }
+
+ /// Angle content, set if found in current context
+ double getAngle() const { return mfAngle; }
+ void setAngle(double fAngle = 0.0) { mfAngle = fAngle; mbOrientAuto = false; }
+
+ /// OrientAuto content, set if found in current context
+ bool getOrientAuto() const { return mbOrientAuto; }
+ void setOrientAuto(bool bOrientAuto = true) { mbOrientAuto = bOrientAuto; }
+
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGMARKERNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgmasknode.hxx b/svgio/inc/svgio/svgreader/svgmasknode.hxx
new file mode 100644
index 000000000000..a5914d7eb327
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgmasknode.hxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGMASKNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGMASKNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgMaskNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ SvgNumber maX;
+ SvgNumber maY;
+ SvgNumber maWidth;
+ SvgNumber maHeight;
+ basegfx::B2DHomMatrix* mpaTransform;
+ SvgUnits maMaskUnits;
+ SvgUnits maMaskContentUnits;
+
+ public:
+ SvgMaskNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgMaskNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const;
+
+ /// apply contained clipPath to given geometry
+ void apply(drawinglayer::primitive2d::Primitive2DSequence& rTarget) const;
+
+ /// x content, set if found in current context
+ const SvgNumber& getX() const { return maX; }
+ void setX(const SvgNumber& rX = SvgNumber()) { maX = rX; }
+
+ /// y content, set if found in current context
+ const SvgNumber& getY() const { return maY; }
+ void setY(const SvgNumber& rY = SvgNumber()) { maY = rY; }
+
+ /// width content, set if found in current context
+ const SvgNumber& getWidth() const { return maWidth; }
+ void setWidth(const SvgNumber& rWidth = SvgNumber()) { maWidth = rWidth; }
+
+ /// height content, set if found in current context
+ const SvgNumber& getHeight() const { return maHeight; }
+ void setHeight(const SvgNumber& rHeight = SvgNumber()) { maHeight = rHeight; }
+
+ /// transform content
+ const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; }
+ void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); }
+
+ /// MaskUnits content
+ SvgUnits getMaskUnits() const { return maMaskUnits; }
+ void setMaskUnits(const SvgUnits aMaskUnits) { maMaskUnits = aMaskUnits; }
+
+ /// MaskContentUnits content
+ SvgUnits getMaskContentUnits() const { return maMaskContentUnits; }
+ void setMaskContentUnits(const SvgUnits aMaskContentUnits) { maMaskContentUnits = aMaskContentUnits; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGMASKNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgnode.hxx b/svgio/inc/svgio/svgreader/svgnode.hxx
new file mode 100644
index 000000000000..5b3a2694dd18
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgnode.hxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgtools.hxx>
+#include <svgio/svgreader/svgtoken.hxx>
+#include <svgio/svgreader/svgpaint.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <com/sun/star/xml/sax/XAttributeList.hpp>
+#include <vector>
+#include <boost/unordered_map.hpp>
+
+//////////////////////////////////////////////////////////////////////////////
+// predefines
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgNode;
+ class SvgDocument;
+ class SvgStyleAttributes;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ typedef ::std::vector< SvgNode* > SvgNodeVector;
+
+ enum XmlSpace
+ {
+ XmlSpace_notset,
+ XmlSpace_default,
+ XmlSpace_preserve
+ };
+
+ class SvgNode : private boost::noncopyable, public InfoProvider
+ {
+ private:
+ /// basic data, Type, document we belong to and parent (if not root)
+ SVGToken maType;
+ SvgDocument& mrDocument;
+ const SvgNode* mpParent;
+ const SvgNode* mpAlternativeParent;
+
+ /// sub hierarchy
+ SvgNodeVector maChildren;
+
+ /// Id svan value
+ rtl::OUString* mpId;
+
+ /// Class svan value
+ rtl::OUString* mpClass;
+
+ /// XmlSpace value
+ XmlSpace maXmlSpace;
+
+ public:
+ SvgNode(
+ SVGToken aType,
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgNode();
+
+ void parseAttributes(const com::sun::star::uno::Reference< com::sun::star::xml::sax::XAttributeList >& xAttribs);
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const;
+
+ /// basic data read access
+ SVGToken getType() const { return maType; }
+ const SvgDocument& getDocument() const { return mrDocument; }
+ const SvgNode* getParent() const { if(mpAlternativeParent) return mpAlternativeParent; return mpParent; }
+ const SvgNodeVector& getChildren() const { return maChildren; }
+
+ /// InfoProvider support for %, em and ex values
+ virtual const basegfx::B2DRange* getCurrentViewPort() const;
+ virtual double getCurrentFontSize() const;
+ virtual double getCurrentXHeight() const;
+
+ /// Id access
+ const rtl::OUString* getId() const { return mpId; }
+ void setId(const rtl::OUString* pfId = 0);
+
+ /// Class access
+ const rtl::OUString* getClass() const { return mpClass; }
+ void setClass(const rtl::OUString* pfClass = 0);
+
+ /// XmlSpace access
+ XmlSpace getXmlSpace() const;
+ void setXmlSpace(XmlSpace eXmlSpace = XmlSpace_notset) { maXmlSpace = eXmlSpace; }
+
+ /// alternative parent
+ void setAlternativeParent(const SvgNode* pAlternativeParent = 0) { mpAlternativeParent = pAlternativeParent; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgpaint.hxx b/svgio/inc/svgio/svgreader/svgpaint.hxx
new file mode 100644
index 000000000000..361125d107df
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgpaint.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGPAINT_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGPAINT_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <basegfx/color/bcolor.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgPaint
+ {
+ private:
+ basegfx::BColor maColor;
+
+ /// bitfield
+ bool mbSet : 1;
+ bool mbOn : 1;
+ bool mbCurrent : 1;
+
+ public:
+ SvgPaint(const basegfx::BColor& rColor = basegfx::BColor(0.0, 0.0, 0.0), bool bSet = false, bool bOn = false, bool bCurrent = false)
+ : maColor(rColor),
+ mbSet(bSet),
+ mbOn(bOn),
+ mbCurrent(bCurrent)
+ {
+ }
+
+ const basegfx::BColor& getBColor() const { return maColor; }
+ bool isSet() const { return mbSet; }
+ bool isOn() const { return mbOn; }
+ bool isCurrent() const { return mbCurrent; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGPAINT_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgpathnode.hxx b/svgio/inc/svgio/svgreader/svgpathnode.hxx
new file mode 100644
index 000000000000..a7506cee7f8e
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgpathnode.hxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGPATHNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGPATHNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgPathNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ basegfx::B2DPolyPolygon* mpPolyPolygon;
+ basegfx::B2DHomMatrix* mpaTransform;
+ SvgNumber maPathLength;
+
+ public:
+ SvgPathNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgPathNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const;
+
+ /// path content, set if found in current context
+ const basegfx::B2DPolyPolygon* getPath() const { return mpPolyPolygon; }
+ void setPath(const basegfx::B2DPolyPolygon* pPath = 0) { if(mpPolyPolygon) delete mpPolyPolygon; mpPolyPolygon = 0; if(pPath) mpPolyPolygon = new basegfx::B2DPolyPolygon(*pPath); }
+
+ /// transform content, set if found in current context
+ const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; }
+ void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); }
+
+ /// PathLength content
+ const SvgNumber& getPathLength() const { return maPathLength; }
+ void setPathLength(const SvgNumber& rPathLength = SvgNumber()) { maPathLength = rPathLength; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGPATHNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgpatternnode.hxx b/svgio/inc/svgio/svgreader/svgpatternnode.hxx
new file mode 100644
index 000000000000..946fdbfcb1a5
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgpatternnode.hxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGPATTERNNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGPATTERNNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgPatternNode : public SvgNode
+ {
+ private:
+ /// buffered decomposition
+ drawinglayer::primitive2d::Primitive2DSequence aPrimitives;
+
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ basegfx::B2DRange* mpViewBox;
+ SvgAspectRatio maSvgAspectRatio;
+ SvgNumber maX;
+ SvgNumber maY;
+ SvgNumber maWidth;
+ SvgNumber maHeight;
+ SvgUnits* mpPatternUnits;
+ SvgUnits* mpPatternContentUnits;
+ basegfx::B2DHomMatrix* mpaPatternTransform;
+
+ /// link to another pattern used as style. If maXLink
+ /// is set, the node can be fetched on demand by using
+ // tryToFindLink (buffered)
+ rtl::OUString maXLink;
+ const SvgPatternNode* mpXLink;
+
+ /// link on demand
+ void tryToFindLink();
+
+ public:
+ SvgPatternNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgPatternNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+
+ /// global helpers
+ void getValuesRelative(double& rfX, double& rfY, double& rfW, double& rfH, const basegfx::B2DRange& rGeoRange, SvgNode& rUser) const;
+
+ /// get pattern primitives buffered, uses decomposeSvgNode internally
+ const drawinglayer::primitive2d::Primitive2DSequence& getPatternPrimitives() const;
+
+ /// InfoProvider support for % values
+ virtual const basegfx::B2DRange* getCurrentViewPort() const;
+
+ /// viewBox content
+ const basegfx::B2DRange* getViewBox() const;
+ void setViewBox(const basegfx::B2DRange* pViewBox = 0) { if(mpViewBox) delete mpViewBox; mpViewBox = 0; if(pViewBox) mpViewBox = new basegfx::B2DRange(*pViewBox); }
+
+ /// SvgAspectRatio content
+ const SvgAspectRatio& getSvgAspectRatio() const;
+ void setSvgAspectRatio(const SvgAspectRatio& rSvgAspectRatio = SvgAspectRatio()) { maSvgAspectRatio = rSvgAspectRatio; }
+
+ /// X content, set if found in current context
+ const SvgNumber& getX() const;
+ void setX(const SvgNumber& rX = SvgNumber()) { maX = rX; }
+
+ /// Y content, set if found in current context
+ const SvgNumber& getY() const;
+ void setY(const SvgNumber& rY = SvgNumber()) { maY = rY; }
+
+ /// Width content, set if found in current context
+ const SvgNumber& getWidth() const;
+ void setWidth(const SvgNumber& rWidth = SvgNumber()) { maWidth = rWidth; }
+
+ /// Height content, set if found in current context
+ const SvgNumber& getHeight() const;
+ void setHeight(const SvgNumber& rHeight = SvgNumber()) { maHeight = rHeight; }
+
+ /// PatternUnits content
+ const SvgUnits* getPatternUnits() const;
+ void setPatternUnits(const SvgUnits aPatternUnits) { if(mpPatternUnits) delete mpPatternUnits; mpPatternUnits = 0; mpPatternUnits = new SvgUnits(aPatternUnits); }
+
+ /// PatternContentUnits content
+ const SvgUnits* getPatternContentUnits() const;
+ void setPatternContentUnits(const SvgUnits aPatternContentUnits) { if(mpPatternContentUnits) delete mpPatternContentUnits; mpPatternContentUnits = 0; mpPatternContentUnits = new SvgUnits(aPatternContentUnits); }
+
+ /// PatternTransform content
+ const basegfx::B2DHomMatrix* getPatternTransform() const;
+ void setPatternTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaPatternTransform) delete mpaPatternTransform; mpaPatternTransform = 0; if(pMatrix) mpaPatternTransform = new basegfx::B2DHomMatrix(*pMatrix); }
+
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGPATTERNNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgpolynode.hxx b/svgio/inc/svgio/svgreader/svgpolynode.hxx
new file mode 100644
index 000000000000..5ebd8076bb58
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgpolynode.hxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGPOLYNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGPOLYNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgPolyNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ basegfx::B2DPolygon* mpPolygon;
+ basegfx::B2DHomMatrix* mpaTransform;
+
+ /// bitfield
+ bool mbIsPolyline : 1; // true = polyline, false = polygon
+
+ public:
+ SvgPolyNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent,
+ bool bIsPolyline);
+ virtual ~SvgPolyNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const;
+
+ /// type read access
+ bool isPolyline() const { return mbIsPolyline; }
+
+ /// Polygon content, set if found in current context
+ const basegfx::B2DPolygon* getPolygon() const { return mpPolygon; }
+ void setPolygon(const basegfx::B2DPolygon* pPolygon = 0) { if(mpPolygon) delete mpPolygon; mpPolygon = 0; if(pPolygon) mpPolygon = new basegfx::B2DPolygon(*pPolygon); }
+
+ /// transform content, set if found in current context
+ const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; }
+ void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGPOLYNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgrectnode.hxx b/svgio/inc/svgio/svgreader/svgrectnode.hxx
new file mode 100644
index 000000000000..f6e10eac2e98
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgrectnode.hxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGRECTNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGRECTNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgRectNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ SvgNumber maX;
+ SvgNumber maY;
+ SvgNumber maWidth;
+ SvgNumber maHeight;
+ SvgNumber maRx;
+ SvgNumber maRy;
+ basegfx::B2DHomMatrix* mpaTransform;
+
+ public:
+ SvgRectNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgRectNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const;
+
+ /// x content, set if found in current context
+ const SvgNumber& getX() const { return maX; }
+ void setX(const SvgNumber& rX = SvgNumber()) { maX = rX; }
+
+ /// y content, set if found in current context
+ const SvgNumber& getY() const { return maY; }
+ void setY(const SvgNumber& rY = SvgNumber()) { maY = rY; }
+
+ /// width content, set if found in current context
+ const SvgNumber& getWidth() const { return maWidth; }
+ void setWidth(const SvgNumber& rWidth = SvgNumber()) { maWidth = rWidth; }
+
+ /// height content, set if found in current context
+ const SvgNumber& getHeight() const { return maHeight; }
+ void setHeight(const SvgNumber& rHeight = SvgNumber()) { maHeight = rHeight; }
+
+ /// Rx content, set if found in current context
+ const SvgNumber& getRx() const { return maRx; }
+ void setRx(const SvgNumber& rRx = SvgNumber()) { maRx = rRx; }
+
+ /// Ry content, set if found in current context
+ const SvgNumber& getRy() const { return maRy; }
+ void setRy(const SvgNumber& rRy = SvgNumber()) { maRy = rRy; }
+
+ /// transform content, set if found in current context
+ const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; }
+ void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGRECTNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgstyleattributes.hxx b/svgio/inc/svgio/svgreader/svgstyleattributes.hxx
new file mode 100644
index 000000000000..66789586ad6b
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgstyleattributes.hxx
@@ -0,0 +1,411 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGSTYLEATTRIBUTES_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGSTYLEATTRIBUTES_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgpaint.hxx>
+#include <svgio/svgreader/svgnode.hxx>
+#include <vcl/vclenum.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// predefines
+
+namespace svgio { namespace svgreader {
+ class SvgGradientNode;
+ class SvgPatternNode;
+ class SvgMarkerNode;
+}}
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ enum StrokeLinecap
+ {
+ StrokeLinecap_notset,
+ StrokeLinecap_butt,
+ StrokeLinecap_round,
+ StrokeLinecap_square
+ };
+
+ enum StrokeLinejoin
+ {
+ StrokeLinejoin_notset,
+ StrokeLinejoin_miter,
+ StrokeLinejoin_round,
+ StrokeLinejoin_bevel
+ };
+
+ enum FontStretch
+ {
+ FontStretch_notset,
+ FontStretch_normal,
+ FontStretch_wider,
+ FontStretch_narrower,
+ FontStretch_ultra_condensed,
+ FontStretch_extra_condensed,
+ FontStretch_condensed,
+ FontStretch_semi_condensed,
+ FontStretch_semi_expanded,
+ FontStretch_expanded,
+ FontStretch_extra_expanded,
+ FontStretch_ultra_expanded
+ };
+
+ FontStretch getWider(FontStretch aSource);
+ FontStretch getNarrower(FontStretch aSource);
+
+ enum FontStyle
+ {
+ FontStyle_notset,
+ FontStyle_normal,
+ FontStyle_italic,
+ FontStyle_oblique
+ };
+
+ enum FontVariant
+ {
+ FontVariant_notset,
+ FontVariant_normal,
+ FontVariant_small_caps
+ };
+
+ enum FontWeight
+ {
+ FontWeight_notset,
+ FontWeight_100,
+ FontWeight_200,
+ FontWeight_300,
+ FontWeight_400, // same as FontWeight_normal
+ FontWeight_500,
+ FontWeight_600,
+ FontWeight_700, // same as FontWeight_bold
+ FontWeight_800,
+ FontWeight_900,
+ FontWeight_bolder,
+ FontWeight_lighter,
+ };
+
+ FontWeight getBolder(FontWeight aSource);
+ FontWeight getLighter(FontWeight aSource);
+ ::FontWeight getVclFontWeight(FontWeight aSource);
+
+ enum TextAlign
+ {
+ TextAlign_notset,
+ TextAlign_left,
+ TextAlign_right,
+ TextAlign_center,
+ TextAlign_justify
+ };
+
+ enum TextDecoration
+ {
+ TextDecoration_notset,
+ TextDecoration_none,
+ TextDecoration_underline,
+ TextDecoration_overline,
+ TextDecoration_line_through,
+ TextDecoration_blink
+ };
+
+ enum TextAnchor
+ {
+ TextAnchor_notset,
+ TextAnchor_start,
+ TextAnchor_middle,
+ TextAnchor_end
+ };
+
+ class SvgStyleAttributes
+ {
+ private:
+ SvgNode& mrOwner;
+ const SvgStyleAttributes* mpCssStyleParent;
+
+ SvgPaint maFill;
+ SvgPaint maStroke;
+ SvgPaint maStopColor;
+ SvgNumber maStrokeWidth;
+ SvgNumber maStopOpacity;
+ const SvgGradientNode* mpSvgGradientNodeFill;
+ const SvgGradientNode* mpSvgGradientNodeStroke;
+ const SvgPatternNode* mpSvgPatternNodeFill;
+ const SvgPatternNode* mpSvgPatternNodeStroke;
+ SvgNumber maFillOpacity;
+ SvgNumberVector maStrokeDasharray;
+ SvgNumber maStrokeDashOffset;
+ StrokeLinecap maStrokeLinecap;
+ StrokeLinejoin maStrokeLinejoin;
+ SvgNumber maStrokeMiterLimit;
+ SvgNumber maStrokeOpacity;
+ SvgStringVector maFontFamily;
+ SvgNumber maFontSize;
+ FontStretch maFontStretch;
+ FontStyle maFontStyle;
+ FontVariant maFontVariant;
+ FontWeight maFontWeight;
+ TextAlign maTextAlign;
+ TextDecoration maTextDecoration;
+ TextAnchor maTextAnchor;
+ SvgPaint maColor;
+ SvgNumber maOpacity;
+
+ /// link to content. If set, the node can be fetched on demand
+ rtl::OUString maClipPathXLink;
+ rtl::OUString maMaskXLink;
+
+ /// link to markers. If set, the node can be fetched on demand
+ rtl::OUString maMarkerStartXLink;
+ const SvgMarkerNode* mpMarkerStartXLink;
+ rtl::OUString maMarkerMidXLink;
+ const SvgMarkerNode* mpMarkerMidXLink;
+ rtl::OUString maMarkerEndXLink;
+ const SvgMarkerNode* mpMarkerEndXLink;
+
+ /// bitfield
+ bool maFillRule : 1; // true: NonZero, false: EvenOdd
+ bool maFillRuleSet : 1;
+
+ // defines if this attributes are part of a ClipPath. If yes,
+ // rough geometry will be created on decomposition by patching
+ // vaules for fill, stroke, strokeWidth and others
+ bool mbIsClipPathContent : 1;
+
+ // ClipRule setting (only valid wne mbIsClipPathContent == true)
+ bool mbClipRule : 1; // true == nonzero(default), false == evenodd
+
+ /// internal helpers
+ void add_fillGradient(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const SvgGradientNode& rFillGradient,
+ const basegfx::B2DRange& rGeoRange) const;
+ void add_fillPatternTransform(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const SvgPatternNode& rFillGradient,
+ const basegfx::B2DRange& rGeoRange) const;
+ void add_fillPattern(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const SvgPatternNode& rFillGradient,
+ const basegfx::B2DRange& rGeoRange) const;
+ void add_fill(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const basegfx::B2DRange& rGeoRange) const;
+ void add_stroke(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const basegfx::B2DRange& rGeoRange) const;
+ bool prepare_singleMarker(
+ drawinglayer::primitive2d::Primitive2DSequence& rMarkerPrimitives,
+ basegfx::B2DHomMatrix& rMarkerTransform,
+ basegfx::B2DRange& rClipRange,
+ const SvgMarkerNode& rMarker) const;
+ void add_singleMarker(
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const drawinglayer::primitive2d::Primitive2DSequence& rMarkerPrimitives,
+ const basegfx::B2DHomMatrix& rMarkerTransform,
+ const basegfx::B2DRange& rClipRange,
+ const SvgMarkerNode& rMarker,
+ const basegfx::B2DPolygon& rCandidate,
+ const sal_uInt32 nIndex) const;
+ void add_markers(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget) const;
+
+ public:
+ /// local attribute scanner
+ void parseStyleAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+
+ /// helper which does the necessary with a given path
+ void add_text(
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ drawinglayer::primitive2d::Primitive2DSequence& rSource) const;
+ void add_path(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget) const;
+ void add_postProcess(
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const drawinglayer::primitive2d::Primitive2DSequence& rSource,
+ const basegfx::B2DHomMatrix* pTransform) const;
+
+ /// helper to evtl. link to css style
+ void checkForCssStyle(const rtl::OUString& rClassStr) const;
+
+ /// scan helpers
+ void readStyle(const rtl::OUString& rCandidate);
+ const SvgStyleAttributes* getParentStyle() const;
+
+ SvgStyleAttributes(SvgNode& rOwner);
+ ~SvgStyleAttributes();
+
+ /// fill content
+ const basegfx::BColor* getFill() const;
+ void setFill(const SvgPaint& rFill) { maFill = rFill; }
+
+ /// stroke content
+ const basegfx::BColor* getStroke() const;
+ void setStroke(const SvgPaint& rStroke) { maStroke = rStroke; }
+
+ /// stop color content
+ const basegfx::BColor& getStopColor() const;
+ void setStopColor(const SvgPaint& rStopColor) { maStopColor = rStopColor; }
+
+ /// stroke-width content
+ const SvgNumber getStrokeWidth() const;
+ void setStrokeWidth(const SvgNumber& rStrokeWidth = SvgNumber()) { maStrokeWidth = rStrokeWidth; }
+
+ /// stop opacity content
+ const SvgNumber getStopOpacity() const;
+ void setStopOpacity(const SvgNumber& rStopOpacity = SvgNumber()) { maStopOpacity = rStopOpacity; }
+
+ /// access to evtl. set fill gradient
+ const SvgGradientNode* getSvgGradientNodeFill() const;
+ void setSvgGradientNodeFill(const SvgGradientNode* pNew) { mpSvgGradientNodeFill = pNew; }
+
+ /// access to evtl. set fill pattern
+ const SvgPatternNode* getSvgPatternNodeFill() const;
+ void setSvgPatternNodeFill(const SvgPatternNode* pNew) { mpSvgPatternNodeFill = pNew; }
+
+ /// access to evtl. set stroke gradient
+ const SvgGradientNode* getSvgGradientNodeStroke() const;
+ void setSvgGradientNodeStroke(const SvgGradientNode* pNew) { mpSvgGradientNodeStroke = pNew; }
+
+ /// access to evtl. set stroke pattern
+ const SvgPatternNode* getSvgPatternNodeStroke() const;
+ void setSvgPatternNodeStroke(const SvgPatternNode* pNew) { mpSvgPatternNodeStroke = pNew; }
+
+ /// fill opacity content
+ const SvgNumber getFillOpacity() const;
+ void setFillOpacity(const SvgNumber& rFillOpacity = SvgNumber()) { maFillOpacity = rFillOpacity; }
+
+ /// fill rule content
+ bool getFillRule() const;
+ void setFillRule(const bool* pFillRule = 0);
+
+ /// fill StrokeDasharray content
+ const SvgNumberVector& getStrokeDasharray() const;
+ void setStrokeDasharray(const SvgNumberVector& rStrokeDasharray = SvgNumberVector()) { maStrokeDasharray = rStrokeDasharray; }
+
+ /// StrokeDashOffset content
+ const SvgNumber getStrokeDashOffset() const;
+ void setStrokeDashOffset(const SvgNumber& rStrokeDashOffset = SvgNumber()) { maStrokeDashOffset = rStrokeDashOffset; }
+
+ /// StrokeLinecap content
+ StrokeLinecap getStrokeLinecap() const;
+ void setStrokeLinecap(const StrokeLinecap aStrokeLinecap = StrokeLinecap_notset) { maStrokeLinecap = aStrokeLinecap; }
+
+ /// StrokeLinejoin content
+ StrokeLinejoin getStrokeLinejoin() const;
+ void setStrokeLinejoin(const StrokeLinejoin aStrokeLinejoin = StrokeLinejoin_notset) { maStrokeLinejoin = aStrokeLinejoin; }
+
+ /// StrokeMiterLimit content
+ const SvgNumber getStrokeMiterLimit() const;
+ void setStrokeMiterLimit(const SvgNumber& rStrokeMiterLimit = SvgNumber()) { maStrokeMiterLimit = rStrokeMiterLimit; }
+
+ /// StrokeOpacity content
+ const SvgNumber getStrokeOpacity() const;
+ void setStrokeOpacity(const SvgNumber& rStrokeOpacity = SvgNumber()) { maStrokeOpacity = rStrokeOpacity; }
+
+ /// Font content
+ const SvgStringVector& getFontFamily() const;
+ void setFontFamily(const SvgStringVector& rSvgStringVector = SvgStringVector()) { maFontFamily = rSvgStringVector; }
+
+ /// FontSize content
+ const SvgNumber getFontSize() const;
+ void setFontSize(const SvgNumber& rFontSize = SvgNumber()) { maFontSize = rFontSize; }
+
+ /// FontStretch content
+ FontStretch getFontStretch() const;
+ void setFontStretch(const FontStretch aFontStretch = FontStretch_notset) { maFontStretch = aFontStretch; }
+
+ /// FontStyle content
+ FontStyle getFontStyle() const;
+ void setFontStyle(const FontStyle aFontStyle = FontStyle_notset) { maFontStyle = aFontStyle; }
+
+ /// FontVariant content
+ FontVariant getFontVariant() const;
+ void setFontVariant(const FontVariant aFontVariant = FontVariant_notset) { maFontVariant = aFontVariant; }
+
+ /// FontWeight content
+ FontWeight getFontWeight() const;
+ void setFontWeight(const FontWeight aFontWeight = FontWeight_notset) { maFontWeight = aFontWeight; }
+
+ /// TextAlign content
+ TextAlign getTextAlign() const;
+ void setTextAlign(const TextAlign aTextAlign = TextAlign_notset) { maTextAlign = aTextAlign; }
+
+ /// TextDecoration content
+ const SvgStyleAttributes* getTextDecorationDefiningSvgStyleAttributes() const;
+ TextDecoration getTextDecoration() const;
+ void setTextDecoration(const TextDecoration aTextDecoration = TextDecoration_notset) { maTextDecoration = aTextDecoration; }
+
+ /// TextAnchor content
+ TextAnchor getTextAnchor() const;
+ void setTextAnchor(const TextAnchor aTextAnchor = TextAnchor_notset) { maTextAnchor = aTextAnchor; }
+
+ /// Color content
+ const basegfx::BColor* getColor() const;
+ void setColor(const SvgPaint& rColor) { maColor = rColor; }
+
+ /// Opacity content
+ const SvgNumber getOpacity() const { return maOpacity; }
+ void setOpacity(const SvgNumber& rOpacity = SvgNumber()) { maOpacity = rOpacity; }
+
+ // ClipPathXLink content
+ const rtl::OUString getClipPathXLink() const { return maClipPathXLink; }
+ void setClipPathXLink(const rtl::OUString& rNew) { maClipPathXLink = rNew; }
+
+ // MaskXLink content
+ const rtl::OUString getMaskXLink() const { return maMaskXLink; }
+ void setMaskXLink(const rtl::OUString& rNew) { maMaskXLink = rNew; }
+
+ // MarkerStartXLink content
+ const rtl::OUString getMarkerStartXLink() const;
+ const SvgMarkerNode* accessMarkerStartXLink() const;
+ void setMarkerStartXLink(const rtl::OUString& rNew) { maMarkerStartXLink = rNew; }
+
+ // MarkerMidXLink content
+ const rtl::OUString getMarkerMidXLink() const;
+ const SvgMarkerNode* accessMarkerMidXLink() const;
+ void setMarkerMidXLink(const rtl::OUString& rNew) { maMarkerMidXLink = rNew; }
+
+ // MarkerEndXLink content
+ const rtl::OUString getMarkerEndXLink() const;
+ const SvgMarkerNode* accessMarkerEndXLink() const;
+ void setMarkerEndXLink(const rtl::OUString& rNew) { maMarkerEndXLink = rNew; }
+
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGSTYLEATTRIBUTES_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgstylenode.hxx b/svgio/inc/svgio/svgreader/svgstylenode.hxx
new file mode 100644
index 000000000000..37a7ef7d8eb3
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgstylenode.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGSTYLENODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGSTYLENODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgStyleNode : public SvgNode
+ {
+ private:
+ /// use styles
+ std::vector< SvgStyleAttributes* > maSvgStyleAttributes;
+
+ /// bitfield
+ bool mbTextCss : 1; // true == type is 'text/css'
+
+ public:
+ SvgStyleNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgStyleNode();
+
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ void addCssStyleSheet(const rtl::OUString& aContent);
+
+ /// textCss access
+ bool isTextCss() const { return mbTextCss; }
+ void setTextCss(bool bNew) { mbTextCss = bNew; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGSTYLENODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgsvgnode.hxx b/svgio/inc/svgio/svgreader/svgsvgnode.hxx
new file mode 100644
index 000000000000..0da68741b636
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgsvgnode.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGSVGNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGSVGNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgSvgNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ basegfx::B2DRange* mpViewBox;
+ SvgAspectRatio maSvgAspectRatio;
+ SvgNumber maX;
+ SvgNumber maY;
+ SvgNumber maWidth;
+ SvgNumber maHeight;
+ SvgNumber maVersion;
+
+ public:
+ SvgSvgNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgSvgNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const;
+
+ /// InfoProvider support for % values
+ virtual const basegfx::B2DRange* getCurrentViewPort() const;
+
+ /// viewBox content
+ const basegfx::B2DRange* getViewBox() const { return mpViewBox; }
+ void setViewBox(const basegfx::B2DRange* pViewBox = 0) { if(mpViewBox) delete mpViewBox; mpViewBox = 0; if(pViewBox) mpViewBox = new basegfx::B2DRange(*pViewBox); }
+
+ /// SvgAspectRatio content
+ const SvgAspectRatio& getSvgAspectRatio() const { return maSvgAspectRatio; }
+ void setSvgAspectRatio(const SvgAspectRatio& rSvgAspectRatio = SvgAspectRatio()) { maSvgAspectRatio = rSvgAspectRatio; }
+
+ /// x content
+ const SvgNumber& getX() const { return maX; }
+ void setX(const SvgNumber& rX = SvgNumber()) { maX = rX; }
+
+ /// y content
+ const SvgNumber& getY() const { return maY; }
+ void setY(const SvgNumber& rY = SvgNumber()) { maY = rY; }
+
+ /// width content
+ const SvgNumber& getWidth() const { return maWidth; }
+ void setWidth(const SvgNumber& rWidth = SvgNumber()) { maWidth = rWidth; }
+
+ /// height content
+ const SvgNumber& getHeight() const { return maHeight; }
+ void setHeight(const SvgNumber& rHeight = SvgNumber()) { maHeight = rHeight; }
+
+ /// version content
+ const SvgNumber& getVersion() const { return maVersion; }
+ void setVersion(const SvgNumber& rVersion = SvgNumber()) { maVersion = rVersion; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGSVGNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgsymbolnode.hxx b/svgio/inc/svgio/svgreader/svgsymbolnode.hxx
new file mode 100644
index 000000000000..b4fd0428c7d3
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgsymbolnode.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGSYMBOLNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGSYMBOLNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgSymbolNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ basegfx::B2DRange* mpViewBox;
+ SvgAspectRatio maSvgAspectRatio;
+
+ public:
+ SvgSymbolNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgSymbolNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+
+ /// viewBox content
+ const basegfx::B2DRange* getViewBox() const { return mpViewBox; }
+ void setViewBox(const basegfx::B2DRange* pViewBox = 0) { if(mpViewBox) delete mpViewBox; mpViewBox = 0; if(pViewBox) mpViewBox = new basegfx::B2DRange(*pViewBox); }
+
+ /// SvgAspectRatio content
+ const SvgAspectRatio& getSvgAspectRatio() const { return maSvgAspectRatio; }
+ void setSvgAspectRatio(const SvgAspectRatio& rSvgAspectRatio = SvgAspectRatio()) { maSvgAspectRatio = rSvgAspectRatio; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGSYMBOLNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgtextnode.hxx b/svgio/inc/svgio/svgreader/svgtextnode.hxx
new file mode 100644
index 000000000000..59ff27eac756
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgtextnode.hxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGTEXTNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGTEXTNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+#include <svgio/svgreader/svgcharacternode.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgTextNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ basegfx::B2DHomMatrix* mpaTransform;
+ SvgTextPositions maSvgTextPositions;
+
+ /// local helpers
+ void DecomposeChild(
+ const SvgNode& rCandidate,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ SvgTextPosition& rSvgTextPosition) const;
+ void addTextPrimitives(
+ const SvgNode& rCandidate,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ drawinglayer::primitive2d::Primitive2DSequence& rSource) const;
+
+ public:
+ SvgTextNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgTextNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const;
+
+ /// transform content, set if found in current context
+ const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; }
+ void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); }
+
+ /// access to SvgTextPositions
+ const SvgTextPositions& getSvgTextPositions() const { return maSvgTextPositions; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGTEXTNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgtextpathnode.hxx b/svgio/inc/svgio/svgreader/svgtextpathnode.hxx
new file mode 100644
index 000000000000..8c9a1d13281f
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgtextpathnode.hxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGTEXTPATHNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGTEXTPATHNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+#include <svgio/svgreader/svgpathnode.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgTextPathNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// link to path content. If maXLink
+ /// is set, the node can be fetched on demand
+ rtl::OUString maXLink;
+
+ /// variable scan values, dependent of given XAttributeList
+ SvgNumber maStartOffset;
+
+ /// bitfield
+ bool mbMethod : 1; // true = align, false = stretch
+ bool mbSpacing : 1; // true = auto, false = exact
+
+ public:
+ SvgTextPathNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgTextPathNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ void decomposePathNode(
+ const drawinglayer::primitive2d::Primitive2DSequence& rPathContent,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const basegfx::B2DPoint& rTextStart) const;
+ bool isValid() const;
+
+ /// StartOffset content
+ const SvgNumber& getStartOffset() const { return maStartOffset; }
+ void setStartOffset(const SvgNumber& rStartOffset = SvgNumber()) { maStartOffset = rStartOffset; }
+
+ /// Method content
+ bool getMethod() const { return mbMethod; }
+ void setMethod(bool bNew) { mbMethod = bNew; }
+
+ /// Spacing content
+ bool getSpacing() const { return mbSpacing; }
+ void setSpacing(bool bNew) { mbSpacing = bNew; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGTEXTPATHNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgtoken.hxx b/svgio/inc/svgio/svgreader/svgtoken.hxx
new file mode 100644
index 000000000000..c0c68fbef3ba
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgtoken.hxx
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGTOKEN_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGTOKEN_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <rtl/ustring.hxx>
+#include <boost/unordered_map.hpp>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ // SVG token mapper with hashing
+ enum SVGToken
+ {
+ SVGTokenUnknown = 0,
+
+ // diverse attribute tokens
+ SVGTokenWidth,
+ SVGTokenHeight,
+ SVGTokenViewBox,
+ SVGTokenTransform,
+ SVGTokenStyle,
+ SVGTokenD,
+ SVGTokenX,
+ SVGTokenY,
+ SVGTokenXmlns,
+ SVGTokenVersion,
+ SVGTokenId,
+ SVGTokenRx,
+ SVGTokenRy,
+ SVGTokenPoints,
+ SVGTokenDx,
+ SVGTokenDy,
+ SVGTokenRotate,
+ SVGTokenTextLength,
+ SVGTokenLengthAdjust,
+ SVGTokenFont,
+ SVGTokenFontFamily,
+ SVGTokenFontSize,
+ SVGTokenFontSizeAdjust,
+ SVGTokenFontStretch,
+ SVGTokenFontStyle,
+ SVGTokenFontVariant,
+ SVGTokenFontWeight,
+ SVGTokenDirection,
+ SVGTokenLetterSpacing,
+ SVGTokenTextDecoration,
+ SVGTokenUnicodeBidi,
+ SVGTokenWordSpacing,
+ SVGTokenCharacter, // not in the hash, just for simple text handling in SvgCharacterNode
+ SVGTokenTspan,
+ SVGTokenTref,
+ SVGTokenTextPath,
+ SVGTokenStartOffset,
+ SVGTokenMethod,
+ SVGTokenSpacing,
+ SVGTokenTextAlign,
+ SVGTokenPathLength,
+ SVGTokenType,
+ SVGTokenClass,
+ SVGTokenTextAnchor,
+ SVGTokenXmlSpace,
+ SVGTokenColor,
+ SVGTokenClipPathNode,
+ SVGTokenClipPathProperty,
+ SVGTokenMask,
+ SVGTokenClipPathUnits,
+ SVGTokenMaskUnits,
+ SVGTokenMaskContentUnits,
+ SVGTokenClipRule,
+ SVGTokenMarker,
+ SVGTokenMarkerStart,
+ SVGTokenMarkerMid,
+ SVGTokenMarkerEnd,
+ SVGTokenRefX,
+ SVGTokenRefY,
+ SVGTokenMarkerUnits,
+ SVGTokenMarkerWidth,
+ SVGTokenMarkerHeight,
+ SVGTokenOrient,
+ SVGTokenPattern,
+ SVGTokenPatternUnits,
+ SVGTokenPatternContentUnits,
+ SVGTokenPatternTransform,
+ SVGTokenOpacity,
+
+ // AspectRatio and params
+ SVGTokenPreserveAspectRatio,
+ SVGTokenDefer,
+ SVGTokenNone,
+ SVGTokenXMinYMin,
+ SVGTokenXMidYMin,
+ SVGTokenXMaxYMin,
+ SVGTokenXMinYMid,
+ SVGTokenXMidYMid,
+ SVGTokenXMaxYMid,
+ SVGTokenXMinYMax,
+ SVGTokenXMidYMax,
+ SVGTokenXMaxYMax,
+ SVGTokenMeet,
+ SVGTokenSlice,
+
+ // structural elements
+ SVGTokenDefs,
+ SVGTokenG,
+ SVGTokenSvg,
+ SVGTokenSymbol,
+ SVGTokenUse,
+
+ // shape elements
+ SVGTokenCircle,
+ SVGTokenEllipse,
+ SVGTokenLine,
+ SVGTokenPath,
+ SVGTokenPolygon,
+ SVGTokenPolyline,
+ SVGTokenRect,
+ SVGTokenImage,
+
+ // gradient elements and tokens
+ SVGTokenLinearGradient,
+ SVGTokenRadialGradient,
+ SVGTokenStop,
+ SVGTokenOffset,
+ SVGTokenX1,
+ SVGTokenY1,
+ SVGTokenX2,
+ SVGTokenY2,
+ SVGTokenCx,
+ SVGTokenCy,
+ SVGTokenFx,
+ SVGTokenFy,
+ SVGTokenR,
+ SVGTokenGradientUnits,
+ SVGTokenGradientTransform,
+ SVGTokenSpreadMethod,
+ SVGTokenXlinkHref,
+ SVGTokenStopColor,
+ SVGTokenStopOpacity,
+
+ // fill tokens
+ SVGTokenFill,
+ SVGTokenFillOpacity,
+ SVGTokenFillRule,
+
+ // stroke tokens
+ SVGTokenStroke,
+ SVGTokenStrokeDasharray,
+ SVGTokenStrokeDashoffset,
+ SVGTokenStrokeLinecap,
+ SVGTokenStrokeLinejoin,
+ SVGTokenStrokeMiterlimit,
+ SVGTokenStrokeOpacity,
+ SVGTokenStrokeWidth,
+
+ // text tokens
+ SVGTokenText,
+
+ SVGTokenLast
+ };
+
+ SVGToken StrToSVGToken(const rtl::OUString& rStr);
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGTOKEN_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgtools.hxx b/svgio/inc/svgio/svgreader/svgtools.hxx
new file mode 100644
index 000000000000..5f9645e6d0cf
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgtools.hxx
@@ -0,0 +1,229 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGTOOLS_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGTOOLS_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <drawinglayer/primitive2d/baseprimitive2d.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <svgio/svgreader/svgpaint.hxx>
+#include <vector>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+#ifdef DBG_UTIL
+ // error helper
+ void myAssert(const rtl::OUString& rMessage);
+#endif
+
+ // common non-token strings
+ struct commonStrings
+ {
+ static const rtl::OUString aStrUserSpaceOnUse;
+ static const rtl::OUString aStrObjectBoundingBox;
+ static const rtl::OUString aStrNonzero;
+ static const rtl::OUString aStrEvenOdd;
+ };
+
+ enum SvgUnits
+ {
+ userSpaceOnUse,
+ objectBoundingBox
+ };
+
+ enum NumberType
+ {
+ xcoordinate,
+ ycoordinate,
+ length
+ };
+
+ class InfoProvider
+ {
+ public:
+ virtual ~InfoProvider() {}
+ virtual const basegfx::B2DRange* getCurrentViewPort() const = 0;
+ virtual double getCurrentFontSize() const = 0;
+ virtual double getCurrentXHeight() const = 0;
+ };
+
+ enum SvgUnit
+ {
+ Unit_em = 0, // relative to current font size
+ Unit_ex, // relative to current x-height
+
+ Unit_px, // 'user unit'
+ Unit_pt, // points, 1.25 px
+ Unit_pc, // 15.0 px
+ Unit_cm, // 35.43307 px
+ Unit_mm, // 3.543307 px
+ Unit_in, // 90 px
+
+ Unit_percent // relative to range
+ };
+
+ class SvgNumber
+ {
+ private:
+ double mfNumber;
+ SvgUnit meUnit;
+
+ /// bitfield
+ bool mbSet : 1;
+
+ public:
+ SvgNumber()
+ : mfNumber(0.0),
+ meUnit(Unit_px),
+ mbSet(false)
+ {
+ }
+
+ SvgNumber(double fNum, SvgUnit aSvgUnit = Unit_px, bool bSet = true)
+ : mfNumber(fNum),
+ meUnit(aSvgUnit),
+ mbSet(bSet)
+ {
+ }
+
+ double getNumber() const
+ {
+ return mfNumber;
+ }
+
+ SvgUnit getUnit() const
+ {
+ return meUnit;
+ }
+
+ bool isSet() const
+ {
+ return mbSet;
+ }
+
+ bool isPositive() const;
+
+ double solve(const InfoProvider& rInfoProvider, NumberType aNumberType = length) const;
+ };
+
+ typedef ::std::vector< SvgNumber > SvgNumberVector;
+
+ enum SvgAlign
+ {
+ Align_none,
+ Align_xMinYMin,
+ Align_xMidYMin,
+ Align_xMaxYMin,
+ Align_xMinYMid,
+ Align_xMidYMid, // default
+ Align_xMaxYMid,
+ Align_xMinYMax,
+ Align_xMidYMax,
+ Align_xMaxYMax
+ };
+
+ class SvgAspectRatio
+ {
+ private:
+ SvgAlign maSvgAlign;
+
+ /// bitfield
+ bool mbDefer : 1; // default is false
+ bool mbMeetOrSlice : 1; // true = meet (default), false = slice
+ bool mbSet : 1;
+
+ public:
+ SvgAspectRatio()
+ : maSvgAlign(Align_xMidYMid),
+ mbDefer(false),
+ mbMeetOrSlice(true),
+ mbSet(false)
+ {
+ }
+
+ SvgAspectRatio(SvgAlign aSvgAlign, bool bDefer, bool bMeetOrSlice)
+ : maSvgAlign(aSvgAlign),
+ mbDefer(bDefer),
+ mbMeetOrSlice(bMeetOrSlice),
+ mbSet(true)
+ {
+ }
+
+ /// data read access
+ SvgAlign getSvgAlign() const { return maSvgAlign; }
+ bool isDefer() const { return mbDefer; }
+ bool isMeetOrSlice() const { return mbMeetOrSlice; }
+ bool isSet() const { return mbSet; }
+
+ /// tooling
+ static basegfx::B2DHomMatrix createLinearMapping(const basegfx::B2DRange& rTarget, const basegfx::B2DRange& rSource);
+ basegfx::B2DHomMatrix createMapping(const basegfx::B2DRange& rTarget, const basegfx::B2DRange& rSource) const;
+ };
+
+ void skip_char(const rtl::OUString& rCandidate, const sal_Unicode& rChar, sal_Int32& nPos, const sal_Int32 nLen);
+ void skip_char(const rtl::OUString& rCandidate, const sal_Unicode& rCharA, const sal_Unicode& rCharB, sal_Int32& nPos, const sal_Int32 nLen);
+ void copySign(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen);
+ void copyNumber(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen);
+ void copyHex(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen);
+ void copyString(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen);
+ void copyToLimiter(const rtl::OUString& rCandidate, const sal_Unicode& rLimiter, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen);
+ bool readNumber(const rtl::OUString& rCandidate, sal_Int32& nPos, double& fNum, const sal_Int32 nLen);
+ SvgUnit readUnit(const rtl::OUString& rCandidate, sal_Int32& nPos, const sal_Int32 nLen);
+ bool readNumberAndUnit(const rtl::OUString& rCandidate, sal_Int32& nPos, SvgNumber& aNum, const sal_Int32 nLen);
+ bool readAngle(const rtl::OUString& rCandidate, sal_Int32& nPos, double& fAngle, const sal_Int32 nLen);
+ sal_Int32 read_hex(const sal_Unicode& rChar);
+ bool match_colorKeyword(basegfx::BColor& rColor, const rtl::OUString& rName);
+ bool read_color(const rtl::OUString& rCandidate, basegfx::BColor& rColor);
+ basegfx::B2DRange readViewBox(const rtl::OUString& rCandidate, InfoProvider& rInfoProvider);
+ basegfx::B2DHomMatrix readTransform(const rtl::OUString& rCandidate, InfoProvider& rInfoProvider);
+ bool readSingleNumber(const rtl::OUString& rCandidate, SvgNumber& aNum);
+ bool readLocalUrl(const rtl::OUString& rCandidate, rtl::OUString& rURL);
+ bool readSvgPaint(const rtl::OUString& rCandidate, SvgPaint& rSvgPaint, rtl::OUString& rURL);
+
+ bool readSvgNumberVector(const rtl::OUString& rCandidate, SvgNumberVector& rSvgNumberVector);
+ ::std::vector< double > solveSvgNumberVector(const SvgNumberVector& rInput, const InfoProvider& rInfoProvider, NumberType aNumberType = length);
+
+ SvgAspectRatio readSvgAspectRatio(const rtl::OUString& rCandidate);
+
+ typedef ::std::vector< rtl::OUString > SvgStringVector;
+ bool readSvgStringVector(const rtl::OUString& rCandidate, SvgStringVector& rSvgStringVector);
+
+ void readImageLink(const rtl::OUString& rCandidate, rtl::OUString& rXLink, rtl::OUString& rUrl, rtl::OUString& rMimeType, rtl::OUString& rData);
+
+ rtl::OUString convert(const rtl::OUString& rCandidate, const sal_Unicode& rPattern, const sal_Unicode& rNew, bool bRemove);
+ rtl::OUString consolidateContiguosSpace(const rtl::OUString& rCandidate);
+ rtl::OUString whiteSpaceHandlingDefault(const rtl::OUString& rCandidate);
+ rtl::OUString whiteSpaceHandlingPreserve(const rtl::OUString& rCandidate);
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGTOOLS_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgtrefnode.hxx b/svgio/inc/svgio/svgreader/svgtrefnode.hxx
new file mode 100644
index 000000000000..782faa17d089
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgtrefnode.hxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGTREFNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGTREFNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+#include <svgio/svgreader/svgtextnode.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgTrefNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// link to text content. If maXLink
+ /// is set, the node can be fetched on demand
+ rtl::OUString maXLink;
+
+ public:
+ SvgTrefNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgTrefNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+
+ /// access to referenced SvgTextNode
+ const SvgTextNode* getReferencedSvgTextNode() const;
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGTREFNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgtspannode.hxx b/svgio/inc/svgio/svgreader/svgtspannode.hxx
new file mode 100644
index 000000000000..24bf96812fb7
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgtspannode.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_SVGTSPANNODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_SVGTSPANNODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgcharacternode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+#include <svgio/svgreader/svgtools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgTspanNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ SvgTextPositions maSvgTextPositions;
+
+ public:
+ SvgTspanNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgTspanNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+
+ /// access to SvgTextPositions
+ const SvgTextPositions& getSvgTextPositions() const { return maSvgTextPositions; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_SVGTSPANNODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgio/svgreader/svgusenode.hxx b/svgio/inc/svgio/svgreader/svgusenode.hxx
new file mode 100644
index 000000000000..d7613e68092f
--- /dev/null
+++ b/svgio/inc/svgio/svgreader/svgusenode.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVGIO_SVGREADER_USENODE_HXX
+#define INCLUDED_SVGIO_SVGREADER_USENODE_HXX
+
+#include <svgio/svgiodllapi.h>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class SvgUseNode : public SvgNode
+ {
+ private:
+ /// use styles
+ SvgStyleAttributes maSvgStyleAttributes;
+
+ /// variable scan values, dependent of given XAttributeList
+ basegfx::B2DHomMatrix* mpaTransform;
+ SvgNumber maX;
+ SvgNumber maY;
+ SvgNumber maWidth;
+ SvgNumber maHeight;
+
+ /// link to content. If maXLink is set, the node can be fetched
+ // on demand
+ rtl::OUString maXLink;
+
+ public:
+ SvgUseNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent);
+ virtual ~SvgUseNode();
+
+ virtual const SvgStyleAttributes* getSvgStyleAttributes() const;
+ virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent);
+ virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const;
+
+ /// transform content
+ const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; }
+ void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); }
+
+ /// x content
+ const SvgNumber& getX() const { return maX; }
+ void setX(const SvgNumber& rX = SvgNumber()) { maX = rX; }
+
+ /// y content
+ const SvgNumber& getY() const { return maY; }
+ void setY(const SvgNumber& rY = SvgNumber()) { maY = rY; }
+
+ /// width content
+ const SvgNumber& getWidth() const { return maWidth; }
+ void setWidth(const SvgNumber& rWidth = SvgNumber()) { maWidth = rWidth; }
+
+ /// height content
+ const SvgNumber& getHeight() const { return maHeight; }
+ void setHeight(const SvgNumber& rHeight = SvgNumber()) { maHeight = rHeight; }
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif //INCLUDED_SVGIO_SVGREADER_USENODE_HXX
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/prj/build.lst b/svgio/prj/build.lst
new file mode 100644
index 000000000000..ff858ab1ddda
--- /dev/null
+++ b/svgio/prj/build.lst
@@ -0,0 +1,2 @@
+dl svgio : sal basegfx drawinglayer cppuhelper cppu svtools NULL
+dl svgio\prj nmake - all svgio_prj NULL
diff --git a/svgio/prj/d.lst b/svgio/prj/d.lst
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/svgio/prj/d.lst
diff --git a/svgio/prj/makefile.mk b/svgio/prj/makefile.mk
new file mode 100644
index 000000000000..f3e47cb7f1a3
--- /dev/null
+++ b/svgio/prj/makefile.mk
@@ -0,0 +1,33 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+
+
+PRJ=..
+TARGET=prj
+
+.INCLUDE : settings.mk
+
+.IF "$(VERBOSE)"!=""
+VERBOSEFLAG :=
+.ELSE
+VERBOSEFLAG := -s
+.ENDIF
+
+all:
+ cd $(PRJ) && $(GNUMAKE) $(VERBOSEFLAG) -r -j$(MAXPROCESS) $(gb_MAKETARGET) && $(GNUMAKE) $(VERBOSEFLAG) -r deliverlog
diff --git a/svgio/source/svgreader/svgcharacternode.cxx b/svgio/source/svgreader/svgcharacternode.cxx
new file mode 100644
index 000000000000..552db36ea939
--- /dev/null
+++ b/svgio/source/svgreader/svgcharacternode.cxx
@@ -0,0 +1,740 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgcharacternode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+#include <drawinglayer/attribute/fontattribute.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <drawinglayer/primitive2d/textbreakuphelper.hxx>
+#include <drawinglayer/primitive2d/groupprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgTextPositions::SvgTextPositions()
+ : maX(),
+ maY(),
+ maDx(),
+ maDy(),
+ maRotate(),
+ maTextLength(),
+ mbLengthAdjust(true)
+ {
+ }
+
+ void SvgTextPositions::parseTextPositionAttributes(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenX:
+ {
+ if(aContent.getLength())
+ {
+ SvgNumberVector aVector;
+
+ if(readSvgNumberVector(aContent, aVector))
+ {
+ setX(aVector);
+ }
+ }
+ break;
+ }
+ case SVGTokenY:
+ {
+ if(aContent.getLength())
+ {
+ SvgNumberVector aVector;
+
+ if(readSvgNumberVector(aContent, aVector))
+ {
+ setY(aVector);
+ }
+ }
+ break;
+ }
+ case SVGTokenDx:
+ {
+ if(aContent.getLength())
+ {
+ SvgNumberVector aVector;
+
+ if(readSvgNumberVector(aContent, aVector))
+ {
+ setDx(aVector);
+ }
+ }
+ break;
+ }
+ case SVGTokenDy:
+ {
+ if(aContent.getLength())
+ {
+ SvgNumberVector aVector;
+
+ if(readSvgNumberVector(aContent, aVector))
+ {
+ setDy(aVector);
+ }
+ }
+ break;
+ }
+ case SVGTokenRotate:
+ {
+ if(aContent.getLength())
+ {
+ SvgNumberVector aVector;
+
+ if(readSvgNumberVector(aContent, aVector))
+ {
+ setRotate(aVector);
+ }
+ }
+ break;
+ }
+ case SVGTokenTextLength:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setTextLength(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenLengthAdjust:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrSpacing(rtl::OUString::createFromAscii("spacing"));
+ static rtl::OUString aStrSpacingAndGlyphs(rtl::OUString::createFromAscii("spacingAndGlyphs"));
+
+ if(aContent.match(aStrSpacing))
+ {
+ setLengthAdjust(true);
+ }
+ else if(aContent.match(aStrSpacingAndGlyphs))
+ {
+ setLengthAdjust(false);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class localTextBreakupHelper : public drawinglayer::primitive2d::TextBreakupHelper
+ {
+ private:
+ SvgTextPosition& mrSvgTextPosition;
+
+ protected:
+ /// allow user callback to allow changes to the new TextTransformation. Default
+ /// does nothing.
+ virtual bool allowChange(sal_uInt32 nCount, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 nIndex, sal_uInt32 nLength);
+
+ public:
+ localTextBreakupHelper(
+ const drawinglayer::primitive2d::TextSimplePortionPrimitive2D& rSource,
+ SvgTextPosition& rSvgTextPosition)
+ : drawinglayer::primitive2d::TextBreakupHelper(rSource),
+ mrSvgTextPosition(rSvgTextPosition)
+ {
+ }
+ };
+
+ bool localTextBreakupHelper::allowChange(sal_uInt32 /*nCount*/, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 /*nIndex*/, sal_uInt32 /*nLength*/)
+ {
+ const double fRotation(mrSvgTextPosition.consumeRotation());
+
+ if(0.0 != fRotation)
+ {
+ const basegfx::B2DPoint aBasePoint(rNewTransform * basegfx::B2DPoint(0.0, 0.0));
+
+ rNewTransform.translate(-aBasePoint.getX(), -aBasePoint.getY());
+ rNewTransform.rotate(fRotation);
+ rNewTransform.translate(aBasePoint.getX(), aBasePoint.getY());
+ }
+
+ return true;
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgCharacterNode::SvgCharacterNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent,
+ const rtl::OUString& rText)
+ : SvgNode(SVGTokenCharacter, rDocument, pParent),
+ maText(rText)
+ {
+ }
+
+ SvgCharacterNode::~SvgCharacterNode()
+ {
+ }
+
+ const SvgStyleAttributes* SvgCharacterNode::getSvgStyleAttributes() const
+ {
+ // no own style, use parent's
+ if(getParent())
+ {
+ return getParent()->getSvgStyleAttributes();
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ drawinglayer::primitive2d::TextSimplePortionPrimitive2D* SvgCharacterNode::createSimpleTextPrimitive(
+ SvgTextPosition& rSvgTextPosition,
+ const SvgStyleAttributes& rSvgStyleAttributes) const
+ {
+ // prepare retval, index and length
+ drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pRetval = 0;
+ sal_uInt32 nIndex(0);
+ sal_uInt32 nLength(getText().getLength());
+
+ if(nLength)
+ {
+ // prepare FontAttribute
+ const rtl::OUString aFontFamily = rSvgStyleAttributes.getFontFamily().empty() ?
+ rtl::OUString(rtl::OUString::createFromAscii("Times New Roman")) :
+ rSvgStyleAttributes.getFontFamily()[0];
+ const ::FontWeight nFontWeight(getVclFontWeight(rSvgStyleAttributes.getFontWeight()));
+ bool bSymbol(false);
+ bool bVertical(false);
+ bool bItalic(FontStyle_italic == rSvgStyleAttributes.getFontStyle() || FontStyle_oblique == rSvgStyleAttributes.getFontStyle());
+ bool bMonospaced(false);
+ bool bOutline(false);
+ bool bRTL(false);
+ bool bBiDiStrong(false);
+
+ const drawinglayer::attribute::FontAttribute aFontAttribute(
+ aFontFamily,
+ rtl::OUString(),
+ nFontWeight,
+ bSymbol,
+ bVertical,
+ bItalic,
+ bMonospaced,
+ bOutline,
+ bRTL,
+ bBiDiStrong);
+
+ // prepare FontSize
+ double fFontWidth(rSvgStyleAttributes.getFontSize().solve(*this, length));
+ double fFontHeight(fFontWidth);
+
+ // prepare locale
+ ::com::sun::star::lang::Locale aLocale;
+
+ // prepare TextLayouterDevice
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
+ aTextLayouterDevice.setFontAttribute(aFontAttribute, fFontWidth, fFontHeight, aLocale);
+
+ // prepare TextArray
+ ::std::vector< double > aTextArray(rSvgTextPosition.getX());
+
+ if(!aTextArray.empty() && aTextArray.size() < nLength)
+ {
+ const sal_uInt32 nArray(aTextArray.size());
+
+ if(nArray < nLength)
+ {
+ double fStartX(0.0);
+
+ if(rSvgTextPosition.getParent() && rSvgTextPosition.getParent()->getAbsoluteX())
+ {
+ fStartX = rSvgTextPosition.getParent()->getPosition().getX();
+ }
+ else
+ {
+ fStartX = aTextArray[nArray - 1];
+ }
+
+ ::std::vector< double > aExtendArray(aTextLayouterDevice.getTextArray(getText(), nArray, nLength - nArray));
+ aTextArray.reserve(nLength);
+
+ for(sal_uInt32 a(0); a < aExtendArray.size(); a++)
+ {
+ aTextArray.push_back(aExtendArray[a] + fStartX);
+ }
+ }
+ }
+
+ // get current TextPosition and TextWidth in units
+ basegfx::B2DPoint aPosition(rSvgTextPosition.getPosition());
+ double fTextWidth(aTextLayouterDevice.getTextWidth(getText(), nIndex, nLength));
+
+ // check for user-given TextLength
+ if(0.0 != rSvgTextPosition.getTextLength()
+ && !basegfx::fTools::equal(fTextWidth, rSvgTextPosition.getTextLength()))
+ {
+ const double fFactor(rSvgTextPosition.getTextLength() / fTextWidth);
+
+ if(rSvgTextPosition.getLengthAdjust())
+ {
+ // spacing, need to create and expand TextArray
+ if(aTextArray.empty())
+ {
+ aTextArray = aTextLayouterDevice.getTextArray(getText(), nIndex, nLength);
+ }
+
+ for(sal_uInt32 a(0); a < aTextArray.size(); a++)
+ {
+ aTextArray[a] *= fFactor;
+ }
+ }
+ else
+ {
+ // spacing and glyphs, just apply to FontWidth
+ fFontWidth *= fFactor;
+ }
+
+ fTextWidth = rSvgTextPosition.getTextLength();
+ }
+
+ // get TextAlign
+ TextAlign aTextAlign(rSvgStyleAttributes.getTextAlign());
+
+ // map TextAnchor to TextAlign, there seems not to be a difference
+ if(TextAnchor_notset != rSvgStyleAttributes.getTextAnchor())
+ {
+ switch(rSvgStyleAttributes.getTextAnchor())
+ {
+ case TextAnchor_start:
+ {
+ aTextAlign = TextAlign_left;
+ break;
+ }
+ case TextAnchor_middle:
+ {
+ aTextAlign = TextAlign_center;
+ break;
+ }
+ case TextAnchor_end:
+ {
+ aTextAlign = TextAlign_right;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ // apply TextAlign
+ switch(aTextAlign)
+ {
+ case TextAlign_right:
+ {
+ aPosition.setX(aPosition.getX() - fTextWidth);
+ break;
+ }
+ case TextAlign_center:
+ {
+ aPosition.setX(aPosition.getX() - (fTextWidth * 0.5));
+ break;
+ }
+ case TextAlign_notset:
+ case TextAlign_left:
+ case TextAlign_justify:
+ {
+ // TextAlign_notset, TextAlign_left: nothing to do
+ // TextAlign_justify is not clear currently; handle as TextAlign_left
+ break;
+ }
+ }
+
+ // get fill color
+ const basegfx::BColor aFill(rSvgStyleAttributes.getFill()
+ ? *rSvgStyleAttributes.getFill()
+ : basegfx::BColor(0.0, 0.0, 0.0));
+
+ // prepare TextTransformation
+ basegfx::B2DHomMatrix aTextTransform;
+
+ aTextTransform.scale(fFontWidth, fFontHeight);
+ aTextTransform.translate(aPosition.getX(), aPosition.getY());
+
+ // check TextDecoration and if TextDecoratedPortionPrimitive2D is needed
+ const TextDecoration aDeco(rSvgStyleAttributes.getTextDecoration());
+
+ if(TextDecoration_underline == aDeco
+ || TextDecoration_overline == aDeco
+ || TextDecoration_line_through == aDeco)
+ {
+ // get the fill for decroation as described by SVG. We cannot
+ // have different stroke colors/definitions for those, though
+ const SvgStyleAttributes* pDecoDef = rSvgStyleAttributes.getTextDecorationDefiningSvgStyleAttributes();
+ const basegfx::BColor aDecoColor(pDecoDef && pDecoDef->getFill() ? *pDecoDef->getFill() : aFill);
+
+ // create decorated text primitive
+ pRetval = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
+ aTextTransform,
+ getText(),
+ nIndex,
+ nLength,
+ aTextArray,
+ aFontAttribute,
+ aLocale,
+ aFill,
+
+ // extra props for decorated
+ aDecoColor,
+ aDecoColor,
+ TextDecoration_overline == aDeco ? drawinglayer::primitive2d::TEXT_LINE_SINGLE : drawinglayer::primitive2d::TEXT_LINE_NONE,
+ TextDecoration_underline == aDeco ? drawinglayer::primitive2d::TEXT_LINE_SINGLE : drawinglayer::primitive2d::TEXT_LINE_NONE,
+ false,
+ TextDecoration_line_through == aDeco ? drawinglayer::primitive2d::TEXT_STRIKEOUT_SINGLE : drawinglayer::primitive2d::TEXT_STRIKEOUT_NONE,
+ false,
+ drawinglayer::primitive2d::TEXT_EMPHASISMARK_NONE,
+ true,
+ false,
+ drawinglayer::primitive2d::TEXT_RELIEF_NONE,
+ false);
+ }
+ else
+ {
+ // create text primitive
+ pRetval = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
+ aTextTransform,
+ getText(),
+ nIndex,
+ nLength,
+ aTextArray,
+ aFontAttribute,
+ aLocale,
+ aFill);
+ }
+
+ // advance current TextPosition
+ rSvgTextPosition.setPosition(rSvgTextPosition.getPosition() + basegfx::B2DVector(fTextWidth, 0.0));
+ }
+
+ return pRetval;
+ }
+
+ void SvgCharacterNode::decomposeTextWithStyle(
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ SvgTextPosition& rSvgTextPosition,
+ const SvgStyleAttributes& rSvgStyleAttributes) const
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xRef(
+ createSimpleTextPrimitive(
+ rSvgTextPosition,
+ rSvgStyleAttributes));
+
+ if(xRef.is())
+ {
+ if(!rSvgTextPosition.isRotated())
+ {
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef);
+ }
+ else
+ {
+ // need to apply rotations to each character as given
+ const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pCandidate =
+ dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(xRef.get());
+
+ if(pCandidate)
+ {
+ const localTextBreakupHelper alocalTextBreakupHelper(*pCandidate, rSvgTextPosition);
+ const drawinglayer::primitive2d::Primitive2DSequence aResult(
+ alocalTextBreakupHelper.getResult(drawinglayer::primitive2d::BreakupUnit_character));
+
+ if(aResult.hasElements())
+ {
+ drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aResult);
+ }
+
+ // also consume for the implied single space
+ rSvgTextPosition.consumeRotation();
+ }
+ else
+ {
+ OSL_ENSURE(false, "Used primitive is not a text primitive (!)");
+ }
+ }
+ }
+ }
+
+ void SvgCharacterNode::whiteSpaceHandling()
+ {
+ if(XmlSpace_default == getXmlSpace())
+ {
+ maText = whiteSpaceHandlingDefault(maText);
+ }
+ else
+ {
+ maText = whiteSpaceHandlingPreserve(maText);
+ }
+ }
+
+ void SvgCharacterNode::addGap()
+ {
+ maText += rtl::OUString(sal_Unicode(' '));
+ }
+
+ void SvgCharacterNode::concatenate(const rtl::OUString& rText)
+ {
+ maText += rText;
+ }
+
+ void SvgCharacterNode::decomposeText(drawinglayer::primitive2d::Primitive2DSequence& rTarget, SvgTextPosition& rSvgTextPosition) const
+ {
+ if(getText().getLength())
+ {
+ const SvgStyleAttributes* pSvgStyleAttributes = getSvgStyleAttributes();
+
+ if(pSvgStyleAttributes)
+ {
+ decomposeTextWithStyle(rTarget, rSvgTextPosition, *pSvgStyleAttributes);
+ }
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgTextPosition::SvgTextPosition(
+ SvgTextPosition* pParent,
+ const InfoProvider& rInfoProvider,
+ const SvgTextPositions& rSvgTextPositions)
+ : mpParent(pParent),
+ maX(), // computed below
+ maY(), // computed below
+ maRotate(solveSvgNumberVector(rSvgTextPositions.getRotate(), rInfoProvider, length)),
+ mfTextLength(0.0),
+ maPosition(), // computed below
+ mnRotationIndex(0),
+ mbLengthAdjust(rSvgTextPositions.getLengthAdjust()),
+ mbAbsoluteX(false),
+ mbAbsoluteY(false)
+ {
+ // get TextLength if provided
+ if(rSvgTextPositions.getTextLength().isSet())
+ {
+ mfTextLength = rSvgTextPositions.getTextLength().solve(rInfoProvider, length);
+ }
+
+ // SVG does not really define in which units a ‘rotate’ for Text/TSpan is given,
+ // but it seems to be degrees. Convert here to radians
+ if(!maRotate.empty())
+ {
+ const double fFactor(F_PI / 180.0);
+
+ for(sal_uInt32 a(0); a < maRotate.size(); a++)
+ {
+ maRotate[a] *= fFactor;
+ }
+ }
+
+ // get text positions X
+ const sal_uInt32 nSizeX(rSvgTextPositions.getX().size());
+
+ if(nSizeX)
+ {
+ // we have absolute positions, get first one as current text position X
+ maPosition.setX(rSvgTextPositions.getX()[0].solve(rInfoProvider, xcoordinate));
+ mbAbsoluteX = true;
+
+ if(nSizeX > 1)
+ {
+ // fill deltas to maX
+ maX.reserve(nSizeX);
+
+ for(sal_uInt32 a(1); a < nSizeX; a++)
+ {
+ maX.push_back(rSvgTextPositions.getX()[a].solve(rInfoProvider, xcoordinate) - maPosition.getX());
+ }
+ }
+ }
+ else
+ {
+ // no absolute position, get from parent
+ if(pParent)
+ {
+ maPosition.setX(pParent->getPosition().getX());
+ }
+
+ const sal_uInt32 nSizeDx(rSvgTextPositions.getDx().size());
+
+ if(nSizeDx)
+ {
+ // relative positions given, translate position derived from parent
+ maPosition.setX(maPosition.getX() + rSvgTextPositions.getDx()[0].solve(rInfoProvider, xcoordinate));
+
+ if(nSizeDx > 1)
+ {
+ // fill deltas to maX
+ maX.reserve(nSizeDx);
+
+ for(sal_uInt32 a(1); a < nSizeDx; a++)
+ {
+ maX.push_back(rSvgTextPositions.getDx()[a].solve(rInfoProvider, xcoordinate));
+ }
+ }
+ }
+ }
+
+ // get text positions Y
+ const sal_uInt32 nSizeY(rSvgTextPositions.getY().size());
+
+ if(nSizeY)
+ {
+ // we have absolute positions, get first one as current text position Y
+ maPosition.setY(rSvgTextPositions.getY()[0].solve(rInfoProvider, ycoordinate));
+ mbAbsoluteX = true;
+
+ if(nSizeY > 1)
+ {
+ // fill deltas to maY
+ maY.reserve(nSizeY);
+
+ for(sal_uInt32 a(1); a < nSizeY; a++)
+ {
+ maY.push_back(rSvgTextPositions.getY()[a].solve(rInfoProvider, ycoordinate) - maPosition.getY());
+ }
+ }
+ }
+ else
+ {
+ // no absolute position, get from parent
+ if(pParent)
+ {
+ maPosition.setY(pParent->getPosition().getY());
+ }
+
+ const sal_uInt32 nSizeDy(rSvgTextPositions.getDy().size());
+
+ if(nSizeDy)
+ {
+ // relative positions given, translate position derived from parent
+ maPosition.setY(maPosition.getY() + rSvgTextPositions.getDy()[0].solve(rInfoProvider, ycoordinate));
+
+ if(nSizeDy > 1)
+ {
+ // fill deltas to maY
+ maY.reserve(nSizeDy);
+
+ for(sal_uInt32 a(1); a < nSizeDy; a++)
+ {
+ maY.push_back(rSvgTextPositions.getDy()[a].solve(rInfoProvider, ycoordinate));
+ }
+ }
+ }
+ }
+ }
+
+ bool SvgTextPosition::isRotated() const
+ {
+ if(maRotate.empty())
+ {
+ if(getParent())
+ {
+ return getParent()->isRotated();
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ double SvgTextPosition::consumeRotation()
+ {
+ double fRetval(0.0);
+
+ if(maRotate.empty())
+ {
+ if(getParent())
+ {
+ fRetval = mpParent->consumeRotation();
+ }
+ else
+ {
+ fRetval = 0.0;
+ }
+ }
+ else
+ {
+ const sal_uInt32 nSize(maRotate.size());
+
+ if(mnRotationIndex < nSize)
+ {
+ fRetval = maRotate[mnRotationIndex++];
+ }
+ else
+ {
+ fRetval = maRotate[nSize - 1];
+ }
+ }
+
+ return fRetval;
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgcirclenode.cxx b/svgio/source/svgreader/svgcirclenode.cxx
new file mode 100644
index 000000000000..b9ef1f7bd624
--- /dev/null
+++ b/svgio/source/svgreader/svgcirclenode.cxx
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgcirclenode.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgCircleNode::SvgCircleNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenCircle, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ maCx(0),
+ maCy(0),
+ maR(0),
+ mpaTransform(0)
+ {
+ }
+
+ SvgCircleNode::~SvgCircleNode()
+ {
+ if(mpaTransform) delete mpaTransform;
+ }
+
+ const SvgStyleAttributes* SvgCircleNode::getSvgStyleAttributes() const
+ {
+ static rtl::OUString aClassStr(rtl::OUString::createFromAscii("circle"));
+ maSvgStyleAttributes.checkForCssStyle(aClassStr);
+
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgCircleNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenCx:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setCx(aNum);
+ }
+ break;
+ }
+ case SVGTokenCy:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setCy(aNum);
+ }
+ break;
+ }
+ case SVGTokenR:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setR(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenTransform:
+ {
+ const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
+
+ if(!aMatrix.isIdentity())
+ {
+ setTransform(&aMatrix);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgCircleNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const
+ {
+ const SvgStyleAttributes* pStyle = getSvgStyleAttributes();
+
+ if(pStyle && getR().isSet())
+ {
+ const double fR(getR().solve(*this, xcoordinate));
+
+ if(fR > 0.0)
+ {
+ const basegfx::B2DPolygon aPath(
+ basegfx::tools::createPolygonFromCircle(
+ basegfx::B2DPoint(
+ getCx().isSet() ? getCx().solve(*this, xcoordinate) : 0.0,
+ getCy().isSet() ? getCy().solve(*this, ycoordinate) : 0.0),
+ fR));
+
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget);
+
+ if(aNewTarget.hasElements())
+ {
+ pStyle->add_postProcess(rTarget, aNewTarget, getTransform());
+ }
+ }
+ }
+ }
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgclippathnode.cxx b/svgio/source/svgreader/svgclippathnode.cxx
new file mode 100644
index 000000000000..5c271400d5f0
--- /dev/null
+++ b/svgio/source/svgreader/svgclippathnode.cxx
@@ -0,0 +1,203 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgclippathnode.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/processor2d/contourextractor2d.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgClipPathNode::SvgClipPathNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenClipPathNode, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ mpaTransform(0),
+ maClipPathUnits(userSpaceOnUse)
+ {
+ }
+
+ SvgClipPathNode::~SvgClipPathNode()
+ {
+ if(mpaTransform) delete mpaTransform;
+ }
+
+ const SvgStyleAttributes* SvgClipPathNode::getSvgStyleAttributes() const
+ {
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgClipPathNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenTransform:
+ {
+ const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
+
+ if(!aMatrix.isIdentity())
+ {
+ setTransform(&aMatrix);
+ }
+ break;
+ }
+ case SVGTokenClipPathUnits:
+ {
+ if(aContent.getLength())
+ {
+ if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0))
+ {
+ setClipPathUnits(userSpaceOnUse);
+ }
+ else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0))
+ {
+ setClipPathUnits(objectBoundingBox);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgClipPathNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const
+ {
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ // decompose childs
+ SvgNode::decomposeSvgNode(aNewTarget, bReferenced);
+
+ if(aNewTarget.hasElements())
+ {
+ if(getTransform())
+ {
+ // create embedding group element with transformation
+ const drawinglayer::primitive2d::Primitive2DReference xRef(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ *getTransform(),
+ aNewTarget));
+
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef);
+ }
+ else
+ {
+ // append to current target
+ drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget);
+ }
+ }
+ }
+
+ void SvgClipPathNode::apply(drawinglayer::primitive2d::Primitive2DSequence& rContent) const
+ {
+ if(rContent.hasElements())
+ {
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ drawinglayer::primitive2d::Primitive2DSequence aClipTarget;
+ basegfx::B2DPolyPolygon aClipPolyPolygon;
+
+ // get clipPath definition as primitives
+ decomposeSvgNode(aClipTarget, true);
+
+ if(aClipTarget.hasElements())
+ {
+ // extract filled plygons as base for a mask PolyPolygon
+ drawinglayer::processor2d::ContourExtractor2D aExtractor(aViewInformation2D, true);
+
+ aExtractor.process(aClipTarget);
+
+ const basegfx::B2DPolyPolygonVector& rResult(aExtractor.getExtractedContour());
+ const sal_uInt32 nSize(rResult.size());
+
+ if(nSize > 1)
+ {
+ // merge to single clipPolyPolygon
+ aClipPolyPolygon = basegfx::tools::mergeToSinglePolyPolygon(rResult);
+ }
+ else
+ {
+ aClipPolyPolygon = rResult[0];
+ }
+ }
+
+ if(aClipPolyPolygon.count())
+ {
+ if(objectBoundingBox == getClipPathUnits())
+ {
+ // clip is object-relative, transform using content transformation
+ const basegfx::B2DRange aContentRange(
+ drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
+ rContent,
+ aViewInformation2D));
+
+ aClipPolyPolygon.transform(
+ basegfx::tools::createScaleTranslateB2DHomMatrix(
+ aContentRange.getRange(),
+ aContentRange.getMinimum()));
+ }
+
+ // redefine target. Use MaskPrimitive2D with created clip
+ // geometry. Using the automatically set mbIsClipPathContent at
+ // SvgStyleAttributes the clip definition is without fill, stroke,
+ // and strokeWidth and forced to black
+ const drawinglayer::primitive2d::Primitive2DReference xEmbedTransparence(
+ new drawinglayer::primitive2d::MaskPrimitive2D(
+ aClipPolyPolygon,
+ rContent));
+
+ rContent = drawinglayer::primitive2d::Primitive2DSequence(&xEmbedTransparence, 1);
+ }
+ else
+ {
+ // An empty clipping path will completely clip away the element that had
+ // the ‘clip-path’ property applied. (Svg spec)
+ rContent.realloc(0);
+ }
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgdocument.cxx b/svgio/source/svgreader/svgdocument.cxx
new file mode 100644
index 000000000000..e5dd4acb5db2
--- /dev/null
+++ b/svgio/source/svgreader/svgdocument.cxx
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgdocument.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgDocument::SvgDocument(const rtl::OUString& rAbsolutePath)
+ : maNodes(),
+ maAbsolutePath(rAbsolutePath),
+ maIdTokenMapperList(),
+ maIdStyleTokenMapperList()
+ {
+ }
+
+ SvgDocument::~SvgDocument()
+ {
+ while(!maNodes.empty())
+ {
+ SvgNode* pCandidate = maNodes[maNodes.size() - 1];
+ delete pCandidate;
+ maNodes.pop_back();
+ }
+ }
+
+ void SvgDocument::appendNode(SvgNode* pNode)
+ {
+ OSL_ENSURE(pNode, "OOps, empty node added (!)");
+ maNodes.push_back(pNode);
+ }
+
+ void SvgDocument::addSvgNodeToMapper(const rtl::OUString& rStr, const SvgNode& rNode)
+ {
+ if(rStr.getLength())
+ {
+ maIdTokenMapperList.insert(IdTokenValueType(rStr, &rNode));
+ }
+ }
+
+ void SvgDocument::removeSvgNodeFromMapper(const rtl::OUString& rStr)
+ {
+ if(rStr.getLength())
+ {
+ maIdTokenMapperList.erase(rStr);
+ }
+ }
+
+ const SvgNode* SvgDocument::findSvgNodeById(const rtl::OUString& rStr) const
+ {
+ const IdTokenMapper::const_iterator aResult(maIdTokenMapperList.find(rStr));
+
+ if(aResult == maIdTokenMapperList.end())
+ {
+ return 0;
+ }
+ else
+ {
+ return aResult->second;
+ }
+ }
+
+ void SvgDocument::addSvgStyleAttributesToMapper(const rtl::OUString& rStr, const SvgStyleAttributes& rSvgStyleAttributes)
+ {
+ if(rStr.getLength())
+ {
+ maIdStyleTokenMapperList.insert(IdStyleTokenValueType(rStr, &rSvgStyleAttributes));
+ }
+ }
+
+ void SvgDocument::removeSvgStyleAttributesFromMapper(const rtl::OUString& rStr)
+ {
+ if(rStr.getLength())
+ {
+ maIdStyleTokenMapperList.erase(rStr);
+ }
+ }
+
+ const SvgStyleAttributes* SvgDocument::findSvgStyleAttributesById(const rtl::OUString& rStr) const
+ {
+ const IdStyleTokenMapper::const_iterator aResult(maIdStyleTokenMapperList.find(rStr));
+
+ if(aResult == maIdStyleTokenMapperList.end())
+ {
+ return 0;
+ }
+ else
+ {
+ return aResult->second;
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgdocumenthandler.cxx b/svgio/source/svgreader/svgdocumenthandler.cxx
new file mode 100644
index 000000000000..7cb91a790051
--- /dev/null
+++ b/svgio/source/svgreader/svgdocumenthandler.cxx
@@ -0,0 +1,549 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgdocumenthandler.hxx>
+#include <svgio/svgreader/svgtoken.hxx>
+#include <svgio/svgreader/svgsvgnode.hxx>
+#include <svgio/svgreader/svggnode.hxx>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgpathnode.hxx>
+#include <svgio/svgreader/svgrectnode.hxx>
+#include <svgio/svgreader/svggradientnode.hxx>
+#include <svgio/svgreader/svggradientstopnode.hxx>
+#include <svgio/svgreader/svgsymbolnode.hxx>
+#include <svgio/svgreader/svgusenode.hxx>
+#include <svgio/svgreader/svgcirclenode.hxx>
+#include <svgio/svgreader/svgellipsenode.hxx>
+#include <svgio/svgreader/svglinenode.hxx>
+#include <svgio/svgreader/svgpolynode.hxx>
+#include <svgio/svgreader/svgsymbolnode.hxx>
+#include <svgio/svgreader/svgtextnode.hxx>
+#include <svgio/svgreader/svgcharacternode.hxx>
+#include <svgio/svgreader/svgtspannode.hxx>
+#include <svgio/svgreader/svgtrefnode.hxx>
+#include <svgio/svgreader/svgtextpathnode.hxx>
+#include <svgio/svgreader/svgstylenode.hxx>
+#include <svgio/svgreader/svgimagenode.hxx>
+#include <svgio/svgreader/svgclippathnode.hxx>
+#include <svgio/svgreader/svgmasknode.hxx>
+#include <svgio/svgreader/svgmarkernode.hxx>
+#include <svgio/svgreader/svgpatternnode.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+ svgio::svgreader::SvgCharacterNode* whiteSpaceHandling(svgio::svgreader::SvgNode* pNode, svgio::svgreader::SvgCharacterNode* pLast)
+ {
+ if(pNode)
+ {
+ const svgio::svgreader::SvgNodeVector& rChilds = pNode->getChildren();
+ const sal_uInt32 nCount(rChilds.size());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ svgio::svgreader::SvgNode* pCandidate = rChilds[a];
+
+ if(pCandidate)
+ {
+ switch(pCandidate->getType())
+ {
+ case svgio::svgreader::SVGTokenCharacter:
+ {
+ // clean whitespace in text span
+ svgio::svgreader::SvgCharacterNode* pCharNode = static_cast< svgio::svgreader::SvgCharacterNode* >(pCandidate);
+ pCharNode->whiteSpaceHandling();
+
+ // pCharNode may have lost all text. If that's the case, ignore
+ // as invalid character node
+ if(pCharNode->getText().getLength())
+ {
+ if(pLast)
+ {
+ // add in-between whitespace (single space) to last
+ // known character node
+ pLast->addGap();
+ }
+
+ // remember new last corected character node
+ pLast = pCharNode;
+ }
+ break;
+ }
+ case svgio::svgreader::SVGTokenTspan:
+ case svgio::svgreader::SVGTokenTextPath:
+ case svgio::svgreader::SVGTokenTref:
+ {
+ // recursively clean whitespaces in subhierarchy
+ pLast = whiteSpaceHandling(pCandidate, pLast);
+ break;
+ }
+ default:
+ {
+ OSL_ENSURE(false, "Unexpected token inside SVGTokenText (!)");
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return pLast;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgDocHdl::SvgDocHdl(const rtl::OUString& aAbsolutePath)
+ : maDocument(aAbsolutePath),
+ mpTarget(0),
+ maCssContents()
+ {
+ }
+
+ SvgDocHdl::~SvgDocHdl()
+ {
+#ifdef DBG_UTIL
+ if(mpTarget)
+ {
+ OSL_ENSURE(false, "SvgDocHdl destructed with active target (!)");
+ delete mpTarget;
+ }
+ OSL_ENSURE(!maCssContents.size(), "SvgDocHdl destructed with active css style stack entry (!)");
+#endif
+ }
+
+ void SvgDocHdl::startDocument( ) throw (xml::sax::SAXException, uno::RuntimeException)
+ {
+ OSL_ENSURE(!mpTarget, "Already a target at document start (!)");
+ OSL_ENSURE(!maCssContents.size(), "SvgDocHdl startDocument with active css style stack entry (!)");
+ }
+
+ void SvgDocHdl::endDocument( ) throw (xml::sax::SAXException, uno::RuntimeException)
+ {
+ OSL_ENSURE(!mpTarget, "Still a target at document end (!)");
+ OSL_ENSURE(!maCssContents.size(), "SvgDocHdl endDocument with active css style stack entry (!)");
+ }
+
+ void SvgDocHdl::startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException)
+ {
+ if(aName.getLength())
+ {
+ const SVGToken aSVGToken(StrToSVGToken(aName));
+
+ switch(aSVGToken)
+ {
+ /// structural elements
+ case SVGTokenSymbol:
+ {
+ /// new basic node for Symbol. Content gets scanned, but
+ /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced)
+ mpTarget = new SvgSymbolNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+ case SVGTokenDefs:
+ case SVGTokenG:
+ {
+ /// new node for Defs/G
+ mpTarget = new SvgGNode(aSVGToken, maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+ case SVGTokenSvg:
+ {
+ /// new node for Svg
+ mpTarget = new SvgSvgNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+ case SVGTokenUse:
+ {
+ /// new node for Use
+ mpTarget = new SvgUseNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+
+ /// shape elements
+ case SVGTokenCircle:
+ {
+ /// new node for Circle
+ mpTarget = new SvgCircleNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+ case SVGTokenEllipse:
+ {
+ /// new node for Ellipse
+ mpTarget = new SvgEllipseNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+ case SVGTokenLine:
+ {
+ /// new node for Line
+ mpTarget = new SvgLineNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+ case SVGTokenPath:
+ {
+ /// new node for Path
+ mpTarget = new SvgPathNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+ case SVGTokenPolygon:
+ {
+ /// new node for Polygon
+ mpTarget = new SvgPolyNode(maDocument, mpTarget, false);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+ case SVGTokenPolyline:
+ {
+ /// new node for Polyline
+ mpTarget = new SvgPolyNode(maDocument, mpTarget, true);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+ case SVGTokenRect:
+ {
+ /// new node for Rect
+ mpTarget = new SvgRectNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+ case SVGTokenImage:
+ {
+ /// new node for Image
+ mpTarget = new SvgImageNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+
+ /// gradients
+ case SVGTokenLinearGradient:
+ case SVGTokenRadialGradient:
+ {
+ mpTarget = new SvgGradientNode(aSVGToken, maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+
+ /// gradient stops
+ case SVGTokenStop:
+ {
+ mpTarget = new SvgGradientStopNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+
+ /// text
+ case SVGTokenText:
+ {
+ mpTarget = new SvgTextNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+ case SVGTokenTspan:
+ {
+ mpTarget = new SvgTspanNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+ case SVGTokenTref:
+ {
+ mpTarget = new SvgTrefNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+ case SVGTokenTextPath:
+ {
+ mpTarget = new SvgTextPathNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+
+ /// styles (as stylesheets)
+ case SVGTokenStyle:
+ {
+ SvgStyleNode* pNew = new SvgStyleNode(maDocument, mpTarget);
+ mpTarget = pNew;
+ mpTarget->parseAttributes(xAttribs);
+
+ if(pNew->isTextCss())
+ {
+ maCssContents.push_back(rtl::OUString());
+ }
+ break;
+ }
+
+ /// structural elements clip-path and mask. Content gets scanned, but
+ /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced)
+ case SVGTokenClipPathNode:
+ {
+ /// new node for ClipPath
+ mpTarget = new SvgClipPathNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+ case SVGTokenMask:
+ {
+ /// new node for Mask
+ mpTarget = new SvgMaskNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+
+ /// structural element marker
+ case SVGTokenMarker:
+ {
+ /// new node for marker
+ mpTarget = new SvgMarkerNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+
+ /// structural element pattern
+ case SVGTokenPattern:
+ {
+ /// new node for pattern
+ mpTarget = new SvgPatternNode(maDocument, mpTarget);
+ mpTarget->parseAttributes(xAttribs);
+ break;
+ }
+
+ default:
+ {
+ /// invalid token, ignore
+#ifdef DBG_UTIL
+ myAssert(
+ rtl::OUString::createFromAscii("Unknown Base SvgToken <") +
+ aName +
+ rtl::OUString::createFromAscii("> (!)"));
+#endif
+ break;
+ }
+ }
+ }
+ }
+
+ void SvgDocHdl::endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException)
+ {
+ if(aName.getLength())
+ {
+ const SVGToken aSVGToken(StrToSVGToken(aName));
+ SvgNode* pWhitespaceCheck(SVGTokenText == aSVGToken ? mpTarget : 0);
+ SvgStyleNode* pCssStyle(SVGTokenStyle == aSVGToken ? static_cast< SvgStyleNode* >(mpTarget) : 0);
+
+ switch(aSVGToken)
+ {
+ /// valid tokens for which a new one was created
+
+ /// structural elements
+ case SVGTokenDefs:
+ case SVGTokenG:
+ case SVGTokenSvg:
+ case SVGTokenSymbol:
+ case SVGTokenUse:
+
+ /// shape elements
+ case SVGTokenCircle:
+ case SVGTokenEllipse:
+ case SVGTokenLine:
+ case SVGTokenPath:
+ case SVGTokenPolygon:
+ case SVGTokenPolyline:
+ case SVGTokenRect:
+ case SVGTokenImage:
+
+ /// gradients
+ case SVGTokenLinearGradient:
+ case SVGTokenRadialGradient:
+
+ /// gradient stops
+ case SVGTokenStop:
+
+ /// text
+ case SVGTokenText:
+ case SVGTokenTspan:
+ case SVGTokenTextPath:
+ case SVGTokenTref:
+
+ /// styles (as stylesheets)
+ case SVGTokenStyle:
+
+ /// structural elements clip-path and mask
+ case SVGTokenClipPathNode:
+ case SVGTokenMask:
+
+ /// structural element marker
+ case SVGTokenMarker:
+
+ /// structural element pattern
+ case SVGTokenPattern:
+
+ /// content handling after parsing
+ {
+ if(mpTarget)
+ {
+ if(!mpTarget->getParent())
+ {
+ // last element closing, save this tree
+ maDocument.appendNode(mpTarget);
+ }
+
+ mpTarget = const_cast< SvgNode* >(mpTarget->getParent());
+ }
+ else
+ {
+ OSL_ENSURE(false, "Closing token, but no context (!)");
+ }
+ break;
+ }
+ default:
+ {
+ /// invalid token, ignore
+ }
+ }
+
+ if(pCssStyle && pCssStyle->isTextCss())
+ {
+ // css style parsing
+ if(maCssContents.size())
+ {
+ // need to interpret css styles and remember them as StyleSheets
+ pCssStyle->addCssStyleSheet(*(maCssContents.end() - 1));
+ maCssContents.pop_back();
+ }
+ else
+ {
+ OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)");
+ }
+ }
+
+ if(pWhitespaceCheck)
+ {
+ // cleanup read strings
+ whiteSpaceHandling(pWhitespaceCheck, 0);
+ }
+ }
+ }
+
+ void SvgDocHdl::characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException)
+ {
+ if(mpTarget)
+ {
+ const sal_uInt32 nLength(aChars.getLength());
+
+ if(nLength &&
+ (SVGTokenText == mpTarget->getType() ||
+ SVGTokenTspan == mpTarget->getType() ||
+ SVGTokenTextPath == mpTarget->getType() ||
+ SVGTokenStyle == mpTarget->getType()))
+ {
+ switch(mpTarget->getType())
+ {
+ case SVGTokenText:
+ case SVGTokenTspan:
+ case SVGTokenTextPath:
+ {
+ const SvgNodeVector& rChilds = mpTarget->getChildren();
+ SvgCharacterNode* pTarget = 0;
+
+ if(rChilds.size())
+ {
+ pTarget = dynamic_cast< SvgCharacterNode* >(rChilds[rChilds.size() - 1]);
+ }
+
+ if(pTarget)
+ {
+ // concatenate to current character span
+ pTarget->concatenate(aChars);
+ }
+ else
+ {
+ // add character span as simplified tspan (no arguments)
+ // as direct child of SvgTextNode/SvgTspanNode/SvgTextPathNode
+ new SvgCharacterNode(maDocument, mpTarget, aChars);
+ }
+ break;
+ }
+ case SVGTokenStyle:
+ {
+ SvgStyleNode& rSvgStyleNode = static_cast< SvgStyleNode& >(*mpTarget);
+
+ if(rSvgStyleNode.isTextCss())
+ {
+ // collect characters for css style
+ if(maCssContents.size())
+ {
+ const ::rtl::OUString aTrimmedChars(aChars.trim());
+
+ if(aTrimmedChars.getLength())
+ {
+ std::vector< rtl::OUString >::iterator aString(maCssContents.end() - 1);
+ (*aString) += aTrimmedChars;
+ }
+ }
+ else
+ {
+ OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)");
+ }
+ }
+ break;
+ }
+ default:
+ {
+ // characters not used by a known node
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ void SvgDocHdl::ignorableWhitespace(const ::rtl::OUString& /*aWhitespaces*/) throw (xml::sax::SAXException, uno::RuntimeException)
+ {
+ }
+
+ void SvgDocHdl::processingInstruction(const ::rtl::OUString& /*aTarget*/, const ::rtl::OUString& /*aData*/) throw (xml::sax::SAXException, uno::RuntimeException)
+ {
+ }
+
+ void SvgDocHdl::setDocumentLocator(const uno::Reference< xml::sax::XLocator >& /*xLocator*/) throw (xml::sax::SAXException, uno::RuntimeException)
+ {
+ }
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgellipsenode.cxx b/svgio/source/svgreader/svgellipsenode.cxx
new file mode 100644
index 000000000000..f34edb244f4a
--- /dev/null
+++ b/svgio/source/svgreader/svgellipsenode.cxx
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgellipsenode.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgEllipseNode::SvgEllipseNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenEllipse, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ maCx(0),
+ maCy(0),
+ maRx(0),
+ maRy(0),
+ mpaTransform(0)
+ {
+ }
+
+ SvgEllipseNode::~SvgEllipseNode()
+ {
+ if(mpaTransform) delete mpaTransform;
+ }
+
+ const SvgStyleAttributes* SvgEllipseNode::getSvgStyleAttributes() const
+ {
+ static rtl::OUString aClassStr(rtl::OUString::createFromAscii("ellipse"));
+ maSvgStyleAttributes.checkForCssStyle(aClassStr);
+
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgEllipseNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenCx:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setCx(aNum);
+ }
+ break;
+ }
+ case SVGTokenCy:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setCy(aNum);
+ }
+ break;
+ }
+ case SVGTokenRx:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setRx(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenRy:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setRy(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenTransform:
+ {
+ const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
+
+ if(!aMatrix.isIdentity())
+ {
+ setTransform(&aMatrix);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgEllipseNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const
+ {
+ const SvgStyleAttributes* pStyle = getSvgStyleAttributes();
+
+ if(pStyle && getRx().isSet() && getRy().isSet())
+ {
+ const double fRx(getRx().solve(*this, xcoordinate));
+ const double fRy(getRy().solve(*this, ycoordinate));
+
+ if(fRx > 0.0 && fRy > 0.0)
+ {
+ const basegfx::B2DPolygon aPath(
+ basegfx::tools::createPolygonFromEllipse(
+ basegfx::B2DPoint(
+ getCx().isSet() ? getCx().solve(*this, xcoordinate) : 0.0,
+ getCy().isSet() ? getCy().solve(*this, ycoordinate) : 0.0),
+ fRx, fRy));
+
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget);
+
+ if(aNewTarget.hasElements())
+ {
+ pStyle->add_postProcess(rTarget, aNewTarget, getTransform());
+ }
+ }
+ }
+ }
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svggnode.cxx b/svgio/source/svgreader/svggnode.cxx
new file mode 100644
index 000000000000..df2ad5aed125
--- /dev/null
+++ b/svgio/source/svgreader/svggnode.cxx
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svggnode.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgGNode::SvgGNode(
+ SVGToken aType,
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(aType, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ mpaTransform(0)
+ {
+ OSL_ENSURE(aType == SVGTokenDefs || aType == SVGTokenG, "SvgGNode should ony be used for Group and Defs (!)");
+ }
+
+ SvgGNode::~SvgGNode()
+ {
+ if(mpaTransform) delete mpaTransform;
+ }
+
+ const SvgStyleAttributes* SvgGNode::getSvgStyleAttributes() const
+ {
+ static rtl::OUString aClassStr(rtl::OUString::createFromAscii("g"));
+ maSvgStyleAttributes.checkForCssStyle(aClassStr);
+
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgGNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenTransform:
+ {
+ const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
+
+ if(!aMatrix.isIdentity())
+ {
+ setTransform(&aMatrix);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgGNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const
+ {
+ const SvgStyleAttributes* pStyle = getSvgStyleAttributes();
+
+ if(pStyle)
+ {
+ const double fOpacity(pStyle->getOpacity().getNumber());
+
+ if(fOpacity > 0.0)
+ {
+ drawinglayer::primitive2d::Primitive2DSequence aContent;
+
+ // decompose childs
+ SvgNode::decomposeSvgNode(aContent, bReferenced);
+
+ if(aContent.hasElements())
+ {
+ pStyle->add_postProcess(rTarget, aContent, getTransform());
+ }
+ }
+ }
+ }
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svggradientnode.cxx b/svgio/source/svgreader/svggradientnode.cxx
new file mode 100644
index 000000000000..74878d1ecb9e
--- /dev/null
+++ b/svgio/source/svgreader/svggradientnode.cxx
@@ -0,0 +1,508 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svggradientnode.hxx>
+#include <svgio/svgreader/svgdocument.hxx>
+#include <svgio/svgreader/svggradientstopnode.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ void SvgGradientNode::tryToFindLink()
+ {
+ if(!mpXLink && maXLink.getLength())
+ {
+ mpXLink = dynamic_cast< const SvgGradientNode* >(getDocument().findSvgNodeById(maXLink));
+ }
+ }
+
+ SvgGradientNode::SvgGradientNode(
+ SVGToken aType,
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(aType, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ maX1(),
+ maY1(),
+ maX2(),
+ maY2(),
+ maCx(),
+ maCy(),
+ maR(),
+ maFx(),
+ maFy(),
+ maGradientUnits(objectBoundingBox),
+ maSpreadMethod(drawinglayer::primitive2d::Spread_pad),
+ mpaGradientTransform(0),
+ maXLink(),
+ mpXLink(0)
+ {
+ }
+
+ SvgGradientNode::~SvgGradientNode()
+ {
+ if(mpaGradientTransform) delete mpaGradientTransform;
+ // do NOT delete mpXLink, it's only referenced, not owned
+ }
+
+ const SvgStyleAttributes* SvgGradientNode::getSvgStyleAttributes() const
+ {
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgGradientNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenX1:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setX1(aNum);
+ }
+ break;
+ }
+ case SVGTokenY1:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setY1(aNum);
+ }
+ break;
+ }
+ case SVGTokenX2:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setX2(aNum);
+ }
+ break;
+ }
+ case SVGTokenY2:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setY2(aNum);
+ }
+ break;
+ }
+ case SVGTokenCx:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setCx(aNum);
+ }
+ break;
+ }
+ case SVGTokenCy:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setCy(aNum);
+ }
+ break;
+ }
+ case SVGTokenFx:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setFx(aNum);
+ }
+ break;
+ }
+ case SVGTokenFy:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setFy(aNum);
+ }
+ break;
+ }
+ case SVGTokenR:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setR(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenGradientUnits:
+ {
+ if(aContent.getLength())
+ {
+ if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0))
+ {
+ setGradientUnits(userSpaceOnUse);
+ }
+ else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0))
+ {
+ setGradientUnits(objectBoundingBox);
+ }
+ }
+ break;
+ }
+ case SVGTokenSpreadMethod:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrPad(rtl::OUString::createFromAscii("pad"));
+ static rtl::OUString aStrReflect(rtl::OUString::createFromAscii("reflect"));
+ static rtl::OUString aStrRepeat(rtl::OUString::createFromAscii("repeat"));
+
+ if(aContent.match(aStrPad, 0))
+ {
+ setSpreadMethod(drawinglayer::primitive2d::Spread_pad);
+ }
+ else if(aContent.match(aStrReflect, 0))
+ {
+ setSpreadMethod(drawinglayer::primitive2d::Spread_reflect);
+ }
+ else if(aContent.match(aStrRepeat, 0))
+ {
+ setSpreadMethod(drawinglayer::primitive2d::Spread_repeat);
+ }
+ }
+ break;
+ }
+ case SVGTokenGradientTransform:
+ {
+ const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
+
+ if(!aMatrix.isIdentity())
+ {
+ setGradientTransform(&aMatrix);
+ }
+ break;
+ }
+ case SVGTokenXlinkHref:
+ {
+ const sal_Int32 nLen(aContent.getLength());
+
+ if(nLen && sal_Unicode('#') == aContent[0])
+ {
+ maXLink = aContent.copy(1);
+ tryToFindLink();
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgGradientNode::collectGradientEntries(drawinglayer::primitive2d::SvgGradientEntryVector& aVector) const
+ {
+ if(getChildren().empty())
+ {
+ const_cast< SvgGradientNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ mpXLink->collectGradientEntries(aVector);
+ }
+ }
+ else
+ {
+ const sal_uInt32 nCount(getChildren().size());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const SvgGradientStopNode* pCandidate = dynamic_cast< const SvgGradientStopNode* >(getChildren()[a]);
+
+ if(pCandidate)
+ {
+ const SvgStyleAttributes* pStyle = pCandidate->getSvgStyleAttributes();
+
+ if(pStyle)
+ {
+ const SvgNumber aOffset(pCandidate->getOffset());
+ double fOffset(0.0);
+
+ if(Unit_percent == aOffset.getUnit())
+ {
+ // percent is not relative to distances in ColorStop context, solve locally
+ fOffset = aOffset.getNumber() * 0.01;
+ }
+ else
+ {
+ fOffset = aOffset.solve(*this);
+ }
+
+ if(fOffset < 0.0)
+ {
+ OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)");
+ fOffset = 0.0;
+ }
+ else if(fOffset > 1.0)
+ {
+ OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)");
+ fOffset = 1.0;
+ }
+
+ aVector.push_back(
+ drawinglayer::primitive2d::SvgGradientEntry(
+ fOffset,
+ pStyle->getStopColor(),
+ pStyle->getStopOpacity().solve(*this)));
+ }
+ else
+ {
+ OSL_ENSURE(false, "OOps, SvgGradientStopNode without Style (!)");
+ }
+ }
+ }
+ }
+ }
+
+ const SvgNumber SvgGradientNode::getX1() const
+ {
+ if(maX1.isSet())
+ {
+ return maX1;
+ }
+
+ const_cast< SvgGradientNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getX1();
+ }
+
+ // default is 0%
+ return SvgNumber(0.0, Unit_percent);
+ }
+
+ const SvgNumber SvgGradientNode::getY1() const
+ {
+ if(maY1.isSet())
+ {
+ return maY1;
+ }
+
+ const_cast< SvgGradientNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getY1();
+ }
+
+ // default is 0%
+ return SvgNumber(0.0, Unit_percent);
+ }
+
+ const SvgNumber SvgGradientNode::getX2() const
+ {
+ if(maX2.isSet())
+ {
+ return maX2;
+ }
+
+ const_cast< SvgGradientNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getX2();
+ }
+
+ // default is 100%
+ return SvgNumber(100.0, Unit_percent);
+ }
+
+ const SvgNumber SvgGradientNode::getY2() const
+ {
+ if(maY2.isSet())
+ {
+ return maY2;
+ }
+
+ const_cast< SvgGradientNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getY2();
+ }
+
+ // default is 0%
+ return SvgNumber(0.0, Unit_percent);
+ }
+
+ const SvgNumber SvgGradientNode::getCx() const
+ {
+ if(maCx.isSet())
+ {
+ return maCx;
+ }
+
+ const_cast< SvgGradientNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getCx();
+ }
+
+ // default is 50%
+ return SvgNumber(50.0, Unit_percent);
+ }
+
+ const SvgNumber SvgGradientNode::getCy() const
+ {
+ if(maCy.isSet())
+ {
+ return maCy;
+ }
+
+ const_cast< SvgGradientNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getCy();
+ }
+
+ // default is 50%
+ return SvgNumber(50.0, Unit_percent);
+ }
+
+ const SvgNumber SvgGradientNode::getR() const
+ {
+ if(maR.isSet())
+ {
+ return maR;
+ }
+
+ const_cast< SvgGradientNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getR();
+ }
+
+ // default is 50%
+ return SvgNumber(50.0, Unit_percent);
+ }
+
+ const SvgNumber* SvgGradientNode::getFx() const
+ {
+ if(maFx.isSet())
+ {
+ return &maFx;
+ }
+
+ const_cast< SvgGradientNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getFx();
+ }
+
+ return 0;
+ }
+
+ const SvgNumber* SvgGradientNode::getFy() const
+ {
+ if(maFy.isSet())
+ {
+ return &maFy;
+ }
+
+ const_cast< SvgGradientNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getFy();
+ }
+
+ return 0;
+ }
+
+ const basegfx::B2DHomMatrix* SvgGradientNode::getGradientTransform() const
+ {
+ if(mpaGradientTransform)
+ {
+ return mpaGradientTransform;
+ }
+
+ const_cast< SvgGradientNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getGradientTransform();
+ }
+
+ return 0;
+ }
+
+ void SvgGradientNode::setGradientTransform(const basegfx::B2DHomMatrix* pMatrix)
+ {
+ if(mpaGradientTransform)
+ {
+ delete mpaGradientTransform;
+ mpaGradientTransform = 0;
+ }
+
+ if(pMatrix)
+ {
+ mpaGradientTransform = new basegfx::B2DHomMatrix(*pMatrix);
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svggradientstopnode.cxx b/svgio/source/svgreader/svggradientstopnode.cxx
new file mode 100644
index 000000000000..cf9b069395d5
--- /dev/null
+++ b/svgio/source/svgreader/svggradientstopnode.cxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svggradientstopnode.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgGradientStopNode::SvgGradientStopNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenStop, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ maOffset()
+ {
+ }
+
+ SvgGradientStopNode::~SvgGradientStopNode()
+ {
+ }
+
+ const SvgStyleAttributes* SvgGradientStopNode::getSvgStyleAttributes() const
+ {
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgGradientStopNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenOffset:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setOffset(aNum);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgimagenode.cxx b/svgio/source/svgreader/svgimagenode.cxx
new file mode 100644
index 000000000000..b57bf800c29e
--- /dev/null
+++ b/svgio/source/svgreader/svgimagenode.cxx
@@ -0,0 +1,354 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgimagenode.hxx>
+#include <svgio/svgreader/svgdocument.hxx>
+#include <sax/tools/converter.hxx>
+#include <tools/stream.hxx>
+#include <vcl/bitmapex.hxx>
+#include <svtools/filter.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/groupprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <rtl/uri.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgImageNode::SvgImageNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenRect, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ maSvgAspectRatio(),
+ mpaTransform(0),
+ maX(0),
+ maY(0),
+ maWidth(0),
+ maHeight(0),
+ maXLink(),
+ maUrl(),
+ maMimeType(),
+ maData()
+ {
+ }
+
+ SvgImageNode::~SvgImageNode()
+ {
+ if(mpaTransform) delete mpaTransform;
+ }
+
+ const SvgStyleAttributes* SvgImageNode::getSvgStyleAttributes() const
+ {
+ static rtl::OUString aClassStr(rtl::OUString::createFromAscii("image"));
+ maSvgStyleAttributes.checkForCssStyle(aClassStr);
+
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgImageNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenPreserveAspectRatio:
+ {
+ setSvgAspectRatio(readSvgAspectRatio(aContent));
+ break;
+ }
+ case SVGTokenTransform:
+ {
+ const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
+
+ if(!aMatrix.isIdentity())
+ {
+ setTransform(&aMatrix);
+ }
+ break;
+ }
+ case SVGTokenX:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setX(aNum);
+ }
+ break;
+ }
+ case SVGTokenY:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setY(aNum);
+ }
+ break;
+ }
+ case SVGTokenWidth:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setWidth(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenHeight:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setHeight(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenXlinkHref:
+ {
+ const sal_Int32 nLen(aContent.getLength());
+
+ if(nLen)
+ {
+ readImageLink(aContent, maXLink, maUrl, maMimeType, maData);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void extractFromGraphic(
+ const Graphic& rGraphic,
+ drawinglayer::primitive2d::Primitive2DSequence& rEmbedded,
+ basegfx::B2DRange& rViewBox,
+ BitmapEx& rBitmapEx)
+ {
+ if(GRAPHIC_BITMAP == rGraphic.GetType())
+ {
+ if(rGraphic.getSvgData().get())
+ {
+ // embedded Svg
+ rEmbedded = rGraphic.getSvgData()->getPrimitive2DSequence();
+
+ // fill aViewBox
+ rViewBox = rGraphic.getSvgData()->getRange();
+ }
+ else
+ {
+ // get bitmap
+ rBitmapEx = rGraphic.GetBitmapEx();
+ }
+ }
+ else
+ {
+ // evtl. convert to bitmap
+ rBitmapEx = rGraphic.GetBitmapEx();
+ }
+ }
+
+ void SvgImageNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const
+ {
+ // get size range and create path
+ const SvgStyleAttributes* pStyle = getSvgStyleAttributes();
+
+ if(pStyle && getWidth().isSet() && getHeight().isSet())
+ {
+ const double fWidth(getWidth().solve(*this, xcoordinate));
+ const double fHeight(getHeight().solve(*this, ycoordinate));
+
+ if(fWidth > 0.0 && fHeight > 0.0)
+ {
+ BitmapEx aBitmapEx;
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ // prepare Target and ViewBox for evtl. AspectRatio mappings
+ const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0);
+ const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0);
+ const basegfx::B2DRange aTarget(fX, fY, fX + fWidth, fY + fHeight);
+ basegfx::B2DRange aViewBox(aTarget);
+
+ if(maMimeType.getLength() && maData.getLength())
+ {
+ // use embedded base64 encoded data
+ ::com::sun::star::uno::Sequence< sal_Int8 > aPass;
+ ::sax::Converter::decodeBase64(aPass, maData);
+
+ if(aPass.hasElements())
+ {
+ SvMemoryStream aStream(aPass.getArray(), aPass.getLength(), STREAM_READ);
+ Graphic aGraphic;
+
+ if(GRFILTER_OK == GraphicFilter::GetGraphicFilter().ImportGraphic(
+ aGraphic,
+ String(),
+ aStream))
+ {
+ extractFromGraphic(aGraphic, aNewTarget, aViewBox, aBitmapEx);
+ }
+ }
+ }
+ else if(maUrl.getLength())
+ {
+ const rtl::OUString& rPath = getDocument().getAbsolutePath();
+ const rtl::OUString aAbsUrl(rtl::Uri::convertRelToAbs(rPath, maUrl));
+
+ if(aAbsUrl.getLength())
+ {
+ SvFileStream aStream(aAbsUrl, STREAM_STD_READ);
+ Graphic aGraphic;
+
+ if(GRFILTER_OK == GraphicFilter::GetGraphicFilter().ImportGraphic(
+ aGraphic,
+ aAbsUrl,
+ aStream))
+ {
+ extractFromGraphic(aGraphic, aNewTarget, aViewBox, aBitmapEx);
+ }
+ }
+ }
+ else if(maXLink.getLength())
+ {
+ const SvgNode* mpXLink = getDocument().findSvgNodeById(maXLink);
+
+ if(mpXLink)
+ {
+ mpXLink->decomposeSvgNode(aNewTarget, true);
+
+ if(aNewTarget.hasElements())
+ {
+ aViewBox = drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
+ aNewTarget,
+ drawinglayer::geometry::ViewInformation2D());
+ }
+ }
+ }
+
+ if(!aBitmapEx.IsEmpty())
+ {
+ // create content from created bitmap
+ aNewTarget.realloc(1);
+ aNewTarget[0] = new drawinglayer::primitive2d::BitmapPrimitive2D(
+ aBitmapEx,
+ basegfx::B2DHomMatrix());
+
+ // fill aViewBox. No size set yet, use unit size
+ aViewBox = basegfx::B2DRange(0.0, 0.0, 1.0, 1.0);
+ }
+
+ if(aNewTarget.hasElements())
+ {
+ if(aTarget.equal(aViewBox))
+ {
+ // just add to rTarget
+ drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget);
+ }
+ else
+ {
+ // create mapping
+ const SvgAspectRatio& rRatio = getSvgAspectRatio();
+
+ if(rRatio.isSet())
+ {
+ // let mapping be created from SvgAspectRatio
+ const basegfx::B2DHomMatrix aEmbeddingTransform(rRatio.createMapping(aTarget, aViewBox));
+
+ if(!aEmbeddingTransform.isIdentity())
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xRef(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aEmbeddingTransform,
+ aNewTarget));
+
+ aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
+ }
+
+ if(!rRatio.isMeetOrSlice())
+ {
+ // need to embed in MaskPrimitive2D to ensure clipping
+ const drawinglayer::primitive2d::Primitive2DReference xMask(
+ new drawinglayer::primitive2d::MaskPrimitive2D(
+ basegfx::B2DPolyPolygon(
+ basegfx::tools::createPolygonFromRect(aTarget)),
+ aNewTarget));
+
+ aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1);
+ }
+ }
+ else
+ {
+ // choose default mapping
+ const basegfx::B2DHomMatrix aEmbeddingTransform(rRatio.createLinearMapping(aTarget, aViewBox));
+
+ if(!aEmbeddingTransform.isIdentity())
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xRef(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aEmbeddingTransform,
+ aNewTarget));
+
+ aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
+ }
+ }
+
+ // embed and add to rTarget, take local extra-transform into account
+ pStyle->add_postProcess(rTarget, aNewTarget, getTransform());
+ }
+ }
+ }
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svglinenode.cxx b/svgio/source/svgreader/svglinenode.cxx
new file mode 100644
index 000000000000..bd8ad988635c
--- /dev/null
+++ b/svgio/source/svgreader/svglinenode.cxx
@@ -0,0 +1,166 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svglinenode.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgLineNode::SvgLineNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenLine, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ maX1(0),
+ maY1(0),
+ maX2(0),
+ maY2(0),
+ mpaTransform(0)
+ {
+ }
+
+ SvgLineNode::~SvgLineNode()
+ {
+ if(mpaTransform) delete mpaTransform;
+ }
+
+ const SvgStyleAttributes* SvgLineNode::getSvgStyleAttributes() const
+ {
+ static rtl::OUString aClassStr(rtl::OUString::createFromAscii("line"));
+ maSvgStyleAttributes.checkForCssStyle(aClassStr);
+
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgLineNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenX1:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setX1(aNum);
+ }
+ break;
+ }
+ case SVGTokenY1:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setY1(aNum);
+ }
+ break;
+ }
+ case SVGTokenX2:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setX2(aNum);
+ }
+ break;
+ }
+ case SVGTokenY2:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setY2(aNum);
+ }
+ break;
+ }
+ case SVGTokenTransform:
+ {
+ const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
+
+ if(!aMatrix.isIdentity())
+ {
+ setTransform(&aMatrix);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgLineNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const
+ {
+ const SvgStyleAttributes* pStyle = getSvgStyleAttributes();
+
+ if(pStyle)
+ {
+ const basegfx::B2DPoint X(
+ getX1().isSet() ? getX1().solve(*this, xcoordinate) : 0.0,
+ getY1().isSet() ? getY1().solve(*this, ycoordinate) : 0.0);
+ const basegfx::B2DPoint Y(
+ getX2().isSet() ? getX2().solve(*this, xcoordinate) : 0.0,
+ getY2().isSet() ? getY2().solve(*this, ycoordinate) : 0.0);
+
+ if(!X.equal(Y))
+ {
+ basegfx::B2DPolygon aPath;
+
+ aPath.append(X);
+ aPath.append(Y);
+
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget);
+
+ if(aNewTarget.hasElements())
+ {
+ pStyle->add_postProcess(rTarget, aNewTarget, getTransform());
+ }
+ }
+ }
+ }
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgmarkernode.cxx b/svgio/source/svgreader/svgmarkernode.cxx
new file mode 100644
index 000000000000..444ff3266420
--- /dev/null
+++ b/svgio/source/svgreader/svgmarkernode.cxx
@@ -0,0 +1,213 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgmarkernode.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgMarkerNode::SvgMarkerNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenMarker, rDocument, pParent),
+ aPrimitives(),
+ maSvgStyleAttributes(*this),
+ mpViewBox(0),
+ maSvgAspectRatio(),
+ maRefX(0),
+ maRefY(0),
+ maMarkerUnits(strokeWidth),
+ maMarkerWidth(3),
+ maMarkerHeight(3),
+ mfAngle(0.0),
+ mbOrientAuto(false)
+ {
+ }
+
+ SvgMarkerNode::~SvgMarkerNode()
+ {
+ if(mpViewBox) delete mpViewBox;
+ }
+
+ const SvgStyleAttributes* SvgMarkerNode::getSvgStyleAttributes() const
+ {
+ static rtl::OUString aClassStr(rtl::OUString::createFromAscii("marker"));
+ maSvgStyleAttributes.checkForCssStyle(aClassStr);
+
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgMarkerNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenViewBox:
+ {
+ const basegfx::B2DRange aRange(readViewBox(aContent, *this));
+
+ if(!aRange.isEmpty())
+ {
+ setViewBox(&aRange);
+ }
+ break;
+ }
+ case SVGTokenPreserveAspectRatio:
+ {
+ setSvgAspectRatio(readSvgAspectRatio(aContent));
+ break;
+ }
+ case SVGTokenRefX:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setRefX(aNum);
+ }
+ break;
+ }
+ case SVGTokenRefY:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setRefY(aNum);
+ }
+ break;
+ }
+ case SVGTokenMarkerUnits:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrStrokeWidth(rtl::OUString::createFromAscii("strokeWidth"));
+
+ if(aContent.match(aStrStrokeWidth, 0))
+ {
+ setMarkerUnits(strokeWidth);
+ }
+ else if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0))
+ {
+ setMarkerUnits(userSpaceOnUse);
+ }
+ }
+ break;
+ }
+ case SVGTokenMarkerWidth:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setMarkerWidth(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenMarkerHeight:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setMarkerHeight(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenOrient:
+ {
+ const sal_Int32 nLen(aContent.getLength());
+
+ if(nLen)
+ {
+ static rtl::OUString aStrAuto(rtl::OUString::createFromAscii("auto"));
+
+ if(aContent.match(aStrAuto, 0))
+ {
+ setOrientAuto(true);
+ }
+ else
+ {
+ sal_Int32 nPos(0);
+ double fAngle(0.0);
+
+ if(readAngle(aContent, nPos, fAngle, nLen))
+ {
+ setAngle(fAngle);
+ }
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ const drawinglayer::primitive2d::Primitive2DSequence& SvgMarkerNode::getMarkerPrimitives() const
+ {
+ if(!aPrimitives.hasElements())
+ {
+ decomposeSvgNode(const_cast< SvgMarkerNode* >(this)->aPrimitives, true);
+ }
+
+ return aPrimitives;
+ }
+
+ const basegfx::B2DRange* SvgMarkerNode::getCurrentViewPort() const
+ {
+ if(getViewBox())
+ {
+ return getViewBox();
+ }
+ else
+ {
+ return SvgNode::getCurrentViewPort();
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgmasknode.cxx b/svgio/source/svgreader/svgmasknode.cxx
new file mode 100644
index 000000000000..bc1ac3243e85
--- /dev/null
+++ b/svgio/source/svgreader/svgmasknode.cxx
@@ -0,0 +1,315 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgmasknode.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgMaskNode::SvgMaskNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenMask, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ maX(SvgNumber(-10.0, Unit_percent, true)),
+ maY(SvgNumber(-10.0, Unit_percent, true)),
+ maWidth(SvgNumber(120.0, Unit_percent, true)),
+ maHeight(SvgNumber(120.0, Unit_percent, true)),
+ mpaTransform(0),
+ maMaskUnits(objectBoundingBox),
+ maMaskContentUnits(userSpaceOnUse)
+ {
+ }
+
+ SvgMaskNode::~SvgMaskNode()
+ {
+ if(mpaTransform) delete mpaTransform;
+ }
+
+ const SvgStyleAttributes* SvgMaskNode::getSvgStyleAttributes() const
+ {
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgMaskNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenX:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setX(aNum);
+ }
+ break;
+ }
+ case SVGTokenY:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setY(aNum);
+ }
+ break;
+ }
+ case SVGTokenWidth:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setWidth(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenHeight:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setHeight(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenTransform:
+ {
+ const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
+
+ if(!aMatrix.isIdentity())
+ {
+ setTransform(&aMatrix);
+ }
+ break;
+ }
+ case SVGTokenMaskUnits:
+ {
+ if(aContent.getLength())
+ {
+ if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0))
+ {
+ setMaskUnits(userSpaceOnUse);
+ }
+ else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0))
+ {
+ setMaskUnits(objectBoundingBox);
+ }
+ }
+ break;
+ }
+ case SVGTokenMaskContentUnits:
+ {
+ if(aContent.getLength())
+ {
+ if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0))
+ {
+ setMaskContentUnits(userSpaceOnUse);
+ }
+ else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0))
+ {
+ setMaskContentUnits(objectBoundingBox);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgMaskNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const
+ {
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ // decompose childs
+ SvgNode::decomposeSvgNode(aNewTarget, bReferenced);
+
+ if(aNewTarget.hasElements())
+ {
+ if(getTransform())
+ {
+ // create embedding group element with transformation
+ const drawinglayer::primitive2d::Primitive2DReference xRef(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ *getTransform(),
+ aNewTarget));
+
+ aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
+ }
+
+ // append to current target
+ drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget);
+ }
+ }
+
+ void SvgMaskNode::apply(drawinglayer::primitive2d::Primitive2DSequence& rTarget) const
+ {
+ if(rTarget.hasElements())
+ {
+ drawinglayer::primitive2d::Primitive2DSequence aMaskTarget;
+
+ // get mask definition as primitives
+ decomposeSvgNode(aMaskTarget, true);
+
+ if(aMaskTarget.hasElements())
+ {
+ // get range of content to be masked
+ const basegfx::B2DRange aContentRange(
+ drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
+ rTarget,
+ drawinglayer::geometry::ViewInformation2D()));
+ const double fContentWidth(aContentRange.getWidth());
+ const double fContentHeight(aContentRange.getHeight());
+
+ if(fContentWidth > 0.0 && fContentHeight > 0.0)
+ {
+ // create OffscreenBufferRange
+ basegfx::B2DRange aOffscreenBufferRange;
+
+ if(objectBoundingBox == getMaskUnits())
+ {
+ // fractions or percentages of the bounding box of the element to which the mask is applied
+ const double fX(Unit_percent == getX().getUnit() ? getX().getNumber() * 0.01 : getX().getNumber());
+ const double fY(Unit_percent == getY().getUnit() ? getY().getNumber() * 0.01 : getY().getNumber());
+ const double fW(Unit_percent == getWidth().getUnit() ? getWidth().getNumber() * 0.01 : getWidth().getNumber());
+ const double fH(Unit_percent == getHeight().getUnit() ? getHeight().getNumber() * 0.01 : getHeight().getNumber());
+
+ aOffscreenBufferRange = basegfx::B2DRange(
+ aContentRange.getMinX() + (fX * fContentWidth),
+ aContentRange.getMinY() + (fY * fContentHeight),
+ aContentRange.getMinX() + ((fX + fW) * fContentWidth),
+ aContentRange.getMinY() + ((fY + fH) * fContentHeight));
+ }
+ else
+ {
+ const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0);
+ const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0);
+
+ aOffscreenBufferRange = basegfx::B2DRange(
+ fX,
+ fY,
+ fX + (getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : 0.0),
+ fY + (getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : 0.0));
+ }
+
+ if(objectBoundingBox == getMaskContentUnits())
+ {
+ // mask is object-relative, embed in content transformation
+ const drawinglayer::primitive2d::Primitive2DReference xTransform(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ basegfx::tools::createScaleTranslateB2DHomMatrix(
+ aContentRange.getRange(),
+ aContentRange.getMinimum()),
+ aMaskTarget));
+
+ aMaskTarget = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1);
+ }
+
+ // embed content to a ModifiedColorPrimitive2D since the definitions
+ // how content is used as alpha is special for Svg
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xInverseMask(
+ new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
+ aMaskTarget,
+ basegfx::BColorModifier(
+ basegfx::BColor(0.0, 0.0, 0.0),
+ 0.5,
+ basegfx::BCOLORMODIFYMODE_LUMINANCE_TO_ALPHA)));
+
+ aMaskTarget = drawinglayer::primitive2d::Primitive2DSequence(&xInverseMask, 1);
+ }
+
+ // prepare new content
+ drawinglayer::primitive2d::Primitive2DReference xNewContent(
+ new drawinglayer::primitive2d::TransparencePrimitive2D(
+ rTarget,
+ aMaskTarget));
+
+ // output up to now is defined by aContentRange and mask is oriented
+ // relative to it. It is possible that aOffscreenBufferRange defines
+ // a smaller area. In that case, embed to a mask primitive
+ if(!aOffscreenBufferRange.isInside(aContentRange))
+ {
+ xNewContent = new drawinglayer::primitive2d::MaskPrimitive2D(
+ basegfx::B2DPolyPolygon(
+ basegfx::tools::createPolygonFromRect(
+ aOffscreenBufferRange)),
+ drawinglayer::primitive2d::Primitive2DSequence(&xNewContent, 1));
+ }
+
+ // redefine target. Use TransparencePrimitive2D with created mask
+ // geometry
+ rTarget = drawinglayer::primitive2d::Primitive2DSequence(&xNewContent, 1);
+ }
+ else
+ {
+ // content is geometrically empty
+ rTarget.realloc(0);
+ }
+ }
+ else
+ {
+ // An empty clipping path will completely clip away the element that had
+ // the ‘clip-path’ property applied. (Svg spec)
+ rTarget.realloc(0);
+ }
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgnode.cxx b/svgio/source/svgreader/svgnode.cxx
new file mode 100644
index 000000000000..74f29909e110
--- /dev/null
+++ b/svgio/source/svgreader/svgnode.cxx
@@ -0,0 +1,289 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgnode.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svgio/svgreader/svgdocument.hxx>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ const SvgStyleAttributes* SvgNode::getSvgStyleAttributes() const
+ {
+ return 0;
+ }
+
+ SvgNode::SvgNode(
+ SVGToken aType,
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : maType(aType),
+ mrDocument(rDocument),
+ mpParent(pParent),
+ mpAlternativeParent(0),
+ maChildren(),
+ mpId(0),
+ mpClass(0),
+ maXmlSpace(XmlSpace_notset)
+ {
+ OSL_ENSURE(SVGTokenUnknown != maType, "SvgNode with unknown type created (!)");
+
+ if(pParent)
+ {
+ pParent->maChildren.push_back(this);
+ }
+ else
+ {
+#ifdef DBG_UTIL
+ if(SVGTokenSvg != getType())
+ {
+ OSL_ENSURE(false, "No parent for this node (!)");
+ }
+#endif
+ }
+ }
+
+ SvgNode::~SvgNode()
+ {
+ while(maChildren.size())
+ {
+ delete maChildren[maChildren.size() - 1];
+ maChildren.pop_back();
+ }
+
+ if(mpId) delete mpId;
+ if(mpClass) delete mpClass;
+ }
+
+ void SvgNode::parseAttributes(const com::sun::star::uno::Reference< com::sun::star::xml::sax::XAttributeList >& xAttribs)
+ {
+ const sal_uInt32 nAttributes(xAttribs->getLength());
+
+ for(sal_uInt32 a(0); a < nAttributes; a++)
+ {
+ const ::rtl::OUString aTokenName(xAttribs->getNameByIndex(a));
+
+ parseAttribute(aTokenName, StrToSVGToken(aTokenName), xAttribs->getValueByIndex(a));
+ }
+ }
+
+ void SvgNode::parseAttribute(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ switch(aSVGToken)
+ {
+ case SVGTokenId:
+ {
+ if(aContent.getLength())
+ {
+ setId(&aContent);
+ }
+ break;
+ }
+ case SVGTokenClass:
+ {
+ if(aContent.getLength())
+ {
+ setClass(&aContent);
+ }
+ break;
+ }
+ case SVGTokenXmlSpace:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrDefault(rtl::OUString::createFromAscii("default"));
+ static rtl::OUString aStrPreserve(rtl::OUString::createFromAscii("preserve"));
+
+ if(aContent.match(aStrDefault))
+ {
+ setXmlSpace(XmlSpace_default);
+ }
+ else if(aContent.match(aStrPreserve))
+ {
+ setXmlSpace(XmlSpace_preserve);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const
+ {
+ if(!bReferenced)
+ {
+ if(SVGTokenDefs == getType() ||
+ SVGTokenSymbol == getType() ||
+ SVGTokenClipPathNode == getType() ||
+ SVGTokenMask == getType() ||
+ SVGTokenMarker == getType() ||
+ SVGTokenPattern == getType())
+ {
+ // do not decompose defs or symbol nodes (these hold only style-like
+ // objects which may be used by referencing them) except when doing
+ // so controlled referenced
+
+ // also do not decompose ClipPaths and Masks. These should be embedded
+ // in a defs node (which gets not decomposed by itself), but you never
+ // know
+
+ // also not directly used are Markers and Patterns, only indirecty used
+ // by reference
+ return;
+ }
+ }
+
+ const SvgNodeVector& rChildren = getChildren();
+
+ if(!rChildren.empty())
+ {
+ const sal_uInt32 nCount(rChildren.size());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ SvgNode* pCandidate = rChildren[a];
+
+ if(pCandidate)
+ {
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ pCandidate->decomposeSvgNode(aNewTarget, bReferenced);
+
+ if(aNewTarget.hasElements())
+ {
+ drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget);
+ }
+ }
+ else
+ {
+ OSL_ENSURE(false, "Null-Pointer in child node list (!)");
+ }
+ }
+ }
+ }
+
+ const basegfx::B2DRange* SvgNode::getCurrentViewPort() const
+ {
+ if(getParent())
+ {
+ return getParent()->getCurrentViewPort();
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ double SvgNode::getCurrentFontSize() const
+ {
+ if(getSvgStyleAttributes())
+ {
+ return getSvgStyleAttributes()->getFontSize().solve(*this, xcoordinate);
+ }
+ else if(getParent())
+ {
+ return getParent()->getCurrentFontSize();
+ }
+ else
+ {
+ return 0.0;
+ }
+ }
+
+ double SvgNode::getCurrentXHeight() const
+ {
+ if(getSvgStyleAttributes())
+ {
+ // for XHeight, use FontSize currently
+ return getSvgStyleAttributes()->getFontSize().solve(*this, ycoordinate);
+ }
+ else if(getParent())
+ {
+ return getParent()->getCurrentXHeight();
+ }
+ else
+ {
+ return 0.0;
+ }
+ }
+
+ void SvgNode::setId(const rtl::OUString* pfId)
+ {
+ if(mpId)
+ {
+ mrDocument.removeSvgNodeFromMapper(*mpId);
+ delete mpId;
+ mpId = 0;
+ }
+
+ if(pfId)
+ {
+ mpId = new rtl::OUString(*pfId);
+ mrDocument.addSvgNodeToMapper(*mpId, *this);
+ }
+ }
+
+ void SvgNode::setClass(const rtl::OUString* pfClass)
+ {
+ if(mpClass)
+ {
+ mrDocument.removeSvgNodeFromMapper(*mpClass);
+ delete mpClass;
+ mpClass = 0;
+ }
+
+ if(pfClass)
+ {
+ mpClass = new rtl::OUString(*pfClass);
+ mrDocument.addSvgNodeToMapper(*mpClass, *this);
+ }
+ }
+
+ XmlSpace SvgNode::getXmlSpace() const
+ {
+ if(maXmlSpace != XmlSpace_notset)
+ {
+ return maXmlSpace;
+ }
+
+ if(getParent())
+ {
+ return getParent()->getXmlSpace();
+ }
+
+ // default is XmlSpace_default
+ return XmlSpace_default;
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgpaint.cxx b/svgio/source/svgreader/svgpaint.cxx
new file mode 100644
index 000000000000..91c721236441
--- /dev/null
+++ b/svgio/source/svgreader/svgpaint.cxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgpaint.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgpathnode.cxx b/svgio/source/svgreader/svgpathnode.cxx
new file mode 100644
index 000000000000..cd66017a5765
--- /dev/null
+++ b/svgio/source/svgreader/svgpathnode.cxx
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgpathnode.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgPathNode::SvgPathNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenPath, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ mpPolyPolygon(0),
+ mpaTransform(0),
+ maPathLength()
+ {
+ }
+
+ SvgPathNode::~SvgPathNode()
+ {
+ if(mpPolyPolygon) delete mpPolyPolygon;
+ if(mpaTransform) delete mpaTransform;
+ }
+
+ const SvgStyleAttributes* SvgPathNode::getSvgStyleAttributes() const
+ {
+ static rtl::OUString aClassStr(rtl::OUString::createFromAscii("path"));
+ maSvgStyleAttributes.checkForCssStyle(aClassStr);
+
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgPathNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenD:
+ {
+ basegfx::B2DPolyPolygon aPath;
+
+ if(basegfx::tools::importFromSvgD(aPath, aContent))
+ {
+ if(aPath.count())
+ {
+ setPath(&aPath);
+ }
+ }
+ break;
+ }
+ case SVGTokenTransform:
+ {
+ const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
+
+ if(!aMatrix.isIdentity())
+ {
+ setTransform(&aMatrix);
+ }
+ break;
+ }
+ case SVGTokenPathLength:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setPathLength(aNum);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgPathNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const
+ {
+ // fill and/or stroke needed, also a path
+ const SvgStyleAttributes* pStyle = getSvgStyleAttributes();
+
+ if(pStyle && getPath())
+ {
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ pStyle->add_path(*getPath(), aNewTarget);
+
+ if(aNewTarget.hasElements())
+ {
+ pStyle->add_postProcess(rTarget, aNewTarget, getTransform());
+ }
+ }
+ }
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgpatternnode.cxx b/svgio/source/svgreader/svgpatternnode.cxx
new file mode 100644
index 000000000000..6aa7a7cd63a3
--- /dev/null
+++ b/svgio/source/svgreader/svgpatternnode.cxx
@@ -0,0 +1,463 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgpatternnode.hxx>
+#include <svgio/svgreader/svgdocument.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ void SvgPatternNode::tryToFindLink()
+ {
+ if(!mpXLink && maXLink.getLength())
+ {
+ mpXLink = dynamic_cast< const SvgPatternNode* >(getDocument().findSvgNodeById(maXLink));
+ }
+ }
+
+ SvgPatternNode::SvgPatternNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenPattern, rDocument, pParent),
+ aPrimitives(),
+ maSvgStyleAttributes(*this),
+ mpViewBox(0),
+ maSvgAspectRatio(),
+ maX(),
+ maY(),
+ maWidth(),
+ maHeight(),
+ mpPatternUnits(0),
+ mpPatternContentUnits(0),
+ mpaPatternTransform(0),
+ maXLink(),
+ mpXLink(0)
+ {
+ }
+
+ SvgPatternNode::~SvgPatternNode()
+ {
+ if(mpViewBox) delete mpViewBox;
+ if(mpaPatternTransform) delete mpaPatternTransform;
+ if(mpPatternUnits) delete mpPatternUnits;
+ if(mpPatternContentUnits) delete mpPatternContentUnits;
+ }
+
+ const SvgStyleAttributes* SvgPatternNode::getSvgStyleAttributes() const
+ {
+ static rtl::OUString aClassStr(rtl::OUString::createFromAscii("pattern"));
+ maSvgStyleAttributes.checkForCssStyle(aClassStr);
+
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgPatternNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenViewBox:
+ {
+ const basegfx::B2DRange aRange(readViewBox(aContent, *this));
+
+ if(!aRange.isEmpty())
+ {
+ setViewBox(&aRange);
+ }
+ break;
+ }
+ case SVGTokenPreserveAspectRatio:
+ {
+ setSvgAspectRatio(readSvgAspectRatio(aContent));
+ break;
+ }
+ case SVGTokenX:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setX(aNum);
+ }
+ break;
+ }
+ case SVGTokenY:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setY(aNum);
+ }
+ break;
+ }
+ case SVGTokenWidth:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setWidth(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenHeight:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setHeight(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenPatternUnits:
+ {
+ if(aContent.getLength())
+ {
+ if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0))
+ {
+ setPatternUnits(userSpaceOnUse);
+ }
+ else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0))
+ {
+ setPatternUnits(objectBoundingBox);
+ }
+ }
+ break;
+ }
+ case SVGTokenPatternContentUnits:
+ {
+ if(aContent.getLength())
+ {
+ if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0))
+ {
+ setPatternContentUnits(userSpaceOnUse);
+ }
+ else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0))
+ {
+ setPatternContentUnits(objectBoundingBox);
+ }
+ }
+ break;
+ }
+ case SVGTokenPatternTransform:
+ {
+ const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
+
+ if(!aMatrix.isIdentity())
+ {
+ setPatternTransform(&aMatrix);
+ }
+ break;
+ }
+ case SVGTokenXlinkHref:
+ {
+ const sal_Int32 nLen(aContent.getLength());
+
+ if(nLen && sal_Unicode('#') == aContent[0])
+ {
+ maXLink = aContent.copy(1);
+ tryToFindLink();
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgPatternNode::getValuesRelative(double& rfX, double& rfY, double& rfW, double& rfH, const basegfx::B2DRange& rGeoRange, SvgNode& rUser) const
+ {
+ double fTargetWidth(rGeoRange.getWidth());
+ double fTargetHeight(rGeoRange.getHeight());
+
+ if(fTargetWidth > 0.0 && fTargetHeight > 0.0)
+ {
+ const SvgUnits aPatternUnits(getPatternUnits() ? *getPatternUnits() : objectBoundingBox);
+
+ if(objectBoundingBox == aPatternUnits)
+ {
+ rfW = (getWidth().isSet()) ? getWidth().getNumber() : 0.0;
+ rfH = (getHeight().isSet()) ? getHeight().getNumber() : 0.0;
+
+ if(Unit_percent == getWidth().getUnit())
+ {
+ rfW *= 0.01;
+ }
+
+ if(Unit_percent == getHeight().getUnit())
+ {
+ rfH *= 0.01;
+ }
+ }
+ else
+ {
+ rfW = (getWidth().isSet()) ? getWidth().solve(rUser, xcoordinate) : 0.0;
+ rfH = (getHeight().isSet()) ? getHeight().solve(rUser, ycoordinate) : 0.0;
+
+ // make relative to rGeoRange
+ rfW /= fTargetWidth;
+ rfH /= fTargetHeight;
+ }
+
+ if(rfW > 0.0 && rfH > 0.0)
+ {
+ if(objectBoundingBox == aPatternUnits)
+ {
+ rfX = (getX().isSet()) ? getX().getNumber() : 0.0;
+ rfY = (getY().isSet()) ? getY().getNumber() : 0.0;
+
+ if(Unit_percent == getX().getUnit())
+ {
+ rfX *= 0.01;
+ }
+
+ if(Unit_percent == getY().getUnit())
+ {
+ rfY *= 0.01;
+ }
+ }
+ else
+ {
+ rfX = (getX().isSet()) ? getX().solve(rUser, xcoordinate) : 0.0;
+ rfY = (getY().isSet()) ? getY().solve(rUser, ycoordinate) : 0.0;
+
+ // make relative to rGeoRange
+ rfX = (rfX - rGeoRange.getMinX()) / fTargetWidth;
+ rfY = (rfY - rGeoRange.getMinY()) / fTargetHeight;
+ }
+ }
+ }
+ }
+
+ const drawinglayer::primitive2d::Primitive2DSequence& SvgPatternNode::getPatternPrimitives() const
+ {
+ if(!aPrimitives.hasElements())
+ {
+ decomposeSvgNode(const_cast< SvgPatternNode* >(this)->aPrimitives, true);
+ }
+
+ if(!aPrimitives.hasElements() && maXLink.getLength())
+ {
+ const_cast< SvgPatternNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getPatternPrimitives();
+ }
+ }
+
+ return aPrimitives;
+ }
+
+ const basegfx::B2DRange* SvgPatternNode::getCurrentViewPort() const
+ {
+ if(getViewBox())
+ {
+ return getViewBox();
+ }
+ else
+ {
+ return SvgNode::getCurrentViewPort();
+ }
+ }
+
+ const basegfx::B2DRange* SvgPatternNode::getViewBox() const
+ {
+ if(mpViewBox)
+ {
+ return mpViewBox;
+ }
+
+ const_cast< SvgPatternNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getViewBox();
+ }
+
+ return 0;
+ }
+
+ const SvgAspectRatio& SvgPatternNode::getSvgAspectRatio() const
+ {
+ if(maSvgAspectRatio.isSet())
+ {
+ return maSvgAspectRatio;
+ }
+
+ const_cast< SvgPatternNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getSvgAspectRatio();
+ }
+
+ return maSvgAspectRatio;
+ }
+
+ const SvgNumber& SvgPatternNode::getX() const
+ {
+ if(maX.isSet())
+ {
+ return maX;
+ }
+
+ const_cast< SvgPatternNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getX();
+ }
+
+ return maX;
+ }
+
+ const SvgNumber& SvgPatternNode::getY() const
+ {
+ if(maY.isSet())
+ {
+ return maY;
+ }
+
+ const_cast< SvgPatternNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getY();
+ }
+
+ return maY;
+ }
+
+ const SvgNumber& SvgPatternNode::getWidth() const
+ {
+ if(maWidth.isSet())
+ {
+ return maWidth;
+ }
+
+ const_cast< SvgPatternNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getWidth();
+ }
+
+ return maWidth;
+ }
+
+ const SvgNumber& SvgPatternNode::getHeight() const
+ {
+ if(maHeight.isSet())
+ {
+ return maHeight;
+ }
+
+ const_cast< SvgPatternNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getHeight();
+ }
+
+ return maHeight;
+ }
+
+ const SvgUnits* SvgPatternNode::getPatternUnits() const
+ {
+ if(mpPatternUnits)
+ {
+ return mpPatternUnits;
+ }
+
+ const_cast< SvgPatternNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getPatternUnits();
+ }
+
+ return 0;
+ }
+
+ const SvgUnits* SvgPatternNode::getPatternContentUnits() const
+ {
+ if(mpPatternContentUnits)
+ {
+ return mpPatternContentUnits;
+ }
+
+ const_cast< SvgPatternNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getPatternContentUnits();
+ }
+
+ return 0;
+ }
+
+ const basegfx::B2DHomMatrix* SvgPatternNode::getPatternTransform() const
+ {
+ if(mpaPatternTransform)
+ {
+ return mpaPatternTransform;
+ }
+
+ const_cast< SvgPatternNode* >(this)->tryToFindLink();
+
+ if(mpXLink)
+ {
+ return mpXLink->getPatternTransform();
+ }
+
+ return 0;
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgpolynode.cxx b/svgio/source/svgreader/svgpolynode.cxx
new file mode 100644
index 000000000000..a814402d46f8
--- /dev/null
+++ b/svgio/source/svgreader/svgpolynode.cxx
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgpolynode.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgPolyNode::SvgPolyNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent,
+ bool bIsPolyline)
+ : SvgNode(SVGTokenPolygon, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ mpPolygon(0),
+ mpaTransform(0),
+ mbIsPolyline(bIsPolyline)
+ {
+ }
+
+ SvgPolyNode::~SvgPolyNode()
+ {
+ if(mpaTransform) delete mpaTransform;
+ if(mpPolygon) delete mpPolygon;
+ }
+
+ const SvgStyleAttributes* SvgPolyNode::getSvgStyleAttributes() const
+ {
+ static rtl::OUString aClassStrA(rtl::OUString::createFromAscii("polygon"));
+ static rtl::OUString aClassStrB(rtl::OUString::createFromAscii("polyline"));
+ maSvgStyleAttributes.checkForCssStyle(mbIsPolyline? aClassStrB : aClassStrA);
+
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgPolyNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenPoints:
+ {
+ basegfx::B2DPolygon aPath;
+
+ if(basegfx::tools::importFromSvgPoints(aPath, aContent))
+ {
+ if(aPath.count())
+ {
+ if(!isPolyline())
+ {
+ aPath.setClosed(true);
+ }
+
+ setPolygon(&aPath);
+ }
+ }
+ break;
+ }
+ case SVGTokenTransform:
+ {
+ const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
+
+ if(!aMatrix.isIdentity())
+ {
+ setTransform(&aMatrix);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgPolyNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const
+ {
+ const SvgStyleAttributes* pStyle = getSvgStyleAttributes();
+
+ if(pStyle && getPolygon())
+ {
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ pStyle->add_path(basegfx::B2DPolyPolygon(*getPolygon()), aNewTarget);
+
+ if(aNewTarget.hasElements())
+ {
+ pStyle->add_postProcess(rTarget, aNewTarget, getTransform());
+ }
+ }
+ }
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgrectnode.cxx b/svgio/source/svgreader/svgrectnode.cxx
new file mode 100644
index 000000000000..e826b8546f03
--- /dev/null
+++ b/svgio/source/svgreader/svgrectnode.cxx
@@ -0,0 +1,227 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgrectnode.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgRectNode::SvgRectNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenRect, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ maX(0),
+ maY(0),
+ maWidth(0),
+ maHeight(0),
+ maRx(0),
+ maRy(0),
+ mpaTransform(0)
+ {
+ }
+
+ SvgRectNode::~SvgRectNode()
+ {
+ if(mpaTransform) delete mpaTransform;
+ }
+
+ const SvgStyleAttributes* SvgRectNode::getSvgStyleAttributes() const
+ {
+ static rtl::OUString aClassStr(rtl::OUString::createFromAscii("rect"));
+ maSvgStyleAttributes.checkForCssStyle(aClassStr);
+
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgRectNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenX:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setX(aNum);
+ }
+ break;
+ }
+ case SVGTokenY:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setY(aNum);
+ }
+ break;
+ }
+ case SVGTokenWidth:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setWidth(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenHeight:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setHeight(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenRx:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setRx(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenRy:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setRy(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenTransform:
+ {
+ const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
+
+ if(!aMatrix.isIdentity())
+ {
+ setTransform(&aMatrix);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgRectNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const
+ {
+ // get size range and create path
+ const SvgStyleAttributes* pStyle = getSvgStyleAttributes();
+
+ if(pStyle && getWidth().isSet() && getHeight().isSet())
+ {
+ const double fWidth(getWidth().solve(*this, xcoordinate));
+ const double fHeight(getHeight().solve(*this, ycoordinate));
+
+ if(fWidth > 0.0 && fHeight > 0.0)
+ {
+ const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0);
+ const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0);
+ const basegfx::B2DRange aRange(fX, fY, fX + fWidth, fY + fHeight);
+ basegfx::B2DPolygon aPath;
+
+ if(getRx().isSet() || getRy().isSet())
+ {
+ double frX(getRx().isSet() ? getRx().solve(*this, xcoordinate) : 0.0);
+ double frY(getRy().isSet() ? getRy().solve(*this, ycoordinate) : 0.0);
+
+ frX = std::max(0.0, frX);
+ frY = std::max(0.0, frY);
+
+ if(0.0 == frY && frX > 0.0)
+ {
+ frY = frX;
+ }
+ else if(0.0 == frX && frY > 0.0)
+ {
+ frX = frY;
+ }
+
+ frX /= fWidth;
+ frY /= fHeight;
+
+ frX = std::min(0.5, frX);
+ frY = std::min(0.5, frY);
+
+ aPath = basegfx::tools::createPolygonFromRect(aRange, frX * 2.0, frY * 2.0);
+ }
+ else
+ {
+ aPath = basegfx::tools::createPolygonFromRect(aRange);
+ }
+
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget);
+
+ if(aNewTarget.hasElements())
+ {
+ pStyle->add_postProcess(rTarget, aNewTarget, getTransform());
+ }
+ }
+ }
+ }
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgstyleattributes.cxx b/svgio/source/svgreader/svgstyleattributes.cxx
new file mode 100644
index 000000000000..1a2755e52b1c
--- /dev/null
+++ b/svgio/source/svgreader/svgstyleattributes.cxx
@@ -0,0 +1,2489 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgstyleattributes.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgdocument.hxx>
+#include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
+#include <svgio/svgreader/svggradientnode.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <basegfx/vector/b2enums.hxx>
+#include <drawinglayer/processor2d/linegeometryextractor2d.hxx>
+#include <drawinglayer/processor2d/textaspolygonextractor2d.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+#include <svgio/svgreader/svgclippathnode.hxx>
+#include <svgio/svgreader/svgmasknode.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svgio/svgreader/svgmarkernode.hxx>
+#include <basegfx/curve/b2dcubicbezier.hxx>
+#include <svgio/svgreader/svgpatternnode.hxx>
+#include <drawinglayer/primitive2d/patternfillprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ basegfx::B2DLineJoin StrokeLinejoinToB2DLineJoin(StrokeLinejoin aStrokeLinejoin)
+ {
+ if(StrokeLinejoin_round == aStrokeLinejoin)
+ {
+ return basegfx::B2DLINEJOIN_ROUND;
+ }
+ else if(StrokeLinejoin_bevel == aStrokeLinejoin)
+ {
+ return basegfx::B2DLINEJOIN_BEVEL;
+ }
+
+ return basegfx::B2DLINEJOIN_MITER;
+ }
+
+ com::sun::star::drawing::LineCap StrokeLinecapToDrawingLineCap(StrokeLinecap aStrokeLinecap)
+ {
+ switch(aStrokeLinecap)
+ {
+ default: /* StrokeLinecap_notset, StrokeLinecap_butt */
+ {
+ return com::sun::star::drawing::LineCap_BUTT;
+ break;
+ }
+ case StrokeLinecap_round:
+ {
+ return com::sun::star::drawing::LineCap_ROUND;
+ break;
+ }
+ case StrokeLinecap_square:
+ {
+ return com::sun::star::drawing::LineCap_SQUARE;
+ break;
+ }
+ }
+ }
+
+ FontStretch getWider(FontStretch aSource)
+ {
+ switch(aSource)
+ {
+ case FontStretch_ultra_condensed: aSource = FontStretch_extra_condensed; break;
+ case FontStretch_extra_condensed: aSource = FontStretch_condensed; break;
+ case FontStretch_condensed: aSource = FontStretch_semi_condensed; break;
+ case FontStretch_semi_condensed: aSource = FontStretch_normal; break;
+ case FontStretch_normal: aSource = FontStretch_semi_expanded; break;
+ case FontStretch_semi_expanded: aSource = FontStretch_expanded; break;
+ case FontStretch_expanded: aSource = FontStretch_extra_expanded; break;
+ case FontStretch_extra_expanded: aSource = FontStretch_ultra_expanded; break;
+ default: break;
+ }
+
+ return aSource;
+ }
+
+ FontStretch getNarrower(FontStretch aSource)
+ {
+ switch(aSource)
+ {
+ case FontStretch_extra_condensed: aSource = FontStretch_ultra_condensed; break;
+ case FontStretch_condensed: aSource = FontStretch_extra_condensed; break;
+ case FontStretch_semi_condensed: aSource = FontStretch_condensed; break;
+ case FontStretch_normal: aSource = FontStretch_semi_condensed; break;
+ case FontStretch_semi_expanded: aSource = FontStretch_normal; break;
+ case FontStretch_expanded: aSource = FontStretch_semi_expanded; break;
+ case FontStretch_extra_expanded: aSource = FontStretch_expanded; break;
+ case FontStretch_ultra_expanded: aSource = FontStretch_extra_expanded; break;
+ default: break;
+ }
+
+ return aSource;
+ }
+
+ FontWeight getBolder(FontWeight aSource)
+ {
+ switch(aSource)
+ {
+ case FontWeight_100: aSource = FontWeight_200; break;
+ case FontWeight_200: aSource = FontWeight_300; break;
+ case FontWeight_300: aSource = FontWeight_400; break;
+ case FontWeight_400: aSource = FontWeight_500; break;
+ case FontWeight_500: aSource = FontWeight_600; break;
+ case FontWeight_600: aSource = FontWeight_700; break;
+ case FontWeight_700: aSource = FontWeight_800; break;
+ case FontWeight_800: aSource = FontWeight_900; break;
+ default: break;
+ }
+
+ return aSource;
+ }
+
+ FontWeight getLighter(FontWeight aSource)
+ {
+ switch(aSource)
+ {
+ case FontWeight_200: aSource = FontWeight_100; break;
+ case FontWeight_300: aSource = FontWeight_200; break;
+ case FontWeight_400: aSource = FontWeight_300; break;
+ case FontWeight_500: aSource = FontWeight_400; break;
+ case FontWeight_600: aSource = FontWeight_500; break;
+ case FontWeight_700: aSource = FontWeight_600; break;
+ case FontWeight_800: aSource = FontWeight_700; break;
+ case FontWeight_900: aSource = FontWeight_800; break;
+ default: break;
+ }
+
+ return aSource;
+ }
+
+ ::FontWeight getVclFontWeight(FontWeight aSource)
+ {
+ ::FontWeight nRetval(WEIGHT_NORMAL);
+
+ switch(aSource)
+ {
+ case FontWeight_100: nRetval = WEIGHT_ULTRALIGHT; break;
+ case FontWeight_200: nRetval = WEIGHT_LIGHT; break;
+ case FontWeight_300: nRetval = WEIGHT_SEMILIGHT; break;
+ case FontWeight_400: nRetval = WEIGHT_NORMAL; break;
+ case FontWeight_500: nRetval = WEIGHT_MEDIUM; break;
+ case FontWeight_600: nRetval = WEIGHT_SEMIBOLD; break;
+ case FontWeight_700: nRetval = WEIGHT_BOLD; break;
+ case FontWeight_800: nRetval = WEIGHT_ULTRABOLD; break;
+ case FontWeight_900: nRetval = WEIGHT_BLACK; break;
+ default: break;
+ }
+
+ return nRetval;
+ }
+
+ void SvgStyleAttributes::readStyle(const rtl::OUString& rCandidate)
+ {
+ const sal_Int32 nLen(rCandidate.getLength());
+ sal_Int32 nPos(0);
+
+ while(nPos < nLen)
+ {
+ const sal_Int32 nInitPos(nPos);
+ skip_char(rCandidate, sal_Unicode(' '), nPos, nLen);
+ rtl::OUStringBuffer aTokenName;
+ copyString(rCandidate, nPos, aTokenName, nLen);
+
+ if(aTokenName.getLength())
+ {
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(':'), nPos, nLen);
+ rtl::OUStringBuffer aTokenValue;
+ copyToLimiter(rCandidate, sal_Unicode(';'), nPos, aTokenValue, nLen);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(';'), nPos, nLen);
+ const rtl::OUString aOUTokenName(aTokenName.makeStringAndClear());
+ const rtl::OUString aOUTokenValue(aTokenValue.makeStringAndClear());
+
+ parseStyleAttribute(aOUTokenName, StrToSVGToken(aOUTokenName), aOUTokenValue);
+ }
+
+ if(nInitPos == nPos)
+ {
+ OSL_ENSURE(false, "Could not interpret on current position (!)");
+ nPos++;
+ }
+ }
+ }
+
+ void SvgStyleAttributes::checkForCssStyle(const rtl::OUString& rClassStr) const
+ {
+ if(!mpCssStyleParent)
+ {
+ const SvgDocument& rDocument = mrOwner.getDocument();
+ const SvgStyleAttributes* pNew = 0;
+
+ if(rDocument.hasSvgStyleAttributesById())
+ {
+ if(mrOwner.getClass())
+ {
+ rtl::OUString aId(rtl::OUString::createFromAscii("."));
+ aId = aId + *mrOwner.getClass();
+ pNew = rDocument.findSvgStyleAttributesById(aId);
+
+ if(!pNew && rClassStr.getLength())
+ {
+ aId = rClassStr + aId;
+
+ pNew = rDocument.findSvgStyleAttributesById(aId);
+ }
+ }
+
+ if(!pNew && mrOwner.getId())
+ {
+ pNew = rDocument.findSvgStyleAttributesById(*mrOwner.getId());
+ }
+
+ if(!pNew && rClassStr.getLength())
+ {
+ pNew = rDocument.findSvgStyleAttributesById(rClassStr);
+ }
+
+ if(pNew)
+ {
+ // found css style, set as parent
+ const_cast< SvgStyleAttributes* >(this)->mpCssStyleParent = pNew;
+ }
+ }
+ }
+ }
+
+ const SvgStyleAttributes* SvgStyleAttributes::getParentStyle() const
+ {
+ if(mpCssStyleParent)
+ {
+ return mpCssStyleParent;
+ }
+
+ if(mrOwner.getParent())
+ {
+ return mrOwner.getParent()->getSvgStyleAttributes();
+ }
+
+ return 0;
+ }
+
+ void SvgStyleAttributes::add_text(
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ drawinglayer::primitive2d::Primitive2DSequence& rSource) const
+ {
+ if(rSource.hasElements())
+ {
+ // at this point the primitives in rSource are of type TextSimplePortionPrimitive2D
+ // or TextDecoratedPortionPrimitive2D and have the Fill Color (pAttributes->getFill())
+ // set. When another fill is used and also evtl. stroke is set it gets necessary to
+ // dismantle to geometry and add needed primitives
+ const basegfx::BColor* pFill = getFill();
+ const SvgGradientNode* pFillGradient = getSvgGradientNodeFill();
+ const SvgPatternNode* pFillPattern = getSvgPatternNodeFill();
+ const basegfx::BColor* pStroke = getStroke();
+ const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke();
+ const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke();
+ basegfx::B2DPolyPolygon aMergedArea;
+
+ if(pFillGradient || pFillPattern || pStroke || pStrokeGradient || pStrokePattern)
+ {
+ // text geometry is needed, create
+ // use neutral ViewInformation and create LineGeometryExtractor2D
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D);
+
+ // proccess
+ aExtractor.process(rSource);
+
+ // get results
+ const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget();
+ const sal_uInt32 nResultCount(rResult.size());
+ basegfx::B2DPolyPolygonVector aTextFillVector;
+ aTextFillVector.reserve(nResultCount);
+
+ for(sal_uInt32 a(0); a < nResultCount; a++)
+ {
+ const drawinglayer::processor2d::TextAsPolygonDataNode& rCandidate = rResult[a];
+
+ if(rCandidate.getIsFilled())
+ {
+ aTextFillVector.push_back(rCandidate.getB2DPolyPolygon());
+ }
+ }
+
+ if(!aTextFillVector.empty())
+ {
+ aMergedArea = basegfx::tools::mergeToSinglePolyPolygon(aTextFillVector);
+ }
+ }
+
+ const bool bStrokeUsed(pStroke || pStrokeGradient || pStrokePattern);
+
+ // add fill. Use geometry even for simple color fill when stroke
+ // is used, else text rendering and the geometry-based stroke will
+ // normally not really match optically due to divrese system text
+ // renderers
+ if(aMergedArea.count() && (pFillGradient || pFillPattern || bStrokeUsed))
+ {
+ // create text fill content based on geometry
+ add_fill(aMergedArea, rTarget, aMergedArea.getB2DRange());
+ }
+ else if(pFill)
+ {
+ // add the already prepared primitives for single color fill
+ drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, rSource);
+ }
+
+ // add stroke
+ if(aMergedArea.count() && bStrokeUsed)
+ {
+ // create text stroke content
+ add_stroke(aMergedArea, rTarget, aMergedArea.getB2DRange());
+ }
+ }
+ }
+
+ void SvgStyleAttributes::add_fillGradient(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const SvgGradientNode& rFillGradient,
+ const basegfx::B2DRange& rGeoRange) const
+ {
+ // create fill content
+ drawinglayer::primitive2d::SvgGradientEntryVector aSvgGradientEntryVector;
+
+ // get the color stops
+ rFillGradient.collectGradientEntries(aSvgGradientEntryVector);
+
+ if(!aSvgGradientEntryVector.empty())
+ {
+ basegfx::B2DHomMatrix aGeoToUnit;
+
+ if(rFillGradient.getGradientTransform())
+ {
+ aGeoToUnit = *rFillGradient.getGradientTransform();
+ }
+
+ if(userSpaceOnUse == rFillGradient.getGradientUnits())
+ {
+ aGeoToUnit.translate(-rGeoRange.getMinX(), -rGeoRange.getMinY());
+ aGeoToUnit.scale(1.0 / rGeoRange.getWidth(), 1.0 / rGeoRange.getHeight());
+ }
+
+ if(SVGTokenLinearGradient == rFillGradient.getType())
+ {
+ basegfx::B2DPoint aStart(0.0, 0.0);
+ basegfx::B2DPoint aEnd(1.0, 0.0);
+
+ if(userSpaceOnUse == rFillGradient.getGradientUnits())
+ {
+ // all possible units
+ aStart.setX(rFillGradient.getX1().solve(mrOwner, xcoordinate));
+ aStart.setY(rFillGradient.getY1().solve(mrOwner, ycoordinate));
+ aEnd.setX(rFillGradient.getX2().solve(mrOwner, xcoordinate));
+ aEnd.setY(rFillGradient.getY2().solve(mrOwner, ycoordinate));
+ }
+ else
+ {
+ // fractions or percent relative to object bounds
+ const SvgNumber X1(rFillGradient.getX1());
+ const SvgNumber Y1(rFillGradient.getY1());
+ const SvgNumber X2(rFillGradient.getX2());
+ const SvgNumber Y2(rFillGradient.getY2());
+
+ aStart.setX(Unit_percent == X1.getUnit() ? X1.getNumber() * 0.01 : X1.getNumber());
+ aStart.setY(Unit_percent == Y1.getUnit() ? Y1.getNumber() * 0.01 : Y1.getNumber());
+ aEnd.setX(Unit_percent == X2.getUnit() ? X2.getNumber() * 0.01 : X2.getNumber());
+ aEnd.setY(Unit_percent == Y2.getUnit() ? Y2.getNumber() * 0.01 : Y2.getNumber());
+ }
+
+ if(!aGeoToUnit.isIdentity())
+ {
+ aStart *= aGeoToUnit;
+ aEnd *= aGeoToUnit;
+ }
+
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
+ rTarget,
+ new drawinglayer::primitive2d::SvgLinearGradientPrimitive2D(
+ rPath,
+ aSvgGradientEntryVector,
+ aStart,
+ aEnd,
+ rFillGradient.getSpreadMethod()));
+ }
+ else
+ {
+ basegfx::B2DPoint aStart(0.5, 0.5);
+ basegfx::B2DPoint aFocal;
+ double fRadius(0.5);
+ const SvgNumber* pFx = rFillGradient.getFx();
+ const SvgNumber* pFy = rFillGradient.getFy();
+ const bool bFocal(pFx || pFy);
+
+ if(userSpaceOnUse == rFillGradient.getGradientUnits())
+ {
+ // all possible units
+ aStart.setX(rFillGradient.getCx().solve(mrOwner, xcoordinate));
+ aStart.setY(rFillGradient.getCy().solve(mrOwner, ycoordinate));
+ fRadius = rFillGradient.getR().solve(mrOwner, length);
+
+ if(bFocal)
+ {
+ aFocal.setX(pFx ? pFx->solve(mrOwner, xcoordinate) : aStart.getX());
+ aFocal.setY(pFy ? pFy->solve(mrOwner, ycoordinate) : aStart.getY());
+ }
+ }
+ else
+ {
+ // fractions or percent relative to object bounds
+ const SvgNumber Cx(rFillGradient.getCx());
+ const SvgNumber Cy(rFillGradient.getCy());
+ const SvgNumber R(rFillGradient.getR());
+
+ aStart.setX(Unit_percent == Cx.getUnit() ? Cx.getNumber() * 0.01 : Cx.getNumber());
+ aStart.setY(Unit_percent == Cy.getUnit() ? Cy.getNumber() * 0.01 : Cy.getNumber());
+ fRadius = (Unit_percent == R.getUnit()) ? R.getNumber() * 0.01 : R.getNumber();
+
+ if(bFocal)
+ {
+ aFocal.setX(pFx ? (Unit_percent == pFx->getUnit() ? pFx->getNumber() * 0.01 : pFx->getNumber()) : aStart.getX());
+ aFocal.setY(pFy ? (Unit_percent == pFy->getUnit() ? pFy->getNumber() * 0.01 : pFy->getNumber()) : aStart.getY());
+ }
+ }
+
+ if(!aGeoToUnit.isIdentity())
+ {
+ aStart *= aGeoToUnit;
+ fRadius = (aGeoToUnit * basegfx::B2DVector(fRadius, 0.0)).getLength();
+
+ if(bFocal)
+ {
+ aFocal *= aGeoToUnit;
+ }
+ }
+
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
+ rTarget,
+ new drawinglayer::primitive2d::SvgRadialGradientPrimitive2D(
+ rPath,
+ aSvgGradientEntryVector,
+ aStart,
+ fRadius,
+ rFillGradient.getSpreadMethod(),
+ bFocal ? &aFocal : 0));
+ }
+ }
+ }
+
+ void SvgStyleAttributes::add_fillPatternTransform(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const SvgPatternNode& rFillPattern,
+ const basegfx::B2DRange& rGeoRange) const
+ {
+ // prepare fill polyPolygon with given pattern, check for patternTransform
+ if(rFillPattern.getPatternTransform() && !rFillPattern.getPatternTransform()->isIdentity())
+ {
+ // PatternTransform is active; Handle by filling the inverse transformed
+ // path and back-transforming the result
+ basegfx::B2DPolyPolygon aPath(rPath);
+ basegfx::B2DHomMatrix aInv(*rFillPattern.getPatternTransform());
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ aInv.invert();
+ aPath.transform(aInv);
+ add_fillPattern(aPath, aNewTarget, rFillPattern, aPath.getB2DRange());
+
+ if(aNewTarget.hasElements())
+ {
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
+ rTarget,
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ *rFillPattern.getPatternTransform(),
+ aNewTarget));
+ }
+ }
+ else
+ {
+ // no patternTransform, create fillPattern directly
+ add_fillPattern(rPath, rTarget, rFillPattern, rGeoRange);
+ }
+ }
+
+ void SvgStyleAttributes::add_fillPattern(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const SvgPatternNode& rFillPattern,
+ const basegfx::B2DRange& rGeoRange) const
+ {
+ // fill polyPolygon with given pattern
+ const drawinglayer::primitive2d::Primitive2DSequence& rPrimitives = rFillPattern.getPatternPrimitives();
+
+ if(rPrimitives.hasElements())
+ {
+ double fTargetWidth(rGeoRange.getWidth());
+ double fTargetHeight(rGeoRange.getHeight());
+
+ if(fTargetWidth > 0.0 && fTargetHeight > 0.0)
+ {
+ // get relative values from pattern
+ double fX(0.0);
+ double fY(0.0);
+ double fW(0.0);
+ double fH(0.0);
+
+ rFillPattern.getValuesRelative(fX, fY, fW, fH, rGeoRange, mrOwner);
+
+ if(fW > 0.0 && fH > 0.0)
+ {
+ // build the reference range relative to the rGeoRange
+ const basegfx::B2DRange aReferenceRange(fX, fY, fX + fW, fY + fH);
+
+ // find out how the content is mapped to the reference range
+ basegfx::B2DHomMatrix aMapPrimitivesToUnitRange;
+ const basegfx::B2DRange* pViewBox = rFillPattern.getViewBox();
+
+ if(pViewBox)
+ {
+ // use viewBox/preserveAspectRatio
+ const SvgAspectRatio& rRatio = rFillPattern.getSvgAspectRatio();
+ const basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
+
+ if(rRatio.isSet())
+ {
+ // let mapping be created from SvgAspectRatio
+ aMapPrimitivesToUnitRange = rRatio.createMapping(aUnitRange, *pViewBox);
+ }
+ else
+ {
+ // choose default mapping
+ aMapPrimitivesToUnitRange = rRatio.createLinearMapping(aUnitRange, *pViewBox);
+ }
+ }
+ else
+ {
+ // use patternContentUnits
+ const SvgUnits aPatternContentUnits(rFillPattern.getPatternContentUnits() ? *rFillPattern.getPatternContentUnits() : userSpaceOnUse);
+
+ if(userSpaceOnUse == aPatternContentUnits)
+ {
+ // create relative mapping to unit coordinates
+ aMapPrimitivesToUnitRange.scale(1.0 / (fW * fTargetWidth), 1.0 / (fH * fTargetHeight));
+ }
+ else
+ {
+ aMapPrimitivesToUnitRange.scale(1.0 / fW, 1.0 / fH);
+ }
+ }
+
+ // apply aMapPrimitivesToUnitRange to content when used
+ drawinglayer::primitive2d::Primitive2DSequence aPrimitives(rPrimitives);
+
+ if(!aMapPrimitivesToUnitRange.isIdentity())
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xRef(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aMapPrimitivesToUnitRange,
+ aPrimitives));
+
+ aPrimitives = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
+ }
+
+ // embed in PatternFillPrimitive2D
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
+ rTarget,
+ new drawinglayer::primitive2d::PatternFillPrimitive2D(
+ rPath,
+ aPrimitives,
+ aReferenceRange));
+ }
+ }
+ }
+ }
+
+ void SvgStyleAttributes::add_fill(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const basegfx::B2DRange& rGeoRange) const
+ {
+ const basegfx::BColor* pFill = getFill();
+ const SvgGradientNode* pFillGradient = getSvgGradientNodeFill();
+ const SvgPatternNode* pFillPattern = getSvgPatternNodeFill();
+
+ if(pFill || pFillGradient || pFillPattern)
+ {
+ const double fFillOpacity(getFillOpacity().solve(mrOwner, length));
+
+ if(basegfx::fTools::more(fFillOpacity, 0.0))
+ {
+ drawinglayer::primitive2d::Primitive2DSequence aNewFill;
+
+ if(pFillGradient)
+ {
+ // create fill content with SVG gradient primitive
+ add_fillGradient(rPath, aNewFill, *pFillGradient, rGeoRange);
+ }
+ else if(pFillPattern)
+ {
+ // create fill content with SVG pattern primitive
+ add_fillPatternTransform(rPath, aNewFill, *pFillPattern, rGeoRange);
+ }
+ else // if(pFill)
+ {
+ // create fill content
+ aNewFill.realloc(1);
+ aNewFill[0] = new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ rPath,
+ *pFill);
+ }
+
+ if(aNewFill.hasElements())
+ {
+ if(basegfx::fTools::less(fFillOpacity, 1.0))
+ {
+ // embed in UnifiedTransparencePrimitive2D
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
+ rTarget,
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ aNewFill,
+ 1.0 - fFillOpacity));
+ }
+ else
+ {
+ // append
+ drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewFill);
+ }
+ }
+ }
+ }
+ }
+
+ void SvgStyleAttributes::add_stroke(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const basegfx::B2DRange& rGeoRange) const
+ {
+ const basegfx::BColor* pStroke = getStroke();
+ const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke();
+ const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke();
+
+ if(pStroke || pStrokeGradient || pStrokePattern)
+ {
+ drawinglayer::primitive2d::Primitive2DSequence aNewStroke;
+ const double fStrokeOpacity(getStrokeOpacity().solve(mrOwner, length));
+
+ if(basegfx::fTools::more(fStrokeOpacity, 0.0))
+ {
+ // get stroke width; SVG does not use 0.0 == hairline, so 0.0 is no line at all
+ const double fStrokeWidth(getStrokeWidth().isSet() ? getStrokeWidth().solve(mrOwner, length) : 1.0);
+
+ if(basegfx::fTools::more(fStrokeWidth, 0.0))
+ {
+ // get LineJoin, LineCap and stroke array
+ const basegfx::B2DLineJoin aB2DLineJoin(StrokeLinejoinToB2DLineJoin(getStrokeLinejoin()));
+ const com::sun::star::drawing::LineCap aLineCap(StrokeLinecapToDrawingLineCap(getStrokeLinecap()));
+ ::std::vector< double > aDashArray;
+
+ if(!getStrokeDasharray().empty())
+ {
+ aDashArray = solveSvgNumberVector(getStrokeDasharray(), mrOwner, length);
+ }
+
+ // todo: Handle getStrokeDashOffset()
+
+ // prepare line attribute
+ drawinglayer::primitive2d::Primitive2DReference aNewLinePrimitive;
+ const drawinglayer::attribute::LineAttribute aLineAttribute(
+ pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0),
+ fStrokeWidth,
+ aB2DLineJoin,
+ aLineCap);
+
+ if(aDashArray.empty())
+ {
+ aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
+ rPath,
+ aLineAttribute);
+ }
+ else
+ {
+ const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashArray);
+
+ aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
+ rPath,
+ aLineAttribute,
+ aStrokeAttribute);
+ }
+
+ if(pStrokeGradient || pStrokePattern)
+ {
+ // put primitive into Primitive2DReference and Primitive2DSequence
+ const drawinglayer::primitive2d::Primitive2DSequence aSeq(&aNewLinePrimitive, 1);
+
+ // use neutral ViewInformation and create LineGeometryExtractor2D
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ drawinglayer::processor2d::LineGeometryExtractor2D aExtractor(aViewInformation2D);
+
+ // proccess
+ aExtractor.process(aSeq);
+
+ // check for fill rsults
+ const basegfx::B2DPolyPolygonVector& rLineFillVector(aExtractor.getExtractedLineFills());
+
+ if(!rLineFillVector.empty())
+ {
+ const basegfx::B2DPolyPolygon aMergedArea(
+ basegfx::tools::mergeToSinglePolyPolygon(
+ rLineFillVector));
+
+ if(aMergedArea.count())
+ {
+ if(pStrokeGradient)
+ {
+ // create fill content with SVG gradient primitive. Use original GeoRange,
+ // e.g. from circle without LineWidth
+ add_fillGradient(aMergedArea, aNewStroke, *pStrokeGradient, rGeoRange);
+ }
+ else // if(pStrokePattern)
+ {
+ // create fill content with SVG pattern primitive. Use GeoRange
+ // from the expanded data, e.g. circle with extended geo by half linewidth
+ add_fillPatternTransform(aMergedArea, aNewStroke, *pStrokePattern, aMergedArea.getB2DRange());
+ }
+ }
+ }
+ }
+ else // if(pStroke)
+ {
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aNewStroke, aNewLinePrimitive);
+ }
+
+ if(aNewStroke.hasElements())
+ {
+ if(basegfx::fTools::less(fStrokeOpacity, 1.0))
+ {
+ // embed in UnifiedTransparencePrimitive2D
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
+ rTarget,
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ aNewStroke,
+ 1.0 - fStrokeOpacity));
+ }
+ else
+ {
+ // append
+ drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewStroke);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ double get_markerRotation(
+ const SvgMarkerNode& rMarker,
+ const basegfx::B2DPolygon& rPolygon,
+ const sal_uInt32 nIndex)
+ {
+ double fAngle(0.0);
+ const sal_uInt32 nPointCount(rPolygon.count());
+
+ if(nPointCount)
+ {
+ if(rMarker.getOrientAuto())
+ {
+ const bool bPrev(rPolygon.isClosed() || nIndex > 0);
+ basegfx::B2DCubicBezier aSegment;
+ basegfx::B2DVector aPrev;
+ basegfx::B2DVector aNext;
+
+ if(bPrev)
+ {
+ rPolygon.getBezierSegment((nIndex - 1) % nPointCount, aSegment);
+ aPrev = aSegment.getTangent(1.0);
+ }
+
+ const bool bNext(rPolygon.isClosed() || nIndex + 1 < nPointCount);
+
+ if(bNext)
+ {
+ rPolygon.getBezierSegment(nIndex % nPointCount, aSegment);
+ aNext = aSegment.getTangent(0.0);
+ }
+
+ if(bPrev && bNext)
+ {
+ fAngle = atan2(aPrev.getY() + aNext.getY(), aPrev.getX() + aNext.getX());
+ }
+ else if(bPrev)
+ {
+ fAngle = atan2(aPrev.getY(), aPrev.getX());
+ }
+ else if(bNext)
+ {
+ fAngle = atan2(aNext.getY(), aNext.getX());
+ }
+ }
+ else
+ {
+ fAngle = rMarker.getAngle();
+ }
+ }
+
+ return fAngle;
+ }
+
+ bool SvgStyleAttributes::prepare_singleMarker(
+ drawinglayer::primitive2d::Primitive2DSequence& rMarkerPrimitives,
+ basegfx::B2DHomMatrix& rMarkerTransform,
+ basegfx::B2DRange& rClipRange,
+ const SvgMarkerNode& rMarker) const
+ {
+ // reset return values
+ rMarkerTransform.identity();
+ rClipRange.reset();
+
+ // get marker primitive representation
+ rMarkerPrimitives = rMarker.getMarkerPrimitives();
+
+ if(rMarkerPrimitives.hasElements())
+ {
+ basegfx::B2DRange aPrimitiveRange(0.0, 0.0, 1.0, 1.0);
+ const basegfx::B2DRange* pViewBox = rMarker.getViewBox();
+
+ if(pViewBox)
+ {
+ aPrimitiveRange = *pViewBox;
+ }
+
+ if(aPrimitiveRange.getWidth() > 0.0 && aPrimitiveRange.getHeight() > 0.0)
+ {
+ double fTargetWidth(rMarker.getMarkerWidth().isSet() ? rMarker.getMarkerWidth().solve(mrOwner, xcoordinate) : 3.0);
+ double fTargetHeight(rMarker.getMarkerHeight().isSet() ? rMarker.getMarkerHeight().solve(mrOwner, xcoordinate) : 3.0);
+ const bool bStrokeWidth(SvgMarkerNode::strokeWidth == rMarker.getMarkerUnits());
+ const double fStrokeWidth(getStrokeWidth().isSet() ? getStrokeWidth().solve(mrOwner, length) : 1.0);
+
+ if(bStrokeWidth)
+ {
+ // relative to strokeWidth
+ fTargetWidth *= fStrokeWidth;
+ fTargetHeight *= fStrokeWidth;
+ }
+
+ if(fTargetWidth > 0.0 && fTargetHeight > 0.0)
+ {
+ // create mapping
+ const basegfx::B2DRange aTargetRange(0.0, 0.0, fTargetWidth, fTargetHeight);
+ const SvgAspectRatio& rRatio = rMarker.getSvgAspectRatio();
+
+ if(rRatio.isSet())
+ {
+ // let mapping be created from SvgAspectRatio
+ rMarkerTransform = rRatio.createMapping(aTargetRange, aPrimitiveRange);
+
+ if(rRatio.isMeetOrSlice())
+ {
+ // need to clip
+ rClipRange = aPrimitiveRange;
+ }
+ }
+ else
+ {
+ if(!pViewBox)
+ {
+ if(bStrokeWidth)
+ {
+ // adapt to strokewidth if needed
+ rMarkerTransform.scale(fStrokeWidth, fStrokeWidth);
+ }
+ }
+ else
+ {
+ // choose default mapping
+ rMarkerTransform = rRatio.createLinearMapping(aTargetRange, aPrimitiveRange);
+ }
+ }
+
+ // get and apply reference point. Initially it's in marker local coordinate system
+ basegfx::B2DPoint aRefPoint(
+ rMarker.getRefX().isSet() ? rMarker.getRefX().solve(mrOwner, xcoordinate) : 0.0,
+ rMarker.getRefY().isSet() ? rMarker.getRefY().solve(mrOwner, ycoordinate) : 0.0);
+
+ // apply MarkerTransform to have it in mapped coordinates
+ aRefPoint *= rMarkerTransform;
+
+ // apply by moving RepPoint to (0.0)
+ rMarkerTransform.translate(-aRefPoint.getX(), -aRefPoint.getY());
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ void SvgStyleAttributes::add_singleMarker(
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const drawinglayer::primitive2d::Primitive2DSequence& rMarkerPrimitives,
+ const basegfx::B2DHomMatrix& rMarkerTransform,
+ const basegfx::B2DRange& rClipRange,
+ const SvgMarkerNode& rMarker,
+ const basegfx::B2DPolygon& rCandidate,
+ const sal_uInt32 nIndex) const
+ {
+ const sal_uInt32 nPointCount(rCandidate.count());
+
+ if(nPointCount)
+ {
+ // get and apply rotation
+ basegfx::B2DHomMatrix aCombinedTransform(rMarkerTransform);
+ aCombinedTransform.rotate(get_markerRotation(rMarker, rCandidate, nIndex));
+
+ // get and apply target position
+ const basegfx::B2DPoint aPoint(rCandidate.getB2DPoint(nIndex % nPointCount));
+ aCombinedTransform.translate(aPoint.getX(), aPoint.getY());
+
+ // prepare marker
+ drawinglayer::primitive2d::Primitive2DReference xMarker(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aCombinedTransform,
+ rMarkerPrimitives));
+
+ if(!rClipRange.isEmpty())
+ {
+ // marker needs to be clipped, it's bigger as the mapping
+ basegfx::B2DPolyPolygon aClipPolygon(basegfx::tools::createPolygonFromRect(rClipRange));
+
+ aClipPolygon.transform(aCombinedTransform);
+ xMarker = new drawinglayer::primitive2d::MaskPrimitive2D(
+ aClipPolygon,
+ drawinglayer::primitive2d::Primitive2DSequence(&xMarker, 1));
+ }
+
+ // add marker
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMarker);
+ }
+ }
+
+ void SvgStyleAttributes::add_markers(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget) const
+ {
+ // try to access linked markers
+ const SvgMarkerNode* pStart = accessMarkerStartXLink();
+ const SvgMarkerNode* pMid = accessMarkerMidXLink();
+ const SvgMarkerNode* pEnd = accessMarkerEndXLink();
+
+ if(pStart || pMid || pEnd)
+ {
+ const sal_uInt32 nCount(rPath.count());
+
+ for (sal_uInt32 a(0); a < nCount; a++)
+ {
+ const basegfx::B2DPolygon aCandidate(rPath.getB2DPolygon(a));
+ const sal_uInt32 nPointCount(aCandidate.count());
+
+ if(nPointCount)
+ {
+ const sal_uInt32 nMarkerCount(aCandidate.isClosed() ? nPointCount + 1 : nPointCount);
+ drawinglayer::primitive2d::Primitive2DSequence aMarkerPrimitives;
+ basegfx::B2DHomMatrix aMarkerTransform;
+ basegfx::B2DRange aClipRange;
+ const SvgMarkerNode* pPrepared = 0;
+
+ if(pStart)
+ {
+ if(prepare_singleMarker(aMarkerPrimitives, aMarkerTransform, aClipRange, *pStart))
+ {
+ pPrepared = pStart;
+ add_singleMarker(rTarget, aMarkerPrimitives, aMarkerTransform, aClipRange, *pPrepared, aCandidate, 0);
+ }
+ }
+
+ if(pMid && nMarkerCount > 2)
+ {
+ if(pMid == pPrepared || prepare_singleMarker(aMarkerPrimitives, aMarkerTransform, aClipRange, *pMid))
+ {
+ pPrepared = pMid;
+
+ for(sal_uInt32 b(1); b < nMarkerCount - 1; b++)
+ {
+ add_singleMarker(rTarget, aMarkerPrimitives, aMarkerTransform, aClipRange, *pPrepared, aCandidate, b);
+ }
+ }
+ }
+
+ if(pEnd)
+ {
+ if(pEnd == pPrepared || prepare_singleMarker(aMarkerPrimitives, aMarkerTransform, aClipRange, *pEnd))
+ {
+ pPrepared = pEnd;
+ add_singleMarker(rTarget, aMarkerPrimitives, aMarkerTransform, aClipRange, *pPrepared, aCandidate, nMarkerCount - 1);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void SvgStyleAttributes::add_path(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget) const
+ {
+ const bool bIsLine(1 == rPath.count()
+ && !rPath.areControlPointsUsed()
+ && 2 == rPath.getB2DPolygon(0).count());
+
+ if(!rPath.count())
+ {
+ return;
+ }
+
+ const basegfx::B2DRange aGeoRange(rPath.getB2DRange());
+
+ if(aGeoRange.isEmpty())
+ {
+ return;
+ }
+
+ if(!bIsLine && // not for lines
+ (basegfx::fTools::equalZero(aGeoRange.getWidth())
+ || basegfx::fTools::equalZero(aGeoRange.getHeight())))
+ {
+ return;
+ }
+
+ const double fOpacity(getOpacity().getNumber());
+
+ if(basegfx::fTools::equalZero(fOpacity))
+ {
+ return;
+ }
+
+ if(!bIsLine)
+ {
+ basegfx::B2DPolyPolygon aPath(rPath);
+ const bool bNeedToCheckClipRule(SVGTokenPath == mrOwner.getType() || SVGTokenPolygon == mrOwner.getType());
+ const bool bClipPathIsNonzero(!bIsLine && bNeedToCheckClipRule && mbIsClipPathContent && mbClipRule);
+ const bool bFillRuleIsNonzero(!bIsLine && bNeedToCheckClipRule && !mbIsClipPathContent && getFillRule());
+
+ if(bClipPathIsNonzero || bFillRuleIsNonzero)
+ {
+ // nonzero is wanted, solve geometrically (see description on basegfx)
+ aPath = basegfx::tools::createNonzeroConform(aPath);
+ }
+
+ add_fill(aPath, rTarget, aGeoRange);
+ }
+
+ add_stroke(rPath, rTarget, aGeoRange);
+
+ // Svg supports markers for path, polygon, polyline and line
+ if(SVGTokenPath == mrOwner.getType() || // path
+ SVGTokenPolygon == mrOwner.getType() || // polygon, polyline
+ SVGTokenLine == mrOwner.getType()) // line
+ {
+ // try to add markers
+ add_markers(rPath, rTarget);
+ }
+ }
+
+ void SvgStyleAttributes::add_postProcess(
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const drawinglayer::primitive2d::Primitive2DSequence& rSource,
+ const basegfx::B2DHomMatrix* pTransform) const
+ {
+ if(rSource.hasElements())
+ {
+ const double fOpacity(getOpacity().getNumber());
+
+ if(basegfx::fTools::equalZero(fOpacity))
+ {
+ return;
+ }
+
+ drawinglayer::primitive2d::Primitive2DSequence aSource(rSource);
+
+ if(basegfx::fTools::less(fOpacity, 1.0))
+ {
+ // embed in UnifiedTransparencePrimitive2D
+ const drawinglayer::primitive2d::Primitive2DReference xRef(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ aSource,
+ 1.0 - fOpacity));
+
+ aSource = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
+ }
+
+ if(getClipPathXLink().getLength())
+ {
+ // try to access linked ClipPath
+ const SvgClipPathNode* mpClip = dynamic_cast< const SvgClipPathNode* >(mrOwner.getDocument().findSvgNodeById(getClipPathXLink()));
+
+ if(mpClip)
+ {
+ mpClip->apply(aSource);
+ }
+ }
+
+ if(aSource.hasElements()) // test again, applied clipPath may have lead to empty geometry
+ {
+ if(getMaskXLink().getLength())
+ {
+ // try to access linked Mask
+ const SvgMaskNode* mpMask = dynamic_cast< const SvgMaskNode* >(mrOwner.getDocument().findSvgNodeById(getMaskXLink()));
+
+ if(mpMask)
+ {
+ mpMask->apply(aSource);
+ }
+ }
+
+ if(aSource.hasElements()) // test again, applied mask may have lead to empty geometry
+ {
+ if(pTransform)
+ {
+ // create embedding group element with transformation
+ const drawinglayer::primitive2d::Primitive2DReference xRef(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ *pTransform,
+ aSource));
+
+ aSource = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
+ }
+
+ // append to current target
+ drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSource);
+ }
+ }
+ }
+ }
+
+ SvgStyleAttributes::SvgStyleAttributes(SvgNode& rOwner)
+ : mrOwner(rOwner),
+ mpCssStyleParent(0),
+ maFill(),
+ maStroke(),
+ maStopColor(basegfx::BColor(0.0, 0.0, 0.0), true),
+ maStrokeWidth(),
+ maStopOpacity(),
+ mpSvgGradientNodeFill(0),
+ mpSvgGradientNodeStroke(0),
+ mpSvgPatternNodeFill(0),
+ mpSvgPatternNodeStroke(0),
+ maFillOpacity(),
+ maStrokeDasharray(),
+ maStrokeDashOffset(),
+ maStrokeLinecap(StrokeLinecap_notset),
+ maStrokeLinejoin(StrokeLinejoin_notset),
+ maStrokeMiterLimit(),
+ maStrokeOpacity(),
+ maFontFamily(),
+ maFontSize(),
+ maFontStretch(FontStretch_notset),
+ maFontStyle(FontStyle_notset),
+ maFontVariant(FontVariant_notset),
+ maFontWeight(FontWeight_notset),
+ maTextAlign(TextAlign_notset),
+ maTextDecoration(TextDecoration_notset),
+ maTextAnchor(TextAnchor_notset),
+ maColor(),
+ maOpacity(1.0),
+ maClipPathXLink(),
+ maMaskXLink(),
+ maMarkerStartXLink(),
+ mpMarkerStartXLink(0),
+ maMarkerMidXLink(),
+ mpMarkerMidXLink(0),
+ maMarkerEndXLink(),
+ mpMarkerEndXLink(0),
+ maFillRule(true),
+ maFillRuleSet(false),
+ mbIsClipPathContent(SVGTokenClipPathNode == mrOwner.getType()),
+ mbClipRule(true)
+ {
+ if(!mbIsClipPathContent)
+ {
+ const SvgStyleAttributes* pParentStyle = getParentStyle();
+
+ if(pParentStyle)
+ {
+ mbIsClipPathContent = pParentStyle->mbIsClipPathContent;
+ }
+ }
+ }
+
+ SvgStyleAttributes::~SvgStyleAttributes()
+ {
+ }
+
+ void SvgStyleAttributes::parseStyleAttribute(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ switch(aSVGToken)
+ {
+ case SVGTokenFill:
+ {
+ SvgPaint aSvgPaint;
+ rtl::OUString aURL;
+
+ if(readSvgPaint(aContent, aSvgPaint, aURL))
+ {
+ setFill(aSvgPaint);
+ }
+ else if(aURL.getLength())
+ {
+ const SvgNode* pNode = mrOwner.getDocument().findSvgNodeById(aURL);
+
+ if(pNode)
+ {
+ if(SVGTokenLinearGradient == pNode->getType() || SVGTokenRadialGradient == pNode->getType())
+ {
+ setSvgGradientNodeFill(static_cast< const SvgGradientNode* >(pNode));
+ }
+ else if(SVGTokenPattern == pNode->getType())
+ {
+ setSvgPatternNodeFill(static_cast< const SvgPatternNode* >(pNode));
+ }
+ }
+ }
+ break;
+ }
+ case SVGTokenFillOpacity:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setFillOpacity(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenFillRule:
+ {
+ if(aContent.getLength())
+ {
+ if(aContent.match(commonStrings::aStrNonzero))
+ {
+ maFillRule = true;
+ maFillRuleSet = true;
+ }
+ else if(aContent.match(commonStrings::aStrEvenOdd))
+ {
+ maFillRule = false;
+ maFillRuleSet = true;
+ }
+ }
+ break;
+ }
+ case SVGTokenStroke:
+ {
+ SvgPaint aSvgPaint;
+ rtl::OUString aURL;
+
+ if(readSvgPaint(aContent, aSvgPaint, aURL))
+ {
+ setStroke(aSvgPaint);
+ }
+ else if(aURL.getLength())
+ {
+ const SvgNode* pNode = mrOwner.getDocument().findSvgNodeById(aURL);
+
+ if(pNode)
+ {
+ if(SVGTokenLinearGradient == pNode->getType() || SVGTokenRadialGradient == pNode->getType())
+ {
+ setSvgGradientNodeStroke(static_cast< const SvgGradientNode* >(pNode));
+ }
+ else if(SVGTokenPattern == pNode->getType())
+ {
+ setSvgPatternNodeStroke(static_cast< const SvgPatternNode* >(pNode));
+ }
+ }
+ }
+ break;
+ }
+ case SVGTokenStrokeDasharray:
+ {
+ if(aContent.getLength())
+ {
+ SvgNumberVector aVector;
+
+ if(readSvgNumberVector(aContent, aVector))
+ {
+ setStrokeDasharray(aVector);
+ }
+ }
+ break;
+ }
+ case SVGTokenStrokeDashoffset:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setStrokeDashOffset(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenStrokeLinecap:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrButt(rtl::OUString::createFromAscii("butt"));
+ static rtl::OUString aStrRound(rtl::OUString::createFromAscii("round"));
+ static rtl::OUString aStrSquare(rtl::OUString::createFromAscii("square"));
+
+ if(aContent.match(aStrButt))
+ {
+ setStrokeLinecap(StrokeLinecap_butt);
+ }
+ else if(aContent.match(aStrRound))
+ {
+ setStrokeLinecap(StrokeLinecap_round);
+ }
+ else if(aContent.match(aStrSquare))
+ {
+ setStrokeLinecap(StrokeLinecap_square);
+ }
+ }
+ break;
+ }
+ case SVGTokenStrokeLinejoin:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrMiter(rtl::OUString::createFromAscii("miter"));
+ static rtl::OUString aStrRound(rtl::OUString::createFromAscii("round"));
+ static rtl::OUString aStrBevel(rtl::OUString::createFromAscii("bevel"));
+
+ if(aContent.match(aStrMiter))
+ {
+ setStrokeLinejoin(StrokeLinejoin_miter);
+ }
+ else if(aContent.match(aStrRound))
+ {
+ setStrokeLinejoin(StrokeLinejoin_round);
+ }
+ else if(aContent.match(aStrBevel))
+ {
+ setStrokeLinejoin(StrokeLinejoin_bevel);
+ }
+ }
+ break;
+ }
+ case SVGTokenStrokeMiterlimit:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setStrokeMiterLimit(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenStrokeOpacity:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setStrokeOpacity(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenStrokeWidth:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setStrokeWidth(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenStopColor:
+ {
+ SvgPaint aSvgPaint;
+ rtl::OUString aURL;
+
+ if(readSvgPaint(aContent, aSvgPaint, aURL))
+ {
+ setStopColor(aSvgPaint);
+ }
+ break;
+ }
+ case SVGTokenStopOpacity:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setStopOpacity(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenFont:
+ {
+ break;
+ }
+ case SVGTokenFontFamily:
+ {
+ SvgStringVector aSvgStringVector;
+
+ if(readSvgStringVector(aContent, aSvgStringVector))
+ {
+ setFontFamily(aSvgStringVector);
+ }
+ break;
+ }
+ case SVGTokenFontSize:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setFontSize(aNum);
+ }
+ break;
+ }
+ case SVGTokenFontSizeAdjust:
+ {
+ break;
+ }
+ case SVGTokenFontStretch:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
+ static rtl::OUString aStrWider(rtl::OUString::createFromAscii("wider"));
+ static rtl::OUString aStrNarrower(rtl::OUString::createFromAscii("narrower"));
+ static rtl::OUString aStrUltra_condensed(rtl::OUString::createFromAscii("ultra-condensed"));
+ static rtl::OUString aStrExtra_condensed(rtl::OUString::createFromAscii("extra-condensed"));
+ static rtl::OUString aStrCondensed(rtl::OUString::createFromAscii("condensed"));
+ static rtl::OUString aStrSemi_condensed(rtl::OUString::createFromAscii("semi-condensed"));
+ static rtl::OUString aStrSemi_expanded(rtl::OUString::createFromAscii("semi-expanded"));
+ static rtl::OUString aStrExpanded(rtl::OUString::createFromAscii("expanded"));
+ static rtl::OUString aStrExtra_expanded(rtl::OUString::createFromAscii("extra-expanded"));
+ static rtl::OUString aStrUltra_expanded(rtl::OUString::createFromAscii("ultra-expanded"));
+
+ if(aContent.match(aStrNormal))
+ {
+ setFontStretch(FontStretch_normal);
+ }
+ else if(aContent.match(aStrWider))
+ {
+ setFontStretch(FontStretch_wider);
+ }
+ else if(aContent.match(aStrNarrower))
+ {
+ setFontStretch(FontStretch_narrower);
+ }
+ else if(aContent.match(aStrUltra_condensed))
+ {
+ setFontStretch(FontStretch_ultra_condensed);
+ }
+ else if(aContent.match(aStrExtra_condensed))
+ {
+ setFontStretch(FontStretch_extra_condensed);
+ }
+ else if(aContent.match(aStrCondensed))
+ {
+ setFontStretch(FontStretch_condensed);
+ }
+ else if(aContent.match(aStrSemi_condensed))
+ {
+ setFontStretch(FontStretch_semi_condensed);
+ }
+ else if(aContent.match(aStrSemi_expanded))
+ {
+ setFontStretch(FontStretch_semi_expanded);
+ }
+ else if(aContent.match(aStrExpanded))
+ {
+ setFontStretch(FontStretch_expanded);
+ }
+ else if(aContent.match(aStrExtra_expanded))
+ {
+ setFontStretch(FontStretch_extra_expanded);
+ }
+ else if(aContent.match(aStrUltra_expanded))
+ {
+ setFontStretch(FontStretch_ultra_expanded);
+ }
+ }
+ break;
+ }
+ case SVGTokenFontStyle:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
+ static rtl::OUString aStrItalic(rtl::OUString::createFromAscii("italic"));
+ static rtl::OUString aStrOblique(rtl::OUString::createFromAscii("oblique"));
+
+ if(aContent.match(aStrNormal))
+ {
+ setFontStyle(FontStyle_normal);
+ }
+ else if(aContent.match(aStrItalic))
+ {
+ setFontStyle(FontStyle_italic);
+ }
+ else if(aContent.match(aStrOblique))
+ {
+ setFontStyle(FontStyle_oblique);
+ }
+ }
+ break;
+ }
+ case SVGTokenFontVariant:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
+ static rtl::OUString aStrSmallCaps(rtl::OUString::createFromAscii("small-caps"));
+
+ if(aContent.match(aStrNormal))
+ {
+ setFontVariant(FontVariant_normal);
+ }
+ else if(aContent.match(aStrSmallCaps))
+ {
+ setFontVariant(FontVariant_small_caps);
+ }
+ }
+ break;
+ }
+ case SVGTokenFontWeight:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
+ static rtl::OUString aStrBold(rtl::OUString::createFromAscii("bold"));
+ static rtl::OUString aStrBolder(rtl::OUString::createFromAscii("bolder"));
+ static rtl::OUString aStrLighter(rtl::OUString::createFromAscii("lighter"));
+ static rtl::OUString aStr100(rtl::OUString::createFromAscii("100"));
+ static rtl::OUString aStr200(rtl::OUString::createFromAscii("200"));
+ static rtl::OUString aStr300(rtl::OUString::createFromAscii("300"));
+ static rtl::OUString aStr400(rtl::OUString::createFromAscii("400"));
+ static rtl::OUString aStr500(rtl::OUString::createFromAscii("500"));
+ static rtl::OUString aStr600(rtl::OUString::createFromAscii("600"));
+ static rtl::OUString aStr700(rtl::OUString::createFromAscii("700"));
+ static rtl::OUString aStr800(rtl::OUString::createFromAscii("800"));
+ static rtl::OUString aStr900(rtl::OUString::createFromAscii("900"));
+
+ if(aContent.match(aStr100))
+ {
+ setFontWeight(FontWeight_100);
+ }
+ else if(aContent.match(aStr200))
+ {
+ setFontWeight(FontWeight_200);
+ }
+ else if(aContent.match(aStr300))
+ {
+ setFontWeight(FontWeight_300);
+ }
+ else if(aContent.match(aStr400) || aContent.match(aStrNormal))
+ {
+ setFontWeight(FontWeight_400);
+ }
+ else if(aContent.match(aStr500))
+ {
+ setFontWeight(FontWeight_500);
+ }
+ else if(aContent.match(aStr600))
+ {
+ setFontWeight(FontWeight_600);
+ }
+ else if(aContent.match(aStr700) || aContent.match(aStrBold))
+ {
+ setFontWeight(FontWeight_700);
+ }
+ else if(aContent.match(aStr800))
+ {
+ setFontWeight(FontWeight_800);
+ }
+ else if(aContent.match(aStr900))
+ {
+ setFontWeight(FontWeight_900);
+ }
+ else if(aContent.match(aStrBolder))
+ {
+ setFontWeight(FontWeight_bolder);
+ }
+ else if(aContent.match(aStrLighter))
+ {
+ setFontWeight(FontWeight_lighter);
+ }
+ }
+ break;
+ }
+ case SVGTokenDirection:
+ {
+ break;
+ }
+ case SVGTokenLetterSpacing:
+ {
+ break;
+ }
+ case SVGTokenTextDecoration:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrNone(rtl::OUString::createFromAscii("none"));
+ static rtl::OUString aStrUnderline(rtl::OUString::createFromAscii("underline"));
+ static rtl::OUString aStrOverline(rtl::OUString::createFromAscii("overline"));
+ static rtl::OUString aStrLineThrough(rtl::OUString::createFromAscii("line-through"));
+ static rtl::OUString aStrBlink(rtl::OUString::createFromAscii("blink"));
+
+ if(aContent.match(aStrNone))
+ {
+ setTextDecoration(TextDecoration_none);
+ }
+ else if(aContent.match(aStrUnderline))
+ {
+ setTextDecoration(TextDecoration_underline);
+ }
+ else if(aContent.match(aStrOverline))
+ {
+ setTextDecoration(TextDecoration_overline);
+ }
+ else if(aContent.match(aStrLineThrough))
+ {
+ setTextDecoration(TextDecoration_line_through);
+ }
+ else if(aContent.match(aStrBlink))
+ {
+ setTextDecoration(TextDecoration_blink);
+ }
+ }
+ break;
+ }
+ case SVGTokenUnicodeBidi:
+ {
+ break;
+ }
+ case SVGTokenWordSpacing:
+ {
+ break;
+ }
+ case SVGTokenTextAnchor:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrStart(rtl::OUString::createFromAscii("start"));
+ static rtl::OUString aStrMiddle(rtl::OUString::createFromAscii("middle"));
+ static rtl::OUString aStrEnd(rtl::OUString::createFromAscii("end"));
+
+ if(aContent.match(aStrStart))
+ {
+ setTextAnchor(TextAnchor_start);
+ }
+ else if(aContent.match(aStrMiddle))
+ {
+ setTextAnchor(TextAnchor_middle);
+ }
+ else if(aContent.match(aStrEnd))
+ {
+ setTextAnchor(TextAnchor_end);
+ }
+ }
+ break;
+ }
+ case SVGTokenTextAlign:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrLeft(rtl::OUString::createFromAscii("left"));
+ static rtl::OUString aStrRight(rtl::OUString::createFromAscii("right"));
+ static rtl::OUString aStrCenter(rtl::OUString::createFromAscii("center"));
+ static rtl::OUString aStrJustify(rtl::OUString::createFromAscii("justify"));
+
+ if(aContent.match(aStrLeft))
+ {
+ setTextAlign(TextAlign_left);
+ }
+ else if(aContent.match(aStrRight))
+ {
+ setTextAlign(TextAlign_right);
+ }
+ else if(aContent.match(aStrCenter))
+ {
+ setTextAlign(TextAlign_center);
+ }
+ else if(aContent.match(aStrJustify))
+ {
+ setTextAlign(TextAlign_justify);
+ }
+ }
+ break;
+ }
+ case SVGTokenColor:
+ {
+ SvgPaint aSvgPaint;
+ rtl::OUString aURL;
+
+ if(readSvgPaint(aContent, aSvgPaint, aURL))
+ {
+ setColor(aSvgPaint);
+ }
+ break;
+ }
+ case SVGTokenOpacity:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setOpacity(SvgNumber(basegfx::clamp(aNum.getNumber(), 0.0, 1.0), aNum.getUnit(), aNum.isSet()));
+ }
+ break;
+ }
+ case SVGTokenClipPathProperty:
+ {
+ readLocalUrl(aContent, maClipPathXLink);
+ break;
+ }
+ case SVGTokenMask:
+ {
+ readLocalUrl(aContent, maMaskXLink);
+ break;
+ }
+ case SVGTokenClipRule:
+ {
+ if(aContent.getLength())
+ {
+ if(aContent.match(commonStrings::aStrNonzero))
+ {
+ mbClipRule = true;
+ }
+ else if(aContent.match(commonStrings::aStrEvenOdd))
+ {
+ mbClipRule = false;
+ }
+ }
+ break;
+ }
+ case SVGTokenMarker:
+ {
+ readLocalUrl(aContent, maMarkerEndXLink);
+ maMarkerStartXLink = maMarkerMidXLink = maMarkerEndXLink;
+ break;
+ }
+ case SVGTokenMarkerStart:
+ {
+ readLocalUrl(aContent, maMarkerStartXLink);
+ break;
+ }
+ case SVGTokenMarkerMid:
+ {
+ readLocalUrl(aContent, maMarkerMidXLink);
+ break;
+ }
+ case SVGTokenMarkerEnd:
+ {
+ readLocalUrl(aContent, maMarkerEndXLink);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ const basegfx::BColor* SvgStyleAttributes::getFill() const
+ {
+ if(mbIsClipPathContent)
+ {
+ static basegfx::BColor aBlack(0.0, 0.0, 0.0);
+
+ return &aBlack;
+ }
+ else if(maFill.isSet())
+ {
+ if(maFill.isCurrent())
+ {
+ return getColor();
+ }
+ else if(maFill.isOn())
+ {
+ return &maFill.getBColor();
+ }
+ }
+ else
+ {
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getFill();
+ }
+ }
+
+ return 0;
+ }
+
+ const basegfx::BColor* SvgStyleAttributes::getStroke() const
+ {
+ if(mbIsClipPathContent)
+ {
+ return 0;
+ }
+ else if(maStroke.isSet())
+ {
+ if(maStroke.isCurrent())
+ {
+ return getColor();
+ }
+ else if(maStroke.isOn())
+ {
+ return &maStroke.getBColor();
+ }
+ }
+ else
+ {
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStroke();
+ }
+ }
+
+ return 0;
+ }
+
+ const basegfx::BColor& SvgStyleAttributes::getStopColor() const
+ {
+ if(maStopColor.isCurrent())
+ {
+ return *getColor();
+ }
+ else
+ {
+ return maStopColor.getBColor();
+ }
+ }
+
+ const SvgGradientNode* SvgStyleAttributes::getSvgGradientNodeFill() const
+ {
+ if(mbIsClipPathContent)
+ {
+ return 0;
+ }
+ else if(mpSvgGradientNodeFill)
+ {
+ return mpSvgGradientNodeFill;
+ }
+ else
+ {
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getSvgGradientNodeFill();
+ }
+ }
+
+ return 0;
+ }
+
+ const SvgGradientNode* SvgStyleAttributes::getSvgGradientNodeStroke() const
+ {
+ if(mbIsClipPathContent)
+ {
+ return 0;
+ }
+ else if(mpSvgGradientNodeStroke)
+ {
+ return mpSvgGradientNodeStroke;
+ }
+ else
+ {
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getSvgGradientNodeStroke();
+ }
+ }
+
+ return 0;
+ }
+
+ const SvgPatternNode* SvgStyleAttributes::getSvgPatternNodeFill() const
+ {
+ if(mbIsClipPathContent)
+ {
+ return 0;
+ }
+ else if(mpSvgPatternNodeFill)
+ {
+ return mpSvgPatternNodeFill;
+ }
+ else
+ {
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getSvgPatternNodeFill();
+ }
+ }
+
+ return 0;
+ }
+
+ const SvgPatternNode* SvgStyleAttributes::getSvgPatternNodeStroke() const
+ {
+ if(mbIsClipPathContent)
+ {
+ return 0;
+ }
+ else if(mpSvgPatternNodeStroke)
+ {
+ return mpSvgPatternNodeStroke;
+ }
+ else
+ {
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getSvgPatternNodeStroke();
+ }
+ }
+
+ return 0;
+ }
+
+ const SvgNumber SvgStyleAttributes::getStrokeWidth() const
+ {
+ if(mbIsClipPathContent)
+ {
+ return SvgNumber(0.0);
+ }
+ else if(maStrokeWidth.isSet())
+ {
+ return maStrokeWidth;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStrokeWidth();
+ }
+
+ // default is 1
+ return SvgNumber(1.0);
+ }
+
+ const SvgNumber SvgStyleAttributes::getStopOpacity() const
+ {
+ if(maStopOpacity.isSet())
+ {
+ return maStopOpacity;
+ }
+
+ // default is 1
+ return SvgNumber(1.0);
+ }
+
+ const SvgNumber SvgStyleAttributes::getFillOpacity() const
+ {
+ if(mbIsClipPathContent)
+ {
+ return SvgNumber(1.0);
+ }
+ else if(maFillOpacity.isSet())
+ {
+ return maFillOpacity;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getFillOpacity();
+ }
+
+ // default is 1
+ return SvgNumber(1.0);
+ }
+
+ bool SvgStyleAttributes::getFillRule() const
+ {
+ if(maFillRuleSet)
+ {
+ return maFillRule;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getFillRule();
+ }
+
+ // default is NonZero
+ return true;
+ }
+
+ void SvgStyleAttributes::setFillRule(const bool* pFillRule)
+ {
+ if(pFillRule)
+ {
+ maFillRuleSet = true;
+ maFillRule = *pFillRule;
+ }
+ else
+ {
+ maFillRuleSet = false;
+ }
+ }
+
+ const SvgNumberVector& SvgStyleAttributes::getStrokeDasharray() const
+ {
+ if(!maStrokeDasharray.empty())
+ {
+ return maStrokeDasharray;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStrokeDasharray();
+ }
+
+ // default empty
+ return maStrokeDasharray;
+ }
+
+ const SvgNumber SvgStyleAttributes::getStrokeDashOffset() const
+ {
+ if(maStrokeDashOffset.isSet())
+ {
+ return maStrokeDashOffset;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStrokeDashOffset();
+ }
+
+ // default is 0
+ return SvgNumber(0.0);
+ }
+
+ StrokeLinecap SvgStyleAttributes::getStrokeLinecap() const
+ {
+ if(maStrokeLinecap != StrokeLinecap_notset)
+ {
+ return maStrokeLinecap;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStrokeLinecap();
+ }
+
+ // default is StrokeLinecap_butt
+ return StrokeLinecap_butt;
+ }
+
+ StrokeLinejoin SvgStyleAttributes::getStrokeLinejoin() const
+ {
+ if(maStrokeLinejoin != StrokeLinejoin_notset)
+ {
+ return maStrokeLinejoin;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStrokeLinejoin();
+ }
+
+ // default is StrokeLinejoin_butt
+ return StrokeLinejoin_miter;
+ }
+
+ const SvgNumber SvgStyleAttributes::getStrokeMiterLimit() const
+ {
+ if(maStrokeMiterLimit.isSet())
+ {
+ return maStrokeMiterLimit;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStrokeMiterLimit();
+ }
+
+ // default is 4
+ return SvgNumber(4.0);
+ }
+
+ const SvgNumber SvgStyleAttributes::getStrokeOpacity() const
+ {
+ if(maStrokeOpacity.isSet())
+ {
+ return maStrokeOpacity;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStrokeOpacity();
+ }
+
+ // default is 1
+ return SvgNumber(1.0);
+ }
+
+ const SvgStringVector& SvgStyleAttributes::getFontFamily() const
+ {
+ if(!maFontFamily.empty())
+ {
+ return maFontFamily;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getFontFamily();
+ }
+
+ // default is empty
+ return maFontFamily;
+ }
+
+ const SvgNumber SvgStyleAttributes::getFontSize() const
+ {
+ if(maFontSize.isSet())
+ {
+ return maFontSize;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getFontSize();
+ }
+
+ // default is 'medium'
+ return SvgNumber(12.0);
+ }
+
+ FontStretch SvgStyleAttributes::getFontStretch() const
+ {
+ if(maFontStretch != FontStretch_notset)
+ {
+ if(FontStretch_wider != maFontStretch && FontStretch_narrower != maFontStretch)
+ {
+ return maFontStretch;
+ }
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ FontStretch aInherited = pSvgStyleAttributes->getFontStretch();
+
+ if(FontStretch_wider == maFontStretch)
+ {
+ aInherited = getWider(aInherited);
+ }
+ else if(FontStretch_narrower == maFontStretch)
+ {
+ aInherited = getNarrower(aInherited);
+ }
+
+ return aInherited;
+ }
+
+ // default is FontStretch_normal
+ return FontStretch_normal;
+ }
+
+ FontStyle SvgStyleAttributes::getFontStyle() const
+ {
+ if(maFontStyle != FontStyle_notset)
+ {
+ return maFontStyle;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getFontStyle();
+ }
+
+ // default is FontStyle_normal
+ return FontStyle_normal;
+ }
+
+ FontWeight SvgStyleAttributes::getFontWeight() const
+ {
+ if(maFontWeight != FontWeight_notset)
+ {
+ if(FontWeight_bolder != maFontWeight && FontWeight_lighter != maFontWeight)
+ {
+ return maFontWeight;
+ }
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ FontWeight aInherited = pSvgStyleAttributes->getFontWeight();
+
+ if(FontWeight_bolder == maFontWeight)
+ {
+ aInherited = getBolder(aInherited);
+ }
+ else if(FontWeight_lighter == maFontWeight)
+ {
+ aInherited = getLighter(aInherited);
+ }
+
+ return aInherited;
+ }
+
+ // default is FontWeight_400 (FontWeight_normal)
+ return FontWeight_400;
+ }
+
+ TextAlign SvgStyleAttributes::getTextAlign() const
+ {
+ if(maTextAlign != TextAlign_notset)
+ {
+ return maTextAlign;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getTextAlign();
+ }
+
+ // default is TextAlign_left
+ return TextAlign_left;
+ }
+
+ const SvgStyleAttributes* SvgStyleAttributes::getTextDecorationDefiningSvgStyleAttributes() const
+ {
+ if(maTextDecoration != TextDecoration_notset)
+ {
+ return this;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getTextDecorationDefiningSvgStyleAttributes();
+ }
+
+ // default is 0
+ return 0;
+ }
+
+ TextDecoration SvgStyleAttributes::getTextDecoration() const
+ {
+ const SvgStyleAttributes* pDefining = getTextDecorationDefiningSvgStyleAttributes();
+
+ if(pDefining)
+ {
+ return pDefining->maTextDecoration;
+ }
+ else
+ {
+ // default is TextDecoration_none
+ return TextDecoration_none;
+ }
+ }
+
+ TextAnchor SvgStyleAttributes::getTextAnchor() const
+ {
+ if(maTextAnchor != TextAnchor_notset)
+ {
+ return maTextAnchor;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getTextAnchor();
+ }
+
+ // default is TextAnchor_start
+ return TextAnchor_start;
+ }
+
+ const basegfx::BColor* SvgStyleAttributes::getColor() const
+ {
+ if(maColor.isSet())
+ {
+ if(maColor.isCurrent())
+ {
+ OSL_ENSURE(false, "Svg error: current color uses current color (!)");
+ return 0;
+ }
+ else if(maColor.isOn())
+ {
+ return &maColor.getBColor();
+ }
+ }
+ else
+ {
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getColor();
+ }
+ }
+
+ return 0;
+ }
+
+ const rtl::OUString SvgStyleAttributes::getMarkerStartXLink() const
+ {
+ if(maMarkerStartXLink.getLength())
+ {
+ return maMarkerStartXLink;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getMarkerStartXLink();
+ }
+
+ return rtl::OUString();
+ }
+
+ const SvgMarkerNode* SvgStyleAttributes::accessMarkerStartXLink() const
+ {
+ if(!mpMarkerStartXLink)
+ {
+ const rtl::OUString aMarker(getMarkerStartXLink());
+
+ if(aMarker.getLength())
+ {
+ const_cast< SvgStyleAttributes* >(this)->mpMarkerStartXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerStartXLink()));
+ }
+ }
+
+ return mpMarkerStartXLink;
+ }
+
+ const rtl::OUString SvgStyleAttributes::getMarkerMidXLink() const
+ {
+ if(maMarkerMidXLink.getLength())
+ {
+ return maMarkerMidXLink;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getMarkerMidXLink();
+ }
+
+ return rtl::OUString();
+ }
+
+ const SvgMarkerNode* SvgStyleAttributes::accessMarkerMidXLink() const
+ {
+ if(!mpMarkerMidXLink)
+ {
+ const rtl::OUString aMarker(getMarkerMidXLink());
+
+ if(aMarker.getLength())
+ {
+ const_cast< SvgStyleAttributes* >(this)->mpMarkerMidXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerMidXLink()));
+ }
+ }
+
+ return mpMarkerMidXLink;
+ }
+
+ const rtl::OUString SvgStyleAttributes::getMarkerEndXLink() const
+ {
+ if(maMarkerEndXLink.getLength())
+ {
+ return maMarkerEndXLink;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getMarkerEndXLink();
+ }
+
+ return rtl::OUString();
+ }
+
+ const SvgMarkerNode* SvgStyleAttributes::accessMarkerEndXLink() const
+ {
+ if(!mpMarkerEndXLink)
+ {
+ const rtl::OUString aMarker(getMarkerEndXLink());
+
+ if(aMarker.getLength())
+ {
+ const_cast< SvgStyleAttributes* >(this)->mpMarkerEndXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerEndXLink()));
+ }
+ }
+
+ return mpMarkerEndXLink;
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgstylenode.cxx b/svgio/source/svgreader/svgstylenode.cxx
new file mode 100644
index 000000000000..9060ac0b9a7d
--- /dev/null
+++ b/svgio/source/svgreader/svgstylenode.cxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgstylenode.hxx>
+#include <svgio/svgreader/svgdocument.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgStyleNode::SvgStyleNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenStyle, rDocument, pParent),
+ maSvgStyleAttributes(),
+ mbTextCss(false)
+ {
+ }
+
+ SvgStyleNode::~SvgStyleNode()
+ {
+ while(!maSvgStyleAttributes.empty())
+ {
+ delete *(maSvgStyleAttributes.end() - 1);
+ maSvgStyleAttributes.pop_back();
+ }
+ }
+
+ void SvgStyleNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenType:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrTextCss(rtl::OUString::createFromAscii("text/css"));
+
+ if(aContent.match(aStrTextCss))
+ {
+ setTextCss(true);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgStyleNode::addCssStyleSheet(const rtl::OUString& aContent)
+ {
+ const sal_Int32 nLen(aContent.getLength());
+
+ if(nLen)
+ {
+ sal_Int32 nPos(0);
+ rtl::OUStringBuffer aTokenValue;
+
+ while(nPos < nLen)
+ {
+ const sal_Int32 nInitPos(nPos);
+ skip_char(aContent, sal_Unicode(' '), sal_Unicode('#'), nPos, nLen);
+ copyToLimiter(aContent, sal_Unicode('{'), nPos, aTokenValue, nLen);
+ const rtl::OUString aStyleName = aTokenValue.makeStringAndClear().trim();
+
+ if(aStyleName.getLength() && nPos < nLen)
+ {
+ skip_char(aContent, sal_Unicode(' '), sal_Unicode('{'), nPos, nLen);
+ copyToLimiter(aContent, sal_Unicode('}'), nPos, aTokenValue, nLen);
+ skip_char(aContent, sal_Unicode(' '), sal_Unicode('}'), nPos, nLen);
+ const rtl::OUString aStyleContent = aTokenValue.makeStringAndClear().trim();
+
+ if(aStyleContent.getLength())
+ {
+ // create new style
+ SvgStyleAttributes* pNewStyle = new SvgStyleAttributes(*this);
+ maSvgStyleAttributes.push_back(pNewStyle);
+
+ // fill with content
+ pNewStyle->readStyle(aStyleContent);
+
+ // register new style at document
+ const_cast< SvgDocument& >(getDocument()).addSvgStyleAttributesToMapper(aStyleName, *pNewStyle);
+ }
+ }
+
+ if(nInitPos == nPos)
+ {
+ OSL_ENSURE(false, "Could not interpret on current position (!)");
+ nPos++;
+ }
+ }
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgsvgnode.cxx b/svgio/source/svgreader/svgsvgnode.cxx
new file mode 100644
index 000000000000..ecf74d9bb4a6
--- /dev/null
+++ b/svgio/source/svgreader/svgsvgnode.cxx
@@ -0,0 +1,423 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgsvgnode.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgSvgNode::SvgSvgNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenSvg, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ mpViewBox(0),
+ maSvgAspectRatio(),
+ maX(),
+ maY(),
+ maWidth(),
+ maHeight(),
+ maVersion()
+ {
+ if(!getParent())
+ {
+ // initial fill is black
+ maSvgStyleAttributes.setFill(SvgPaint(basegfx::BColor(0.0, 0.0, 0.0), true, true));
+ }
+ }
+
+ SvgSvgNode::~SvgSvgNode()
+ {
+ if(mpViewBox) delete mpViewBox;
+ }
+
+ const SvgStyleAttributes* SvgSvgNode::getSvgStyleAttributes() const
+ {
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgSvgNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenViewBox:
+ {
+ const basegfx::B2DRange aRange(readViewBox(aContent, *this));
+
+ if(!aRange.isEmpty())
+ {
+ setViewBox(&aRange);
+ }
+ break;
+ }
+ case SVGTokenPreserveAspectRatio:
+ {
+ setSvgAspectRatio(readSvgAspectRatio(aContent));
+ break;
+ }
+ case SVGTokenX:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setX(aNum);
+ }
+ break;
+ }
+ case SVGTokenY:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setY(aNum);
+ }
+ break;
+ }
+ case SVGTokenWidth:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setWidth(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenHeight:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setHeight(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenVersion:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setVersion(aNum);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgSvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const
+ {
+ drawinglayer::primitive2d::Primitive2DSequence aSequence;
+
+ // decompose childs
+ SvgNode::decomposeSvgNode(aSequence, bReferenced);
+
+ if(aSequence.hasElements())
+ {
+ if(getParent())
+ {
+ if(getViewBox())
+ {
+ // Svg defines that with no width or no height the viewBox content is empty,
+ // so both need to exist
+ if(!basegfx::fTools::equalZero(getViewBox()->getWidth()) && !basegfx::fTools::equalZero(getViewBox()->getHeight()))
+ {
+ // create target range homing x,y, width and height as given
+ const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0);
+ const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0);
+ const double fW(getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : getViewBox()->getWidth());
+ const double fH(getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : getViewBox()->getHeight());
+ const basegfx::B2DRange aTarget(fX, fY, fX + fW, fY + fH);
+
+ if(aTarget.equal(*getViewBox()))
+ {
+ // no mapping needed, append
+ drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence);
+ }
+ else
+ {
+ // create mapping
+ const SvgAspectRatio& rRatio = getSvgAspectRatio();
+
+ if(rRatio.isSet())
+ {
+ // let mapping be created from SvgAspectRatio
+ const basegfx::B2DHomMatrix aEmbeddingTransform(
+ rRatio.createMapping(aTarget, *getViewBox()));
+
+ // prepare embedding in transformation
+ const drawinglayer::primitive2d::Primitive2DReference xRef(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aEmbeddingTransform,
+ aSequence));
+
+ if(rRatio.isMeetOrSlice())
+ {
+ // embed in transformation
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef);
+ }
+ else
+ {
+ // need to embed in MaskPrimitive2D, too
+ const drawinglayer::primitive2d::Primitive2DReference xMask(
+ new drawinglayer::primitive2d::MaskPrimitive2D(
+ basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aTarget)),
+ drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1)));
+
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask);
+ }
+ }
+ else
+ {
+ // choose default mapping
+ const basegfx::B2DHomMatrix aEmbeddingTransform(
+ rRatio.createLinearMapping(
+ aTarget, *getViewBox()));
+
+ // embed in transformation
+ const drawinglayer::primitive2d::Primitive2DReference xTransform(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aEmbeddingTransform,
+ aSequence));
+
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xTransform);
+ }
+ }
+ }
+ }
+ else
+ {
+ // check if we have a size
+ const double fW(getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : 0.0);
+ const double fH(getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : 0.0);
+
+ // Svg defines that a negative value is an error and that 0.0 disables rendering
+ if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0))
+ {
+ // check if we have a x,y position
+ const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0);
+ const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0);
+
+ if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY))
+ {
+ // embed in transform
+ const drawinglayer::primitive2d::Primitive2DReference xRef(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ basegfx::tools::createTranslateB2DHomMatrix(fX, fY),
+ aSequence));
+
+ aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
+ }
+
+ // embed in MaskPrimitive2D to clip
+ const drawinglayer::primitive2d::Primitive2DReference xMask(
+ new drawinglayer::primitive2d::MaskPrimitive2D(
+ basegfx::B2DPolyPolygon(
+ basegfx::tools::createPolygonFromRect(
+ basegfx::B2DRange(fX, fY, fX + fW, fY + fH))),
+ aSequence));
+
+ // append
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask);
+ }
+ }
+ }
+ else
+ {
+ // Outermost SVG element; create target range homing width and height as given.
+ // SVG defines that x,y has no meanig for the outermost SVG element. Use a fallback
+ // width and height of din A 4 (21 x 29,7 cm)
+ double fW(getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : (210.0 * 3.543307));
+ double fH(getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : (297.0 * 3.543307));
+
+ // Svg defines that a negative value is an error and that 0.0 disables rendering
+ if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0))
+ {
+ const basegfx::B2DRange aSvgCanvasRange(0.0, 0.0, fW, fH);
+
+ if(getViewBox())
+ {
+ if(!basegfx::fTools::equalZero(getViewBox()->getWidth()) && !basegfx::fTools::equalZero(getViewBox()->getHeight()))
+ {
+ // create mapping
+ const SvgAspectRatio& rRatio = getSvgAspectRatio();
+ basegfx::B2DHomMatrix aViewBoxMapping;
+
+ if(rRatio.isSet())
+ {
+ // let mapping be created from SvgAspectRatio
+ aViewBoxMapping = rRatio.createMapping(aSvgCanvasRange, *getViewBox());
+
+ // no need to check ratio here for slice, the outermost Svg will
+ // be clipped anyways (see below)
+ }
+ else
+ {
+ // choose default mapping
+ aViewBoxMapping = rRatio.createLinearMapping(aSvgCanvasRange, *getViewBox());
+ }
+
+ // scale content to viewBox definitions
+ const drawinglayer::primitive2d::Primitive2DReference xTransform(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aViewBoxMapping,
+ aSequence));
+
+ aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1);
+ }
+ }
+
+ // to be completely correct in Svg sense it is necessary to clip
+ // the whole content to the given canvas. I choose here to do this
+ // initially despite I found various examples of Svg files out there
+ // which have no correct values for this clipping. It's correct
+ // due to the Svg spec.
+ bool bDoCorrectCanvasClipping(true);
+
+ if(bDoCorrectCanvasClipping)
+ {
+ // different from Svg we have the possibility with primitives to get
+ // a correct bounding box for the geometry. Get it for evtl. taking action
+ const basegfx::B2DRange aContentRange(
+ drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
+ aSequence,
+ drawinglayer::geometry::ViewInformation2D()));
+
+ if(aSvgCanvasRange.isInside(aContentRange))
+ {
+ // no clip needed, but an invisible HiddenGeometryPrimitive2D
+ // to allow getting the full Svg range using the primitive mechanisms.
+ // This is needed since e.g. an SdrObject using this as graphic will
+ // create a mapping transformation to exactly map the content to it's
+ // real life size
+ const drawinglayer::primitive2d::Primitive2DReference xLine(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ basegfx::tools::createPolygonFromRect(
+ aSvgCanvasRange),
+ basegfx::BColor(0.0, 0.0, 0.0)));
+ const drawinglayer::primitive2d::Primitive2DReference xHidden(
+ new drawinglayer::primitive2d::HiddenGeometryPrimitive2D(
+ drawinglayer::primitive2d::Primitive2DSequence(&xLine, 1)));
+
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aSequence, xHidden);
+ }
+ else if(aSvgCanvasRange.overlaps(aContentRange))
+ {
+ // Clip is necessary. This will make Svg images evtl. smaller
+ // than wanted from Svg (the free space which may be around it is
+ // conform to the Svg spec), but avoids an expensive and unneccessary
+ // clip. Keep the full Svg range here to get the correct mappings
+ // to objects using this. Optimizations can be done in the processors
+ const drawinglayer::primitive2d::Primitive2DReference xMask(
+ new drawinglayer::primitive2d::MaskPrimitive2D(
+ basegfx::B2DPolyPolygon(
+ basegfx::tools::createPolygonFromRect(
+ aSvgCanvasRange)),
+ aSequence));
+
+ aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1);
+ }
+ else
+ {
+ // not inside, no overlap. Empty Svg
+ aSequence.realloc(0);
+ }
+ }
+
+ if(aSequence.hasElements())
+ {
+ // embed in transform primitive to scale to 1/100th mm
+ // where 1 mm == 3.543307 px to get from Svg coordinates to
+ // drawinglayer ones
+ const double fScaleTo100thmm(100.0 / 3.543307);
+ const basegfx::B2DHomMatrix aTransform(
+ basegfx::tools::createScaleB2DHomMatrix(
+ fScaleTo100thmm,
+ fScaleTo100thmm));
+
+ const drawinglayer::primitive2d::Primitive2DReference xTransform(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aTransform,
+ aSequence));
+
+ aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1);
+
+ // append to result
+ drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence);
+ }
+ }
+ }
+ }
+ }
+
+ const basegfx::B2DRange* SvgSvgNode::getCurrentViewPort() const
+ {
+ if(getViewBox())
+ {
+ return getViewBox();
+ }
+ else
+ {
+ return SvgNode::getCurrentViewPort();
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgsymbolnode.cxx b/svgio/source/svgreader/svgsymbolnode.cxx
new file mode 100644
index 000000000000..2c8ec2ef8149
--- /dev/null
+++ b/svgio/source/svgreader/svgsymbolnode.cxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgsymbolnode.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgSymbolNode::SvgSymbolNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenSvg, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ mpViewBox(0),
+ maSvgAspectRatio()
+ {
+ }
+
+ SvgSymbolNode::~SvgSymbolNode()
+ {
+ if(mpViewBox) delete mpViewBox;
+ }
+
+ const SvgStyleAttributes* SvgSymbolNode::getSvgStyleAttributes() const
+ {
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgSymbolNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenViewBox:
+ {
+ const basegfx::B2DRange aRange(readViewBox(aContent, *this));
+
+ if(!aRange.isEmpty())
+ {
+ setViewBox(&aRange);
+ }
+ break;
+ }
+ case SVGTokenPreserveAspectRatio:
+ {
+ setSvgAspectRatio(readSvgAspectRatio(aContent));
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgtextnode.cxx b/svgio/source/svgreader/svgtextnode.cxx
new file mode 100644
index 000000000000..8340abd31d98
--- /dev/null
+++ b/svgio/source/svgreader/svgtextnode.cxx
@@ -0,0 +1,274 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgtextnode.hxx>
+#include <svgio/svgreader/svgcharacternode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+#include <svgio/svgreader/svgtrefnode.hxx>
+#include <svgio/svgreader/svgtextpathnode.hxx>
+#include <svgio/svgreader/svgtspannode.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgTextNode::SvgTextNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenText, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ mpaTransform(0),
+ maSvgTextPositions()
+ {
+ }
+
+ SvgTextNode::~SvgTextNode()
+ {
+ if(mpaTransform) delete mpaTransform;
+ }
+
+ const SvgStyleAttributes* SvgTextNode::getSvgStyleAttributes() const
+ {
+ static rtl::OUString aClassStr(rtl::OUString::createFromAscii("text"));
+ maSvgStyleAttributes.checkForCssStyle(aClassStr);
+
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgTextNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // read text position attributes
+ maSvgTextPositions.parseTextPositionAttributes(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenTransform:
+ {
+ const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
+
+ if(!aMatrix.isIdentity())
+ {
+ setTransform(&aMatrix);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgTextNode::addTextPrimitives(
+ const SvgNode& rCandidate,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ drawinglayer::primitive2d::Primitive2DSequence& rSource) const
+ {
+ if(rSource.hasElements())
+ {
+ const SvgStyleAttributes* pAttributes = rCandidate.getSvgStyleAttributes();
+
+ if(pAttributes)
+ {
+ // add text with taking all Fill/Stroke attributes into account
+ pAttributes->add_text(rTarget, rSource);
+ }
+ else
+ {
+ // should not happen, every subnode from SvgTextNode will at least
+ // return the attributes from SvgTextNode. Nonetheless, add text
+ drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, rSource);
+ }
+ }
+ }
+
+ void SvgTextNode::DecomposeChild(const SvgNode& rCandidate, drawinglayer::primitive2d::Primitive2DSequence& rTarget, SvgTextPosition& rSvgTextPosition) const
+ {
+ switch(rCandidate.getType())
+ {
+ case SVGTokenCharacter:
+ {
+ // direct SvgTextPathNode derivates, decompose them
+ const SvgCharacterNode& rSvgCharacterNode = static_cast< const SvgCharacterNode& >(rCandidate);
+ rSvgCharacterNode.decomposeText(rTarget, rSvgTextPosition);
+ break;
+ }
+ case SVGTokenTextPath:
+ {
+ // direct TextPath decompose
+ const SvgTextPathNode& rSvgTextPathNode = static_cast< const SvgTextPathNode& >(rCandidate);
+ const SvgNodeVector& rChildren = rSvgTextPathNode.getChildren();
+ const sal_uInt32 nCount(rChildren.size());
+
+ if(nCount && rSvgTextPathNode.isValid())
+ {
+ // remember original TextStart to later detect hor/ver offsets
+ const basegfx::B2DPoint aTextStart(rSvgTextPosition.getPosition());
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ // decompose to regular TextPrimitives
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ DecomposeChild(*rChildren[a], aNewTarget, rSvgTextPosition);
+ }
+
+ if(aNewTarget.hasElements())
+ {
+ const drawinglayer::primitive2d::Primitive2DSequence aPathContent(aNewTarget);
+ aNewTarget.realloc(0);
+
+ // dismantle TextPrimitives and map them on curve/path
+ rSvgTextPathNode.decomposePathNode(aPathContent, aNewTarget, aTextStart);
+ }
+
+ if(aNewTarget.hasElements())
+ {
+ addTextPrimitives(rCandidate, rTarget, aNewTarget);
+ }
+ }
+
+ break;
+ }
+ case SVGTokenTspan:
+ {
+ // Tspan may have children, call recursively
+ const SvgTspanNode& rSvgTspanNode = static_cast< const SvgTspanNode& >(rCandidate);
+ const SvgNodeVector& rChildren = rSvgTspanNode.getChildren();
+ const sal_uInt32 nCount(rChildren.size());
+
+ if(nCount)
+ {
+ SvgTextPosition aSvgTextPosition(&rSvgTextPosition, rSvgTspanNode, rSvgTspanNode.getSvgTextPositions());
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ DecomposeChild(*rChildren[a], aNewTarget, aSvgTextPosition);
+ }
+
+ rSvgTextPosition.setPosition(aSvgTextPosition.getPosition());
+
+ if(aNewTarget.hasElements())
+ {
+ addTextPrimitives(rCandidate, rTarget, aNewTarget);
+ }
+ }
+ break;
+ }
+ case SVGTokenTref:
+ {
+ const SvgTrefNode& rSvgTrefNode = static_cast< const SvgTrefNode& >(rCandidate);
+ const SvgTextNode* pRefText = rSvgTrefNode.getReferencedSvgTextNode();
+
+ if(pRefText)
+ {
+ const SvgNodeVector& rChildren = pRefText->getChildren();
+ const sal_uInt32 nCount(rChildren.size());
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ if(nCount)
+ {
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const SvgNode& rChildCandidate = *rChildren[a];
+ const_cast< SvgNode& >(rChildCandidate).setAlternativeParent(this);
+
+ DecomposeChild(rChildCandidate, aNewTarget, rSvgTextPosition);
+ const_cast< SvgNode& >(rChildCandidate).setAlternativeParent(0);
+ }
+
+ if(aNewTarget.hasElements())
+ {
+ addTextPrimitives(rCandidate, rTarget, aNewTarget);
+ }
+ }
+ }
+
+ break;
+ }
+ default:
+ {
+ OSL_ENSURE(false, "Unexpected node in text token (!)");
+ break;
+ }
+ }
+ }
+
+ void SvgTextNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced`*/) const
+ {
+ // text has a group of child nodes, allowed are SVGTokenCharacter, SVGTokenTspan,
+ // SVGTokenTref and SVGTokenTextPath. These increase a given current text position
+ const SvgStyleAttributes* pStyle = getSvgStyleAttributes();
+
+ if(pStyle && !getChildren().empty())
+ {
+ const double fOpacity(pStyle->getOpacity().getNumber());
+
+ if(fOpacity > 0.0)
+ {
+ SvgTextPosition aSvgTextPosition(0, *this, getSvgTextPositions());
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+ const SvgNodeVector& rChildren = getChildren();
+ const sal_uInt32 nCount(rChildren.size());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const SvgNode& rCandidate = *rChildren[a];
+
+ DecomposeChild(rCandidate, aNewTarget, aSvgTextPosition);
+ }
+
+ if(aNewTarget.hasElements())
+ {
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget2;
+
+ addTextPrimitives(*this, aNewTarget2, aNewTarget);
+ aNewTarget = aNewTarget2;
+ }
+
+ if(aNewTarget.hasElements())
+ {
+ pStyle->add_postProcess(rTarget, aNewTarget, getTransform());
+ }
+ }
+ }
+ }
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgtextpathnode.cxx b/svgio/source/svgreader/svgtextpathnode.cxx
new file mode 100644
index 000000000000..ba7de86612ae
--- /dev/null
+++ b/svgio/source/svgreader/svgtextpathnode.cxx
@@ -0,0 +1,511 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgtextpathnode.hxx>
+#include <svgio/svgreader/svgstyleattributes.hxx>
+#include <svgio/svgreader/svgpathnode.hxx>
+#include <svgio/svgreader/svgdocument.hxx>
+#include <svgio/svgreader/svgtrefnode.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/textbreakuphelper.hxx>
+#include <drawinglayer/primitive2d/groupprimitive2d.hxx>
+#include <basegfx/curve/b2dcubicbezier.hxx>
+#include <basegfx/curve/b2dbeziertools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class pathTextBreakupHelper : public drawinglayer::primitive2d::TextBreakupHelper
+ {
+ private:
+ const basegfx::B2DPolygon& mrPolygon;
+ const double mfBasegfxPathLength;
+ const double mfUserToBasegfx;
+ double mfPosition;
+ const basegfx::B2DPoint& mrTextStart;
+
+ const sal_uInt32 mnMaxIndex;
+ sal_uInt32 mnIndex;
+ basegfx::B2DCubicBezier maCurrentSegment;
+ basegfx::B2DCubicBezierHelper* mpB2DCubicBezierHelper;
+ double mfCurrentSegmentLength;
+ double mfSegmentStartPosition;
+
+ protected:
+ /// allow user callback to allow changes to the new TextTransformation. Default
+ /// does nothing.
+ virtual bool allowChange(sal_uInt32 nCount, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 nIndex, sal_uInt32 nLength);
+
+ void freeB2DCubicBezierHelper();
+ basegfx::B2DCubicBezierHelper* getB2DCubicBezierHelper();
+ void advanceToPosition(double fNewPosition);
+
+ public:
+ pathTextBreakupHelper(
+ const drawinglayer::primitive2d::TextSimplePortionPrimitive2D& rSource,
+ const basegfx::B2DPolygon& rPolygon,
+ const double fBasegfxPathLength,
+ const double fUserToBasegfx,
+ double fPosition,
+ const basegfx::B2DPoint& rTextStart);
+ virtual ~pathTextBreakupHelper();
+
+ // read access to evtl. advanced position
+ double getPosition() const { return mfPosition; }
+
+ // get length of given text
+ double getLength(const rtl::OUString& rText) const;
+ };
+
+ double pathTextBreakupHelper::getLength(const rtl::OUString& rText) const
+ {
+ const sal_uInt32 nLength(rText.getLength());
+
+ if(nLength)
+ {
+ return getTextLayouter().getTextWidth(rText, 0, nLength);
+ }
+
+ return 0.0;
+ }
+
+ void pathTextBreakupHelper::freeB2DCubicBezierHelper()
+ {
+ if(mpB2DCubicBezierHelper)
+ {
+ delete mpB2DCubicBezierHelper;
+ mpB2DCubicBezierHelper = 0;
+ }
+ }
+
+ basegfx::B2DCubicBezierHelper* pathTextBreakupHelper::getB2DCubicBezierHelper()
+ {
+ if(!mpB2DCubicBezierHelper && maCurrentSegment.isBezier())
+ {
+ mpB2DCubicBezierHelper = new basegfx::B2DCubicBezierHelper(maCurrentSegment);
+ }
+
+ return mpB2DCubicBezierHelper;
+ }
+
+ void pathTextBreakupHelper::advanceToPosition(double fNewPosition)
+ {
+ while(mfSegmentStartPosition + mfCurrentSegmentLength < fNewPosition && mnIndex < mnMaxIndex)
+ {
+ mfSegmentStartPosition += mfCurrentSegmentLength;
+ mnIndex++;
+
+ if(mnIndex < mnMaxIndex)
+ {
+ freeB2DCubicBezierHelper();
+ mrPolygon.getBezierSegment(mnIndex % mrPolygon.count(), maCurrentSegment);
+ maCurrentSegment.testAndSolveTrivialBezier();
+ mfCurrentSegmentLength = getB2DCubicBezierHelper()
+ ? getB2DCubicBezierHelper()->getLength()
+ : maCurrentSegment.getLength();
+ }
+ }
+
+ mfPosition = fNewPosition;
+ }
+
+ pathTextBreakupHelper::pathTextBreakupHelper(
+ const drawinglayer::primitive2d::TextSimplePortionPrimitive2D& rSource,
+ const basegfx::B2DPolygon& rPolygon,
+ const double fBasegfxPathLength,
+ const double fUserToBasegfx,
+ double fPosition,
+ const basegfx::B2DPoint& rTextStart)
+ : drawinglayer::primitive2d::TextBreakupHelper(rSource),
+ mrPolygon(rPolygon),
+ mfBasegfxPathLength(fBasegfxPathLength),
+ mfUserToBasegfx(fUserToBasegfx),
+ mfPosition(0.0),
+ mrTextStart(rTextStart),
+ mnMaxIndex(rPolygon.isClosed() ? rPolygon.count() : rPolygon.count() - 1),
+ mnIndex(0),
+ maCurrentSegment(),
+ mpB2DCubicBezierHelper(0),
+ mfCurrentSegmentLength(0.0),
+ mfSegmentStartPosition(0.0)
+ {
+ mrPolygon.getBezierSegment(mnIndex % mrPolygon.count(), maCurrentSegment);
+ mfCurrentSegmentLength = maCurrentSegment.getLength();
+
+ advanceToPosition(fPosition);
+ }
+
+ pathTextBreakupHelper::~pathTextBreakupHelper()
+ {
+ freeB2DCubicBezierHelper();
+ }
+
+ bool pathTextBreakupHelper::allowChange(sal_uInt32 /*nCount*/, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 nIndex, sal_uInt32 nLength)
+ {
+ bool bRetval(false);
+
+ if(mfPosition < mfBasegfxPathLength && nLength && mnIndex < mnMaxIndex)
+ {
+ const double fSnippetWidth(
+ getTextLayouter().getTextWidth(
+ getSource().getText(),
+ nIndex,
+ nLength));
+
+ if(basegfx::fTools::more(fSnippetWidth, 0.0))
+ {
+ const ::rtl::OUString aText(getSource().getText());
+ const ::rtl::OUString aTrimmedChars(aText.copy(nIndex, nLength).trim());
+ const double fEndPos(mfPosition + fSnippetWidth);
+
+ if(aTrimmedChars.getLength() && (mfPosition < mfBasegfxPathLength || fEndPos > 0.0))
+ {
+ const double fHalfSnippetWidth(fSnippetWidth * 0.5);
+
+ advanceToPosition(mfPosition + fHalfSnippetWidth);
+
+ // create representation for this snippet
+ bRetval = true;
+
+ // get target position and tangent in that pint
+ basegfx::B2DPoint aPosition(0.0, 0.0);
+ basegfx::B2DVector aTangent(0.0, 1.0);
+
+ if(mfPosition < 0.0)
+ {
+ // snippet center is left of first segment, but right edge is on it (SVG allows that)
+ aTangent = maCurrentSegment.getTangent(0.0);
+ aTangent.normalize();
+ aPosition = maCurrentSegment.getStartPoint() + (aTangent * (mfPosition - mfSegmentStartPosition));
+ }
+ else if(mfPosition > mfBasegfxPathLength)
+ {
+ // snippet center is right of last segment, but left edge is on it (SVG allows that)
+ aTangent = maCurrentSegment.getTangent(1.0);
+ aTangent.normalize();
+ aPosition = maCurrentSegment.getEndPoint() + (aTangent * (mfPosition - mfSegmentStartPosition));
+ }
+ else
+ {
+ // snippet center inside segment, interpolate
+ double fBezierDistance(mfPosition - mfSegmentStartPosition);
+
+ if(getB2DCubicBezierHelper())
+ {
+ // use B2DCubicBezierHelper to bridge the non-linear gap between
+ // length and bezier distances (if it's a bezier segment)
+ fBezierDistance = getB2DCubicBezierHelper()->distanceToRelative(fBezierDistance);
+ }
+ else
+ {
+ // linear relationship, make relative to segment length
+ fBezierDistance = fBezierDistance / mfCurrentSegmentLength;
+ }
+
+ aPosition = maCurrentSegment.interpolatePoint(fBezierDistance);
+ aTangent = maCurrentSegment.getTangent(fBezierDistance);
+ aTangent.normalize();
+ }
+
+ // detect evtl. hor/ver translations (depends on text direction)
+ const basegfx::B2DPoint aBasePoint(rNewTransform * basegfx::B2DPoint(0.0, 0.0));
+ const basegfx::B2DVector aOffset(aBasePoint - mrTextStart);
+
+ if(!basegfx::fTools::equalZero(aOffset.getY()))
+ {
+ // ...and apply
+ aPosition.setY(aPosition.getY() + aOffset.getY());
+ }
+
+ // move target position from snippet center to left text start
+ aPosition -= fHalfSnippetWidth * aTangent;
+
+ // remove current translation
+ rNewTransform.translate(-aBasePoint.getX(), -aBasePoint.getY());
+
+ // rotate due to tangent
+ rNewTransform.rotate(atan2(aTangent.getY(), aTangent.getX()));
+
+ // add new translation
+ rNewTransform.translate(aPosition.getX(), aPosition.getY());
+ }
+
+ // advance to end
+ advanceToPosition(fEndPos);
+ }
+ }
+
+ return bRetval;
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgTextPathNode::SvgTextPathNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenTextPath, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ maXLink(),
+ maStartOffset(),
+ mbMethod(true),
+ mbSpacing(false)
+ {
+ }
+
+ SvgTextPathNode::~SvgTextPathNode()
+ {
+ }
+
+ const SvgStyleAttributes* SvgTextPathNode::getSvgStyleAttributes() const
+ {
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgTextPathNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenStartOffset:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setStartOffset(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenMethod:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrAlign(rtl::OUString::createFromAscii("align"));
+ static rtl::OUString aStrStretch(rtl::OUString::createFromAscii("stretch"));
+
+ if(aContent.match(aStrAlign))
+ {
+ setMethod(true);
+ }
+ else if(aContent.match(aStrStretch))
+ {
+ setMethod(false);
+ }
+ }
+ break;
+ }
+ case SVGTokenSpacing:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrAuto(rtl::OUString::createFromAscii("auto"));
+ static rtl::OUString aStrExact(rtl::OUString::createFromAscii("exact"));
+
+ if(aContent.match(aStrAuto))
+ {
+ setSpacing(true);
+ }
+ else if(aContent.match(aStrExact))
+ {
+ setSpacing(false);
+ }
+ }
+ break;
+ }
+ case SVGTokenXlinkHref:
+ {
+ const sal_Int32 nLen(aContent.getLength());
+
+ if(nLen && sal_Unicode('#') == aContent[0])
+ {
+ maXLink = aContent.copy(1);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ bool SvgTextPathNode::isValid() const
+ {
+ const SvgPathNode* pSvgPathNode = dynamic_cast< const SvgPathNode* >(getDocument().findSvgNodeById(maXLink));
+
+ if(!pSvgPathNode)
+ {
+ return false;
+ }
+
+ const basegfx::B2DPolyPolygon* pPolyPolyPath = pSvgPathNode->getPath();
+
+ if(!pPolyPolyPath || !pPolyPolyPath->count())
+ {
+ return false;
+ }
+
+ const basegfx::B2DPolygon aPolygon(pPolyPolyPath->getB2DPolygon(0));
+
+ if(!aPolygon.count())
+ {
+ return false;
+ }
+
+ const double fBasegfxPathLength(basegfx::tools::getLength(aPolygon));
+
+ if(basegfx::fTools::equalZero(fBasegfxPathLength))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ void SvgTextPathNode::decomposePathNode(
+ const drawinglayer::primitive2d::Primitive2DSequence& rPathContent,
+ drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+ const basegfx::B2DPoint& rTextStart) const
+ {
+ if(rPathContent.hasElements())
+ {
+ const SvgPathNode* pSvgPathNode = dynamic_cast< const SvgPathNode* >(getDocument().findSvgNodeById(maXLink));
+
+ if(pSvgPathNode)
+ {
+ const basegfx::B2DPolyPolygon* pPolyPolyPath = pSvgPathNode->getPath();
+
+ if(pPolyPolyPath && pPolyPolyPath->count())
+ {
+ basegfx::B2DPolygon aPolygon(pPolyPolyPath->getB2DPolygon(0));
+
+ if(pSvgPathNode->getTransform())
+ {
+ aPolygon.transform(*pSvgPathNode->getTransform());
+ }
+
+ const double fBasegfxPathLength(basegfx::tools::getLength(aPolygon));
+
+ if(!basegfx::fTools::equalZero(fBasegfxPathLength))
+ {
+ double fUserToBasegfx(1.0); // multiply: user->basegfx, divide: basegfx->user
+
+ if(pSvgPathNode->getPathLength().isSet())
+ {
+ const double fUserLength(pSvgPathNode->getPathLength().solve(*this, length));
+
+ if(fUserLength > 0.0 && !basegfx::fTools::equal(fUserLength, fBasegfxPathLength))
+ {
+ fUserToBasegfx = fUserLength / fBasegfxPathLength;
+ }
+ }
+
+ double fPosition(0.0);
+
+ if(getStartOffset().isSet())
+ {
+ if(Unit_percent == getStartOffset().getUnit())
+ {
+ // percent are relative to path length
+ fPosition = getStartOffset().getNumber() * 0.01 * fBasegfxPathLength;
+ }
+ else
+ {
+ fPosition = getStartOffset().solve(*this, length) * fUserToBasegfx;
+ }
+ }
+
+ if(fPosition >= 0.0)
+ {
+ const sal_Int32 nLength(rPathContent.getLength());
+ sal_Int32 nCurrent(0);
+
+ while(fPosition < fBasegfxPathLength && nCurrent < nLength)
+ {
+ const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pCandidate = 0;
+ const drawinglayer::primitive2d::Primitive2DReference xReference(rPathContent[nCurrent]);
+
+ if(xReference.is())
+ {
+ pCandidate = dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(xReference.get());
+ }
+
+ if(pCandidate)
+ {
+ const pathTextBreakupHelper aPathTextBreakupHelper(
+ *pCandidate,
+ aPolygon,
+ fBasegfxPathLength,
+ fUserToBasegfx,
+ fPosition,
+ rTextStart);
+
+ const drawinglayer::primitive2d::Primitive2DSequence aResult(
+ aPathTextBreakupHelper.getResult(drawinglayer::primitive2d::BreakupUnit_character));
+
+ if(aResult.hasElements())
+ {
+ drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aResult);
+ }
+
+ // advance position to consumed
+ fPosition = aPathTextBreakupHelper.getPosition();
+ }
+
+ nCurrent++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgtoken.cxx b/svgio/source/svgreader/svgtoken.cxx
new file mode 100644
index 000000000000..a165e9aa4311
--- /dev/null
+++ b/svgio/source/svgreader/svgtoken.cxx
@@ -0,0 +1,318 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgtoken.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ static rtl::OUString aSVGStrWidth(rtl::OUString::createFromAscii("width"));
+ static rtl::OUString aSVGStrHeight(rtl::OUString::createFromAscii("height"));
+ static rtl::OUString aSVGStrViewBox(rtl::OUString::createFromAscii("viewBox"));
+ static rtl::OUString aSVGStrTransform(rtl::OUString::createFromAscii("transform"));
+ static rtl::OUString aSVGStrStyle(rtl::OUString::createFromAscii("style"));
+ static rtl::OUString aSVGStrD(rtl::OUString::createFromAscii("d"));
+ static rtl::OUString aSVGStrX(rtl::OUString::createFromAscii("x"));
+ static rtl::OUString aSVGStrY(rtl::OUString::createFromAscii("y"));
+ static rtl::OUString aSVGStrXmlns(rtl::OUString::createFromAscii("xmlns"));
+ static rtl::OUString aSVGStrVersion(rtl::OUString::createFromAscii("version"));
+ static rtl::OUString aSVGStrId(rtl::OUString::createFromAscii("id"));
+ static rtl::OUString aSVGStrRx(rtl::OUString::createFromAscii("rx"));
+ static rtl::OUString aSVGStrRy(rtl::OUString::createFromAscii("ry"));
+ static rtl::OUString aSVGStrPoints(rtl::OUString::createFromAscii("points"));
+ static rtl::OUString aSVGStrDx(rtl::OUString::createFromAscii("dx"));
+ static rtl::OUString aSVGStrDy(rtl::OUString::createFromAscii("dy"));
+ static rtl::OUString aSVGStrRotate(rtl::OUString::createFromAscii("rotate"));
+ static rtl::OUString aSVGStrTextLength(rtl::OUString::createFromAscii("textLength"));
+ static rtl::OUString aSVGStrLengthAdjust(rtl::OUString::createFromAscii("lengthAdjust"));
+ static rtl::OUString aSVGStrFont(rtl::OUString::createFromAscii("font"));
+ static rtl::OUString aSVGStrFontFamily(rtl::OUString::createFromAscii("font-family"));
+ static rtl::OUString aSVGStrFontSize(rtl::OUString::createFromAscii("font-size"));
+ static rtl::OUString aSVGStrFontSizeAdjust(rtl::OUString::createFromAscii("font-size-adjust"));
+ static rtl::OUString aSVGStrFontStretch(rtl::OUString::createFromAscii("font-stretch"));
+ static rtl::OUString aSVGStrFontStyle(rtl::OUString::createFromAscii("font-style"));
+ static rtl::OUString aSVGStrFontVariant(rtl::OUString::createFromAscii("font-variant"));
+ static rtl::OUString aSVGStrFontWeight(rtl::OUString::createFromAscii("font-weight"));
+ static rtl::OUString aSVGStrDirection(rtl::OUString::createFromAscii("direction"));
+ static rtl::OUString aSVGStrLetterSpacing(rtl::OUString::createFromAscii("letter-spacing"));
+ static rtl::OUString aSVGStrTextDecoration(rtl::OUString::createFromAscii("text-decoration"));
+ static rtl::OUString aSVGStrUnicodeBidi(rtl::OUString::createFromAscii("unicode-bidi"));
+ static rtl::OUString aSVGStrWordSpacing(rtl::OUString::createFromAscii("word-spacing"));
+ static rtl::OUString aSVGStrTspan(rtl::OUString::createFromAscii("tspan"));
+ static rtl::OUString aSVGStrTref(rtl::OUString::createFromAscii("tref"));
+ static rtl::OUString aSVGStrTextPath(rtl::OUString::createFromAscii("textPath"));
+ static rtl::OUString aSVGStrStartOffset(rtl::OUString::createFromAscii("startOffset"));
+ static rtl::OUString aSVGStrMethod(rtl::OUString::createFromAscii("method"));
+ static rtl::OUString aSVGStrSpacing(rtl::OUString::createFromAscii("spacing"));
+ static rtl::OUString aSVGStrTextAlign(rtl::OUString::createFromAscii("text-align"));
+ static rtl::OUString aSVGStrPathLength(rtl::OUString::createFromAscii("pathLength"));
+ static rtl::OUString aSVGStrType(rtl::OUString::createFromAscii("type"));
+ static rtl::OUString aSVGStrClass(rtl::OUString::createFromAscii("class"));
+ static rtl::OUString aSVGStrTextAnchor(rtl::OUString::createFromAscii("text-anchor"));
+ static rtl::OUString aSVGStrXmlSpace(rtl::OUString::createFromAscii("xml:space"));
+ static rtl::OUString aSVGStrColor(rtl::OUString::createFromAscii("color"));
+ static rtl::OUString aSVGStrClipPathNode(rtl::OUString::createFromAscii("clipPath"));
+ static rtl::OUString aSVGStrClipPathProperty(rtl::OUString::createFromAscii("clip-path"));
+ static rtl::OUString aSVGStrMask(rtl::OUString::createFromAscii("mask"));
+ static rtl::OUString aSVGStrClipPathUnits(rtl::OUString::createFromAscii("clipPathUnits"));
+ static rtl::OUString aSVGStrMaskUnits(rtl::OUString::createFromAscii("maskUnits"));
+ static rtl::OUString aSVGStrMaskContentUnits(rtl::OUString::createFromAscii("maskContentUnits"));
+ static rtl::OUString aSVGStrClipRule(rtl::OUString::createFromAscii("clip-rule"));
+ static rtl::OUString aSVGStrMarker(rtl::OUString::createFromAscii("marker"));
+ static rtl::OUString aSVGStrMarkerStart(rtl::OUString::createFromAscii("marker-start"));
+ static rtl::OUString aSVGStrMarkerMid(rtl::OUString::createFromAscii("marker-mid"));
+ static rtl::OUString aSVGStrMarkerEnd(rtl::OUString::createFromAscii("marker-end"));
+ static rtl::OUString aSVGStrRefX(rtl::OUString::createFromAscii("refX"));
+ static rtl::OUString aSVGStrRefY(rtl::OUString::createFromAscii("refY"));
+ static rtl::OUString aSVGStrMarkerUnits(rtl::OUString::createFromAscii("markerUnits"));
+ static rtl::OUString aSVGStrMarkerWidth(rtl::OUString::createFromAscii("markerWidth"));
+ static rtl::OUString aSVGStrMarkerHeight(rtl::OUString::createFromAscii("markerHeight"));
+ static rtl::OUString aSVGStrOrient(rtl::OUString::createFromAscii("orient"));
+ static rtl::OUString aSVGStrPattern(rtl::OUString::createFromAscii("pattern"));
+ static rtl::OUString aSVGStrPatternUnits(rtl::OUString::createFromAscii("patternUnits"));
+ static rtl::OUString aSVGStrPatternContentUnits(rtl::OUString::createFromAscii("patternContentUnits"));
+ static rtl::OUString aSVGStrPatternTransform(rtl::OUString::createFromAscii("patternTransform"));
+ static rtl::OUString aSVGStrOpacity(rtl::OUString::createFromAscii("opacity"));
+
+ static rtl::OUString aSVGStrPreserveAspectRatio(rtl::OUString::createFromAscii("preserveAspectRatio"));
+ static rtl::OUString aSVGStrDefer(rtl::OUString::createFromAscii("defer"));
+ static rtl::OUString aSVGStrNone(rtl::OUString::createFromAscii("none"));
+ static rtl::OUString aSVGStrXMinYMin(rtl::OUString::createFromAscii("xMinYMin"));
+ static rtl::OUString aSVGStrXMidYMin(rtl::OUString::createFromAscii("xMidYMin"));
+ static rtl::OUString aSVGStrXMaxYMin(rtl::OUString::createFromAscii("xMaxYMin"));
+ static rtl::OUString aSVGStrXMinYMid(rtl::OUString::createFromAscii("xMinYMid"));
+ static rtl::OUString aSVGStrXMidYMid(rtl::OUString::createFromAscii("xMidYMid"));
+ static rtl::OUString aSVGStrXMaxYMid(rtl::OUString::createFromAscii("xMaxYMid"));
+ static rtl::OUString aSVGStrXMinYMax(rtl::OUString::createFromAscii("xMinYMax"));
+ static rtl::OUString aSVGStrXMidYMax(rtl::OUString::createFromAscii("xMidYMax"));
+ static rtl::OUString aSVGStrXMaxYMax(rtl::OUString::createFromAscii("xMaxYMax"));
+ static rtl::OUString aSVGStrMeet(rtl::OUString::createFromAscii("meet"));
+ static rtl::OUString aSVGStrSlice(rtl::OUString::createFromAscii("slice"));
+
+ static rtl::OUString aSVGStrDefs(rtl::OUString::createFromAscii("defs"));
+ static rtl::OUString aSVGStrG(rtl::OUString::createFromAscii("g"));
+ static rtl::OUString aSVGStrSvg(rtl::OUString::createFromAscii("svg"));
+ static rtl::OUString aSVGStrSymbol(rtl::OUString::createFromAscii("symbol"));
+ static rtl::OUString aSVGStrUse(rtl::OUString::createFromAscii("use"));
+
+ static rtl::OUString aSVGStrCircle(rtl::OUString::createFromAscii("circle"));
+ static rtl::OUString aSVGStrEllipse(rtl::OUString::createFromAscii("ellipse"));
+ static rtl::OUString aSVGStrLine(rtl::OUString::createFromAscii("line"));
+ static rtl::OUString aSVGStrPath(rtl::OUString::createFromAscii("path"));
+ static rtl::OUString aSVGStrPolygon(rtl::OUString::createFromAscii("polygon"));
+ static rtl::OUString aSVGStrPolyline(rtl::OUString::createFromAscii("polyline"));
+ static rtl::OUString aSVGStrRect(rtl::OUString::createFromAscii("rect"));
+ static rtl::OUString aSVGStrImage(rtl::OUString::createFromAscii("image"));
+
+ static rtl::OUString aSVGStrLinearGradient(rtl::OUString::createFromAscii("linearGradient"));
+ static rtl::OUString aSVGStrRadialGradient(rtl::OUString::createFromAscii("radialGradient"));
+ static rtl::OUString aSVGStrStop(rtl::OUString::createFromAscii("stop"));
+ static rtl::OUString aSVGStrOffset(rtl::OUString::createFromAscii("offset"));
+ static rtl::OUString aSVGStrX1(rtl::OUString::createFromAscii("x1"));
+ static rtl::OUString aSVGStrY1(rtl::OUString::createFromAscii("y1"));
+ static rtl::OUString aSVGStrX2(rtl::OUString::createFromAscii("x2"));
+ static rtl::OUString aSVGStrY2(rtl::OUString::createFromAscii("y2"));
+ static rtl::OUString aSVGStrCx(rtl::OUString::createFromAscii("cx"));
+ static rtl::OUString aSVGStrCy(rtl::OUString::createFromAscii("cy"));
+ static rtl::OUString aSVGStrFx(rtl::OUString::createFromAscii("fx"));
+ static rtl::OUString aSVGStrFy(rtl::OUString::createFromAscii("fy"));
+ static rtl::OUString aSVGStrR(rtl::OUString::createFromAscii("r"));
+ static rtl::OUString aSVGStrGradientUnits(rtl::OUString::createFromAscii("gradientUnits"));
+ static rtl::OUString aSVGStrGradientTransform(rtl::OUString::createFromAscii("gradientTransform"));
+ static rtl::OUString aSVGStrSpreadMethod(rtl::OUString::createFromAscii("spreadMethod"));
+ static rtl::OUString aSVGStrXlinkHref(rtl::OUString::createFromAscii("xlink:href"));
+ static rtl::OUString aSVGStrStopColor(rtl::OUString::createFromAscii("stop-color"));
+ static rtl::OUString aSVGStrStopOpacity(rtl::OUString::createFromAscii("stop-opacity"));
+
+ static rtl::OUString aSVGStrFill(rtl::OUString::createFromAscii("fill"));
+ static rtl::OUString aSVGStrFillOpacity(rtl::OUString::createFromAscii("fill-opacity"));
+ static rtl::OUString aSVGStrFillRule(rtl::OUString::createFromAscii("fill-rule"));
+
+ static rtl::OUString aSVGStrStroke(rtl::OUString::createFromAscii("stroke"));
+ static rtl::OUString aSVGStrStrokeDasharray(rtl::OUString::createFromAscii("stroke-dasharray"));
+ static rtl::OUString aSVGStrStrokeDashoffset(rtl::OUString::createFromAscii("stroke-dashoffset"));
+ static rtl::OUString aSVGStrStrokeLinecap(rtl::OUString::createFromAscii("stroke-linecap"));
+ static rtl::OUString aSVGStrStrokeLinejoin(rtl::OUString::createFromAscii("stroke-linejoin"));
+ static rtl::OUString aSVGStrStrokeMiterlimit(rtl::OUString::createFromAscii("stroke-miterlimit"));
+ static rtl::OUString aSVGStrStrokeOpacity(rtl::OUString::createFromAscii("stroke-opacity"));
+ static rtl::OUString aSVGStrStrokeWidth(rtl::OUString::createFromAscii("stroke-width"));
+
+ static rtl::OUString aSVGStrText(rtl::OUString::createFromAscii("text"));
+
+ SVGToken StrToSVGToken(const rtl::OUString& rStr)
+ {
+ typedef boost::unordered_map< rtl::OUString, SVGToken, rtl::OUStringHash,::std::equal_to< ::rtl::OUString > > SVGTokenMapper;
+ typedef std::pair< rtl::OUString, SVGToken > SVGTokenValueType;
+ static SVGTokenMapper aSVGTokenMapperList;
+
+ if(aSVGTokenMapperList.empty())
+ {
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrWidth, SVGTokenWidth));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrHeight, SVGTokenHeight));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrViewBox, SVGTokenViewBox));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrTransform, SVGTokenTransform));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStyle, SVGTokenStyle));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrD, SVGTokenD));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrX, SVGTokenX));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrY, SVGTokenY));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXmlns, SVGTokenXmlns));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrVersion, SVGTokenVersion));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrId, SVGTokenId));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrRx, SVGTokenRx));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrRy, SVGTokenRy));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPoints, SVGTokenPoints));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrDx, SVGTokenDx));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrDy, SVGTokenDy));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrRotate, SVGTokenRotate));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFont, SVGTokenFont));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFontFamily, SVGTokenFontFamily));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFontSize, SVGTokenFontSize));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFontSizeAdjust, SVGTokenFontSizeAdjust));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFontStretch, SVGTokenFontStretch));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFontStyle, SVGTokenFontStyle));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFontVariant, SVGTokenFontVariant));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFontWeight, SVGTokenFontWeight));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrDirection, SVGTokenDirection));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrLetterSpacing, SVGTokenLetterSpacing));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrTextDecoration, SVGTokenTextDecoration));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrUnicodeBidi, SVGTokenUnicodeBidi));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrWordSpacing, SVGTokenWordSpacing));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrTspan, SVGTokenTspan));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrTref, SVGTokenTref));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrTextPath, SVGTokenTextPath));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStartOffset, SVGTokenStartOffset));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMethod, SVGTokenMethod));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrSpacing, SVGTokenSpacing));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrTextAlign, SVGTokenTextAlign));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPathLength, SVGTokenPathLength));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrType, SVGTokenType));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrClass, SVGTokenClass));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrTextAnchor, SVGTokenTextAnchor));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXmlSpace, SVGTokenXmlSpace));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrColor, SVGTokenColor));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrClipPathNode, SVGTokenClipPathNode));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrClipPathProperty, SVGTokenClipPathProperty));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMask, SVGTokenMask));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrClipPathUnits, SVGTokenClipPathUnits));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMaskUnits, SVGTokenMaskUnits));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMaskContentUnits, SVGTokenMaskContentUnits));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrClipRule, SVGTokenClipRule));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMarker, SVGTokenMarker));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMarkerStart, SVGTokenMarkerStart));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMarkerMid, SVGTokenMarkerMid));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMarkerEnd, SVGTokenMarkerEnd));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrRefX, SVGTokenRefX));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrRefY, SVGTokenRefY));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMarkerUnits, SVGTokenMarkerUnits));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMarkerWidth, SVGTokenMarkerWidth));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMarkerHeight, SVGTokenMarkerHeight));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrOrient, SVGTokenOrient));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPattern, SVGTokenPattern));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPatternUnits, SVGTokenPatternUnits));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPatternContentUnits, SVGTokenPatternContentUnits));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPatternTransform, SVGTokenPatternTransform));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrOpacity, SVGTokenOpacity));
+
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPreserveAspectRatio, SVGTokenPreserveAspectRatio));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrDefer, SVGTokenDefer));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrNone, SVGTokenNone));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMinYMin, SVGTokenXMinYMin));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMidYMin, SVGTokenXMidYMin));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMaxYMin, SVGTokenXMaxYMin));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMinYMid, SVGTokenXMinYMid));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMidYMid, SVGTokenXMidYMid));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMaxYMid, SVGTokenXMaxYMid));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMinYMax, SVGTokenXMinYMax));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMidYMax, SVGTokenXMidYMax));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMaxYMax, SVGTokenXMaxYMax));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMeet, SVGTokenMeet));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrSlice, SVGTokenSlice));
+
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrDefs, SVGTokenDefs));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrG, SVGTokenG));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrSvg, SVGTokenSvg));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrSymbol, SVGTokenSymbol));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrUse, SVGTokenUse));
+
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrCircle, SVGTokenCircle));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrEllipse, SVGTokenEllipse));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrLine, SVGTokenLine));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPath, SVGTokenPath));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPolygon, SVGTokenPolygon));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPolyline, SVGTokenPolyline));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrRect, SVGTokenRect));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrImage, SVGTokenImage));
+
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrLinearGradient, SVGTokenLinearGradient));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrRadialGradient, SVGTokenRadialGradient));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStop, SVGTokenStop));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrOffset, SVGTokenOffset));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrX1, SVGTokenX1));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrY1, SVGTokenY1));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrX2, SVGTokenX2));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrY2, SVGTokenY2));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrCx, SVGTokenCx));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrCy, SVGTokenCy));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFx, SVGTokenFx));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFy, SVGTokenFy));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrR, SVGTokenR));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrGradientUnits, SVGTokenGradientUnits));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrGradientTransform, SVGTokenGradientTransform));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrSpreadMethod, SVGTokenSpreadMethod));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXlinkHref, SVGTokenXlinkHref));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStopColor, SVGTokenStopColor));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStopOpacity, SVGTokenStopOpacity));
+
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFill, SVGTokenFill));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFillOpacity, SVGTokenFillOpacity));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFillRule, SVGTokenFillRule));
+
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStroke, SVGTokenStroke));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStrokeDasharray, SVGTokenStrokeDasharray));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStrokeDashoffset, SVGTokenStrokeDashoffset));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStrokeLinecap, SVGTokenStrokeLinecap));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStrokeLinejoin, SVGTokenStrokeLinejoin));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStrokeMiterlimit, SVGTokenStrokeMiterlimit));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStrokeOpacity, SVGTokenStrokeOpacity));
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStrokeWidth, SVGTokenStrokeWidth));
+
+ aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrText, SVGTokenText));
+ }
+
+ const SVGTokenMapper::const_iterator aResult(aSVGTokenMapperList.find(rStr));
+
+ if(aResult == aSVGTokenMapperList.end())
+ {
+ return SVGTokenUnknown;
+ }
+ else
+ {
+ return aResult->second;
+ }
+ }
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgtools.cxx b/svgio/source/svgreader/svgtools.cxx
new file mode 100644
index 000000000000..ae0df2fca7c9
--- /dev/null
+++ b/svgio/source/svgreader/svgtools.cxx
@@ -0,0 +1,1592 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgtools.hxx>
+#include <osl/thread.h>
+#include <tools/color.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <svgio/svgreader/svgtoken.hxx>
+#include <boost/unordered_map.hpp>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+#ifdef DBG_UTIL
+ void myAssert(const rtl::OUString& rMessage)
+ {
+ rtl::OString aMessage2;
+
+ rMessage.convertToString(&aMessage2, osl_getThreadTextEncoding(), RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR|RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR);
+ OSL_ENSURE(false, aMessage2.getStr());
+ }
+#endif
+
+ // common non-token strings
+ const rtl::OUString commonStrings::aStrUserSpaceOnUse(rtl::OUString::createFromAscii("userSpaceOnUse"));
+ const rtl::OUString commonStrings::aStrObjectBoundingBox(rtl::OUString::createFromAscii("objectBoundingBox"));
+ const rtl::OUString commonStrings::aStrNonzero(rtl::OUString::createFromAscii("nonzero"));
+ const rtl::OUString commonStrings::aStrEvenOdd(rtl::OUString::createFromAscii("evenodd"));
+
+ basegfx::B2DHomMatrix SvgAspectRatio::createLinearMapping(const basegfx::B2DRange& rTarget, const basegfx::B2DRange& rSource)
+ {
+ basegfx::B2DHomMatrix aRetval;
+ const double fSWidth(rSource.getWidth());
+ const double fSHeight(rSource.getHeight());
+ const bool bNoSWidth(basegfx::fTools::equalZero(fSWidth));
+ const bool bNoSHeight(basegfx::fTools::equalZero(fSHeight));
+
+ // transform from source state to unit range
+ aRetval.translate(-rSource.getMinX(), -rSource.getMinY());
+ aRetval.scale(
+ (bNoSWidth ? 1.0 : 1.0 / fSWidth) * rTarget.getWidth(),
+ (bNoSHeight ? 1.0 : 1.0 / fSHeight) * rTarget.getHeight());
+
+ // transform from unit rage to target range
+ aRetval.translate(rTarget.getMinX(), rTarget.getMinY());
+
+ return aRetval;
+ }
+
+ basegfx::B2DHomMatrix SvgAspectRatio::createMapping(const basegfx::B2DRange& rTarget, const basegfx::B2DRange& rSource) const
+ {
+ if(!isSet() || Align_none == getSvgAlign())
+ {
+ // create linear mapping (default)
+ return createLinearMapping(rTarget, rSource);
+ }
+
+ basegfx::B2DHomMatrix aRetval;
+
+ const double fSWidth(rSource.getWidth());
+ const double fSHeight(rSource.getHeight());
+ const bool bNoSWidth(basegfx::fTools::equalZero(fSWidth));
+ const bool bNoSHeight(basegfx::fTools::equalZero(fSHeight));
+ const double fScaleX((bNoSWidth ? 1.0 : 1.0 / fSWidth) * rTarget.getWidth());
+ const double fScaleY((bNoSHeight ? 1.0 : 1.0 / fSHeight) * rTarget.getHeight());
+ const double fScale(isMeetOrSlice() ? std::min(fScaleX, fScaleY) : std::max(fScaleX, fScaleY));
+
+ // remove source translation, apply scale
+ aRetval.translate(-rSource.getMinX(), -rSource.getMinY());
+ aRetval.scale(fScale, fScale);
+
+ // evaluate horizontal alignment
+ const double fNewWidth(fSWidth * fScale);
+ double fTransX(0.0);
+
+ switch(getSvgAlign())
+ {
+ case Align_xMidYMin:
+ case Align_xMidYMid:
+ case Align_xMidYMax:
+ {
+ // centerX
+ const double fFreeSpace(rTarget.getWidth() - fNewWidth);
+ fTransX = fFreeSpace * 0.5;
+ break;
+ }
+ case Align_xMaxYMin:
+ case Align_xMaxYMid:
+ case Align_xMaxYMax:
+ {
+ // Right align
+ const double fFreeSpace(rTarget.getWidth() - fNewWidth);
+ fTransX = fFreeSpace;
+ break;
+ }
+ default: break;
+ }
+
+ // evaluate vertical alignment
+ const double fNewHeight(fSHeight * fScale);
+ double fTransY(0.0);
+
+ switch(getSvgAlign())
+ {
+ case Align_xMinYMid:
+ case Align_xMidYMid:
+ case Align_xMaxYMid:
+ {
+ // centerY
+ const double fFreeSpace(rTarget.getHeight() - fNewHeight);
+ fTransY = fFreeSpace * 0.5;
+ break;
+ }
+ case Align_xMinYMax:
+ case Align_xMidYMax:
+ case Align_xMaxYMax:
+ {
+ // Bottom align
+ const double fFreeSpace(rTarget.getHeight() - fNewHeight);
+ fTransY = fFreeSpace;
+ break;
+ }
+ default: break;
+ }
+
+ // add target translation
+ aRetval.translate(
+ rTarget.getMinX() + fTransX,
+ rTarget.getMinY() + fTransY);
+
+ return aRetval;
+ }
+
+ double SvgNumber::solve(const InfoProvider& rInfoProvider, NumberType aNumberType) const
+ {
+ if(isSet())
+ {
+ switch(meUnit)
+ {
+ case Unit_em:
+ {
+ return mfNumber * rInfoProvider.getCurrentFontSize();
+ break;
+ }
+ case Unit_ex:
+ {
+ return mfNumber * rInfoProvider.getCurrentXHeight() * 0.5;
+ break;
+ }
+ case Unit_px:
+ {
+ return mfNumber;
+ break;
+ }
+ case Unit_pt:
+ case Unit_pc:
+ case Unit_cm:
+ case Unit_mm:
+ case Unit_in:
+ {
+ double fRetval(mfNumber);
+
+ switch(meUnit)
+ {
+ case Unit_pt: fRetval *= 1.25; break;
+ case Unit_pc: fRetval *= 15.0; break;
+ case Unit_cm: fRetval *= 35.43307; break;
+ case Unit_mm: fRetval *= 3.543307; break;
+ case Unit_in: fRetval *= 90.0; break;
+ default: break;
+ }
+
+ return fRetval;
+ break;
+ }
+ case Unit_percent:
+ {
+ double fRetval(mfNumber * 0.01);
+ const basegfx::B2DRange* pViewPort = rInfoProvider.getCurrentViewPort();
+
+ if(!pViewPort)
+ {
+ // no viewPort, assume a normal page size (A4)
+ static basegfx::B2DRange aDinA4Range(
+ 0.0,
+ 0.0,
+ 210.0 * 3.543307,
+ 297.0 * 3.543307);
+
+ pViewPort = &aDinA4Range;
+ }
+
+ if(pViewPort)
+ {
+ if(xcoordinate == aNumberType)
+ {
+ // it's a x-coordinate, relative to current width (w)
+ fRetval *= pViewPort->getWidth();
+ }
+ else if(ycoordinate == aNumberType)
+ {
+ // it's a y-coordinate, relative to current height (h)
+ fRetval *= pViewPort->getHeight();
+ }
+ else // length
+ {
+ // it's a length, relative to sqrt(w*w + h*h)/sqrt(2)
+ const double fCurrentWidth(pViewPort->getWidth());
+ const double fCurrentHeight(pViewPort->getHeight());
+ const double fCurrentLength(
+ sqrt(fCurrentWidth * fCurrentWidth + fCurrentHeight * fCurrentHeight)/sqrt(2.0));
+
+ fRetval *= fCurrentLength;
+ }
+ }
+
+ return fRetval;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ /// not set
+ OSL_ENSURE(false, "SvgNumber not set (!)");
+ return 0.0;
+ }
+
+ bool SvgNumber::isPositive() const
+ {
+ return basegfx::fTools::moreOrEqual(mfNumber, 0.0);
+ }
+
+ void skip_char(const rtl::OUString& rCandidate, const sal_Unicode& rChar, sal_Int32& nPos, const sal_Int32 nLen)
+ {
+ while(nPos < nLen && rChar == rCandidate[nPos])
+ {
+ nPos++;
+ }
+ }
+
+ void skip_char(const rtl::OUString& rCandidate, const sal_Unicode& rCharA, const sal_Unicode& rCharB, sal_Int32& nPos, const sal_Int32 nLen)
+ {
+ while(nPos < nLen && (rCharA == rCandidate[nPos] || rCharB == rCandidate[nPos]))
+ {
+ nPos++;
+ }
+ }
+
+ void copySign(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen)
+ {
+ if(nPos < nLen)
+ {
+ const sal_Unicode aChar(rCandidate[nPos]);
+
+ if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
+ {
+ rTarget.append(aChar);
+ nPos++;
+ }
+ }
+ }
+
+ void copyNumber(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen)
+ {
+ bool bOnNumber(true);
+
+ while(bOnNumber && nPos < nLen)
+ {
+ const sal_Unicode aChar(rCandidate[nPos]);
+
+ bOnNumber = (sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar) || sal_Unicode('.') == aChar;
+
+ if(bOnNumber)
+ {
+ rTarget.append(aChar);
+ nPos++;
+ }
+ }
+ }
+
+ void copyHex(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen)
+ {
+ bool bOnHex(true);
+
+ while(bOnHex && nPos < nLen)
+ {
+ const sal_Unicode aChar(rCandidate[nPos]);
+
+ bOnHex = (sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
+ || (sal_Unicode('A') <= aChar && sal_Unicode('F') >= aChar)
+ || (sal_Unicode('a') <= aChar && sal_Unicode('f') >= aChar);
+
+ if(bOnHex)
+ {
+ rTarget.append(aChar);
+ nPos++;
+ }
+ }
+ }
+
+ void copyString(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen)
+ {
+ bool bOnChar(true);
+
+ while(bOnChar && nPos < nLen)
+ {
+ const sal_Unicode aChar(rCandidate[nPos]);
+
+ bOnChar = (sal_Unicode('a') <= aChar && sal_Unicode('z') >= aChar)
+ || (sal_Unicode('A') <= aChar && sal_Unicode('Z') >= aChar)
+ || sal_Unicode('-') == aChar;
+
+ if(bOnChar)
+ {
+ rTarget.append(aChar);
+ nPos++;
+ }
+ }
+ }
+
+ void copyToLimiter(const rtl::OUString& rCandidate, const sal_Unicode& rLimiter, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen)
+ {
+ while(nPos < nLen && rLimiter != rCandidate[nPos])
+ {
+ rTarget.append(rCandidate[nPos]);
+ nPos++;
+ }
+ }
+
+ bool readNumber(const rtl::OUString& rCandidate, sal_Int32& nPos, double& fNum, const sal_Int32 nLen)
+ {
+ if(nPos < nLen)
+ {
+ rtl::OUStringBuffer aNum;
+
+ copySign(rCandidate, nPos, aNum, nLen);
+ copyNumber(rCandidate, nPos, aNum, nLen);
+
+ if(nPos < nLen)
+ {
+ const sal_Unicode aChar(rCandidate[nPos]);
+
+ if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
+ {
+ // try to read exponential number, but be careful. I had
+ // a case where dx="2em" was used, thus the 'e' was consumed
+ // by error. First try if there are numbers after the 'e',
+ // safe current state
+ nPos++;
+ const rtl::OUStringBuffer aNum2(aNum);
+ const sal_Int32 nPosAfterE(nPos);
+
+ aNum.append(aChar);
+ copySign(rCandidate, nPos, aNum, nLen);
+ copyNumber(rCandidate, nPos, aNum, nLen);
+
+ if(nPosAfterE == nPos)
+ {
+ // no number after 'e', go back. Do not
+ // return false, it's still a valid integer number
+ aNum = aNum2;
+ nPos--;
+ }
+ }
+ }
+
+ if(aNum.getLength())
+ {
+ rtl_math_ConversionStatus eStatus;
+
+ fNum = rtl::math::stringToDouble(
+ aNum.makeStringAndClear(), (sal_Unicode)('.'), (sal_Unicode)(','),
+ &eStatus, 0);
+
+ return eStatus == rtl_math_ConversionStatus_Ok;
+ }
+ }
+
+ return false;
+ }
+
+ SvgUnit readUnit(const rtl::OUString& rCandidate, sal_Int32& nPos, const sal_Int32 nLen)
+ {
+ SvgUnit aRetval(Unit_px);
+
+ if(nPos < nLen)
+ {
+ const sal_Unicode aCharA(rCandidate[nPos]);
+
+ if(nPos + 1 < nLen)
+ {
+ const sal_Unicode aCharB(rCandidate[nPos + 1]);
+ bool bTwoCharValid(false);
+
+ switch(aCharA)
+ {
+ case sal_Unicode('e') :
+ {
+ if(sal_Unicode('m') == aCharB)
+ {
+ // 'em' Relative to current font size
+ aRetval = Unit_em;
+ bTwoCharValid = true;
+ }
+ else if(sal_Unicode('x') == aCharB)
+ {
+ // 'ex' Relative to current font x-height
+ aRetval = Unit_ex;
+ bTwoCharValid = true;
+ }
+ break;
+ }
+ case sal_Unicode('p') :
+ {
+ if(sal_Unicode('x') == aCharB)
+ {
+ // 'px' UserUnit (default)
+ bTwoCharValid = true;
+ }
+ else if(sal_Unicode('t') == aCharB)
+ {
+ // 'pt' == 1.25 px
+ aRetval = Unit_pt;
+ bTwoCharValid = true;
+ }
+ else if(sal_Unicode('c') == aCharB)
+ {
+ // 'pc' == 15 px
+ aRetval = Unit_pc;
+ bTwoCharValid = true;
+ }
+ break;
+ }
+ case sal_Unicode('i') :
+ {
+ if(sal_Unicode('n') == aCharB)
+ {
+ // 'in' == 90 px
+ aRetval = Unit_in;
+ bTwoCharValid = true;
+ }
+ break;
+ }
+ case sal_Unicode('c') :
+ {
+ if(sal_Unicode('m') == aCharB)
+ {
+ // 'cm' == 35.43307 px
+ aRetval = Unit_cm;
+ bTwoCharValid = true;
+ }
+ break;
+ }
+ case sal_Unicode('m') :
+ {
+ if(sal_Unicode('m') == aCharB)
+ {
+ // 'mm' == 3.543307 px
+ aRetval = Unit_mm;
+ bTwoCharValid = true;
+ }
+ break;
+ }
+ }
+
+ if(bTwoCharValid)
+ {
+ nPos += 2;
+ }
+ }
+ else
+ {
+ if(sal_Unicode('%') == aCharA)
+ {
+ // percent used, relative to current
+ nPos++;
+ aRetval = Unit_percent;
+ }
+ }
+ }
+
+ return aRetval;
+ }
+
+ bool readNumberAndUnit(const rtl::OUString& rCandidate, sal_Int32& nPos, SvgNumber& aNum, const sal_Int32 nLen)
+ {
+ double fNum(0.0);
+
+ if(readNumber(rCandidate, nPos, fNum, nLen))
+ {
+ skip_char(rCandidate, sal_Unicode(' '), nPos, nLen);
+ aNum = SvgNumber(fNum, readUnit(rCandidate, nPos, nLen));
+
+ return true;
+ }
+
+ return false;
+ }
+
+ bool readAngle(const rtl::OUString& rCandidate, sal_Int32& nPos, double& fAngle, const sal_Int32 nLen)
+ {
+ if(readNumber(rCandidate, nPos, fAngle, nLen))
+ {
+ skip_char(rCandidate, sal_Unicode(' '), nPos, nLen);
+
+ enum DegreeType
+ {
+ deg,
+ grad,
+ rad
+ } aType(deg); // degrees is default
+
+ if(nPos < nLen)
+ {
+ const sal_Unicode aChar(rCandidate[nPos]);
+ static rtl::OUString aStrGrad(rtl::OUString::createFromAscii("grad"));
+ static rtl::OUString aStrRad(rtl::OUString::createFromAscii("rad"));
+
+ switch(aChar)
+ {
+ case sal_Unicode('g') :
+ case sal_Unicode('G') :
+ {
+ if(rCandidate.matchIgnoreAsciiCase(aStrGrad, nPos))
+ {
+ // angle in grad
+ nPos += aStrGrad.getLength();
+ }
+ break;
+ }
+ case sal_Unicode('r') :
+ case sal_Unicode('R') :
+ {
+ if(rCandidate.matchIgnoreAsciiCase(aStrRad, nPos))
+ {
+ // angle in radians
+ nPos += aStrRad.getLength();
+ }
+ break;
+ }
+ }
+ }
+
+ // convert to radians
+ if(deg == aType)
+ {
+ fAngle *= F_PI / 180.0;
+ }
+ else if(grad == aType)
+ {
+ // looks like 100 grad is 90 degrees
+ fAngle *= F_PI / 200.0;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ sal_Int32 read_hex(const sal_Unicode& rChar)
+ {
+ if(rChar >= sal_Unicode('0') && rChar <=sal_Unicode('9'))
+ {
+ return sal_Int32(rChar - sal_Unicode('0'));
+ }
+ else if(rChar >= sal_Unicode('A') && rChar <=sal_Unicode('F'))
+ {
+ return 10 + sal_Int32(rChar - sal_Unicode('A'));
+ }
+ else if(rChar >= sal_Unicode('a') && rChar <=sal_Unicode('f'))
+ {
+ return 10 + sal_Int32(rChar - sal_Unicode('a'));
+ }
+ else
+ {
+ // error
+ return 0;
+ }
+ }
+
+ bool match_colorKeyword(basegfx::BColor& rColor, const rtl::OUString& rName)
+ {
+ typedef boost::unordered_map< rtl::OUString, Color,
+ rtl::OUStringHash,
+ ::std::equal_to< ::rtl::OUString >
+ > ColorTokenMapper;
+ typedef std::pair< rtl::OUString, Color > ColorTokenValueType;
+ ColorTokenMapper aColorTokenMapperList;
+
+ if(aColorTokenMapperList.empty())
+ {
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("aliceblue"), Color(240, 248, 255)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("antiquewhite"), Color(250, 235, 215)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("aqua"), Color( 0, 255, 255)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("aquamarine"), Color(127, 255, 212)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("azure"), Color(240, 255, 255)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("beige"), Color(245, 245, 220)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("bisque"), Color(255, 228, 196)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("black"), Color( 0, 0, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("blanchedalmond"), Color(255, 235, 205)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("blue"), Color( 0, 0, 255)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("blueviolet"), Color(138, 43, 226)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("brown"), Color(165, 42, 42)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("burlywood"), Color(222, 184, 135)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("cadetblue"), Color( 95, 158, 160)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("chartreuse"), Color(127, 255, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("chocolate"), Color(210, 105, 30)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("coral"), Color(255, 127, 80)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("cornflowerblue"), Color(100, 149, 237)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("cornsilk"), Color(255, 248, 220)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("crimson"), Color(220, 20, 60)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("cyan"), Color( 0, 255, 255)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkblue"), Color( 0, 0, 139)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkcyan"), Color( 0, 139, 139)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkgoldenrod"), Color(184, 134, 11)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkgray"), Color(169, 169, 169)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkgreen"), Color( 0, 100, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkgrey"), Color(169, 169, 169)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkkhaki"), Color(189, 183, 107)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkmagenta"), Color(139, 0, 139)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkolivegreen"), Color( 85, 107, 47)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkorange"), Color(255, 140, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkorchid"), Color(153, 50, 204)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkred"), Color(139, 0, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darksalmon"), Color(233, 150, 122)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkseagreen"), Color(143, 188, 143)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkslateblue"), Color( 72, 61, 139)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkslategray"), Color( 47, 79, 79)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkslategrey"), Color( 47, 79, 79)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkturquoise"), Color( 0, 206, 209)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkviolet"), Color(148, 0, 211)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("deeppink"), Color(255, 20, 147)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("deepskyblue"), Color( 0, 191, 255)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("dimgray"), Color(105, 105, 105)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("dimgrey"), Color(105, 105, 105)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("dodgerblue"), Color( 30, 144, 255)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("firebrick"), Color(178, 34, 34)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("floralwhite"), Color(255, 250, 240)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("forestgreen"), Color( 34, 139, 34)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("fuchsia"), Color(255, 0, 255)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("gainsboro"), Color(220, 220, 220)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("ghostwhite"), Color(248, 248, 255)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("gold"), Color(255, 215, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("goldenrod"), Color(218, 165, 32)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("gray"), Color(128, 128, 128)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("grey"), Color(128, 128, 128)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("green"), Color(0, 128, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("greenyellow"), Color(173, 255, 47)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("honeydew"), Color(240, 255, 240)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("hotpink"), Color(255, 105, 180)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("indianred"), Color(205, 92, 92)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("indigo"), Color( 75, 0, 130)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("ivory"), Color(255, 255, 240)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("khaki"), Color(240, 230, 140)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lavender"), Color(230, 230, 250)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lavenderblush"), Color(255, 240, 245)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lawngreen"), Color(124, 252, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lemonchiffon"), Color(255, 250, 205)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightblue"), Color(173, 216, 230)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightcoral"), Color(240, 128, 128)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightcyan"), Color(224, 255, 255)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightgoldenrodyellow"), Color(250, 250, 210)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightgray"), Color(211, 211, 211)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightgreen"), Color(144, 238, 144)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightgrey"), Color(211, 211, 211)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightpink"), Color(255, 182, 193)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightsalmon"), Color(255, 160, 122)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightseagreen"), Color( 32, 178, 170)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightskyblue"), Color(135, 206, 250)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightslategray"), Color(119, 136, 153)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightslategrey"), Color(119, 136, 153)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightsteelblue"), Color(176, 196, 222)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightyellow"), Color(255, 255, 224)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lime"), Color( 0, 255, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("limegreen"), Color( 50, 205, 50)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("linen"), Color(250, 240, 230)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("magenta"), Color(255, 0, 255)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("maroon"), Color(128, 0, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumaquamarine"), Color(102, 205, 170)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumblue"), Color( 0, 0, 205)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumorchid"), Color(186, 85, 211)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumpurple"), Color(147, 112, 219)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumseagreen"), Color( 60, 179, 113)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumslateblue"), Color(123, 104, 238)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumspringgreen"), Color( 0, 250, 154)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumturquoise"), Color( 72, 209, 204)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumvioletred"), Color(199, 21, 133)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("midnightblue"), Color( 25, 25, 112)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mintcream"), Color(245, 255, 250)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mistyrose"), Color(255, 228, 225)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("moccasin"), Color(255, 228, 181)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("navajowhite"), Color(255, 222, 173)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("navy"), Color( 0, 0, 128)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("oldlace"), Color(253, 245, 230)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("olive"), Color(128, 128, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("olivedrab"), Color(107, 142, 35)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("orange"), Color(255, 165, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("orangered"), Color(255, 69, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("orchid"), Color(218, 112, 214)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("palegoldenrod"), Color(238, 232, 170)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("palegreen"), Color(152, 251, 152)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("paleturquoise"), Color(175, 238, 238)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("palevioletred"), Color(219, 112, 147)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("papayawhip"), Color(255, 239, 213)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("peachpuff"), Color(255, 218, 185)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("peru"), Color(205, 133, 63)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("pink"), Color(255, 192, 203)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("plum"), Color(221, 160, 221)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("powderblue"), Color(176, 224, 230)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("purple"), Color(128, 0, 128)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("red"), Color(255, 0, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("rosybrown"), Color(188, 143, 143)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("royalblue"), Color( 65, 105, 225)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("saddlebrown"), Color(139, 69, 19)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("salmon"), Color(250, 128, 114)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("sandybrown"), Color(244, 164, 96)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("seagreen"), Color( 46, 139, 87)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("seashell"), Color(255, 245, 238)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("sienna"), Color(160, 82, 45)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("silver"), Color(192, 192, 192)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("skyblue"), Color(135, 206, 235)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("slateblue"), Color(106, 90, 205)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("slategray"), Color(112, 128, 144)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("slategrey"), Color(112, 128, 144)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("snow"), Color(255, 250, 250)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("springgreen"), Color( 0, 255, 127)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("steelblue"), Color( 70, 130, 180)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("tan"), Color(210, 180, 140)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("teal"), Color( 0, 128, 128)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("thistle"), Color(216, 191, 216)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("tomato"), Color(255, 99, 71)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("turquoise"), Color( 64, 224, 208)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("violet"), Color(238, 130, 238)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("wheat"), Color(245, 222, 179)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("white"), Color(255, 255, 255)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("whitesmoke"), Color(245, 245, 245)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("yellow"), Color(255, 255, 0)));
+ aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("yellowgreen"), Color(154, 205, 50)));
+ }
+
+ const ColorTokenMapper::const_iterator aResult(aColorTokenMapperList.find(rName));
+
+ if(aResult == aColorTokenMapperList.end())
+ {
+ return false;
+ }
+ else
+ {
+ rColor = aResult->second.getBColor();
+ return true;
+ }
+ }
+
+ bool read_color(const rtl::OUString& rCandidate, basegfx::BColor& rColor)
+ {
+ const sal_Int32 nLen(rCandidate.getLength());
+
+ if(nLen)
+ {
+ const sal_Unicode aChar(rCandidate[0]);
+ const double fFactor(1.0 / 255.0);
+
+ if(aChar == sal_Unicode('#'))
+ {
+ // hex definition
+ rtl::OUStringBuffer aNum;
+ sal_Int32 nPos(1);
+
+ copyHex(rCandidate, nPos, aNum, nLen);
+ const sal_Int32 nLength(aNum.getLength());
+
+ if(3 == nLength)
+ {
+ const sal_Int32 nR(read_hex(aNum[0]));
+ const sal_Int32 nG(read_hex(aNum[1]));
+ const sal_Int32 nB(read_hex(aNum[2]));
+
+ rColor.setRed((nR | (nR << 4)) * fFactor);
+ rColor.setGreen((nG | (nG << 4)) * fFactor);
+ rColor.setBlue((nB | (nB << 4)) * fFactor);
+
+ return true;
+ }
+ else if(6 == nLength)
+ {
+ const sal_Int32 nR1(read_hex(aNum[0]));
+ const sal_Int32 nR2(read_hex(aNum[1]));
+ const sal_Int32 nG1(read_hex(aNum[2]));
+ const sal_Int32 nG2(read_hex(aNum[3]));
+ const sal_Int32 nB1(read_hex(aNum[4]));
+ const sal_Int32 nB2(read_hex(aNum[5]));
+
+ rColor.setRed((nR2 | (nR1 << 4)) * fFactor);
+ rColor.setGreen((nG2 | (nG1 << 4)) * fFactor);
+ rColor.setBlue((nB2 | (nB1 << 4)) * fFactor);
+
+ return true;
+ }
+ }
+ else
+ {
+ static rtl::OUString aStrRgb(rtl::OUString::createFromAscii("rgb"));
+
+ if(rCandidate.matchIgnoreAsciiCase(aStrRgb, 0))
+ {
+ // rgb definition
+ sal_Int32 nPos(aStrRgb.getLength());
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen);
+ double fR(0.0);
+
+ if(readNumber(rCandidate, nPos, fR, nLen))
+ {
+ skip_char(rCandidate, sal_Unicode(' '), nPos, nLen);
+
+ if(nPos < nLen)
+ {
+ const sal_Unicode aPercentChar(rCandidate[nPos]);
+ const bool bIsPercent(sal_Unicode('%') == aPercentChar);
+ double fG(0.0);
+
+ if(bIsPercent)
+ {
+ skip_char(rCandidate, sal_Unicode('%'), nPos, nLen);
+ }
+
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ if(readNumber(rCandidate, nPos, fG, nLen))
+ {
+ double fB(0.0);
+
+ if(bIsPercent)
+ {
+ skip_char(rCandidate, sal_Unicode('%'), nPos, nLen);
+ }
+
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ if(readNumber(rCandidate, nPos, fB, nLen))
+ {
+ const double fFac(bIsPercent ? 0.01 : fFactor);
+
+ rColor.setRed(fR * fFac);
+ rColor.setGreen(fG * fFac);
+ rColor.setBlue(fB * fFac);
+
+ if(bIsPercent)
+ {
+ skip_char(rCandidate, sal_Unicode('%'), nPos, nLen);
+ }
+
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // color keyword
+ if(match_colorKeyword(rColor, rCandidate))
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange readViewBox(const rtl::OUString& rCandidate, InfoProvider& rInfoProvider)
+ {
+ const sal_Int32 nLen(rCandidate.getLength());
+
+ if(nLen)
+ {
+ sal_Int32 nPos(0);
+ SvgNumber aMinX;
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ if(readNumberAndUnit(rCandidate, nPos, aMinX, nLen))
+ {
+ SvgNumber aMinY;
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ if(readNumberAndUnit(rCandidate, nPos, aMinY, nLen))
+ {
+ SvgNumber aWidth;
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ if(readNumberAndUnit(rCandidate, nPos, aWidth, nLen))
+ {
+ SvgNumber aHeight;
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ if(readNumberAndUnit(rCandidate, nPos, aHeight, nLen))
+ {
+ return basegfx::B2DRange(
+ aMinX.solve(rInfoProvider, xcoordinate),
+ aMinY.solve(rInfoProvider, ycoordinate),
+ aWidth.solve(rInfoProvider, xcoordinate),
+ aHeight.solve(rInfoProvider, ycoordinate));
+ }
+ }
+ }
+ }
+ }
+
+ return basegfx::B2DRange();
+ }
+
+ basegfx::B2DHomMatrix readTransform(const rtl::OUString& rCandidate, InfoProvider& rInfoProvider)
+ {
+ basegfx::B2DHomMatrix aMatrix;
+ const sal_Int32 nLen(rCandidate.getLength());
+
+ if(nLen)
+ {
+ sal_Int32 nPos(0);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ while(nPos < nLen)
+ {
+ const sal_Unicode aChar(rCandidate[nPos]);
+ const sal_Int32 nInitPos(nPos);
+ static rtl::OUString aStrMatrix(rtl::OUString::createFromAscii("matrix"));
+ static rtl::OUString aStrTranslate(rtl::OUString::createFromAscii("translate"));
+ static rtl::OUString aStrScale(rtl::OUString::createFromAscii("scale"));
+ static rtl::OUString aStrRotate(rtl::OUString::createFromAscii("rotate"));
+ static rtl::OUString aStrSkewX(rtl::OUString::createFromAscii("skewX"));
+ static rtl::OUString aStrSkewY(rtl::OUString::createFromAscii("skewY"));
+
+ switch(aChar)
+ {
+ case sal_Unicode('m') :
+ {
+ if(rCandidate.match(aStrMatrix, nPos))
+ {
+ // matrix element
+ nPos += aStrMatrix.getLength();
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen);
+ SvgNumber aVal;
+ basegfx::B2DHomMatrix aNew;
+
+ if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
+ {
+ aNew.set(0, 0, aVal.solve(rInfoProvider)); // Element A
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
+ {
+ aNew.set(1, 0, aVal.solve(rInfoProvider)); // Element B
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
+ {
+ aNew.set(0, 1, aVal.solve(rInfoProvider)); // Element C
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
+ {
+ aNew.set(1, 1, aVal.solve(rInfoProvider)); // Element D
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
+ {
+ aNew.set(0, 2, aVal.solve(rInfoProvider, xcoordinate)); // Element E
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
+ {
+ aNew.set(1, 2, aVal.solve(rInfoProvider, ycoordinate)); // Element F
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ // caution: String is evaluated from left to right, but matrix multiplication
+ // in SVG is right to left, so put the new transformation before the current
+ // one by multiplicating from the right side
+ aMatrix = aMatrix * aNew;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ case sal_Unicode('t') :
+ {
+ if(rCandidate.match(aStrTranslate, nPos))
+ {
+ // translate element
+ nPos += aStrTranslate.getLength();
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen);
+ SvgNumber aTransX;
+
+ if(readNumberAndUnit(rCandidate, nPos, aTransX, nLen))
+ {
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+ SvgNumber aTransY;
+ readNumberAndUnit(rCandidate, nPos, aTransY, nLen);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ aMatrix = aMatrix * basegfx::tools::createTranslateB2DHomMatrix(
+ aTransX.solve(rInfoProvider, xcoordinate),
+ aTransY.solve(rInfoProvider, ycoordinate));
+ }
+ }
+ break;
+ }
+ case sal_Unicode('s') :
+ {
+ if(rCandidate.match(aStrScale, nPos))
+ {
+ // scale element
+ nPos += aStrScale.getLength();
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen);
+ SvgNumber aScaleX;
+
+ if(readNumberAndUnit(rCandidate, nPos, aScaleX, nLen))
+ {
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+ SvgNumber aScaleY(aScaleX);
+ readNumberAndUnit(rCandidate, nPos, aScaleY, nLen);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ aMatrix = aMatrix * basegfx::tools::createScaleB2DHomMatrix(
+ aScaleX.solve(rInfoProvider),
+ aScaleY.solve(rInfoProvider));
+ }
+ }
+ else if(rCandidate.match(aStrSkewX, nPos))
+ {
+ // skewx element
+ nPos += aStrSkewX.getLength();
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen);
+ double fSkewX(0.0);
+
+ if(readAngle(rCandidate, nPos, fSkewX, nLen))
+ {
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ aMatrix = aMatrix * basegfx::tools::createShearXB2DHomMatrix(tan(fSkewX));
+ }
+ }
+ else if(rCandidate.match(aStrSkewY, nPos))
+ {
+ // skewy element
+ nPos += aStrSkewY.getLength();
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen);
+ double fSkewY(0.0);
+
+ if(readAngle(rCandidate, nPos, fSkewY, nLen))
+ {
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ aMatrix = aMatrix * basegfx::tools::createShearYB2DHomMatrix(tan(fSkewY));
+ }
+ }
+ break;
+ }
+ case sal_Unicode('r') :
+ {
+ if(rCandidate.match(aStrRotate, nPos))
+ {
+ // rotate element
+ nPos += aStrRotate.getLength();
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen);
+ double fAngle(0.0);
+
+ if(readAngle(rCandidate, nPos, fAngle, nLen))
+ {
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+ SvgNumber aX;
+ readNumberAndUnit(rCandidate, nPos, aX, nLen);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+ SvgNumber aY;
+ readNumberAndUnit(rCandidate, nPos, aY, nLen);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ const double fX(aX.isSet() ? aX.solve(rInfoProvider, xcoordinate) : 0.0);
+ const double fY(aY.isSet() ? aY.solve(rInfoProvider, ycoordinate) : 0.0);
+
+ if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY))
+ {
+ // rotate around point
+ aMatrix = aMatrix * basegfx::tools::createRotateAroundPoint(fX, fY, fAngle);
+ }
+ else
+ {
+ // rotate
+ aMatrix = aMatrix * basegfx::tools::createRotateB2DHomMatrix(fAngle);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if(nInitPos == nPos)
+ {
+ OSL_ENSURE(false, "Could not interpret on current position (!)");
+ nPos++;
+ }
+ }
+ }
+
+ return aMatrix;
+ }
+
+ bool readSingleNumber(const rtl::OUString& rCandidate, SvgNumber& aNum)
+ {
+ const sal_Int32 nLen(rCandidate.getLength());
+ sal_Int32 nPos(0);
+
+ return readNumberAndUnit(rCandidate, nPos, aNum, nLen);
+ }
+
+ bool readLocalUrl(const rtl::OUString& rCandidate, rtl::OUString& rURL)
+ {
+ static rtl::OUString aStrUrl(rtl::OUString::createFromAscii("url"));
+
+ if(rCandidate.match(aStrUrl, 0))
+ {
+ const sal_Int32 nLen(rCandidate.getLength());
+ sal_Int32 nPos(aStrUrl.getLength());
+
+ skip_char(rCandidate, sal_Unicode('('), sal_Unicode('#'), nPos, nLen);
+ rtl::OUStringBuffer aTokenValue;
+ copyToLimiter(rCandidate, sal_Unicode(')'), nPos, aTokenValue, nLen);
+ rURL = aTokenValue.makeStringAndClear();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ bool readSvgPaint(const rtl::OUString& rCandidate, SvgPaint& rSvgPaint, rtl::OUString& rURL)
+ {
+ const sal_Int32 nLen(rCandidate.getLength());
+
+ if(nLen)
+ {
+ basegfx::BColor aColor;
+
+ if(read_color(rCandidate, aColor))
+ {
+ rSvgPaint = SvgPaint(aColor, true, true);
+ return true;
+ }
+ else
+ {
+ static rtl::OUString aStrNone(rtl::OUString::createFromAscii("none"));
+ static rtl::OUString aStrCurrentColor(rtl::OUString::createFromAscii("currentColor"));
+
+ if(rCandidate.match(aStrNone, 0))
+ {
+ rSvgPaint = SvgPaint(aColor, true, false, false);
+ return true;
+ }
+ else if(readLocalUrl(rCandidate, rURL))
+ {
+ /// Url is copied to rURL, but needs to be solved outside this helper
+ return false;
+ }
+ else if(rCandidate.match(aStrCurrentColor, 0))
+ {
+ rSvgPaint = SvgPaint(aColor, true, true, true);
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ bool readSvgNumberVector(const rtl::OUString& rCandidate, SvgNumberVector& rSvgNumberVector)
+ {
+ const sal_Int32 nLen(rCandidate.getLength());
+ rSvgNumberVector.clear();
+
+ if(nLen)
+ {
+ sal_Int32 nPos(0);
+ SvgNumber aNum;
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ while(readNumberAndUnit(rCandidate, nPos, aNum, nLen))
+ {
+ rSvgNumberVector.push_back(aNum);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+ }
+
+ return !rSvgNumberVector.empty();
+ }
+
+ return false;
+ }
+
+ SvgAspectRatio readSvgAspectRatio(const rtl::OUString& rCandidate)
+ {
+ const sal_Int32 nLen(rCandidate.getLength());
+
+ if(nLen)
+ {
+ sal_Int32 nPos(0);
+ SvgAlign aSvgAlign(Align_xMidYMid);
+ bool bDefer(false);
+ bool bMeetOrSlice(true);
+ bool bChanged(false);
+
+ while(nPos < nLen)
+ {
+ const sal_Int32 nInitPos(nPos);
+ skip_char(rCandidate, sal_Unicode(' '), nPos, nLen);
+ rtl::OUStringBuffer aTokenName;
+ copyString(rCandidate, nPos, aTokenName, nLen);
+
+ if(aTokenName.getLength())
+ {
+ switch(StrToSVGToken(aTokenName.makeStringAndClear()))
+ {
+ case SVGTokenDefer:
+ {
+ bDefer = true;
+ bChanged = true;
+ break;
+ }
+ case SVGTokenNone:
+ {
+ aSvgAlign = Align_none;
+ bChanged = true;
+ break;
+ }
+ case SVGTokenXMinYMin:
+ {
+ aSvgAlign = Align_xMinYMin;
+ bChanged = true;
+ break;
+ }
+ case SVGTokenXMidYMin:
+ {
+ aSvgAlign = Align_xMidYMin;
+ bChanged = true;
+ break;
+ }
+ case SVGTokenXMaxYMin:
+ {
+ aSvgAlign = Align_xMaxYMin;
+ bChanged = true;
+ break;
+ }
+ case SVGTokenXMinYMid:
+ {
+ aSvgAlign = Align_xMinYMid;
+ bChanged = true;
+ break;
+ }
+ case SVGTokenXMidYMid:
+ {
+ aSvgAlign = Align_xMidYMid;
+ bChanged = true;
+ break;
+ }
+ case SVGTokenXMaxYMid:
+ {
+ aSvgAlign = Align_xMaxYMid;
+ bChanged = true;
+ break;
+ }
+ case SVGTokenXMinYMax:
+ {
+ aSvgAlign = Align_xMinYMax;
+ bChanged = true;
+ break;
+ }
+ case SVGTokenXMidYMax:
+ {
+ aSvgAlign = Align_xMidYMax;
+ bChanged = true;
+ break;
+ }
+ case SVGTokenXMaxYMax:
+ {
+ aSvgAlign = Align_xMaxYMax;
+ bChanged = true;
+ break;
+ }
+ case SVGTokenMeet:
+ {
+ bMeetOrSlice = true;
+ bChanged = true;
+ break;
+ }
+ case SVGTokenSlice:
+ {
+ bMeetOrSlice = false;
+ bChanged = true;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ if(nInitPos == nPos)
+ {
+ OSL_ENSURE(false, "Could not interpret on current position (!)");
+ nPos++;
+ }
+ }
+
+ if(bChanged)
+ {
+ return SvgAspectRatio(aSvgAlign, bDefer, bMeetOrSlice);
+ }
+ }
+
+ return SvgAspectRatio();
+ }
+
+ bool readSvgStringVector(const rtl::OUString& rCandidate, SvgStringVector& rSvgStringVector)
+ {
+ rSvgStringVector.clear();
+ const sal_Int32 nLen(rCandidate.getLength());
+
+ if(nLen)
+ {
+ sal_Int32 nPos(0);
+ rtl::OUStringBuffer aTokenValue;
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ while(nPos < nLen)
+ {
+ copyToLimiter(rCandidate, sal_Unicode(','), nPos, aTokenValue, nLen);
+ skip_char(rCandidate, sal_Unicode(','), sal_Unicode(' '), nPos, nLen);
+ const rtl::OUString aString = aTokenValue.makeStringAndClear();
+
+ if(aString.getLength())
+ {
+ rSvgStringVector.push_back(aString);
+ }
+ }
+ }
+
+ return !rSvgStringVector.empty();
+ }
+
+ void readImageLink(const rtl::OUString& rCandidate, rtl::OUString& rXLink, rtl::OUString& rUrl, rtl::OUString& rMimeType, rtl::OUString& rData)
+ {
+ rXLink = rUrl = rMimeType = rData = rtl::OUString();
+
+ if(sal_Unicode('#') == rCandidate[0])
+ {
+ // local link
+ rXLink = rCandidate.copy(1);
+ }
+ else
+ {
+ static rtl::OUString aStrData(rtl::OUString::createFromAscii("data:"));
+
+ if(rCandidate.match(aStrData, 0))
+ {
+ // embedded data
+ sal_Int32 nPos(aStrData.getLength());
+ sal_Int32 nLen(rCandidate.getLength());
+ rtl::OUStringBuffer aBuffer;
+
+ // read mime type
+ skip_char(rCandidate, sal_Unicode(' '), nPos, nLen);
+ copyToLimiter(rCandidate, sal_Unicode(';'), nPos, aBuffer, nLen);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(';'), nPos, nLen);
+ rMimeType = aBuffer.makeStringAndClear();
+
+ if(rMimeType.getLength() && nPos < nLen)
+ {
+ static rtl::OUString aStrImage(rtl::OUString::createFromAscii("image"));
+
+ if(rMimeType.match(aStrImage, 0))
+ {
+ // image data
+ rtl::OUString aData(rCandidate.copy(nPos));
+ static rtl::OUString aStrBase64(rtl::OUString::createFromAscii("base64"));
+
+ if(aData.match(aStrBase64, 0))
+ {
+ // base64 encoded
+ nPos = aStrBase64.getLength();
+ nLen = aData.getLength();
+
+ skip_char(aData, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
+
+ if(nPos < nLen)
+ {
+ rData = aData.copy(nPos);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Url (path and filename)
+ rUrl = rCandidate;
+ }
+ }
+ }
+
+ rtl::OUString convert(const rtl::OUString& rCandidate, const sal_Unicode& rPattern, const sal_Unicode& rNew, bool bRemove)
+ {
+ const sal_Int32 nLen(rCandidate.getLength());
+
+ if(nLen)
+ {
+ sal_Int32 nPos(0);
+ rtl::OUStringBuffer aBuffer;
+ bool bChanged(false);
+
+ while(nPos < nLen)
+ {
+ const sal_Unicode aChar(rCandidate[nPos]);
+
+ if(rPattern == aChar)
+ {
+ bChanged = true;
+
+ if(!bRemove)
+ {
+ aBuffer.append(rNew);
+ }
+ }
+ else
+ {
+ aBuffer.append(aChar);
+ }
+
+ nPos++;
+ }
+
+ if(bChanged)
+ {
+ return aBuffer.makeStringAndClear();
+ }
+ }
+
+ return rCandidate;
+ }
+
+ rtl::OUString consolidateContiguosSpace(const rtl::OUString& rCandidate)
+ {
+ const sal_Int32 nLen(rCandidate.getLength());
+
+ if(nLen)
+ {
+ sal_Int32 nPos(0);
+ rtl::OUStringBuffer aBuffer;
+ bool bInsideSpace(false);
+ const sal_Unicode aSpace(' ');
+
+ while(nPos < nLen)
+ {
+ const sal_Unicode aChar(rCandidate[nPos]);
+
+ if(aSpace == aChar)
+ {
+ bInsideSpace = true;
+ }
+ else
+ {
+ if(bInsideSpace)
+ {
+ bInsideSpace = false;
+ aBuffer.append(aSpace);
+ }
+
+ aBuffer.append(aChar);
+ }
+
+ nPos++;
+ }
+
+ if(bInsideSpace)
+ {
+ aBuffer.append(aSpace);
+ }
+
+ if(aBuffer.getLength() != nLen)
+ {
+ return aBuffer.makeStringAndClear();
+ }
+ }
+
+ return rCandidate;
+ }
+
+ rtl::OUString whiteSpaceHandlingDefault(const rtl::OUString& rCandidate)
+ {
+ const sal_Unicode aNewline('\n');
+ const sal_Unicode aTab('\t');
+ const sal_Unicode aSpace(' ');
+
+ // remove all newline characters
+ rtl::OUString aRetval(convert(rCandidate, aNewline, aNewline, true));
+
+ // convert tab to space
+ aRetval = convert(aRetval, aTab, aSpace, false);
+
+ // strip of all leading and trailing spaces
+ aRetval = aRetval.trim();
+
+ // consolidate contiguos space
+ aRetval = consolidateContiguosSpace(aRetval);
+
+ return aRetval;
+ }
+
+ rtl::OUString whiteSpaceHandlingPreserve(const rtl::OUString& rCandidate)
+ {
+ const sal_Unicode aNewline('\n');
+ const sal_Unicode aTab('\t');
+ const sal_Unicode aSpace(' ');
+
+ // convert newline to space
+ rtl::OUString aRetval(convert(rCandidate, aNewline, aSpace, false));
+
+ // convert tab to space
+ aRetval = convert(rCandidate, aTab, aSpace, false);
+
+ return rCandidate;
+ }
+
+ ::std::vector< double > solveSvgNumberVector(const SvgNumberVector& rInput, const InfoProvider& rInfoProvider, NumberType aNumberType)
+ {
+ ::std::vector< double > aRetval;
+
+ if(!rInput.empty())
+ {
+ const double nCount(rInput.size());
+ aRetval.reserve(nCount);
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ aRetval.push_back(rInput[a].solve(rInfoProvider, aNumberType));
+ }
+ }
+
+ return aRetval;
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgtrefnode.cxx b/svgio/source/svgreader/svgtrefnode.cxx
new file mode 100644
index 000000000000..7e4586345908
--- /dev/null
+++ b/svgio/source/svgreader/svgtrefnode.cxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgtrefnode.hxx>
+#include <svgio/svgreader/svgdocument.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgTrefNode::SvgTrefNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenTref, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ maXLink()
+ {
+ }
+
+ SvgTrefNode::~SvgTrefNode()
+ {
+ }
+
+ const SvgStyleAttributes* SvgTrefNode::getSvgStyleAttributes() const
+ {
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgTrefNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenXlinkHref:
+ {
+ const sal_Int32 nLen(aContent.getLength());
+
+ if(nLen && sal_Unicode('#') == aContent[0])
+ {
+ maXLink = aContent.copy(1);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ const SvgTextNode* SvgTrefNode::getReferencedSvgTextNode() const
+ {
+ return dynamic_cast< const SvgTextNode* >(getDocument().findSvgNodeById(maXLink));
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgtspannode.cxx b/svgio/source/svgreader/svgtspannode.cxx
new file mode 100644
index 000000000000..177830c770f9
--- /dev/null
+++ b/svgio/source/svgreader/svgtspannode.cxx
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgtspannode.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgTspanNode::SvgTspanNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenTspan, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ maSvgTextPositions()
+ {
+ }
+
+ SvgTspanNode::~SvgTspanNode()
+ {
+ }
+
+ const SvgStyleAttributes* SvgTspanNode::getSvgStyleAttributes() const
+ {
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgTspanNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // read text position attributes
+ maSvgTextPositions.parseTextPositionAttributes(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgusenode.cxx b/svgio/source/svgreader/svgusenode.cxx
new file mode 100644
index 000000000000..d978f39ab352
--- /dev/null
+++ b/svgio/source/svgreader/svgusenode.cxx
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgreader/svgusenode.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <svgio/svgreader/svgdocument.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgUseNode::SvgUseNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenG, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ mpaTransform(0),
+ maX(),
+ maY(),
+ maWidth(),
+ maHeight(),
+ maXLink()
+ {
+ }
+
+ SvgUseNode::~SvgUseNode()
+ {
+ if(mpaTransform) delete mpaTransform;
+ }
+
+ const SvgStyleAttributes* SvgUseNode::getSvgStyleAttributes() const
+ {
+ static rtl::OUString aClassStr(rtl::OUString::createFromAscii("use"));
+ maSvgStyleAttributes.checkForCssStyle(aClassStr);
+
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgUseNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenTransform:
+ {
+ const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this));
+
+ if(!aMatrix.isIdentity())
+ {
+ setTransform(&aMatrix);
+ }
+ break;
+ }
+ case SVGTokenX:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setX(aNum);
+ }
+ break;
+ }
+ case SVGTokenY:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setY(aNum);
+ }
+ break;
+ }
+ case SVGTokenWidth:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setWidth(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenHeight:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setHeight(aNum);
+ }
+ }
+ }
+ case SVGTokenXlinkHref:
+ {
+ const sal_Int32 nLen(aContent.getLength());
+
+ if(nLen && sal_Unicode('#') == aContent[0])
+ {
+ maXLink = aContent.copy(1);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ void SvgUseNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const
+ {
+ // try to access link to content
+ const SvgNode* mpXLink = getDocument().findSvgNodeById(maXLink);
+
+ if(mpXLink)
+ {
+ // decompose childs
+ drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
+
+ // todo: in case mpXLink is a SVGTokenSvg or SVGTokenSymbol the
+ // SVG docs want the getWidth() and getHeight() from this node
+ // to be valid for the subtree.
+ const_cast< SvgNode* >(mpXLink)->setAlternativeParent(this);
+ mpXLink->decomposeSvgNode(aNewTarget, true);
+ const_cast< SvgNode* >(mpXLink)->setAlternativeParent(0);
+
+ if(aNewTarget.hasElements())
+ {
+ basegfx::B2DHomMatrix aTransform;
+
+ if(getX().isSet() || getY().isSet())
+ {
+ aTransform.translate(
+ getX().solve(*this, xcoordinate),
+ getY().solve(*this, ycoordinate));
+ }
+
+ if(getTransform())
+ {
+ aTransform = *getTransform() * aTransform;
+ }
+
+ if(!aTransform.isIdentity())
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xRef(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aTransform,
+ aNewTarget));
+
+ drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef);
+ }
+ else
+ {
+ drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget);
+ }
+ }
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svguno/svguno.cxx b/svgio/source/svguno/svguno.cxx
new file mode 100644
index 000000000000..41cc46168b82
--- /dev/null
+++ b/svgio/source/svguno/svguno.cxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svgio/svgiodllapi.h>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <uno/environment.h>
+#include <cppuhelper/factory.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace ::com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+// predefines
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ extern uno::Sequence< rtl::OUString > SAL_CALL XSvgParser_getSupportedServiceNames();
+ extern rtl::OUString SAL_CALL XSvgParser_getImplementationName();
+ extern uno::Reference< uno::XInterface > SAL_CALL XSvgParser_createInstance( const uno::Reference< lang::XMultiServiceFactory > & );
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// component_getImplementationEnvironment
+
+extern "C"
+{
+ SVGIO_DLLPUBLIC void SAL_CALL component_getImplementationEnvironment( const sal_Char ** ppEnvTypeName, uno_Environment ** /* ppEnv */ )
+ {
+ *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// component_getFactory
+
+extern "C"
+{
+ SVGIO_DLLPUBLIC void* SAL_CALL component_getFactory( const sal_Char* pImplName, void* pServiceManager, void* /* pRegistryKey */ )
+ {
+ uno::Reference< lang::XSingleServiceFactory > xFactory;
+ void* pRet = 0;
+
+ if(svgio::svgreader::XSvgParser_getImplementationName().equalsAscii(pImplName))
+ {
+ xFactory = ::cppu::createSingleFactory(
+ reinterpret_cast< lang::XMultiServiceFactory * >(pServiceManager),
+ svgio::svgreader::XSvgParser_getImplementationName(),
+ svgio::svgreader::XSvgParser_createInstance,
+ svgio::svgreader::XSvgParser_getSupportedServiceNames());
+ }
+
+ if(xFactory.is())
+ {
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+
+ return pRet;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svguno/xsvgparser.cxx b/svgio/source/svguno/xsvgparser.cxx
new file mode 100644
index 000000000000..d08080f8fb13
--- /dev/null
+++ b/svgio/source/svguno/xsvgparser.cxx
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/graphic/XSvgParser.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase2.hxx>
+#include <svgio/svgreader/svgdocumenthandler.hxx>
+#include <com/sun/star/xml/sax/XParser.hpp>
+#include <com/sun/star/xml/sax/InputSource.hpp>
+#include <comphelper/processfactory.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace ::com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ class XSvgParser : public ::cppu::WeakAggImplHelper2< graphic::XSvgParser, lang::XServiceInfo >
+ {
+ private:
+ XSvgParser(const XSvgParser&);
+ XSvgParser& operator=(const XSvgParser&);
+
+ protected:
+ public:
+ XSvgParser();
+ virtual ~XSvgParser();
+
+ // XSvgParser
+ virtual uno::Sequence< uno::Reference< ::graphic::XPrimitive2D > > SAL_CALL getDecomposition(
+ const uno::Reference< ::io::XInputStream >& xSVGStream,
+ const ::rtl::OUString& aAbsolutePath) throw (uno::RuntimeException);
+
+ // XServiceInfo
+ virtual rtl::OUString SAL_CALL getImplementationName() throw(uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL supportsService(const rtl::OUString&) throw(uno::RuntimeException);
+ virtual uno::Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames() throw(uno::RuntimeException);
+ };
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// uno functions
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ uno::Sequence< rtl::OUString > XSvgParser_getSupportedServiceNames()
+ {
+ static rtl::OUString aServiceName(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.graphic.SvgTools" ) );
+ static uno::Sequence< rtl::OUString > aServiceNames( &aServiceName, 1 );
+
+ return( aServiceNames );
+ }
+
+ rtl::OUString XSvgParser_getImplementationName()
+ {
+ return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "svgio::svgreader::XSvgParser" ) );
+ }
+
+ uno::Reference< uno::XInterface > SAL_CALL XSvgParser_createInstance(const uno::Reference< lang::XMultiServiceFactory >&)
+ {
+ return static_cast< ::cppu::OWeakObject* >(new XSvgParser);
+ }
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ XSvgParser::XSvgParser()
+ {
+ }
+
+ XSvgParser::~XSvgParser()
+ {
+ }
+
+ uno::Sequence< uno::Reference< ::graphic::XPrimitive2D > > XSvgParser::getDecomposition(
+ const uno::Reference< ::io::XInputStream >& xSVGStream,
+ const ::rtl::OUString& aAbsolutePath ) throw (uno::RuntimeException)
+ {
+ drawinglayer::primitive2d::Primitive2DSequence aRetval;
+
+ if(xSVGStream.is())
+ {
+ // local document handler
+ SvgDocHdl* pSvgDocHdl = new SvgDocHdl(aAbsolutePath);
+ uno::Reference< xml::sax::XDocumentHandler > xSvgDocHdl(pSvgDocHdl);
+
+ try
+ {
+ // prepare ParserInputSrouce
+ xml::sax::InputSource myInputSource;
+ myInputSource.aInputStream = xSVGStream;
+
+ // get parser
+ uno::Reference< xml::sax::XParser > xParser(
+ comphelper::getProcessServiceFactory()->createInstance(
+ rtl::OUString::createFromAscii("com.sun.star.xml.sax.Parser") ),
+ uno::UNO_QUERY_THROW );
+
+ // connect parser and filter
+ xParser->setDocumentHandler(xSvgDocHdl);
+
+ // finally, parse the stream to a hierarchy of
+ // SVGGraphicPrimitive2D which will be embedded to the
+ // primitive sequence. Their decompositions will in the
+ // end create local low-level primitives, thus SVG will
+ // be processable from all our processors
+ xParser->parseStream(myInputSource);
+ }
+ catch(uno::Exception&)
+ {
+ OSL_ENSURE(false, "Parse error (!)");
+ }
+
+ // decompose to primitives
+ const SvgNodeVector& rResults = pSvgDocHdl->getSvgDocument().getSvgNodeVector();
+ const sal_uInt32 nCount(rResults.size());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ rResults[a]->decomposeSvgNode(aRetval, false);
+ }
+ }
+ else
+ {
+ OSL_ENSURE(false, "Invalid stream (!)");
+ }
+
+ return aRetval;
+ }
+
+ rtl::OUString SAL_CALL XSvgParser::getImplementationName() throw(uno::RuntimeException)
+ {
+ return(XSvgParser_getImplementationName());
+ }
+
+ sal_Bool SAL_CALL XSvgParser::supportsService(const rtl::OUString& rServiceName) throw(uno::RuntimeException)
+ {
+ const uno::Sequence< rtl::OUString > aServices(XSvgParser_getSupportedServiceNames());
+
+ for(sal_Int32 nService(0); nService < aServices.getLength(); nService++)
+ {
+ if(rServiceName == aServices[nService])
+ {
+ return sal_True;
+ }
+ }
+
+ return sal_False;
+ }
+
+ uno::Sequence< rtl::OUString > SAL_CALL XSvgParser::getSupportedServiceNames() throw(uno::RuntimeException)
+ {
+ return XSvgParser_getSupportedServiceNames();
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/svgio.component b/svgio/svgio.component
new file mode 100644
index 000000000000..ddba96500dec
--- /dev/null
+++ b/svgio/svgio.component
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="svgio::svgreader::XSvgParser">
+ <service name="com.sun.star.graphic.SvgTools"/>
+ </implementation>
+</component>