[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [krita/kazakov/svg-loading] /: Implemented correct parsing of 'transform' attribute
From: Dmitry Kazakov <dimula73 () gmail ! com>
Date: 2016-10-07 13:14:05
Message-ID: E1bsUyT-0001DF-WC () code ! kde ! org
[Download RAW message or body]
Git commit 821a11671c39b88e0f71adda2c065e86bd5836fa by Dmitry Kazakov.
Committed on 07/10/2016 at 13:13.
Pushed by dkazakov into branch 'kazakov/svg-loading'.
Implemented correct parsing of 'transform' attribute
This patch introduces the dependency from boost::spirit. Implementing
the same thing in regexp were too tedious and complicated.
M +1 -0 libs/flake/CMakeLists.txt
M +7 -2 libs/flake/svg/SvgLoadingContext.cpp
M +15 -4 libs/flake/svg/SvgParser.cpp
M +2 -62 libs/flake/svg/SvgUtil.cpp
M +0 -7 libs/flake/svg/SvgUtil.h
A +278 -0 libs/flake/svg/parsers/SvgTransformParser.cpp [License: GPL (v2+)]
C +14 -22 libs/flake/svg/parsers/SvgTransformParser.h [from: \
libs/flake/tests/TestSvgParser.h - 054% similarity] M +171 -0 \
libs/flake/tests/TestSvgParser.cpp M +6 -0 libs/flake/tests/TestSvgParser.h
M +1 -1 plugins/flake/artistictextshape/ArtisticTextShape.cpp
http://commits.kde.org/krita/821a11671c39b88e0f71adda2c065e86bd5836fa
diff --git a/libs/flake/CMakeLists.txt b/libs/flake/CMakeLists.txt
index aef106e..b6543fd 100644
--- a/libs/flake/CMakeLists.txt
+++ b/libs/flake/CMakeLists.txt
@@ -196,6 +196,7 @@ set(kritaflake_SRCS
svg/SvgClipPathHelper.cpp
svg/SvgLoadingContext.cpp
svg/SvgShapeFactory.cpp
+ svg/parsers/SvgTransformParser.cpp
FlakeDebug.cpp
)
diff --git a/libs/flake/svg/SvgLoadingContext.cpp \
b/libs/flake/svg/SvgLoadingContext.cpp index ca944f7..94789fa 100644
--- a/libs/flake/svg/SvgLoadingContext.cpp
+++ b/libs/flake/svg/SvgLoadingContext.cpp
@@ -82,6 +82,8 @@ SvgGraphicsContext *SvgLoadingContext::currentGC() const
return d->gcStack.top();
}
+#include "parsers/SvgTransformParser.h"
+
SvgGraphicsContext *SvgLoadingContext::pushGraphicsContext(const KoXmlElement \
&element, bool inherit) {
SvgGraphicsContext *gc = new SvgGraphicsContext;
@@ -98,8 +100,11 @@ SvgGraphicsContext *SvgLoadingContext::pushGraphicsContext(const \
KoXmlElement &e
if (!element.isNull()) {
if (element.hasAttribute("transform")) {
- QTransform mat = \
SvgUtil::parseTransform(element.attribute("transform"));
- gc->matrix = mat * gc->matrix;
+ SvgTransformParser p(element.attribute("transform"));
+ if (p.isValid()) {
+ QTransform mat = p.transform();
+ gc->matrix = mat * gc->matrix;
+ }
}
if (element.hasAttribute("xml:base"))
gc->xmlBaseDir = element.attribute("xml:base");
diff --git a/libs/flake/svg/SvgParser.cpp b/libs/flake/svg/SvgParser.cpp
index c1720b6..92e66af 100644
--- a/libs/flake/svg/SvgParser.cpp
+++ b/libs/flake/svg/SvgParser.cpp
@@ -58,6 +58,7 @@
#include "SvgFilterHelper.h"
#include "SvgGradientHelper.h"
#include "SvgClipPathHelper.h"
+#include "parsers/SvgTransformParser.h"
#include "kis_debug.h"
@@ -384,7 +385,14 @@ bool SvgParser::parseGradient(const KoXmlElement &e, const \
KoXmlElement &referen
// Parse the color stops. The referencing gradient does not have colorstops,
// so use the stops from the gradient it references to (e in this case and not \
b) m_context.styleParser().parseColorStops(gradhelper.gradient(), e);
- gradhelper.setTransform(SvgUtil::parseTransform(b.attribute("gradientTransform")));
+
+ if (b.hasAttribute("gradientTransform")) {
+ SvgTransformParser p(e.attribute("gradientTransform"));
+ if (p.isValid()) {
+ gradhelper.setTransform(p.transform());
+ }
+ }
+
m_gradients.insert(gradientId, gradhelper);
return true;
@@ -404,9 +412,12 @@ void SvgParser::parsePattern(SvgPatternHelper &pattern, const \
KoXmlElement &e)
//pattern.setPatternContentViewbox(SvgUtil::parseViewBox(viewBox));
}
- const QString transform = e.attribute("patternTransform");
- if (!transform.isEmpty()) {
- pattern.setTransform(SvgUtil::parseTransform(transform));
+
+ if (e.hasAttribute("patternTransform")) {
+ SvgTransformParser p(e.attribute("patternTransform"));
+ if (p.isValid()) {
+ pattern.setTransform(p.transform());
+ }
}
const QString x = e.attribute("x");
diff --git a/libs/flake/svg/SvgUtil.cpp b/libs/flake/svg/SvgUtil.cpp
index ac38e20..b70870b 100644
--- a/libs/flake/svg/SvgUtil.cpp
+++ b/libs/flake/svg/SvgUtil.cpp
@@ -114,68 +114,6 @@ QSizeF SvgUtil::userSpaceToObject(const QSizeF &size, const \
QRectF &objectBound) return QSizeF(w, h);
}
-QTransform SvgUtil::parseTransform(const QString &transform)
-{
- QTransform result;
-
- // Split string for handling 1 transform statement at a time
- QStringList subtransforms = transform.split(')', QString::SkipEmptyParts);
- QStringList::ConstIterator it = subtransforms.constBegin();
- QStringList::ConstIterator end = subtransforms.constEnd();
- for (; it != end; ++it) {
- QStringList subtransform = (*it).simplified().split('(', \
QString::SkipEmptyParts);
- if (subtransform.count() < 2)
- continue;
-
- subtransform[0] = subtransform[0].trimmed().toLower();
- subtransform[1] = subtransform[1].simplified();
- QRegExp reg("[,( ]");
- QStringList params = subtransform[1].split(reg, QString::SkipEmptyParts);
-
- if (subtransform[0].startsWith(';') || subtransform[0].startsWith(','))
- subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
-
- if (subtransform[0] == "rotate") {
- if (params.count() == 3) {
- double x = params[1].toDouble();
- double y = params[2].toDouble();
-
- result.translate(x, y);
- result.rotate(params[0].toDouble());
- result.translate(-x, -y);
- } else {
- result.rotate(params[0].toDouble());
- }
- } else if (subtransform[0] == "translate") {
- if (params.count() == 2) {
- result.translate(SvgUtil::fromUserSpace(params[0].toDouble()),
- SvgUtil::fromUserSpace(params[1].toDouble()));
- } else { // Spec : if only one param given, assume 2nd param to be 0
- result.translate(SvgUtil::fromUserSpace(params[0].toDouble()) , 0);
- }
- } else if (subtransform[0] == "scale") {
- if (params.count() == 2) {
- result.scale(params[0].toDouble(), params[1].toDouble());
- } else { // Spec : if only one param given, assume uniform scaling
- result.scale(params[0].toDouble(), params[0].toDouble());
- }
- } else if (subtransform[0].toLower() == "skewx") {
- result.shear(tan(DEG2RAD(params[0].toDouble())), 0.0F);
- } else if (subtransform[0].toLower() == "skewy") {
- result.shear(0.0F, tan(DEG2RAD(params[0].toDouble())));
- } else if (subtransform[0] == "matrix") {
- if (params.count() >= 6) {
- result.setMatrix(params[0].toDouble(), params[1].toDouble(), 0,
- params[2].toDouble(), params[3].toDouble(), 0,
- SvgUtil::fromUserSpace(params[4].toDouble()),
- SvgUtil::fromUserSpace(params[5].toDouble()), 1);
- }
- }
- }
-
- return result;
-}
-
QString SvgUtil::transformToString(const QTransform &transform)
{
if (transform.isIdentity())
@@ -198,6 +136,8 @@ bool SvgUtil::parseViewBox(SvgGraphicsContext *gc, const \
KoXmlElement &e, const QRectF &elementBounds,
QRectF *_viewRect, QTransform *_viewTransform)
{
+ Q_UNUSED(gc)
+
KIS_ASSERT(_viewRect);
KIS_ASSERT(_viewTransform);
diff --git a/libs/flake/svg/SvgUtil.h b/libs/flake/svg/SvgUtil.h
index d59f909..6540854 100644
--- a/libs/flake/svg/SvgUtil.h
+++ b/libs/flake/svg/SvgUtil.h
@@ -81,13 +81,6 @@ public:
*/
static QSizeF userSpaceToObject(const QSizeF &size, const QRectF &objectBound);
- /**
- * Parses transform attribute value into a matrix.
- * @param transform the transform attribute value
- * @return the resulting transformation matrix
- */
- static QTransform parseTransform(const QString &transform);
-
/// Converts specified transformation to a string
static QString transformToString(const QTransform &transform);
diff --git a/libs/flake/svg/parsers/SvgTransformParser.cpp \
b/libs/flake/svg/parsers/SvgTransformParser.cpp new file mode 100644
index 0000000..f49e2f4
--- /dev/null
+++ b/libs/flake/svg/parsers/SvgTransformParser.cpp
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2016 Dmitry Kazakov <dimula73@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "SvgTransformParser.h"
+
+#include <QtGlobal>
+
+//#include "kis_debug.h"
+
+#include <boost/config/warning_disable.hpp>
+#include <boost/spirit/include/qi.hpp>
+#include <boost/spirit/include/phoenix_stl.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/spirit/include/phoenix_fusion.hpp>
+
+
+namespace Private
+{
+
+struct matrix
+{
+ qreal a = 0;
+ qreal b = 0;
+ qreal c = 0;
+ qreal d = 0;
+ qreal e = 0;
+ qreal f = 0;
+};
+
+struct translate
+{
+ qreal tx = 0.0;
+ qreal ty = 0.0;
+};
+
+struct scale
+{
+ qreal sx = 0;
+ qreal sy = 0;
+ bool syPresent = false;
+};
+
+struct rotate
+{
+ qreal angle = 0;
+ qreal cx = 0;
+ qreal cy = 0;
+};
+
+struct skewX
+{
+ qreal angle = 0;
+};
+
+struct skewY
+{
+ qreal angle = 0;
+};
+
+struct transform_unit
+{
+ transform_unit() {}
+
+ transform_unit(const matrix &m) {
+ transform = QTransform(m.a, m.b, m.c, m.d, m.e, m.f);
+ }
+
+ transform_unit(const translate &t) {
+ transform = QTransform::fromTranslate(t.tx, t.ty);
+ }
+
+ transform_unit(const scale &sc) {
+ transform =
+ QTransform::fromScale(sc.sx,
+ sc.syPresent ? sc.sy : sc.sx);
+ }
+
+ transform_unit(const rotate &r) {
+ transform.rotate(r.angle);
+ if (r.cx != 0.0 || r.cy != 0.0) {
+ transform =
+ QTransform::fromTranslate(-r.cx, -r.cy) *
+ transform *
+ QTransform::fromTranslate(r.cx, r.cy);
+ }
+ }
+
+ transform_unit(const skewX &sx) {
+ const qreal deg2rad = qreal(0.017453292519943295769);
+ const qreal value = tan(deg2rad * sx.angle);
+ transform.shear(value, 0);
+ }
+
+ transform_unit(const skewY &sy) {
+ const qreal deg2rad = qreal(0.017453292519943295769);
+ const qreal value = tan(deg2rad * sy.angle);
+ transform.shear(0, value);
+ }
+
+ QTransform transform;
+};
+}
+
+// We need to tell fusion about our transform_unit struct
+// to make it a first-class fusion citizen. This has to
+// be in global scope.
+
+BOOST_FUSION_ADAPT_STRUCT(
+ Private::matrix,
+ (qreal, a)
+ (qreal, b)
+ (qreal, c)
+ (qreal, d)
+ (qreal, e)
+ (qreal, f)
+ )
+
+BOOST_FUSION_ADAPT_STRUCT(
+ Private::translate,
+ (qreal, tx)
+ (qreal, ty)
+ )
+
+BOOST_FUSION_ADAPT_STRUCT(
+ Private::scale,
+ (qreal, sx)
+ (qreal, sy)
+ (bool, syPresent)
+ )
+
+BOOST_FUSION_ADAPT_STRUCT(
+ Private::rotate,
+ (qreal, angle)
+ (qreal, cx)
+ (qreal, cy)
+ )
+
+BOOST_FUSION_ADAPT_STRUCT(
+ Private::skewX,
+ (qreal, angle)
+ )
+
+BOOST_FUSION_ADAPT_STRUCT(
+ Private::skewY,
+ (qreal, angle)
+ )
+
+#define BOOST_SPIRIT_DEBUG 1
+
+namespace Private
+{
+ // Define our grammar
+
+ namespace qi = boost::spirit::qi;
+ namespace ascii = boost::spirit::ascii;
+
+ template <typename Iterator>
+ struct transform_unit_parser : qi::grammar<Iterator, \
std::vector<transform_unit>(), ascii::space_type> + {
+ transform_unit_parser() : transform_unit_parser::base_type(start)
+ {
+ namespace phoenix = boost::phoenix;
+ using qi::lit;
+ using qi::double_;
+ using ascii::char_;
+ using qi::cntrl;
+ using phoenix::at_c;
+ using phoenix::push_back;
+ using namespace qi::labels;
+
+
+ comma %= -char_(',');
+
+ matrix_rule %=
+ lit("matrix")
+ >> '('
+ >> double_ >> comma
+ >> double_ >> comma
+ >> double_ >> comma
+ >> double_ >> comma
+ >> double_ >> comma
+ >> double_ >> comma
+ >> ')';
+
+ translate_rule %=
+ lit("translate")
+ >> '(' >> double_ >> comma >> -double_ >> ')';
+
+ scale_rule %=
+ lit("scale")
+ >> '('
+ >> double_ >> comma
+ >> -double_ [at_c<2>(_val) = true]
+ >> ')';
+
+
+ // due to braces "-(...)" we cannot use automated
+ // semantic actions without relayouting the structure
+ rotate_rule =
+ lit("rotate")
+ >> '('
+ >> double_ [at_c<0>(_val) = _1]
+ >> comma
+ >> -(double_ [at_c<1>(_val) = _1]
+ >> comma
+ >> double_ [at_c<2>(_val) = _1])
+ >> ')';
+
+ skewX_rule %= lit("skewX") >> '(' >> double_ >> ')';
+ skewY_rule %= lit("skewY") >> '(' >> double_ >> ')';
+
+ start %=
+ (matrix_rule | translate_rule | scale_rule |
+ rotate_rule | skewX_rule | skewY_rule) %
+ (cntrl | comma);
+ }
+
+ qi::rule<Iterator, std::vector<transform_unit>(), ascii::space_type> start;
+ qi::rule<Iterator, translate(), ascii::space_type> translate_rule;
+ qi::rule<Iterator, matrix(), ascii::space_type> matrix_rule;
+ qi::rule<Iterator, scale(), ascii::space_type> scale_rule;
+ qi::rule<Iterator, rotate(), ascii::space_type> rotate_rule;
+ qi::rule<Iterator, skewX(), ascii::space_type> skewX_rule;
+ qi::rule<Iterator, skewY(), ascii::space_type> skewY_rule;
+ qi::rule<Iterator> comma;
+ };
+}
+
+
+SvgTransformParser::SvgTransformParser(const QString &_str)
+ : m_isValid(false)
+{
+ using boost::spirit::ascii::space;
+ typedef std::string::const_iterator iterator_type;
+ typedef Private::transform_unit_parser<iterator_type> transform_unit_parser;
+
+ transform_unit_parser g; // Our grammar
+ const std::string str = _str.toStdString();
+
+ std::vector<Private::transform_unit> transforms;
+ iterator_type iter = str.begin();
+ iterator_type end = str.end();
+ bool r = phrase_parse(iter, end, g, space, transforms);
+
+ if (r && iter == end) {
+ m_isValid = true;
+
+ for (const Private::transform_unit &t : transforms) {
+ m_transform = t.transform * m_transform;
+ }
+ }
+}
+bool SvgTransformParser::isValid() const
+{
+ return m_isValid;
+}
+
+QTransform SvgTransformParser::transform() const
+{
+ return m_transform;
+}
+
+
diff --git a/libs/flake/tests/TestSvgParser.h \
b/libs/flake/svg/parsers/SvgTransformParser.h similarity index 54%
copy from libs/flake/tests/TestSvgParser.h
copy to libs/flake/svg/parsers/SvgTransformParser.h
index c2eacb7..84bf56f 100644
--- a/libs/flake/tests/TestSvgParser.h
+++ b/libs/flake/svg/parsers/SvgTransformParser.h
@@ -16,31 +16,23 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef TESTSVGPARSER_H
-#define TESTSVGPARSER_H
+#ifndef SVGTRANSFORMPARSER_H
+#define SVGTRANSFORMPARSER_H
-#include <QtTest>
+#include <QTransform>
+#include "kritaflake_export.h"
-class TestSvgParser : public QObject
-{
- Q_OBJECT
-private Q_SLOTS:
- void testUnitPx();
- void testUnitPxResolution();
- void testUnitPt();
- void testUnitIn();
- void testUnitPercentInitial();
- void testScalingViewport();
- void testScalingViewportKeepMeet1();
- void testScalingViewportKeepMeet2();
- void testScalingViewportKeepMeetAlign();
- void testScalingViewportKeepSlice1();
- void testScalingViewportKeepSlice2();
- void testScalingViewportResolution();
- void testScalingViewportPercentInternal();
- void testParsePreserveAspectRatio();
+class KRITAFLAKE_EXPORT SvgTransformParser
+{
+public:
+ SvgTransformParser(const QString &str);
+ bool isValid() const;
+ QTransform transform() const;
+private:
+ bool m_isValid;
+ QTransform m_transform;
};
-#endif // TESTSVGPARSER_H
+#endif // SVGTRANSFORMPARSER_H
diff --git a/libs/flake/tests/TestSvgParser.cpp b/libs/flake/tests/TestSvgParser.cpp
index 7eec035..89c3ab8 100644
--- a/libs/flake/tests/TestSvgParser.cpp
+++ b/libs/flake/tests/TestSvgParser.cpp
@@ -482,4 +482,175 @@ void TestSvgParser::testParsePreserveAspectRatio()
}
}
+#include "parsers/SvgTransformParser.h"
+
+void TestSvgParser::testParseTransform()
+{
+ {
+ QString str("translate(-111.0, 33) translate(-111.0, 33) matrix (1 1 0 0 1, \
3), translate(1)" + "scale(0.5) rotate(10) rotate(10, 3 3) \
skewX(1) skewY(2)"); +
+ SvgTransformParser p(str);
+ QCOMPARE(p.isValid(), true);
+ }
+
+ {
+ // forget about one brace
+ QString str("translate(-111.0, 33) translate(-111.0, 33 matrix (1 1 0 0 1, \
3), translate(1)" + "scale(0.5) rotate(10) rotate(10, 3 3) \
skewX(1) skewY(2)"); +
+ SvgTransformParser p(str);
+ QCOMPARE(p.isValid(), false);
+ }
+
+ {
+ SvgTransformParser p("translate(100, 50)");
+ QCOMPARE(p.isValid(), true);
+ QCOMPARE(p.transform(), QTransform::fromTranslate(100, 50));
+ }
+
+ {
+ SvgTransformParser p("translate(100 50)");
+ QCOMPARE(p.isValid(), true);
+ QCOMPARE(p.transform(), QTransform::fromTranslate(100, 50));
+ }
+
+ {
+ SvgTransformParser p("translate(100)");
+ QCOMPARE(p.isValid(), true);
+ QCOMPARE(p.transform(), QTransform::fromTranslate(100, 0));
+ }
+
+ {
+ SvgTransformParser p("scale(100, 50)");
+ QCOMPARE(p.isValid(), true);
+ QCOMPARE(p.transform(), QTransform::fromScale(100, 50));
+ }
+
+ {
+ SvgTransformParser p("scale(100)");
+ QCOMPARE(p.isValid(), true);
+ QCOMPARE(p.transform(), QTransform::fromScale(100, 100));
+ }
+
+ {
+ SvgTransformParser p("rotate(90 70 74.0)");
+ QCOMPARE(p.isValid(), true);
+ QTransform t;
+ t.rotate(90);
+ t = QTransform::fromTranslate(-70, -74) * t * QTransform::fromTranslate(70, \
74); + qDebug() << ppVar(p.transform());
+ QCOMPARE(p.transform(), t);
+ }
+}
+
+void TestSvgParser::testScalingViewportTransform()
+{
+ /**
+ * Note: 'transform' affects all the attributes of the *current*
+ * element, while 'vewBox' affects only the decendants!
+ */
+
+ const QString data =
+ "<svg width=\"5px\" height=\"10px\" viewBox=\"60 70 20 40\""
+ " transform=\"scale(2)\""
+ " xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
+
+ "<rect id=\"testRect\" x=\"64\" y=\"74\" width=\"12\" height=\"32\""
+ " transform=\"translate(6)\""
+ " fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
+
+ "</svg>";
+
+ SvgTester t (data);
+ t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
+ t.run();
+
+ KoShape *shape = t.findShape("testRect");
+ QVERIFY(shape);
+
+ QCOMPARE(shape->absoluteTransformation(0), QTransform::fromTranslate(10, 4) * \
QTransform::fromScale(0.5, 0.5)); + QCOMPARE(shape->outlineRect(), \
QRectF(0,0,12,32)); + QCOMPARE(shape->absolutePosition(KoFlake::TopLeftCorner), \
QPointF(5,2)); + QCOMPARE(shape->absolutePosition(KoFlake::TopRightCorner), \
QPointF(11,2)); + QCOMPARE(shape->absolutePosition(KoFlake::BottomLeftCorner), \
QPointF(5,18)); + QCOMPARE(shape->absolutePosition(KoFlake::BottomRightCorner), \
QPointF(11,18)); +}
+
+void TestSvgParser::testTransformNesting()
+{
+ const QString data =
+ "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
+ " xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
+
+ "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
+ " transform=\"translate(10,10), scale(2, 1)\""
+ " fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
+
+ "</svg>";
+
+ SvgTester t (data);
+ t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
+ t.run();
+
+ KoShape *shape = t.findShape("testRect");
+ QVERIFY(shape);
+
+ QCOMPARE(shape->boundingRect(), QRectF(10 - 1,10 - 0.5, 20 + 2, 20 + 1));
+ QCOMPARE(shape->outlineRect(), QRectF(0,0,10,20));
+ QCOMPARE(shape->absolutePosition(KoFlake::TopLeftCorner), QPointF(10,10));
+ QCOMPARE(shape->absolutePosition(KoFlake::BottomRightCorner), QPointF(30,30));
+}
+
+void TestSvgParser::testTransformRotation1()
+{
+ const QString data =
+ "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
+ " xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
+
+ "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
+ " transform=\"rotate(90)\""
+ " fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
+
+ "</svg>";
+
+ SvgTester t (data);
+ t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
+ t.run();
+
+ KoShape *shape = t.findShape("testRect");
+ QVERIFY(shape);
+
+ QCOMPARE(shape->boundingRect(), kisGrowRect(QRectF(-20,0,20,10), 0.5));
+ QCOMPARE(shape->outlineRect(), QRectF(0,0,10,20));
+ QCOMPARE(shape->absolutePosition(KoFlake::TopLeftCorner), QPointF(0,0));
+ QCOMPARE(shape->absolutePosition(KoFlake::BottomRightCorner), QPointF(-20,10));
+}
+
+void TestSvgParser::testTransformRotation2()
+{
+ const QString data =
+ "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
+ " xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
+
+ "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
+ " transform=\"rotate(-90 10 5)\""
+ " fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
+
+ "</svg>";
+
+ SvgTester t (data);
+ t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
+ t.run();
+
+ KoShape *shape = t.findShape("testRect");
+ QVERIFY(shape);
+
+ QCOMPARE(shape->boundingRect(), kisGrowRect(QRectF(5,5,20,10), 0.5));
+ QCOMPARE(shape->outlineRect(), QRectF(0,0,10,20));
+ QCOMPARE(shape->absolutePosition(KoFlake::TopLeftCorner), QPointF(5,15));
+ QCOMPARE(shape->absolutePosition(KoFlake::BottomRightCorner), QPointF(25,5));
+}
+
+
QTEST_GUILESS_MAIN(TestSvgParser)
diff --git a/libs/flake/tests/TestSvgParser.h b/libs/flake/tests/TestSvgParser.h
index c2eacb7..150892c 100644
--- a/libs/flake/tests/TestSvgParser.h
+++ b/libs/flake/tests/TestSvgParser.h
@@ -40,6 +40,12 @@ private Q_SLOTS:
void testScalingViewportResolution();
void testScalingViewportPercentInternal();
void testParsePreserveAspectRatio();
+ void testParseTransform();
+
+ void testScalingViewportTransform();
+ void testTransformNesting();
+ void testTransformRotation1();
+ void testTransformRotation2();
};
diff --git a/plugins/flake/artistictextshape/ArtisticTextShape.cpp \
b/plugins/flake/artistictextshape/ArtisticTextShape.cpp index 0cd1f73..52441b5 100644
--- a/plugins/flake/artistictextshape/ArtisticTextShape.cpp
+++ b/plugins/flake/artistictextshape/ArtisticTextShape.cpp
@@ -1219,7 +1219,7 @@ bool ArtisticTextShape::loadSvg(const KoXmlElement \
&textElement, SvgLoadingConte
path->setSize(newSize);
path->setPosition(newPosition);
- path->applyAbsoluteTransformation(SvgUtil::parseTransform(p.attribute("transform")));
+ path->applyAbsoluteTransformation(context.currentGC()->matrix);
}
} else {
path = dynamic_cast<KoPathShape *>(context.shapeById(href));
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic