1 /*
2  *  Copyright (c) 2016 Dmitry Kazakov <dimula73@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include "TestSvgParser.h"
20 
21 
22 #include <QPainterPath>
23 #include <QTest>
24 #include <svg/SvgUtil.h>
25 #include <KoShapeStrokeModel.h>
26 
27 
28 #include "SvgParserTestingUtils.h"
29 
30 #include "../../sdk/tests/qimage_test_util.h"
31 
32 #ifdef USE_ROUND_TRIP
33 #include "SvgWriter.h"
34 #include <QBuffer>
35 #include <QDomDocument>
36 #endif
37 
38 
testUnitPx()39 void TestSvgParser::testUnitPx()
40 {
41     const QString data =
42             "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
43             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
44 
45             "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
46             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
47 
48             "</svg>";
49 
50     SvgTester t (data);
51     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
52     t.run();
53 
54     KoShape *shape = t.findShape("testRect");
55     QVERIFY(shape);
56 
57     QCOMPARE(shape->boundingRect(), QRectF(0,0,10,20));
58     QCOMPARE(shape->absoluteTransformation(), QTransform());
59     QCOMPARE(shape->outlineRect(), QRectF(0,0,10,20));
60     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(0,0));
61     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(10,20));
62 }
63 
testUnitPxResolution()64 void TestSvgParser::testUnitPxResolution()
65 {
66     const QString data =
67             "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
68             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
69 
70             "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
71             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
72 
73             "</svg>";
74 
75     SvgTester t (data);
76     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 144 /* ppi */);
77     t.run();
78 
79     KoShape *shape = t.findShape("testRect");
80     QVERIFY(shape);
81 
82     QCOMPARE(shape->boundingRect(), QRectF(0,0,5,10));
83     QCOMPARE(shape->absoluteTransformation(), QTransform::fromScale(0.5, 0.5));
84     QCOMPARE(shape->outlineRect(), QRectF(0,0,10,20));
85     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(0,0));
86     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(5,10));
87 }
88 
89 
testUnitPt()90 void TestSvgParser::testUnitPt()
91 {
92     const QString data =
93             "<svg width=\"10pt\" height=\"20pt\" viewBox=\"0 0 10 20\""
94             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
95 
96             "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
97             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
98 
99             "</svg>";
100 
101     SvgTester t (data);
102     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 666 /* ppi */);
103     t.run();
104 
105     KoShape *shape = t.findShape("testRect");
106     QVERIFY(shape);
107 
108     QCOMPARE(shape->boundingRect(), kisGrowRect(QRectF(0,0,10,20), 0));
109     QCOMPARE(shape->absoluteTransformation(), QTransform());
110     QCOMPARE(shape->outlineRect(), QRectF(0,0,10,20));
111     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(0,0));
112     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(10,20));
113 }
114 
testUnitIn()115 void TestSvgParser::testUnitIn()
116 {
117     const QString data =
118             "<svg width=\"10in\" height=\"20in\" viewBox=\"0 0 10 20\""
119             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
120 
121             "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
122             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
123 
124             "</svg>";
125 
126     SvgTester t (data);
127     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 666 /* ppi */);
128     t.run();
129 
130     KoShape *shape = t.findShape("testRect");
131     QVERIFY(shape);
132 
133     QCOMPARE(shape->boundingRect(), QRectF(0,0,720,1440));
134     QCOMPARE(shape->absoluteTransformation(), QTransform::fromScale(72, 72));
135     QCOMPARE(shape->outlineRect(), QRectF(0,0,10,20));
136     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(0,0));
137     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(720,1440));
138 }
139 
testUnitPercentInitial()140 void TestSvgParser::testUnitPercentInitial()
141 {
142     const QString data =
143             "<svg width=\"12.5%\" height=\"25%\" viewBox=\"0 0 10 20\""
144             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
145 
146             "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
147             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
148 
149             "</svg>";
150 
151     SvgTester t (data);
152     t.parser.setResolution(QRectF(0, 0, 80, 80) /* px */, 144 /* ppi */);
153     t.run();
154 
155     KoShape *shape = t.findShape("testRect");
156     QVERIFY(shape);
157 
158     QCOMPARE(shape->boundingRect(), QRectF(0,0,5,10));
159     QCOMPARE(shape->absoluteTransformation(), QTransform::fromScale(0.5, 0.5));
160     QCOMPARE(shape->outlineRect(), QRectF(0,0,10,20));
161     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(0,0));
162     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(5,10));
163 }
164 
testScalingViewport()165 void TestSvgParser::testScalingViewport()
166 {
167     const QString data =
168             "<svg width=\"10px\" height=\"20px\" viewBox=\"60 70 20 40\""
169             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
170 
171             "<rect id=\"testRect\" x=\"64\" y=\"74\" width=\"12\" height=\"32\""
172             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
173 
174             "</svg>";
175 
176     SvgTester t (data);
177     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
178     t.run();
179 
180     KoShape *shape = t.findShape("testRect");
181     QVERIFY(shape);
182 
183     QCOMPARE(shape->absoluteTransformation(), QTransform::fromTranslate(4, 4) * QTransform::fromScale(0.5, 0.5));
184     QCOMPARE(shape->outlineRect(), QRectF(0,0,12,32));
185     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(2,2));
186     QCOMPARE(shape->absolutePosition(KoFlake::TopRight), QPointF(8,2));
187     QCOMPARE(shape->absolutePosition(KoFlake::BottomLeft), QPointF(2,18));
188     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(8,18));
189 }
190 
testScalingViewportKeepMeet1()191 void TestSvgParser::testScalingViewportKeepMeet1()
192 {
193     const QString data =
194             "<svg width=\"10px\" height=\"30px\" viewBox=\"60 70 20 40\""
195             "    preserveAspectRatio=\" xMinYMin meet\""
196             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
197 
198             "<rect id=\"testRect\" x=\"64\" y=\"74\" width=\"12\" height=\"32\""
199             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
200 
201             "</svg>";
202 
203     SvgTester t (data);
204     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
205     t.run();
206 
207     KoShape *shape = t.findShape("testRect");
208     QVERIFY(shape);
209 
210     QCOMPARE(shape->absoluteTransformation(), QTransform::fromTranslate(4, 4) * QTransform::fromScale(0.5, 0.5));
211     QCOMPARE(shape->outlineRect(), QRectF(0,0,12,32));
212     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(2,2));
213     QCOMPARE(shape->absolutePosition(KoFlake::TopRight), QPointF(8,2));
214     QCOMPARE(shape->absolutePosition(KoFlake::BottomLeft), QPointF(2,18));
215     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(8,18));
216 }
217 
testScalingViewportKeepMeet2()218 void TestSvgParser::testScalingViewportKeepMeet2()
219 {
220     const QString data =
221             "<svg width=\"15px\" height=\"20px\" viewBox=\"60 70 20 40\""
222             "    preserveAspectRatio=\" xMinYMin meet\""
223             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
224 
225             "<rect id=\"testRect\" x=\"64\" y=\"74\" width=\"12\" height=\"32\""
226             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
227 
228             "</svg>";
229 
230     SvgTester t (data);
231     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
232     t.run();
233 
234     KoShape *shape = t.findShape("testRect");
235     QVERIFY(shape);
236 
237     QCOMPARE(shape->absoluteTransformation(), QTransform::fromTranslate(4, 4) * QTransform::fromScale(0.5, 0.5));
238     QCOMPARE(shape->outlineRect(), QRectF(0,0,12,32));
239     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(2,2));
240     QCOMPARE(shape->absolutePosition(KoFlake::TopRight), QPointF(8,2));
241     QCOMPARE(shape->absolutePosition(KoFlake::BottomLeft), QPointF(2,18));
242     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(8,18));
243 }
244 
testScalingViewportKeepMeetAlign()245 void TestSvgParser::testScalingViewportKeepMeetAlign()
246 {
247     const QString data =
248             "<svg width=\"10px\" height=\"30px\" viewBox=\"60 70 20 40\""
249             "    preserveAspectRatio=\" xMaxYMax meet\""
250             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
251 
252             "<rect id=\"testRect\" x=\"64\" y=\"74\" width=\"12\" height=\"32\""
253             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
254 
255             "</svg>";
256 
257     SvgTester t (data);
258     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
259     t.run();
260 
261     KoShape *shape = t.findShape("testRect");
262     QVERIFY(shape);
263 
264     QCOMPARE(shape->absoluteTransformation(), QTransform::fromTranslate(4, 24) * QTransform::fromScale(0.5, 0.5));
265     QCOMPARE(shape->outlineRect(), QRectF(0,0,12,32));
266     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(2,12));
267     QCOMPARE(shape->absolutePosition(KoFlake::TopRight), QPointF(8,12));
268     QCOMPARE(shape->absolutePosition(KoFlake::BottomLeft), QPointF(2,28));
269     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(8,28));
270 }
271 
testScalingViewportKeepSlice1()272 void TestSvgParser::testScalingViewportKeepSlice1()
273 {
274     const QString data =
275             "<svg width=\"5px\" height=\"20px\" viewBox=\"60 70 20 40\""
276             "    preserveAspectRatio=\" xMinYMin slice\""
277             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
278 
279             "<rect id=\"testRect\" x=\"64\" y=\"74\" width=\"12\" height=\"32\""
280             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
281 
282             "</svg>";
283 
284     SvgTester t (data);
285     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
286     t.run();
287 
288     KoShape *shape = t.findShape("testRect");
289     QVERIFY(shape);
290 
291     QCOMPARE(shape->absoluteTransformation(), QTransform::fromTranslate(4, 4) * QTransform::fromScale(0.5, 0.5));
292     QCOMPARE(shape->outlineRect(), QRectF(0,0,12,32));
293     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(2,2));
294     QCOMPARE(shape->absolutePosition(KoFlake::TopRight), QPointF(8,2));
295     QCOMPARE(shape->absolutePosition(KoFlake::BottomLeft), QPointF(2,18));
296     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(8,18));
297 }
298 
testScalingViewportKeepSlice2()299 void TestSvgParser::testScalingViewportKeepSlice2()
300 {
301     const QString data =
302             "<svg width=\"10px\" height=\"15px\" viewBox=\"60 70 20 40\""
303             "    preserveAspectRatio=\" xMinYMin slice\""
304             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
305 
306             "<rect id=\"testRect\" x=\"64\" y=\"74\" width=\"12\" height=\"32\""
307             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
308 
309             "</svg>";
310 
311     SvgTester t (data);
312     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
313     t.run();
314 
315     KoShape *shape = t.findShape("testRect");
316     QVERIFY(shape);
317 
318     QCOMPARE(shape->absoluteTransformation(), QTransform::fromTranslate(4, 4) * QTransform::fromScale(0.5, 0.5));
319     QCOMPARE(shape->outlineRect(), QRectF(0,0,12,32));
320     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(2,2));
321     QCOMPARE(shape->absolutePosition(KoFlake::TopRight), QPointF(8,2));
322     QCOMPARE(shape->absolutePosition(KoFlake::BottomLeft), QPointF(2,18));
323     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(8,18));
324 }
325 
testScalingViewportResolution()326 void TestSvgParser::testScalingViewportResolution()
327 {
328     const QString data =
329             "<svg width=\"10px\" height=\"20px\" viewBox=\"60 70 20 40\""
330             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
331 
332             "<rect id=\"testRect\" x=\"64\" y=\"74\" width=\"12\" height=\"32\""
333             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
334 
335             "</svg>";
336 
337     SvgTester t (data);
338     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 144 /* ppi */);
339     t.run();
340 
341     KoShape *shape = t.findShape("testRect");
342     QVERIFY(shape);
343 
344     QCOMPARE(shape->absoluteTransformation(), QTransform::fromTranslate(4, 4) * QTransform::fromScale(0.25, 0.25));
345     QCOMPARE(shape->outlineRect(), QRectF(0,0,12,32));
346     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(1,1));
347     QCOMPARE(shape->absolutePosition(KoFlake::TopRight), QPointF(4,1));
348     QCOMPARE(shape->absolutePosition(KoFlake::BottomLeft), QPointF(1,9));
349     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(4,9));
350 }
351 
testScalingViewportPercentInternal()352 void TestSvgParser::testScalingViewportPercentInternal()
353 {
354     const QString data =
355             "<svg width=\"10px\" height=\"20px\" viewBox=\"60 70 20 40\""
356             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
357 
358             "<rect id=\"testRect\" x=\"320%\" y=\"185%\" width=\"60%\" height=\"80%\""
359             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
360 
361             "</svg>";
362 
363     SvgTester t (data);
364     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
365     t.run();
366 
367     KoShape *shape = t.findShape("testRect");
368     QVERIFY(shape);
369 
370     QCOMPARE(shape->absoluteTransformation(), QTransform::fromTranslate(4, 4) * QTransform::fromScale(0.5, 0.5));
371     QCOMPARE(shape->outlineRect(), QRectF(0,0,12,32));
372     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(2,2));
373     QCOMPARE(shape->absolutePosition(KoFlake::TopRight), QPointF(8,2));
374     QCOMPARE(shape->absolutePosition(KoFlake::BottomLeft), QPointF(2,18));
375     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(8,18));
376 }
377 
378 
testParsePreserveAspectRatio()379 void TestSvgParser::testParsePreserveAspectRatio()
380 {
381     {
382         SvgUtil::PreserveAspectRatioParser p(" defer  xMinYMax meet");
383         QCOMPARE(p.defer, true);
384         QCOMPARE(p.mode, Qt::KeepAspectRatio);
385         QCOMPARE(p.xAlignment, SvgUtil::PreserveAspectRatioParser::Min);
386         QCOMPARE(p.yAlignment, SvgUtil::PreserveAspectRatioParser::Max);
387     }
388 
389     {
390         SvgUtil::PreserveAspectRatioParser p(" xMinYMid slice");
391         QCOMPARE(p.defer, false);
392         QCOMPARE(p.mode, Qt::KeepAspectRatioByExpanding);
393         QCOMPARE(p.xAlignment, SvgUtil::PreserveAspectRatioParser::Min);
394         QCOMPARE(p.yAlignment, SvgUtil::PreserveAspectRatioParser::Middle);
395     }
396 
397     {
398         SvgUtil::PreserveAspectRatioParser p(" xmidYMid ");
399         QCOMPARE(p.defer, false);
400         QCOMPARE(p.mode, Qt::KeepAspectRatio);
401         QCOMPARE(p.xAlignment, SvgUtil::PreserveAspectRatioParser::Middle);
402         QCOMPARE(p.yAlignment, SvgUtil::PreserveAspectRatioParser::Middle);
403     }
404 
405     {
406         SvgUtil::PreserveAspectRatioParser p(" NoNe ");
407         QCOMPARE(p.defer, false);
408         QCOMPARE(p.mode, Qt::IgnoreAspectRatio);
409         QCOMPARE(p.xAlignment, SvgUtil::PreserveAspectRatioParser::Min);
410         QCOMPARE(p.yAlignment, SvgUtil::PreserveAspectRatioParser::Min);
411     }
412 
413     {
414         SvgUtil::PreserveAspectRatioParser p("defer NoNe ");
415         QCOMPARE(p.defer, true);
416         QCOMPARE(p.mode, Qt::IgnoreAspectRatio);
417         QCOMPARE(p.xAlignment, SvgUtil::PreserveAspectRatioParser::Min);
418         QCOMPARE(p.yAlignment, SvgUtil::PreserveAspectRatioParser::Min);
419     }
420 
421     {
422         SvgUtil::PreserveAspectRatioParser p("sweet brown fox jumps over a nice svg file");
423         QCOMPARE(p.defer, false);
424         QCOMPARE(p.mode, Qt::IgnoreAspectRatio);
425         QCOMPARE(p.xAlignment, SvgUtil::PreserveAspectRatioParser::Min);
426         QCOMPARE(p.yAlignment, SvgUtil::PreserveAspectRatioParser::Min);
427     }
428 }
429 
430 #include "parsers/SvgTransformParser.h"
431 
testParseTransform()432 void TestSvgParser::testParseTransform()
433 {
434     {
435         QString str("translate(-111.0, 33) translate(-111.0, 33) matrix (1 1 0 0 1, 3), translate(1)"
436                     "scale(0.5) rotate(10) rotate(10, 3 3) skewX(1) skewY(2)");
437 
438         SvgTransformParser p(str);
439         QCOMPARE(p.isValid(), true);
440     }
441 
442     {
443         // forget about one brace
444         QString str("translate(-111.0, 33) translate(-111.0, 33 matrix (1 1 0 0 1, 3), translate(1)"
445                     "scale(0.5) rotate(10) rotate(10, 3 3) skewX(1) skewY(2)");
446 
447         SvgTransformParser p(str);
448         QCOMPARE(p.isValid(), false);
449     }
450 
451     {
452         SvgTransformParser p("translate(100, 50)");
453         QCOMPARE(p.isValid(), true);
454         QCOMPARE(p.transform(), QTransform::fromTranslate(100, 50));
455     }
456 
457     {
458         SvgTransformParser p("translate(100 50)");
459         QCOMPARE(p.isValid(), true);
460         QCOMPARE(p.transform(), QTransform::fromTranslate(100, 50));
461     }
462 
463     {
464         SvgTransformParser p("translate(100)");
465         QCOMPARE(p.isValid(), true);
466         QCOMPARE(p.transform(), QTransform::fromTranslate(100, 0));
467     }
468 
469     {
470         SvgTransformParser p("scale(100, 50)");
471         QCOMPARE(p.isValid(), true);
472         QCOMPARE(p.transform(), QTransform::fromScale(100, 50));
473     }
474 
475     {
476         SvgTransformParser p("scale(100)");
477         QCOMPARE(p.isValid(), true);
478         QCOMPARE(p.transform(), QTransform::fromScale(100, 100));
479     }
480 
481     {
482         SvgTransformParser p("rotate(90 70 74.0)");
483         QCOMPARE(p.isValid(), true);
484         QTransform t;
485         t.rotate(90);
486         t = QTransform::fromTranslate(-70, -74) * t * QTransform::fromTranslate(70, 74);
487         qDebug() << ppVar(p.transform());
488         QCOMPARE(p.transform(), t);
489     }
490 }
491 
testScalingViewportTransform()492 void TestSvgParser::testScalingViewportTransform()
493 {
494     /**
495      * Note: 'transform' affects all the attributes of the *current*
496      * element, while 'viewBox' affects only the descendants!
497      */
498 
499     const QString data =
500             "<svg width=\"5px\" height=\"10px\" viewBox=\"60 70 20 40\""
501             "    transform=\"scale(2)\""
502             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
503 
504             "<rect id=\"testRect\" x=\"64\" y=\"74\" width=\"12\" height=\"32\""
505             "    transform=\"translate(6)\""
506             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
507 
508             "</svg>";
509 
510     SvgTester t (data);
511     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
512     t.run();
513 
514     KoShape *shape = t.findShape("testRect");
515     QVERIFY(shape);
516 
517     QCOMPARE(shape->absoluteTransformation(), QTransform::fromTranslate(10, 4) * QTransform::fromScale(0.5, 0.5));
518     QCOMPARE(shape->outlineRect(), QRectF(0,0,12,32));
519     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(5,2));
520     QCOMPARE(shape->absolutePosition(KoFlake::TopRight), QPointF(11,2));
521     QCOMPARE(shape->absolutePosition(KoFlake::BottomLeft), QPointF(5,18));
522     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(11,18));
523 }
524 
testTransformNesting()525 void TestSvgParser::testTransformNesting()
526 {
527     const QString data =
528             "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
529             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
530 
531             "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
532             "    transform=\"translate(10,10), scale(2, 1)\""
533             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
534 
535             "</svg>";
536 
537     SvgTester t (data);
538     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
539     t.run();
540 
541     KoShape *shape = t.findShape("testRect");
542     QVERIFY(shape);
543 
544     QCOMPARE(shape->boundingRect(), QRectF(10,10,20,20));
545     QCOMPARE(shape->outlineRect(), QRectF(0,0,10,20));
546     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(10,10));
547     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(30,30));
548 }
549 
testTransformNestingGroups()550 void TestSvgParser::testTransformNestingGroups()
551 {
552     const QString data =
553             "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
554             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
555 
556             "<g transform=\"translate(10,10)\">"
557             "    <rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
558             "        transform=\"scale(2, 1)\""
559             "        fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
560             "</g>"
561 
562             "</svg>";
563 
564     SvgTester t (data);
565     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
566     t.run();
567 
568     KoShape *shape = t.findShape("testRect");
569     QVERIFY(shape);
570 
571     QCOMPARE(shape->boundingRect(), QRectF(10,10, 20, 20));
572     QCOMPARE(shape->outlineRect(), QRectF(0,0,10,20));
573     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(10,10));
574     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(30,30));
575 }
576 
testTransformRotation1()577 void TestSvgParser::testTransformRotation1()
578 {
579     const QString data =
580             "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
581             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
582 
583             "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
584             "    transform=\"rotate(90)\""
585             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
586 
587             "</svg>";
588 
589     SvgTester t (data);
590     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
591     t.run();
592 
593     KoShape *shape = t.findShape("testRect");
594     QVERIFY(shape);
595 
596     QCOMPARE(shape->boundingRect(), QRectF(-20,0,20,10));
597     QCOMPARE(shape->outlineRect(), QRectF(0,0,10,20));
598     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(0,0));
599     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(-20,10));
600 }
601 
testTransformRotation2()602 void TestSvgParser::testTransformRotation2()
603 {
604     const QString data =
605             "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
606             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
607 
608             "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
609             "    transform=\"rotate(-90 10 5)\""
610             "    fill=\"none\" stroke=\"none\" stroke-width=\"10\"/>"
611 
612             "</svg>";
613 
614     SvgTester t (data);
615     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 72 /* ppi */);
616     t.run();
617 
618     KoShape *shape = t.findShape("testRect");
619     QVERIFY(shape);
620 
621     QCOMPARE(shape->boundingRect(), QRectF(5,5,20,10));
622     QCOMPARE(shape->outlineRect(), QRectF(0,0,10,20));
623     QCOMPARE(shape->absolutePosition(KoFlake::TopLeft), QPointF(5,15));
624     QCOMPARE(shape->absolutePosition(KoFlake::BottomRight), QPointF(25,5));
625 }
626 
627 
628 
testRenderStrokeNone()629 void TestSvgParser::testRenderStrokeNone()
630 {
631     const QString data =
632             "<svg width=\"30px\" height=\"30px\""
633             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
634 
635             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
636             "    fill=\"cyan\" stroke=\"none\" stroke-width=\"1\"/>"
637 
638             "</svg>";
639 
640     SvgRenderTester t (data);
641     t.test_standard_30px_72ppi("stroke_none");
642 }
643 
testRenderStrokeColorName()644 void TestSvgParser::testRenderStrokeColorName()
645 {
646     const QString data =
647             "<svg width=\"30px\" height=\"30px\""
648             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
649 
650             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
651             "    fill=\"cyan\" stroke=\"blue\" stroke-width=\"1\"/>"
652 
653             "</svg>";
654 
655     SvgRenderTester t (data);
656     t.test_standard_30px_72ppi("stroke_blue");
657 }
658 
testRenderStrokeColorHex3()659 void TestSvgParser::testRenderStrokeColorHex3()
660 {
661     const QString data =
662             "<svg width=\"30px\" height=\"30px\""
663             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
664 
665             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
666             "    fill=\"cyan\" stroke=\"#00f\" stroke-width=\"1\"/>"
667 
668             "</svg>";
669 
670     SvgRenderTester t (data);
671     t.test_standard_30px_72ppi("stroke_blue");
672 }
673 
testRenderStrokeColorHex6()674 void TestSvgParser::testRenderStrokeColorHex6()
675 {
676     const QString data =
677             "<svg width=\"30px\" height=\"30px\""
678             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
679 
680             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
681             "    fill=\"cyan\" stroke=\"#0000ff\" stroke-width=\"1\"/>"
682 
683             "</svg>";
684 
685     SvgRenderTester t (data);
686     t.test_standard_30px_72ppi("stroke_blue");
687 }
688 
testRenderStrokeColorRgbValues()689 void TestSvgParser::testRenderStrokeColorRgbValues()
690 {
691     const QString data =
692             "<svg width=\"30px\" height=\"30px\""
693             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
694 
695             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
696             "    fill=\"cyan\" stroke=\"rgb(0, 0 ,255)\" stroke-width=\"1\"/>"
697 
698             "</svg>";
699 
700     SvgRenderTester t (data);
701     t.test_standard_30px_72ppi("stroke_blue");
702 }
703 
testRenderStrokeColorRgbPercent()704 void TestSvgParser::testRenderStrokeColorRgbPercent()
705 {
706     const QString data =
707             "<svg width=\"30px\" height=\"30px\""
708             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
709 
710             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
711             "    fill=\"cyan\" stroke=\"rgb(0, 0 ,100%)\" stroke-width=\"1\"/>"
712 
713             "</svg>";
714 
715     SvgRenderTester t (data);
716     t.test_standard_30px_72ppi("stroke_blue");
717 }
718 
testRenderStrokeColorCurrent()719 void TestSvgParser::testRenderStrokeColorCurrent()
720 {
721     const QString data =
722             "<svg width=\"30px\" height=\"30px\""
723             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
724 
725             "<g color=\"blue\">"
726             "    <rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
727             "        fill=\"cyan\" stroke=\"currentColor\" stroke-width=\"1\"/>"
728             "</g>"
729 
730             "</svg>";
731 
732     SvgRenderTester t (data);
733     t.test_standard_30px_72ppi("stroke_blue");
734 }
735 
testRenderStrokeColorNonexistentIri()736 void TestSvgParser::testRenderStrokeColorNonexistentIri()
737 {
738     const QString data =
739             "<svg width=\"30px\" height=\"30px\""
740             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
741 
742             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
743             "    fill=\"cyan\" stroke=\"url(notexists) blue\" stroke-width=\"1\"/>"
744 
745             "</svg>";
746 
747     SvgRenderTester t (data);
748     t.test_standard_30px_72ppi("stroke_blue");
749 }
750 
testRenderStrokeWidth()751 void TestSvgParser::testRenderStrokeWidth()
752 {
753     const QString data =
754             "<svg width=\"30px\" height=\"30px\""
755             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
756 
757             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
758             "    fill=\"cyan\" stroke=\"blue\" stroke-width=\"2\"/>"
759 
760             "</svg>";
761 
762     SvgRenderTester t (data);
763     t.test_standard_30px_72ppi("stroke_blue_width_2");
764 }
765 
testRenderStrokeZeroWidth()766 void TestSvgParser::testRenderStrokeZeroWidth()
767 {
768     const QString data =
769             "<svg width=\"30px\" height=\"30px\""
770             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
771 
772             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
773             "    fill=\"cyan\" stroke=\"blue\" stroke-width=\"0\"/>"
774 
775             "</svg>";
776 
777     SvgRenderTester t (data);
778     t.test_standard_30px_72ppi("stroke_none");
779 }
780 
testRenderStrokeOpacity()781 void TestSvgParser::testRenderStrokeOpacity()
782 {
783     const QString data =
784             "<svg width=\"30px\" height=\"30px\""
785             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
786 
787             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
788             "    fill=\"cyan\" stroke=\"blue\" stroke-width=\"4\" stroke-opacity=\"0.3\"/>"
789 
790             "</svg>";
791 
792     SvgRenderTester t (data);
793     t.setFuzzyThreshold(1);
794     t.test_standard_30px_72ppi("stroke_blue_0_3_opacity");
795 }
796 
testRenderStrokeJointRound()797 void TestSvgParser::testRenderStrokeJointRound()
798 {
799     const QString data =
800             "<svg width=\"30px\" height=\"30px\""
801             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
802 
803             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
804             "    fill=\"cyan\" stroke=\"blue\" stroke-width=\"4\" stroke-linejoin=\"round\"/>"
805 
806             "</svg>";
807 
808     SvgRenderTester t (data);
809     t.test_standard_30px_72ppi("stroke_blue_join_round");
810 }
811 
testRenderStrokeLinecap()812 void TestSvgParser::testRenderStrokeLinecap()
813 {
814     const QString data =
815             "<svg width=\"30px\" height=\"30px\""
816             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
817 
818             "<polyline id=\"testRect\" points=\"5,5 10,25 15,5\""
819             "    fill=\"none\" stroke=\"blue\" stroke-width=\"5\" stroke-linecap=\"round\"/>"
820 
821             "</svg>";
822 
823     SvgRenderTester t (data);
824     t.test_standard_30px_72ppi("stroke_blue_linecap_round");
825 }
826 
testRenderStrokeMiterLimit()827 void TestSvgParser::testRenderStrokeMiterLimit()
828 {
829     // TODO:seems like doesn't work!!
830     qWarning() << "WARNING: Miter limit test is skipped!!!";
831     return;
832 
833     const QString data =
834             "<svg width=\"30px\" height=\"30px\""
835             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
836 
837             "<polyline id=\"testRect\" points=\"5,5 10,25 15,5\""
838             "    fill=\"none\" stroke=\"blue\" stroke-width=\"5\" stroke-miterlimit=\"1.114\"/>"
839 
840             "</svg>";
841 
842     SvgRenderTester t (data);
843     t.test_standard_30px_72ppi("stroke_blue_miter_limit");
844 }
845 
testRenderStrokeDashArrayEven()846 void TestSvgParser::testRenderStrokeDashArrayEven()
847 {
848     const QString data =
849             "<svg width=\"30px\" height=\"30px\""
850             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
851 
852             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
853             "    fill=\"cyan\" stroke=\"blue\" stroke-width=\"2\" stroke-dasharray=\"3 2, 5 2\"/>"
854 
855             "</svg>";
856 
857     SvgRenderTester t (data);
858     t.test_standard_30px_72ppi("stroke_blue_dasharray_even");
859 }
860 
testRenderStrokeDashArrayEvenOffset()861 void TestSvgParser::testRenderStrokeDashArrayEvenOffset()
862 {
863     const QString data =
864             "<svg width=\"30px\" height=\"30px\""
865             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
866 
867             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
868             "    fill=\"cyan\" stroke=\"blue\" stroke-width=\"2\" stroke-dasharray=\"3 2, 5 2\""
869             "    stroke-dashoffset=\"1\"/>"
870 
871             "</svg>";
872 
873     SvgRenderTester t (data);
874     t.test_standard_30px_72ppi("stroke_blue_dasharray_even_offset");
875 }
876 
testRenderStrokeDashArrayOdd()877 void TestSvgParser::testRenderStrokeDashArrayOdd()
878 {
879     // SVG 1.1: if the dasharray is odd, repeat it
880 
881     const QString data =
882             "<svg width=\"30px\" height=\"30px\""
883             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
884 
885             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
886             "    fill=\"cyan\" stroke=\"blue\" stroke-width=\"2\" stroke-dasharray=\"3 2, 5\"/>"
887 
888             "</svg>";
889 
890     SvgRenderTester t (data);
891     t.test_standard_30px_72ppi("stroke_blue_dasharray_odd");
892 }
893 
testRenderStrokeDashArrayRelative()894 void TestSvgParser::testRenderStrokeDashArrayRelative()
895 {
896     // SVG 1.1: relative to view box
897     // (40 x 50) * sqrt(2) => dash length = 5 px
898 
899     const QString data =
900             "<svg width=\"42.4264px\" height=\"56.56854px\""
901             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
902 
903             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
904             "    fill=\"cyan\" stroke=\"blue\" stroke-width=\"2\" stroke-dasharray=\"10% 10%\"/>"
905 
906             "</svg>";
907 
908     SvgRenderTester t (data);
909     t.test_standard_30px_72ppi("stroke_blue_dasharray_relative");
910 }
911 
testRenderFillDefault()912 void TestSvgParser::testRenderFillDefault()
913 {
914     const QString data =
915             "<svg width=\"30px\" height=\"30px\""
916             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
917 
918             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\"/>"
919 
920             "</svg>";
921 
922     SvgRenderTester t (data);
923     t.test_standard_30px_72ppi("fill_black");
924 }
925 
testRenderFillRuleNonZero()926 void TestSvgParser::testRenderFillRuleNonZero()
927 {
928     const QString data =
929             "<svg width=\"30px\" height=\"30px\""
930             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
931 
932             "<polyline id=\"testRect\" points=\"5,5 15,11 15,19 5,25 5,19 15,5 15,25 5,11 5,5\""
933             "    fill=\"black\" fill-rule=\"nonzero\"/>"
934 
935             "</svg>";
936 
937     SvgRenderTester t (data);
938     t.test_standard_30px_72ppi("fill_non_zero");
939 }
940 
testRenderFillRuleEvenOdd()941 void TestSvgParser::testRenderFillRuleEvenOdd()
942 {
943     const QString data =
944             "<svg width=\"30px\" height=\"30px\""
945             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
946 
947             "<polyline id=\"testRect\" points=\"5,5 15,11 15,19 5,25 5,19 15,5 15,25 5,11 5,5\""
948             "    fill=\"black\" fill-rule=\"evenodd\"/>"
949 
950             "</svg>";
951 
952     SvgRenderTester t (data);
953     t.test_standard_30px_72ppi("fill_even_odd");
954 }
955 
testRenderFillOpacity()956 void TestSvgParser::testRenderFillOpacity()
957 {
958     const QString data =
959             "<svg width=\"30px\" height=\"30px\""
960             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
961 
962             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
963             "    fill=\"cyan\" fill-opacity=\"0.3\"/>"
964 
965             "</svg>";
966 
967     SvgRenderTester t (data);
968     t.setFuzzyThreshold(1);
969     t.test_standard_30px_72ppi("fill_opacity_0_3");
970 }
971 
testRenderDisplayAttribute()972 void TestSvgParser::testRenderDisplayAttribute()
973 {
974     const QString data =
975             "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
976             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
977 
978             "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
979             "    fill=\"black\" display=\"none\"/>"
980 
981             "</svg>";
982 
983     SvgTester t (data);
984     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 144 /* ppi */);
985     t.run();
986 
987     KoShape *shape = t.findShape("testRect");
988     QVERIFY(shape);
989 
990     QCOMPARE(shape->isVisible(), false);
991 }
992 
testRenderVisibilityAttribute()993 void TestSvgParser::testRenderVisibilityAttribute()
994 {
995     {
996         const QString data =
997                 "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
998                 "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
999 
1000                 "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
1001                 "    fill=\"black\" visibility=\"visible\"/>"
1002 
1003                 "</svg>";
1004 
1005         SvgTester t (data);
1006         t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 144 /* ppi */);
1007         t.run();
1008 
1009         KoShape *shape = t.findShape("testRect");
1010         QVERIFY(shape);
1011 
1012         QCOMPARE(shape->isVisible(), true);
1013     }
1014 
1015     {
1016         const QString data =
1017                 "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
1018                 "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1019 
1020                 "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
1021                 "    fill=\"black\" visibility=\"hidden\"/>"
1022 
1023                 "</svg>";
1024 
1025         SvgTester t (data);
1026         t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 144 /* ppi */);
1027         t.run();
1028 
1029         KoShape *shape = t.findShape("testRect");
1030         QVERIFY(shape);
1031 
1032         QCOMPARE(shape->isVisible(), false);
1033     }
1034 
1035     {
1036         const QString data =
1037                 "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
1038                 "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1039 
1040                 "<rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
1041                 "    fill=\"black\" visibility=\"collapse\"/>"
1042 
1043                 "</svg>";
1044 
1045         SvgTester t (data);
1046         t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 144 /* ppi */);
1047         t.run();
1048 
1049         KoShape *shape = t.findShape("testRect");
1050         QVERIFY(shape);
1051 
1052         QCOMPARE(shape->isVisible(), false);
1053     }
1054 }
1055 
testRenderVisibilityInheritance()1056 void TestSvgParser::testRenderVisibilityInheritance()
1057 {
1058     const QString data =
1059             "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
1060             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1061 
1062             "<g visibility=\"none\">"
1063             "    <rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
1064             "        fill=\"black\" visibility=\"visible\"/>"
1065             "</g>"
1066 
1067             "</svg>";
1068 
1069     SvgTester t (data);
1070     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 144 /* ppi */);
1071     t.run();
1072 
1073     KoShape *shape = t.findShape("testRect");
1074     QVERIFY(shape);
1075 
1076     QCOMPARE(shape->isVisible(false), true);
1077     QCOMPARE(shape->isVisible(true), false);
1078 }
1079 
testRenderDisplayInheritance()1080 void TestSvgParser::testRenderDisplayInheritance()
1081 {
1082     const QString data =
1083             "<svg width=\"10px\" height=\"20px\" viewBox=\"0 0 10 20\""
1084             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1085 
1086             "<g display=\"none\">"
1087             "    <rect id=\"testRect\" x=\"0\" y=\"0\" width=\"10\" height=\"20\""
1088             "        fill=\"black\" visibility=\"visible\"/>"
1089             "</g>"
1090 
1091             "</svg>";
1092 
1093     SvgTester t (data);
1094     t.parser.setResolution(QRectF(0, 0, 600, 400) /* px */, 144 /* ppi */);
1095     t.run();
1096 
1097     KoShape *shape = t.findShape("testRect");
1098     QVERIFY(shape);
1099 
1100     QCOMPARE(shape->isVisible(false), true);
1101     QEXPECT_FAIL("", "TODO: Fix 'display' attribute not to be inherited in shapes hierarchy!", Continue);
1102     QCOMPARE(shape->isVisible(true), true);
1103 }
1104 
testRenderStrokeWithInlineStyle()1105 void TestSvgParser::testRenderStrokeWithInlineStyle()
1106 {
1107     const QString data =
1108             "<svg width=\"30px\" height=\"30px\""
1109             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1110 
1111             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
1112             "    style = \"fill: cyan; stroke :blue; stroke-width:2;\"/>"
1113 
1114             "</svg>";
1115 
1116     SvgRenderTester t (data);
1117     t.test_standard_30px_72ppi("stroke_blue_width_2");
1118 }
1119 
testIccColor()1120 void TestSvgParser::testIccColor()
1121 {
1122     const QString data =
1123             "<svg width=\"30px\" height=\"30px\""
1124             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1125 
1126             "<g xml:base=\"icc\">"
1127             "    <color-profile xlink:href=\"sRGB-elle-V4-srgbtrc.icc\""
1128             "        local=\"133a66607cffeebdd64dd433ada9bf4e\" name=\"default-profile\"/>"
1129 
1130             "    <color-profile xlink:href=\"sRGB-elle-V4-srgbtrc.icc\""
1131             "        local=\"133a66607cffeebdd64dd433ada9bf4e\" name=\"some-other-name\"/>"
1132 
1133             "    <rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
1134             "        style = \"fill: cyan; stroke :blue; stroke-width:2;\"/>"
1135             "</g>"
1136 
1137             "</svg>";
1138 
1139     SvgRenderTester t (data);
1140 
1141     int numFetches = 0;
1142 
1143     t.parser.setFileFetcher(
1144         [&numFetches](const QString &name) {
1145             numFetches++;
1146             const QString fileName = TestUtil::fetchDataFileLazy(name);
1147             QFile file(fileName);
1148             KIS_ASSERT(file.exists());
1149             file.open(QIODevice::ReadOnly);
1150             return file.readAll();
1151         });
1152 
1153     t.test_standard_30px_72ppi("stroke_blue_width_2");
1154     QCOMPARE(numFetches, 1);
1155 }
1156 
testRenderFillLinearGradientRelativePercent()1157 void TestSvgParser::testRenderFillLinearGradientRelativePercent()
1158 {
1159     const QString data =
1160             "<svg width=\"30px\" height=\"30px\""
1161             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1162 
1163             "<defs>"
1164             "    <linearGradient id=\"testGrad\" x1=\"0%\" y1=\"50%\" x2=\"100%\" y2=\"50%\">"
1165             "        <stop offset=\"20%\" stop-color=\"#F60\" />"
1166             "        <stop offset=\"80%\" stop-color=\"#FF6\" />"
1167             "    </linearGradient>"
1168             "</defs>"
1169 
1170             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
1171             "    style = \"fill:url(#testGrad) magenta; stroke:none; stroke-width:2;\"/>"
1172 
1173             "</svg>";
1174 
1175     SvgRenderTester t (data);
1176     t.test_standard_30px_72ppi("fill_gradient");
1177 }
1178 
testRenderFillLinearGradientRelativePortion()1179 void TestSvgParser::testRenderFillLinearGradientRelativePortion()
1180 {
1181     const QString data =
1182             "<svg width=\"30px\" height=\"30px\""
1183             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1184 
1185             "<linearGradient id=\"testGrad\" x1=\"0\" y1=\"0.5\" x2=\"1.0\" y2=\"0.5\">"
1186             "    <stop offset=\"20%\" stop-color=\"#F60\" />"
1187             "    <stop offset=\"80%\" stop-color=\"#FF6\" />"
1188             "</linearGradient>"
1189 
1190             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
1191             "    style = \"fill:url(#testGrad) magenta; stroke:none; stroke-width:2;\"/>"
1192 
1193             "</svg>";
1194 
1195     SvgRenderTester t (data);
1196     t.test_standard_30px_72ppi("fill_gradient");
1197 }
1198 
testRenderFillLinearGradientUserCoord()1199 void TestSvgParser::testRenderFillLinearGradientUserCoord()
1200 {
1201     const QString data =
1202             "<svg width=\"30px\" height=\"30px\" viewBox=\"60 70 60 90\""
1203             "        preserveAspectRatio=\"none meet\""
1204             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1205 
1206             "<linearGradient id=\"testGrad\" x1=\"70\" y1=\"115\" x2=\"90\" y2=\"115\""
1207             "    gradientUnits=\"userSpaceOnUse\">"
1208             "    <stop offset=\"20%\" stop-color=\"#F60\" />"
1209             "    <stop offset=\"80%\" stop-color=\"#FF6\" />"
1210             "</linearGradient>"
1211 
1212             "<rect id=\"testRect\" x=\"70\" y=\"85\" width=\"20\" height=\"60\""
1213             "    fill=\"url(#testGrad) magenta\" stroke=\"none\"/>"
1214 
1215             "</svg>";
1216 
1217     SvgRenderTester t (data);
1218     t.test_standard_30px_72ppi("fill_gradient");
1219 }
1220 
testRenderFillLinearGradientStopPortion()1221 void TestSvgParser::testRenderFillLinearGradientStopPortion()
1222 {
1223     const QString data =
1224             "<svg width=\"30px\" height=\"30px\""
1225             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1226 
1227             "<linearGradient id=\"testGrad\" x1=\"0\" y1=\"0.5\" x2=\"1.0\" y2=\"0.5\">"
1228             "    <stop offset=\"0.2\" stop-color=\"#F60\" />"
1229             "    <stop offset=\"0.8\" stop-color=\"#FF6\" />"
1230             "</linearGradient>"
1231 
1232             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
1233             "    style = \"fill:url(#testGrad) magenta; stroke:none; stroke-width:2;\"/>"
1234 
1235             "</svg>";
1236 
1237     SvgRenderTester t (data);
1238     t.test_standard_30px_72ppi("fill_gradient");
1239 }
1240 
testRenderFillLinearGradientTransform()1241 void TestSvgParser::testRenderFillLinearGradientTransform()
1242 {
1243     const QString data =
1244             "<svg width=\"30px\" height=\"30px\""
1245             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1246 
1247             "<linearGradient id=\"testGrad\" x1=\"0\" y1=\"0.5\" x2=\"1.0\" y2=\"0.5\""
1248             "    gradientTransform=\"rotate(90, 0.5, 0.5)\">"
1249 
1250             "    <stop offset=\"0.2\" stop-color=\"#F60\" />"
1251             "    <stop offset=\"0.8\" stop-color=\"#FF6\" />"
1252             "</linearGradient>"
1253 
1254             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
1255             "    style = \"fill:url(#testGrad) magenta; stroke:none; stroke-width:2;\"/>"
1256 
1257             "</svg>";
1258 
1259     SvgRenderTester t (data);
1260     t.test_standard_30px_72ppi("fill_gradient_vertical");
1261 }
1262 
testRenderFillLinearGradientTransformUserCoord()1263 void TestSvgParser::testRenderFillLinearGradientTransformUserCoord()
1264 {
1265     const QString data =
1266             "<svg width=\"30px\" height=\"30px\" viewBox=\"60 70 60 90\""
1267             "        preserveAspectRatio=\"none meet\""
1268             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1269 
1270             "<linearGradient id=\"testGrad\" x1=\"70\" y1=\"115\" x2=\"90\" y2=\"115\""
1271             "    gradientUnits=\"userSpaceOnUse\""
1272             "    gradientTransform=\"rotate(90, 80, 115)\">"
1273 
1274             "    <stop offset=\"20%\" stop-color=\"#F60\" />"
1275             "    <stop offset=\"80%\" stop-color=\"#FF6\" />"
1276             "</linearGradient>"
1277 
1278             "<rect id=\"testRect\" x=\"70\" y=\"85\" width=\"20\" height=\"60\""
1279             "    fill=\"url(#testGrad) magenta\" stroke=\"none\"/>"
1280 
1281             "</svg>";
1282 
1283     SvgRenderTester t (data);
1284     t.test_standard_30px_72ppi("fill_gradient_vertical_in_user");
1285 }
1286 
testRenderFillLinearGradientRotatedShape()1287 void TestSvgParser::testRenderFillLinearGradientRotatedShape()
1288 {
1289     // DK: I'm not sure I fully understand if it is a correct transformation,
1290     //     but inkscape opens the file in the same way...
1291 
1292     const QString data =
1293             "<svg width=\"30px\" height=\"30px\""
1294             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1295 
1296             "<linearGradient id=\"testGrad\" x1=\"0\" y1=\"0.5\" x2=\"1.0\" y2=\"0.5\""
1297             "    gradientTransform=\"rotate(90, 0.5, 0.5)\">"
1298 
1299             "    <stop offset=\"0.2\" stop-color=\"#F60\" />"
1300             "    <stop offset=\"0.8\" stop-color=\"#FF6\" />"
1301             "</linearGradient>"
1302 
1303             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
1304             "    style = \"fill:url(#testGrad) magenta; stroke:none; stroke-width:2;\""
1305             "    transform=\"rotate(90, 10, 12.5)\"/>"
1306 
1307             "</svg>";
1308 
1309     SvgRenderTester t (data);
1310     t.test_standard_30px_72ppi("fill_gradient_shape_rotated", false);
1311 }
1312 
testRenderFillLinearGradientRotatedShapeUserCoord()1313 void TestSvgParser::testRenderFillLinearGradientRotatedShapeUserCoord()
1314 {
1315     // DK: I'm not sure I fully understand if it is a correct transformation,
1316     //     but inkscape opens the file in the same way...
1317 
1318     const QString data =
1319             "<svg width=\"30px\" height=\"30px\" viewBox=\"60 70 60 90\""
1320             "        preserveAspectRatio=\"none meet\""
1321             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1322 
1323             "<linearGradient id=\"testGrad\" x1=\"70\" y1=\"115\" x2=\"90\" y2=\"115\""
1324             "    gradientUnits=\"userSpaceOnUse\">"
1325 
1326             "    <stop offset=\"20%\" stop-color=\"#F60\" />"
1327             "    <stop offset=\"80%\" stop-color=\"#FF6\" />"
1328             "</linearGradient>"
1329 
1330             "<rect id=\"testRect\" x=\"70\" y=\"85\" width=\"20\" height=\"60\""
1331             "    fill=\"url(#testGrad) magenta\" stroke=\"none\""
1332             "    transform=\"rotate(90, 80, 115)\"/>"
1333 
1334             "</svg>";
1335 
1336     SvgRenderTester t (data);
1337     t.test_standard_30px_72ppi("fill_gradient_shape_rotated_in_user", false);
1338 }
1339 
testRenderFillRadialGradient()1340 void TestSvgParser::testRenderFillRadialGradient()
1341 {
1342     const QString data =
1343             "<svg width=\"30px\" height=\"30px\""
1344             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1345 
1346             "<radialGradient id=\"testGrad\" cx=\"0.5\" cy=\"0.5\" fx=\"0.2\" fy=\"0.2\" r=\"0.5\">"
1347             "    <stop offset=\"0.2\" stop-color=\"#F60\" />"
1348             "    <stop offset=\"0.8\" stop-color=\"#FF6\" />"
1349             "</radialGradient>"
1350 
1351             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
1352             "    style = \"fill:url(#testGrad) magenta; stroke:none; stroke-width:2;\"/>"
1353             "</svg>";
1354 
1355     SvgRenderTester t (data);
1356     t.setFuzzyThreshold(1);
1357     t.test_standard_30px_72ppi("fill_gradient_radial");
1358 }
1359 
testRenderFillRadialGradientUserCoord()1360 void TestSvgParser::testRenderFillRadialGradientUserCoord()
1361 {
1362     const QString data =
1363             "<svg width=\"30px\" height=\"30px\""
1364             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1365 
1366             "<radialGradient id=\"testGrad\" cx=\"10\" cy=\"12.5\" fx=\"7\" fy=\"9\" r=\"5\""
1367             "    gradientUnits=\"userSpaceOnUse\">"
1368 
1369             "    <stop offset=\"0.2\" stop-color=\"#F60\" />"
1370             "    <stop offset=\"0.8\" stop-color=\"#FF6\" />"
1371             "</radialGradient>"
1372 
1373             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
1374             "    style = \"fill:url(#testGrad) magenta; stroke:none; stroke-width:2;\"/>"
1375             "</svg>";
1376 
1377     SvgRenderTester t (data);
1378     t.setFuzzyThreshold(1);
1379     t.test_standard_30px_72ppi("fill_gradient_radial_in_user");
1380 }
1381 
testRenderFillLinearGradientUserCoordPercent()1382 void TestSvgParser::testRenderFillLinearGradientUserCoordPercent()
1383 {
1384     const QString data =
1385             "<svg width=\"30px\" height=\"30px\" viewBox=\"60 70 60 90\""
1386             "        preserveAspectRatio=\"none meet\""
1387             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1388 
1389             "<linearGradient id=\"testGrad\" x1=\"116.667%\" y1=\"127.778%\" x2=\"150%\" y2=\"127.778%\""
1390             "    gradientUnits=\"userSpaceOnUse\">"
1391             "    <stop offset=\"20%\" stop-color=\"#F60\" />"
1392             "    <stop offset=\"80%\" stop-color=\"#FF6\" />"
1393             "</linearGradient>"
1394 
1395             "<rect id=\"testRect\" x=\"70\" y=\"85\" width=\"20\" height=\"60\""
1396             "    fill=\"url(#testGrad) magenta\" stroke=\"none\"/>"
1397 
1398             "</svg>";
1399 
1400     SvgRenderTester t (data);
1401     t.test_standard_30px_72ppi("fill_gradient");
1402 }
1403 
testRenderStrokeLinearGradient()1404 void TestSvgParser::testRenderStrokeLinearGradient()
1405 {
1406     const QString data =
1407             "<svg width=\"30px\" height=\"30px\""
1408             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
1409 
1410             "<defs>"
1411             "    <linearGradient id=\"testGrad\" x1=\"0%\" y1=\"50%\" x2=\"100%\" y2=\"50%\">"
1412             "        <stop offset=\"20%\" stop-color=\"#F60\" />"
1413             "        <stop offset=\"80%\" stop-color=\"#FF6\" />"
1414             "    </linearGradient>"
1415             "</defs>"
1416 
1417             "<rect id=\"testRect\" x=\"5\" y=\"5\" width=\"10\" height=\"20\""
1418             "    style = \"grey; stroke:url(#testGrad); stroke-width:3; stroke-dasharray:3,1\"/>"
1419 
1420             "</svg>";
1421 
1422     SvgRenderTester t (data);
1423     t.test_standard_30px_72ppi("stroke_gradient_dashed");
1424 }
1425 
rotateTransform(qreal degree,const QPointF & center)1426 QTransform rotateTransform(qreal degree, const QPointF &center) {
1427     QTransform rotate;
1428     rotate.rotate(degree);
1429     return
1430         QTransform::fromTranslate(-center.x(), -center.y()) *
1431         rotate *
1432         QTransform::fromTranslate(center.x(), center.y());
1433 }
1434 
viewTransform(const QRectF & src,const QRectF & dst)1435 QTransform viewTransform(const QRectF &src, const QRectF &dst) {
1436     return QTransform::fromTranslate(-src.x(), -src.y()) *
1437             QTransform::fromScale(dst.width() / src.width(),
1438                                   dst.height() / src.height()) *
1439             QTransform::fromTranslate(dst.x(), dst.y());
1440 
1441 }
1442 
1443 
testRenderMeshGradient_bilinear_1by1_UserCoord()1444 void TestSvgParser::testRenderMeshGradient_bilinear_1by1_UserCoord()
1445 {
1446     QString data =
1447         "<svg"
1448         "   width=\"50px\""
1449         "   height=\"50px\""
1450         "   version=\"1.1\""
1451         "   id=\"svg8\">"
1452         "  <defs"
1453         "     id=\"defs2\">"
1454         "    <meshgradient"
1455         "       id=\"meshgradient901\""
1456         "       gradientUnits=\"userSpaceOnUse\""
1457         "       x=\"0\""
1458         "       y=\"0\">"
1459         "      <meshrow"
1460         "         id=\"meshrow903\">"
1461         "        <meshpatch"
1462         "           id=\"meshpatch905\">"
1463         "          <stop"
1464         "             path=\"c 15,0  30,0  45,0\""
1465         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1466         "             id=\"stop907\" />"
1467         "          <stop"
1468         "             path=\"c 0,15  0,30  0,45\""
1469         "             style=\"stop-color:#ff0000;stop-opacity:1\""
1470         "             id=\"stop909\" />"
1471         "          <stop"
1472         "             path=\"c -15,0  -30,0  -45,0\""
1473         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1474         "             id=\"stop911\" />"
1475         "          <stop"
1476         "             path=\"c 0,-15  0,-30  0,-45\""
1477         "             style=\"stop-color:#ff0000;stop-opacity:1\""
1478         "             id=\"stop913\" />"
1479         "        </meshpatch>"
1480         "      </meshrow>"
1481         "    </meshgradient>"
1482         "  </defs>"
1483         "  <rect"
1484         "     style=\"fill:url(#meshgradient901);fill-opacity:1;filter:url(#filter859)\""
1485         "     id=\"testRect\""
1486         "     width=\"45\""
1487         "     height=\"45\""
1488         "     x=\"0\""
1489         "     y=\"0\" />"
1490         "</svg>";
1491 
1492 
1493     SvgRenderTester t(data);
1494     t.setFuzzyThreshold(5);
1495     t.test_standard("meshgradient_bilinear_1by1_in_user", QSize(50, 50), 72);
1496 }
1497 
testRenderMeshGradient_bicubic_1by1_UserCoord()1498 void TestSvgParser::testRenderMeshGradient_bicubic_1by1_UserCoord()
1499 {
1500     QString data =
1501         "<svg id=\"svg8\""
1502         "   version=\"1.1\""
1503         "   height=\"100px\""
1504         "   width=\"100px\">"
1505         "  <defs"
1506         "     id=\"defs2\">"
1507         "    <meshgradient"
1508         "       type=\"bicubic\""
1509         "       y=\"-10\""
1510         "       x=\"-10\""
1511         "       gradientUnits=\"userSpaceOnUse\""
1512         "       id=\"meshgradient1989\">"
1513         "      <meshrow"
1514         "         id=\"meshrow1991\">"
1515         "        <meshpatch"
1516         "           id=\"meshpatch1993\">"
1517         "          <stop"
1518         "             id=\"stop1995\""
1519         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1520         "             path=\"c 30,0  60,0  90,0\" />"
1521         "          <stop"
1522         "             id=\"stop1997\""
1523         "             style=\"stop-color:#ff0000;stop-opacity:1\""
1524         "             path=\"c 0,30  0,60  0,90\" />"
1525         "          <stop"
1526         "             id=\"stop1999\""
1527         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1528         "             path=\"c -30,0  -60,0  -90,0\" />"
1529         "          <stop"
1530         "             id=\"stop2001\""
1531         "             style=\"stop-color:#ff0000;stop-opacity:1\""
1532         "             path=\"c 0,-30  0,-60  0,-90\" />"
1533         "        </meshpatch>"
1534         "      </meshrow>"
1535         "    </meshgradient>"
1536         "  </defs>"
1537         "  <rect"
1538         "     y=\"-10\""
1539         "     x=\"-10\""
1540         "     height=\"90\""
1541         "     width=\"90\""
1542         "     id=\"testRect\""
1543         "     style=\"fill:url(#meshgradient1989);fill-opacity:1\" />"
1544         "</svg>";
1545 
1546 
1547     SvgRenderTester t(data);
1548     t.setFuzzyThreshold(5);
1549     t.test_standard("meshgradient_bicubic_1by1_in_user", QSize(100, 100), 72);
1550 }
1551 
testRenderMeshGradient_bilinear_2by2_UserCoord()1552 void TestSvgParser::testRenderMeshGradient_bilinear_2by2_UserCoord()
1553 {
1554     QString data =
1555         "<svg"
1556         "   version=\"1.1\""
1557         "   width=\"100px\""
1558         "   height=\"100px\""
1559         "   id=\"svg856\">"
1560         "  <defs"
1561         "     id=\"defs850\">"
1562         "    <meshgradient"
1563         "       y=\"0\""
1564         "       x=\"0\""
1565         "       gradientUnits=\"userSpaceOnUse\""
1566         "       id=\"meshgradient832\">"
1567         "      <meshrow"
1568         "         id=\"meshrow834\">"
1569         "        <meshpatch"
1570         "           id=\"meshpatch836\">"
1571         "          <stop"
1572         "             id=\"stop838\""
1573         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1574         "             path=\"c 13.3333,0  26.6667,0  40,0\" />"
1575         "          <stop"
1576         "             id=\"stop840\""
1577         "             style=\"stop-color:#000000;stop-opacity:1\""
1578         "             path=\"c 0,13.3333  0,26.6667  0,40\" />"
1579         "          <stop"
1580         "             id=\"stop842\""
1581         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1582         "             path=\"c -13.3333,0  -26.6667,0  -40,0\" />"
1583         "          <stop"
1584         "             id=\"stop844\""
1585         "             style=\"stop-color:#000000;stop-opacity:1\""
1586         "             path=\"c 0,-13.3333  0,-26.6667  0,-40\" />"
1587         "        </meshpatch>"
1588         "        <meshpatch"
1589         "           id=\"meshpatch846\">"
1590         "          <stop"
1591         "             id=\"stop848\""
1592         "             path=\"c 13.3333,0  26.6667,0  40,0\" />"
1593         "          <stop"
1594         "             id=\"stop850\""
1595         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1596         "             path=\"c 0,13.3333  0,26.6667  0,40\" />"
1597         "          <stop"
1598         "             id=\"stop852\""
1599         "             style=\"stop-color:#000000;stop-opacity:1\""
1600         "             path=\"c -13.3333,0  -26.6667,0  -40,0\" />"
1601         "        </meshpatch>"
1602         "      </meshrow>"
1603         "      <meshrow"
1604         "         id=\"meshrow854\">"
1605         "        <meshpatch"
1606         "           id=\"meshpatch856\">"
1607         "          <stop"
1608         "             id=\"stop858\""
1609         "             path=\"c 0,13.3333  0,26.6667  0,40\" />"
1610         "          <stop"
1611         "             id=\"stop860\""
1612         "             style=\"stop-color:#000000;stop-opacity:1\""
1613         "             path=\"c -13.3333,0  -26.6667,0  -40,0\" />"
1614         "          <stop"
1615         "             id=\"stop862\""
1616         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1617         "             path=\"c 0,-13.3333  0,-26.6667  0,-40\" />"
1618         "        </meshpatch>"
1619         "        <meshpatch"
1620         "           id=\"meshpatch864\">"
1621         "          <stop"
1622         "             id=\"stop866\""
1623         "             path=\"c 0,13.3333  0,26.6667  0,40\" />"
1624         "          <stop"
1625         "             id=\"stop868\""
1626         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1627         "             path=\"c -13.3333,0  -26.6667,0  -40,0\" />"
1628         "        </meshpatch>"
1629         "      </meshrow>"
1630         "    </meshgradient>"
1631         "  </defs>"
1632         ""
1633         "  <rect"
1634         "     style=\"fill:url(#meshgradient832);fill-opacity:1\""
1635         "     id=\"testRect\""
1636         "     width=\"80\""
1637         "     height=\"80\""
1638         "     x=\"0\""
1639         "     y=\"0\" />"
1640         "</svg>";
1641 
1642     SvgRenderTester t(data);
1643     t.setFuzzyThreshold(5);
1644     t.test_standard("meshgradient_bilinear_2by2_in_user", QSize(100, 100), 72);
1645 }
1646 
testRenderMeshGradient_bicubic_2by2_UserCoord()1647 void TestSvgParser::testRenderMeshGradient_bicubic_2by2_UserCoord()
1648 {
1649     QString data =
1650         "<svg width=\"100px\""
1651         "    height=\"100px\">"
1652         "<defs>"
1653         "  <meshgradient id=\"meshgradient0\""
1654         "    gradientUnits=\"userSpaceOnUse\" "
1655         "    x=\"0\" "
1656         "    y=\"0\" "
1657         "    type=\"bicubic\">"
1658         "   <meshrow "
1659         "     id=\"meshrow0\">"
1660         "    <meshpatch "
1661         "      id=\"meshpatch0\">"
1662         "     <stop path=\"C 13.33328,0 26.66664,0 40,0\" "
1663         "       stop-color=\"#ffffff\" stop-opacity=\"1\"/>"
1664         "     <stop path=\"C 40,13.33328 40,26.66664 40,40\" "
1665         "       stop-color=\"#000000\" stop-opacity=\"1\"/>"
1666         "     <stop path=\"C 26.66672,40 13.33336,40 0,40\" "
1667         "       stop-color=\"#ffffff\" stop-opacity=\"1\"/>"
1668         "     <stop path=\"C 0,26.66672 0,13.33336 0,0\" "
1669         "       stop-color=\"#000000\" stop-opacity=\"1\"/>"
1670         "    </meshpatch>"
1671         "    <meshpatch "
1672         "      id=\"meshpatch1\">"
1673         "     <stop path=\"C 53.33328,0 66.666640,0 80,0\"/>"
1674         "     <stop path=\"C 80,13.33328 80,26.66664 80,40\" "
1675         "       stop-color=\"#ffffff\" stop-opacity=\"1\"/>"
1676         "     <stop path=\"C 66.66672,40 53.33336,40 40,40\" "
1677         "       stop-color=\"#000000\" stop-opacity=\"1\"/>"
1678         "    </meshpatch>"
1679         "   </meshrow>"
1680         "   <meshrow "
1681         "     id=\"meshrow1\">"
1682         "    <meshpatch "
1683         "      id=\"meshpatch2\">"
1684         "     <stop path=\"C 40,53.33328 40,66.66664 40,80\"/>"
1685         "     <stop path=\"C 26.66672,80 13.33336,80 0,80\" "
1686         "       stop-color=\"#000000\" stop-opacity=\"1\"/>"
1687         "     <stop path=\"C 0,66.66672 0,53.33336 0,40\" "
1688         "       stop-color=\"#ffffff\" stop-opacity=\"1\"/>"
1689         "    </meshpatch>"
1690         "    <meshpatch "
1691         "      id=\"meshpatch3\">"
1692         "     <stop path=\"C 80,53.33328 80,66.66664 80,80\"/>"
1693         "     <stop path=\"C 66.66672,80 53.33336,80 40,80\" "
1694         "       stop-color=\"#ffffff\" stop-opacity=\"1\"/>"
1695         "    </meshpatch>"
1696         "   </meshrow>"
1697         "  </meshgradient>"
1698         " </defs>"
1699         ""
1700         "<rect id=\"testRect\" fill=\"url(#meshgradient0)\" width=\"80\" height=\"80\"/>"
1701         "</svg>";
1702 
1703     SvgRenderTester t(data);
1704     t.setFuzzyThreshold(5);
1705     t.test_standard("meshgradient_bicubic_2by2", QSize(100, 100), 72);
1706 }
1707 
testRenderMeshGradient_bilinear_1by1_Obb()1708 void TestSvgParser::testRenderMeshGradient_bilinear_1by1_Obb()
1709 {
1710     // inkscape adds 1px border (unreliably) when the bbox doesn't the meshpatch's curves
1711     qWarning() << "WARNING: skipped, the edge couldn't be reliably verified";
1712     return;
1713     // inkscape is _very_ weird with meshgradients in OBB coordinate system
1714     QString data =
1715         "<svg width=\"100px\" height=\"100px\""
1716         "   version=\"1.1\" id=\"svg8\" >"
1717         "  <defs>"
1718         "    <meshgradient id=\"meshgradient1635\" gradientUnits=\"objectBoundingBox\" x=\"0\" y=\"0\">"
1719         "      <meshrow"
1720         "         id=\"meshrow2306\">"
1721         "        <meshpatch"
1722         "           id=\"meshpatch2296\">"
1723         "          <stop"
1724         "             id=\"stop2288\""
1725         "             stop-color=\"#000000\""
1726         "             path=\"c  0.25,-0.25  0.75, 0.25  1,0\" />"
1727         "          <stop"
1728         "             id=\"stop2290\""
1729         "             stop-color=\"#0000ff\""
1730         "             path=\"c  0.25, 0.25 -0.25, 0.75  0,1\" />"
1731         "          <stop"
1732         "             id=\"stop2292\""
1733         "             stop-color=\"#00ff00\""
1734         "             path=\"c -0.25, 0.25 -0.75,-0.25 -1,0\" />"
1735         "          <stop"
1736         "             id=\"stop2294\""
1737         "             stop-color=\"ff0000\""
1738         "             path=\"c -0.25,-0.25, 0.25,-0.75\" />"
1739         "        </meshpatch>"
1740         "      </meshrow>"
1741         "    </meshgradient>"
1742         "  </defs>"
1743         "  <rect"
1744         "     style=\"fill:url(#meshgradient1635);fill-opacity:1\""
1745         "     id=\"testRect\""
1746         "     width=\"70\""
1747         "     height=\"70\""
1748         "     x=\"0\""
1749         "     y=\"0\" />"
1750         "</svg>";
1751 
1752     SvgRenderTester t(data);
1753     t.setFuzzyThreshold(5);
1754     t.test_standard("meshgradient_bilinear_1by1_in_obb", QSize(100, 100), 72);
1755 }
1756 
testRenderMeshGradient_bicubic_2by2_Obb()1757 void TestSvgParser::testRenderMeshGradient_bicubic_2by2_Obb()
1758 {
1759     // inkscape is _very_ weird with meshgradients in OBB coordinate system
1760     QString data =
1761         "<svg"
1762         "   version=\"1.1\""
1763         "   width=\"100px\""
1764         "   height=\"100px\""
1765         "   id=\"svg856\">"
1766         "  <defs"
1767         "     id=\"defs850\">"
1768         "    <meshgradient"
1769         "       y=\"0\""
1770         "       x=\"0\""
1771         "       gradientUnits=\"objectBoundingBox\""
1772         "       id=\"meshgradient832\""
1773         "       type=\"bicubic\" >"
1774         "      <meshrow"
1775         "         id=\"meshrow834\">"
1776         "        <meshpatch"
1777         "           id=\"meshpatch836\">"
1778         "          <stop"
1779         "             id=\"stop838\""
1780         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1781         "             path=\"c 0.166666,0  0.333333,0  0.5,0\" />"
1782         "          <stop"
1783         "             id=\"stop840\""
1784         "             style=\"stop-color:#000000;stop-opacity:1\""
1785         "             path=\"c 0,0.166666  0,0.333333  0,0.5\" />"
1786         "          <stop"
1787         "             id=\"stop842\""
1788         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1789         "             path=\"c -0.166666,0  -0.333333,0  -0.5,0\" />"
1790         "          <stop"
1791         "             id=\"stop844\""
1792         "             style=\"stop-color:#000000;stop-opacity:1\""
1793         "             path=\"c 0,-0.166666  0,-0.333333  0,-0.5\" />"
1794         "        </meshpatch>"
1795         "        <meshpatch"
1796         "           id=\"meshpatch846\">"
1797         "          <stop"
1798         "             id=\"stop848\""
1799         "             path=\"c 0.166666,0  0.333333,0  0.5,0\" />"
1800         "          <stop"
1801         "             id=\"stop850\""
1802         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1803         "             path=\"c 0,0.166666  0,0.333333  0,0.5\" />"
1804         "          <stop"
1805         "             id=\"stop852\""
1806         "             style=\"stop-color:#000000;stop-opacity:1\""
1807         "             path=\"c -0.166666,0  -0.333333,0  -0.5,0\" />"
1808         "        </meshpatch>"
1809         "      </meshrow>"
1810         "      <meshrow"
1811         "         id=\"meshrow854\">"
1812         "        <meshpatch"
1813         "           id=\"meshpatch856\">"
1814         "          <stop"
1815         "             id=\"stop858\""
1816         "             path=\"c 0,0.166666  0,0.333333  0,0.5\" />"
1817         "          <stop"
1818         "             id=\"stop860\""
1819         "             style=\"stop-color:#000000;stop-opacity:1\""
1820         "             path=\"c -0.166666,0  -0.333333,0  -0.5,0\" />"
1821         "          <stop"
1822         "             id=\"stop862\""
1823         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1824         "             path=\"c 0,-0.166666  0,-0.333333  0,-0.5\" />"
1825         "        </meshpatch>"
1826         "        <meshpatch"
1827         "           id=\"meshpatch864\">"
1828         "          <stop"
1829         "             id=\"stop866\""
1830         "             path=\"c 0,0.166666  0,0.333333  0,0.5\" />"
1831         "          <stop"
1832         "             id=\"stop868\""
1833         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1834         "             path=\"c -0.166666,0  -0.333333,0  -0.5,0\" />"
1835         "        </meshpatch>"
1836         "      </meshrow>"
1837         "    </meshgradient>"
1838         "  </defs>"
1839         ""
1840         "  <rect"
1841         "     style=\"fill:url(#meshgradient832);fill-opacity:1\""
1842         "     id=\"testRect\""
1843         "     width=\"80\""
1844         "     height=\"80\""
1845         "     x=\"0\""
1846         "     y=\"0\" />"
1847         "</svg>";
1848 
1849 
1850     SvgRenderTester t(data);
1851     t.setFuzzyThreshold(5);
1852     t.test_standard("meshgradient_bicubic_2by2", QSize(100, 100), 72);
1853 }
1854 
testRenderMeshGradient_MeshTransform_UserCoord()1855 void TestSvgParser::testRenderMeshGradient_MeshTransform_UserCoord()
1856 {
1857     QString data =
1858         "<svg"
1859         "   id=\"svg8\""
1860         "   version=\"1.1\""
1861         "   height=\"100px\""
1862         "   width=\"100px\">"
1863         "  <defs"
1864         "     id=\"defs2\">"
1865         "    <meshgradient"
1866         "       y=\"0\""
1867         "       x=\"0\""
1868         "       gradientUnits=\"userSpaceOnUse\""
1869         "       id=\"meshgradient1989\""
1870         "       transform=\"translate(90, 0) rotate(90)\">"
1871         "      <meshrow"
1872         "         id=\"meshrow1991\">"
1873         "        <meshpatch"
1874         "           id=\"meshpatch1993\">"
1875         "          <stop"
1876         "             id=\"stop1995\""
1877         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1878         "             path=\"c 30,0  60,0  90,0\" />"
1879         "          <stop"
1880         "             id=\"stop1997\""
1881         "             style=\"stop-color:#ff0000;stop-opacity:1\""
1882         "             path=\"c 0,30  0,60  0,90\" />"
1883         "          <stop"
1884         "             id=\"stop1999\""
1885         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1886         "             path=\"c -30,0  -60,0  -90,0\" />"
1887         "          <stop"
1888         "             id=\"stop2001\""
1889         "             style=\"stop-color:#ff0000;stop-opacity:1\""
1890         "             path=\"c 0,-30  0,-60  0,-90\" />"
1891         "        </meshpatch>"
1892         "      </meshrow>"
1893         "    </meshgradient>"
1894         "  </defs>"
1895         "  <rect"
1896         "     y=\"0\""
1897         "     x=\"0\""
1898         "     height=\"100\""
1899         "     width=\"100\""
1900         "     id=\"testRect\""
1901         "     style=\"fill:url(#meshgradient1989);fill-opacity:1\" />"
1902         "</svg>";
1903 
1904     SvgRenderTester t(data);
1905     t.setFuzzyThreshold(5);
1906     t.test_standard("meshgradient_meshtransform_in_user", QSize(100, 100), 72);
1907 }
1908 
testRenderMeshGradient_ShapeTransform_UserCoord()1909 void TestSvgParser::testRenderMeshGradient_ShapeTransform_UserCoord()
1910 {
1911     // QString data = fetchSvgFile("svg_render", "meshgradient_shapetransform_in_user");
1912     QString data =
1913         "<svg"
1914         "   width=\"100px\""
1915         "   height=\"100px\""
1916         "   version=\"1.1\""
1917         "   id=\"svg8\">"
1918         "  <defs"
1919         "     id=\"defs2\">"
1920         "    <meshgradient"
1921         "       y=\"-79.791451\""
1922         "       x=\"-154.33087\""
1923         "       gradientUnits=\"userSpaceOnUse\""
1924         "       id=\"meshgradient839\">"
1925         "      <meshrow"
1926         "         id=\"meshrow841\">"
1927         "        <meshpatch"
1928         "           id=\"meshpatch843\">"
1929         "          <stop"
1930         "             id=\"stop845\""
1931         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1932         "             path=\"c 51.0352,0  102.07,0  153.105,0\" />"
1933         "          <stop"
1934         "             id=\"stop847\""
1935         "             style=\"stop-color:#000000;stop-opacity:1\""
1936         "             path=\"c 0,52.6788  0,105.358  0,158.036\" />"
1937         "          <stop"
1938         "             id=\"stop849\""
1939         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1940         "             path=\"c -51.0352,0  -102.07,0  -153.105,0\" />"
1941         "          <stop"
1942         "             id=\"stop851\""
1943         "             style=\"stop-color:#000000;stop-opacity:1\""
1944         "             path=\"c 0,-52.6788  0,-105.358  0,-158.036\" />"
1945         "        </meshpatch>"
1946         "      </meshrow>"
1947         "    </meshgradient>"
1948         "  </defs>"
1949         "  <rect"
1950         "     style=\"fill:url(#meshgradient839);fill-opacity:1\""
1951         "     id=\"testRect\""
1952         "     width=\"153.10547\""
1953         "     height=\"158.03641\""
1954         "     x=\"-154.33087\""
1955         "     y=\"-79.791451\""
1956         "     transform=\"matrix(-0.71410131,-0.70004237,0.70026385,-0.71388413,0,0)\" />"
1957         "</svg>";
1958 
1959 
1960     SvgRenderTester t(data);
1961     t.setFuzzyThreshold(5);
1962     t.test_standard("meshgradient_shapetransform_in_user", QSize(100, 100), 72);
1963 }
1964 
testRenderMeshGradient_MeshTransform_Obb()1965 void TestSvgParser::testRenderMeshGradient_MeshTransform_Obb()
1966 {
1967     // inkscape is _very_ weird with meshgradients in OBB coordinate system
1968     QString data =
1969         "<svg"
1970         "   version=\"1.1\""
1971         "   height=\"100px\""
1972         "   width=\"100px\">"
1973         "  <defs"
1974         "     id=\"defs2\">"
1975         "    <meshgradient"
1976         "       y=\"0\""
1977         "       x=\"0\""
1978         "       transform=\"translate(0.7, 0) rotate(90)\""
1979         "       gradientUnits=\"objectBoundingBox\""
1980         "       id=\"meshgradient901\">"
1981         "      <meshrow"
1982         "         id=\"meshrow903\">"
1983         "        <meshpatch"
1984         "           id=\"meshpatch905\">"
1985         "          <stop"
1986         "             id=\"stop907\""
1987         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1988         "             path=\"c 0.166666,0  0.333333,0  0.5,0\" />"
1989         "          <stop"
1990         "             id=\"stop909\""
1991         "             style=\"stop-color:#ff0000;stop-opacity:1\""
1992         "             path=\"c 0,0.166666  0,0.333333  0,0.5\" />"
1993         "          <stop"
1994         "             id=\"stop911\""
1995         "             style=\"stop-color:#ffffff;stop-opacity:1\""
1996         "             path=\"c -0.166666,0  -0.333333,0  -0.5,0\" />"
1997         "          <stop"
1998         "             id=\"stop913\""
1999         "             style=\"stop-color:#ff0000;stop-opacity:1\""
2000         "             path=\"c 0,-0.166666 0,-0.333333  0,-0.5\" />"
2001         "        </meshpatch>"
2002         "        <meshpatch"
2003         "           id=\"meshpatch915\">"
2004         "          <stop"
2005         "             id=\"stop917\""
2006         "             path=\"c 0.166666,0  0.333333,0  0.5,0\" />"
2007         "          <stop"
2008         "             id=\"stop919\""
2009         "             style=\"stop-color:#ffffff;stop-opacity:1\""
2010         "             path=\"c 0,0.166666 0,0.333333  0,0.5\" />"
2011         "          <stop"
2012         "             id=\"stop921\""
2013         "             style=\"stop-color:#ff0000;stop-opacity:1\""
2014         "             path=\"c -0.166666,0  -0.333333,0  -0.5,0\" />"
2015         "        </meshpatch>"
2016         "      </meshrow>"
2017         "    </meshgradient>"
2018         "  </defs>"
2019         "  <rect"
2020         "     y=\"0\""
2021         "     x=\"0\""
2022         "     height=\"90\""
2023         "     width=\"90\""
2024         "     id=\"testRect\""
2025         "     style=\"fill:url(#meshgradient901);fill-opacity:1;filter:url(#filter859)\" />"
2026         "</svg>";
2027 
2028 
2029     SvgRenderTester t(data);
2030     t.setFuzzyThreshold(5);
2031     t.test_standard("meshgradient_meshtransform_in_obb", QSize(100, 100), 72);
2032 }
2033 
testRenderMeshGradient_ShapeTransform_Obb()2034 void TestSvgParser::testRenderMeshGradient_ShapeTransform_Obb()
2035 {
2036     // inkscape is _very_ weird with meshgradients in OBB coordinate system
2037     QString data =
2038         "<svg"
2039         "   width=\"100px\""
2040         "   height=\"100px\""
2041         "   version=\"1.1\""
2042         "   id=\"svg8\">"
2043         "  <defs"
2044         "     id=\"defs2\">"
2045         "    <meshgradient"
2046         "       y=\"0\""
2047         "       x=\"0\""
2048         "       gradientUnits=\"objectBoundingBox\""
2049         "       id=\"meshgradient839\">"
2050         "      <meshrow"
2051         "         id=\"meshrow841\">"
2052         "        <meshpatch"
2053         "           id=\"meshpatch843\">"
2054         "          <stop"
2055         "             id=\"stop845\""
2056         "             style=\"stop-color:#ffffff;stop-opacity:1\""
2057         "             path=\"c  0.33333,0  0.666666,0  1,0\" />"
2058         "          <stop"
2059         "             id=\"stop847\""
2060         "             style=\"stop-color:#000000;stop-opacity:1\""
2061         "             path=\"c 0,0.33333  0,0.66667  0,1\" />"
2062         "          <stop"
2063         "             id=\"stop849\""
2064         "             style=\"stop-color:#ffffff;stop-opacity:1\""
2065         "             path=\"c -0.33333,0  -0.666666,0  -1,0\" />"
2066         "          <stop"
2067         "             id=\"stop851\""
2068         "             style=\"stop-color:#000000;stop-opacity:1\""
2069         "             path=\"c 0,-0.33333  0,-0.66667  0,-1\" />"
2070         "        </meshpatch>"
2071         "      </meshrow>"
2072         "    </meshgradient>"
2073         "  </defs>"
2074         "  <rect"
2075         "     style=\"fill:url(#meshgradient839);fill-opacity:1\""
2076         "     id=\"testRect\""
2077         "     width=\"153.10547\""
2078         "     height=\"158.03641\""
2079         "     x=\"-154.33087\""
2080         "     y=\"-79.791451\""
2081         "     transform=\"matrix(-0.71410131,-0.70004237,0.70026385,-0.71388413,0,0)\" />"
2082         "</svg>";
2083 
2084     SvgRenderTester t(data);
2085     t.setFuzzyThreshold(3);
2086     t.test_standard("meshgradient_shapetransform_in_obb", QSize(100, 100), 72);
2087 }
2088 
testRenderMeshGradient_transparent()2089 void TestSvgParser::testRenderMeshGradient_transparent()
2090 {
2091     // here I use Krita's output, due to my lack of knowledge about Inkscape's RGBA
2092     // output format. But the results, have been verified - SZ
2093     QString data =
2094         "<svg"
2095         "   width=\"100px\""
2096         "   height=\"100px\""
2097         "   version=\"1.1\""
2098         "   id=\"svg8\">"
2099         "  <defs"
2100         "     id=\"defs2\">"
2101         "    <meshgradient"
2102         "       id=\"meshgradient1989\""
2103         "       gradientUnits=\"userSpaceOnUse\""
2104         "       x=\"-10\""
2105         "       y=\"-10\""
2106         "       type=\"bilinear\">"
2107         "      <meshrow"
2108         "         id=\"meshrow1991\">"
2109         "        <meshpatch"
2110         "           id=\"meshpatch1993\">"
2111         "          <stop"
2112         "             path=\"c 30,0  60,0  90,0\""
2113         "             style=\"stop-color:#ffffff;stop-opacity:1\""
2114         "             id=\"stop1995\" />"
2115         "          <stop"
2116         "             path=\"c 0,30  0,60  0,90\""
2117         "             style=\"stop-color:#ff0000;stop-opacity:1\""
2118         "             id=\"stop1997\" />"
2119         "          <stop"
2120         "             path=\"c -30,0  -60,0  -90,0\""
2121         "             style=\"stop-color:#ffffff;stop-opacity:0\""
2122         "             id=\"stop1999\" />"
2123         "          <stop"
2124         "             path=\"c 0,-30  0,-60  0,-90\""
2125         "             style=\"stop-color:#ff0000;stop-opacity:1\""
2126         "             id=\"stop2001\" />"
2127         "        </meshpatch>"
2128         "      </meshrow>"
2129         "    </meshgradient>"
2130         "  </defs>"
2131         "  <rect"
2132         "     style=\"fill:url(#meshgradient1989);fill-opacity:1\""
2133         "     id=\"testRect\""
2134         "     width=\"90\""
2135         "     height=\"90\""
2136         "     x=\"-10\""
2137         "     y=\"-10\" />"
2138         "</svg>";
2139 
2140     SvgRenderTester t(data);
2141     t.setFuzzyThreshold(5);
2142     t.setCheckQImagePremultiplied(true);
2143     t.test_standard("meshgradient_transparent", QSize(100, 100), 72);
2144 }
2145 
testRenderMeshGradient_reversed()2146 void TestSvgParser::testRenderMeshGradient_reversed()
2147 {
2148     // Not sure if this is part of specs, but this brings up an underlying problem:
2149     // bounds in QPainterPath are inclusive on right and bottom side, so an extra 1px
2150     // border is drawn.
2151     QString data =
2152         "<svg"
2153         "   id=\"svg856\""
2154         "   height=\"100px\""
2155         "   width=\"100px\""
2156         ">"
2157         "  <defs"
2158         "     id=\"defs850\">"
2159         "    <meshgradient"
2160         "       y=\"0\""
2161         "       x=\"80\""
2162         "       gradientUnits=\"userSpaceOnUse\""
2163         "       id=\"meshgradient903\">"
2164         "      <meshrow"
2165         "         id=\"meshrow905\">"
2166         "        <meshpatch"
2167         "           id=\"meshpatch907\">"
2168         "          <stop"
2169         "             id=\"stop909\""
2170         "             style=\"stop-color:#ffffff;stop-opacity:1\""
2171         "             path=\"c -13.3333,0  -26.6667,0  -40,0\" />"
2172         "          <stop"
2173         "             id=\"stop911\""
2174         "             style=\"stop-color:#000000;stop-opacity:1\""
2175         "             path=\"c 0,26.6667  0,53.3333  0,80\" />"
2176         "          <stop"
2177         "             id=\"stop913\""
2178         "             style=\"stop-color:#ffffff;stop-opacity:1\""
2179         "             path=\"c  13.3333,0   26.6667,0   40,0\" />"
2180         "          <stop"
2181         "             id=\"stop915\""
2182         "             style=\"stop-color:#000000;stop-opacity:1\""
2183         "             path=\"c 0,-26.6667  0,-53.3333  0,-80\" />"
2184         "        </meshpatch>"
2185         "        <meshpatch"
2186         "           id=\"meshpatch917\">"
2187         "          <stop"
2188         "             id=\"stop919\""
2189         "             path=\"c -13.3333,0  -26.6667,0  -40,0\" />"
2190         "          <stop"
2191         "             id=\"stop921\""
2192         "             style=\"stop-color:#ffffff;stop-opacity:1\""
2193         "             path=\"c 0,26.6667  0,53.3333  0,80\" />"
2194         "          <stop"
2195         "             id=\"stop923\""
2196         "             style=\"stop-color:#000000;stop-opacity:1\""
2197         "             path=\"c  13.3333,0   26.6667,0   40,0\" />"
2198         "        </meshpatch>"
2199         "      </meshrow>"
2200         "    </meshgradient>"
2201         "  </defs>"
2202         "  <rect"
2203         "     y=\"0\""
2204         "     x=\"0\""
2205         "     height=\"90\""
2206         "     width=\"90\""
2207         "     id=\"testRect\""
2208         "     style=\"fill:url(#meshgradient903);fill-opacity:1\" />"
2209         "</svg>";
2210 
2211     SvgRenderTester t(data);
2212     t.setFuzzyThreshold(5);
2213     t.test_standard("meshgradient_reversed", QSize(100, 100), 72);
2214 }
2215 
bakeShape(const QPainterPath & path,const QTransform & bakeTransform,bool contentIsObb=false,const QRectF & shapeBoundingRect=QRectF (),bool contentIsViewBox=false,const QRectF & viewBoxRect=QRectF (),const QRectF & refRect=QRectF ())2216 QPainterPath bakeShape(const QPainterPath &path,
2217                        const QTransform &bakeTransform,
2218                        bool contentIsObb = false, const QRectF &shapeBoundingRect = QRectF(),
2219                        bool contentIsViewBox = false, const QRectF &viewBoxRect= QRectF(), const QRectF &refRect = QRectF())
2220 {
2221     const QTransform relativeToShape(shapeBoundingRect.width(), 0, 0, shapeBoundingRect.height(),
2222                                      shapeBoundingRect.x(), shapeBoundingRect.y());
2223 
2224     QTransform newTransform = bakeTransform;
2225 
2226     if (contentIsObb) {
2227         newTransform = relativeToShape * newTransform;
2228     }
2229 
2230     if (contentIsViewBox) {
2231         newTransform = viewTransform(viewBoxRect, refRect) * newTransform;
2232     }
2233 
2234     return newTransform.map(path);
2235 }
2236 
2237 #include <KoBakedShapeRenderer.h>
2238 
renderBakedPath(QPainter & painter,const QPainterPath & bakedFillPath,const QTransform & bakedTransform,const QRect & shapeOutline,const QTransform & shapeTransform,const QRectF & referenceRect,bool contentIsObb,const QRectF & bakedShapeBoundingRect,bool referenceIsObb,const QTransform & patternTransform,QImage * stampResult)2239 void renderBakedPath(QPainter &painter,
2240                      const QPainterPath &bakedFillPath, const QTransform &bakedTransform,
2241                      const QRect &shapeOutline, const QTransform &shapeTransform,
2242                      const QRectF &referenceRect,
2243                      bool contentIsObb, const QRectF &bakedShapeBoundingRect,
2244                      bool referenceIsObb,
2245                      const QTransform &patternTransform,
2246                      QImage *stampResult)
2247 {
2248     painter.setTransform(QTransform());
2249     painter.setPen(Qt::NoPen);
2250 
2251     QPainterPath shapeOutlinePath;
2252     shapeOutlinePath.addRect(shapeOutline);
2253 
2254     KoBakedShapeRenderer renderer(
2255                 shapeOutlinePath,
2256                 shapeTransform,
2257                 bakedTransform,
2258                 referenceRect,
2259                 contentIsObb, bakedShapeBoundingRect,
2260                 referenceIsObb,
2261                 patternTransform);
2262 
2263     QPainter *patchPainter = renderer.bakeShapePainter();
2264     patchPainter->fillPath(bakedFillPath, Qt::blue);
2265     patchPainter->end();
2266 
2267     renderer.renderShape(painter);
2268 
2269     if (stampResult) {
2270         *stampResult = renderer.patchImage();
2271     }
2272 }
2273 
testManualRenderPattern_ContentUser_RefObb()2274 void TestSvgParser::testManualRenderPattern_ContentUser_RefObb()
2275 {
2276     const QRectF referenceRect(0, 0, 1.0, 0.5);
2277 
2278     QPainterPath fillPath;
2279     fillPath.addRect(QRect(2, 2, 6, 6));
2280     fillPath.addRect(QRect(8, 4, 3, 2));
2281 
2282     QTransform bakedTransform = QTransform::fromTranslate(10, 10) * QTransform::fromScale(2, 2);
2283     QPainterPath bakedFillPath = bakeShape(fillPath, bakedTransform);
2284 
2285     QRect shape1OutlineRect(0,0,10,20);
2286 
2287     QImage stampResult;
2288     QImage fillResult(QSize(60,60), QImage::Format_ARGB32);
2289     QPainter gc(&fillResult);
2290 
2291     fillResult.fill(0);
2292     renderBakedPath(gc,
2293                     bakedFillPath, bakedTransform,
2294                     shape1OutlineRect, bakedTransform,
2295                     referenceRect,
2296                     false, QRectF(),
2297                     true,
2298                     QTransform(),
2299                     &stampResult);
2300 
2301     QVERIFY(TestUtil::checkQImage(stampResult, "svg_render", "render", "pattern_c_user_r_obb_patch1"));
2302     QVERIFY(TestUtil::checkQImage(fillResult, "svg_render", "render", "pattern_c_user_r_obb_fill1"));
2303 
2304     QRect shape2OutlineRect(5,5,20,10);
2305     QTransform shape2Transform = QTransform::fromScale(2, 2) * QTransform::fromTranslate(5, 5);
2306 
2307     fillResult.fill(0);
2308     renderBakedPath(gc,
2309                     bakedFillPath, bakedTransform,
2310                     shape2OutlineRect, shape2Transform,
2311                     referenceRect,
2312                     false, QRectF(),
2313                     true,
2314                     QTransform(),
2315                     &stampResult);
2316 
2317     QVERIFY(TestUtil::checkQImage(stampResult, "svg_render", "render", "pattern_c_user_r_obb_patch2"));
2318     QVERIFY(TestUtil::checkQImage(fillResult, "svg_render", "render", "pattern_c_user_r_obb_fill2"));
2319 }
2320 
testManualRenderPattern_ContentObb_RefObb()2321 void TestSvgParser::testManualRenderPattern_ContentObb_RefObb()
2322 {
2323     const QRectF referenceRect(0.3, 0.3, 0.4, 0.4);
2324 
2325     QPainterPath fillPath;
2326     fillPath.addRect(QRectF(0.4, 0.4, 0.2, 0.2));
2327     fillPath.addRect(QRectF(0.6, 0.5, 0.1, 0.1));
2328     fillPath.addRect(QRectF(0.3, 0.4, 0.1, 0.1));
2329 
2330 
2331     const QRect bakedShapeRect(2,2,10,10);
2332     QTransform bakedTransform = QTransform::fromTranslate(10, 10) * QTransform::fromScale(2, 2);
2333 
2334     QPainterPath bakedFillPath = bakeShape(fillPath, bakedTransform, true, bakedShapeRect);
2335 
2336     QImage stampResult;
2337     QImage fillResult(QSize(60,60), QImage::Format_ARGB32);
2338     QPainter gc(&fillResult);
2339 
2340     // Round trip to the same shape
2341 
2342     fillResult.fill(0);
2343     renderBakedPath(gc,
2344                     bakedFillPath, bakedTransform,
2345                     bakedShapeRect, bakedTransform,
2346                     referenceRect,
2347                     true, bakedShapeRect,
2348                     true,
2349                     QTransform(),
2350                     &stampResult);
2351 
2352     QVERIFY(TestUtil::checkQImage(stampResult, "svg_render", "render", "pattern_c_obb_r_obb_patch1"));
2353     QVERIFY(TestUtil::checkQImage(fillResult, "svg_render", "render", "pattern_c_obb_r_obb_fill1"));
2354 
2355     // Move to a different shape
2356 
2357     QRect shape2OutlineRect(5,5,20,10);
2358     QTransform shape2Transform = QTransform::fromScale(2, 2) * QTransform::fromTranslate(5, 5);
2359 
2360     fillResult.fill(0);
2361     renderBakedPath(gc,
2362                     bakedFillPath, bakedTransform,
2363                     shape2OutlineRect, shape2Transform,
2364                     referenceRect,
2365                     true, bakedShapeRect,
2366                     true,
2367                     QTransform(),
2368                     &stampResult);
2369 
2370     QVERIFY(TestUtil::checkQImage(stampResult, "svg_render", "render", "pattern_c_obb_r_obb_patch2"));
2371     QVERIFY(TestUtil::checkQImage(fillResult, "svg_render", "render", "pattern_c_obb_r_obb_fill2"));
2372 }
2373 
testManualRenderPattern_ContentUser_RefUser()2374 void TestSvgParser::testManualRenderPattern_ContentUser_RefUser()
2375 {
2376     const QRectF referenceRect(5, 2, 8, 8);
2377 
2378     QPainterPath fillPath;
2379     fillPath.addRect(QRect(2, 2, 6, 6));
2380     fillPath.addRect(QRect(8, 4, 3, 2));
2381 
2382 
2383     QTransform bakedTransform = QTransform::fromTranslate(10, 10) * QTransform::fromScale(2, 2);
2384     QPainterPath bakedFillPath = bakeShape(fillPath, bakedTransform);
2385 
2386     QRect shape1OutlineRect(0,0,10,20);
2387 
2388     QImage stampResult;
2389     QImage fillResult(QSize(60,60), QImage::Format_ARGB32);
2390     QPainter gc(&fillResult);
2391 
2392     fillResult.fill(0);
2393     renderBakedPath(gc,
2394                     bakedFillPath, bakedTransform,
2395                     shape1OutlineRect, bakedTransform,
2396                     referenceRect,
2397                     false, QRectF(),
2398                     false,
2399                     QTransform(),
2400                     &stampResult);
2401 
2402     QVERIFY(TestUtil::checkQImage(stampResult, "svg_render", "render", "pattern_c_user_r_user_patch1"));
2403     QVERIFY(TestUtil::checkQImage(fillResult, "svg_render", "render", "pattern_c_user_r_user_fill1"));
2404 
2405     QRect shape2OutlineRect(5,5,20,10);
2406     QTransform shape2Transform = QTransform::fromScale(2, 2) * QTransform::fromTranslate(5, 5);
2407 
2408     fillResult.fill(0);
2409     renderBakedPath(gc,
2410                     bakedFillPath, bakedTransform,
2411                     shape2OutlineRect, shape2Transform,
2412                     referenceRect,
2413                     false, QRectF(),
2414                     false,
2415                     QTransform(),
2416                     &stampResult);
2417 
2418     QVERIFY(TestUtil::checkQImage(stampResult, "svg_render", "render", "pattern_c_user_r_user_patch2"));
2419     QVERIFY(TestUtil::checkQImage(fillResult, "svg_render", "render", "pattern_c_user_r_user_fill2"));
2420 }
2421 
testManualRenderPattern_ContentObb_RefObb_Transform_Rotate()2422 void TestSvgParser::testManualRenderPattern_ContentObb_RefObb_Transform_Rotate()
2423 {
2424     const QRectF referenceRect(0.0, 0.0, 0.4, 0.2);
2425 
2426     QPainterPath fillPath;
2427     fillPath.addRect(QRectF(0.0, 0.0, 0.5, 0.1));
2428     fillPath.addRect(QRectF(0.0, 0.1, 0.1, 0.1));
2429 
2430     const QRect bakedShapeRect(2,1,10,10);
2431     QTransform bakedTransform = QTransform::fromScale(2, 2) * QTransform::fromTranslate(10,10);
2432 
2433     QPainterPath bakedFillPath = bakeShape(fillPath, bakedTransform, true, bakedShapeRect);
2434 
2435     QImage stampResult;
2436     QImage fillResult(QSize(60,60), QImage::Format_ARGB32);
2437     QPainter gc(&fillResult);
2438 
2439     QTransform patternTransform;
2440     patternTransform.rotate(90);
2441     patternTransform = patternTransform * QTransform::fromTranslate(0.5, 0.0);
2442 
2443     // Round trip to the same shape
2444 
2445     fillResult.fill(0);
2446     renderBakedPath(gc,
2447                     bakedFillPath, bakedTransform,
2448                     bakedShapeRect, bakedTransform,
2449                     referenceRect,
2450                     true, bakedShapeRect,
2451                     true,
2452                     patternTransform,
2453                     &stampResult);
2454 
2455     QVERIFY(TestUtil::checkQImage(stampResult, "svg_render", "render", "pattern_c_obb_r_obb_rotate_patch1"));
2456     QVERIFY(TestUtil::checkQImage(fillResult, "svg_render", "render", "pattern_c_obb_r_obb_rotate_fill1"));
2457 
2458     QRect shape2OutlineRect(5,5,20,10);
2459     QTransform shape2Transform = QTransform::fromScale(2, 2) * QTransform::fromTranslate(5, 5);
2460 
2461     fillResult.fill(0);
2462     renderBakedPath(gc,
2463                     bakedFillPath, bakedTransform,
2464                     shape2OutlineRect, shape2Transform,
2465                     referenceRect,
2466                     true, bakedShapeRect,
2467                     true,
2468                     patternTransform,
2469                     &stampResult);
2470 
2471     QVERIFY(TestUtil::checkQImage(stampResult, "svg_render", "render", "pattern_c_obb_r_obb_rotate_patch2"));
2472     QVERIFY(TestUtil::checkQImage(fillResult, "svg_render", "render", "pattern_c_obb_r_obb_rotate_fill2"));
2473 }
2474 
2475 
testManualRenderPattern_ContentView_RefObb()2476 void TestSvgParser::testManualRenderPattern_ContentView_RefObb()
2477 {
2478     const QRectF referenceRect(0, 0, 0.5, 1.0/3.0);
2479     const QRectF viewRect(10,10,60,90);
2480 
2481     QPainterPath fillPath;
2482     fillPath.addRect(QRect(30, 10, 20, 60));
2483     fillPath.addRect(QRect(50, 40, 20, 30));
2484 
2485 
2486     QRect shape1OutlineRect(10,20,40,120);
2487 
2488     QTransform bakedTransform = QTransform::fromScale(2, 0.5) * QTransform::fromTranslate(40,30);
2489     QPainterPath bakedFillPath = bakeShape(fillPath, bakedTransform,
2490                                            true, shape1OutlineRect,
2491                                            true, viewRect, referenceRect);
2492 
2493     QImage stampResult;
2494     QImage fillResult(QSize(220,160), QImage::Format_ARGB32);
2495     QPainter gc(&fillResult);
2496 
2497     fillResult.fill(0);
2498     renderBakedPath(gc,
2499                     bakedFillPath, bakedTransform,
2500                     shape1OutlineRect, bakedTransform,
2501                     referenceRect,
2502                     true, shape1OutlineRect,
2503                     true,
2504                     QTransform(),
2505                     &stampResult);
2506 
2507     QVERIFY(TestUtil::checkQImage(stampResult, "svg_render", "render", "pattern_c_view_r_obb_patch1"));
2508     QVERIFY(TestUtil::checkQImage(fillResult, "svg_render", "render", "pattern_c_view_r_obb_fill1"));
2509 
2510     QRect shape2OutlineRect(20,10,60,90);
2511     QTransform shape2Transform = QTransform::fromScale(2, 1) * QTransform::fromTranslate(50, 50);
2512 
2513     fillResult.fill(0);
2514     renderBakedPath(gc,
2515                     bakedFillPath, bakedTransform,
2516                     shape2OutlineRect, shape2Transform,
2517                     referenceRect,
2518                     true, shape1OutlineRect,
2519                     true,
2520                     rotateTransform(90, QPointF(0, 1.0 / 3.0)),
2521                     &stampResult);
2522 
2523     QVERIFY(TestUtil::checkQImage(stampResult, "svg_render", "render", "pattern_c_view_r_obb_patch2"));
2524     QVERIFY(TestUtil::checkQImage(fillResult, "svg_render", "render", "pattern_c_view_r_obb_fill2"));
2525 }
2526 
testManualRenderPattern_ContentView_RefUser()2527 void TestSvgParser::testManualRenderPattern_ContentView_RefUser()
2528 {
2529     const QRectF referenceRect(60, 0, 30, 20);
2530     const QRectF viewRect(10,10,60,90);
2531 
2532     QPainterPath fillPath;
2533     fillPath.addRect(QRect(30, 10, 20, 60));
2534     fillPath.addRect(QRect(50, 40, 20, 30));
2535 
2536 
2537     QRect shape1OutlineRect(10,20,40,120);
2538 
2539     QTransform bakedTransform = QTransform::fromScale(2, 0.5) * QTransform::fromTranslate(40,30);
2540     QPainterPath bakedFillPath = bakeShape(fillPath, bakedTransform,
2541                                            false, shape1OutlineRect,
2542                                            true, viewRect, referenceRect);
2543 
2544     QImage stampResult;
2545     QImage fillResult(QSize(220,160), QImage::Format_ARGB32);
2546     QPainter gc(&fillResult);
2547 
2548     fillResult.fill(0);
2549     renderBakedPath(gc,
2550                     bakedFillPath, bakedTransform,
2551                     shape1OutlineRect, bakedTransform,
2552                     referenceRect,
2553                     false, shape1OutlineRect,
2554                     false,
2555                     QTransform(),
2556                     &stampResult);
2557 
2558     QVERIFY(TestUtil::checkQImage(stampResult, "svg_render", "render", "pattern_c_view_r_user_patch1"));
2559     QVERIFY(TestUtil::checkQImage(fillResult, "svg_render", "render", "pattern_c_view_r_user_fill1"));
2560 
2561     QRect shape2OutlineRect(20,10,60,90);
2562     QTransform shape2Transform = QTransform::fromScale(2, 1) * QTransform::fromTranslate(50, 50);
2563 
2564     QTransform patternTransform2 = rotateTransform(90, QPointF()) * QTransform::fromTranslate(40, 10);
2565 
2566     fillResult.fill(0);
2567     renderBakedPath(gc,
2568                     bakedFillPath, bakedTransform,
2569                     shape2OutlineRect, shape2Transform,
2570                     referenceRect,
2571                     false, shape1OutlineRect,
2572                     false,
2573                     patternTransform2,
2574                     &stampResult);
2575 
2576     QVERIFY(TestUtil::checkQImage(stampResult, "svg_render", "render", "pattern_c_view_r_user_patch2"));
2577     QVERIFY(TestUtil::checkQImage(fillResult, "svg_render", "render", "pattern_c_view_r_user_fill2"));
2578 }
2579 
testRenderPattern_r_User_c_User()2580 void TestSvgParser::testRenderPattern_r_User_c_User()
2581 {
2582     const QString data =
2583             "<svg width=\"30px\" height=\"30px\""
2584             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
2585 
2586             "<defs>"
2587             "    <pattern id=\"TestPattern\" patternUnits=\"userSpaceOnUse\""
2588             "        patternContentUnits=\"userSpaceOnUse\""
2589             "        x=\"60\" y=\"0\" width=\"30\" height=\"20\">"
2590 
2591             "        <g id=\"patternRect\">"
2592             "            <rect id=\"patternRect1\" x=\"70\" y=\"0\" width=\"10\" height=\"13.3333\""
2593             "                fill=\"red\" stroke=\"none\" />"
2594 
2595             "            <rect id=\"patternRect2\" x=\"80\" y=\"6.3333\" width=\"10\" height=\"6.6666\""
2596             "                fill=\"red\" stroke=\"none\" />"
2597             "        </g>"
2598 
2599             "    </pattern>"
2600             "</defs>"
2601 
2602             "<g>"
2603             "    <rect id=\"testRect\" x=\"10\" y=\"20\" width=\"40\" height=\"120\""
2604             "        transform=\"translate(40 30) scale(2 0.5)\""
2605             "        fill=\"url(#TestPattern)blue\" stroke=\"none\"/>"
2606             "</g>"
2607 
2608             "</svg>";
2609 
2610     SvgRenderTester t (data);
2611 
2612     t.test_standard_30px_72ppi("fill_pattern_base", false, QSize(160, 160));
2613 }
2614 
testRenderPattern_InfiniteRecursionWhenInherited()2615 void TestSvgParser::testRenderPattern_InfiniteRecursionWhenInherited()
2616 {
2617     const QString data =
2618             "<svg width=\"30px\" height=\"30px\""
2619             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
2620 
2621             "<defs>"
2622             "    <pattern id=\"TestPattern\" patternUnits=\"userSpaceOnUse\""
2623             "        patternContentUnits=\"userSpaceOnUse\""
2624             "        x=\"60\" y=\"0\" width=\"30\" height=\"20\">"
2625 
2626             "        <g id=\"patternRect\">"
2627             "            <rect id=\"patternRect1\" x=\"70\" y=\"0\" width=\"10\" height=\"13.3333\""
2628             "                stroke=\"none\" />"
2629 
2630             "            <rect id=\"patternRect2\" x=\"80\" y=\"6.3333\" width=\"10\" height=\"6.6666\""
2631             "                stroke=\"none\" />"
2632             "        </g>"
2633 
2634             "    </pattern>"
2635             "</defs>"
2636 
2637             "<g>"
2638             "    <rect id=\"testRect\" x=\"10\" y=\"20\" width=\"40\" height=\"120\""
2639             "        transform=\"translate(40 30) scale(2 0.5)\""
2640             "        fill=\"url(#TestPattern)blue\" stroke=\"none\"/>"
2641             "</g>"
2642 
2643             "</svg>";
2644 
2645     SvgRenderTester t (data);
2646 
2647     t.test_standard_30px_72ppi("fill_pattern_base_black", false, QSize(160, 160));
2648 }
2649 
testRenderPattern_r_User_c_View()2650 void TestSvgParser::testRenderPattern_r_User_c_View()
2651 {
2652     const QString data =
2653             "<svg width=\"30px\" height=\"30px\""
2654             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
2655 
2656             "<defs>"
2657             "    <pattern id=\"TestPattern\" patternUnits=\"userSpaceOnUse\""
2658             "        viewBox=\"10 10 60 90\""
2659             "        preserveAspectRatio=\"none meet\""
2660             "        x=\"60\" y=\"0\" width=\"30\" height=\"20\">"
2661 
2662             "        <g id=\"patternRect\">"
2663             "            <rect id=\"patternRect1\" x=\"30\" y=\"10\" width=\"20\" height=\"60\""
2664             "                fill=\"red\" stroke=\"none\" />"
2665 
2666             // y is changed to 39 from 40 to fix a rounding issue!
2667             "            <rect id=\"patternRect2\" x=\"50\" y=\"39\" width=\"20\" height=\"30\""
2668             "                fill=\"red\" stroke=\"none\" />"
2669             "        </g>"
2670 
2671             "    </pattern>"
2672             "</defs>"
2673 
2674             "<g>"
2675             "    <rect id=\"testRect\" x=\"10\" y=\"20\" width=\"40\" height=\"120\""
2676             "        transform=\"translate(40 30) scale(2 0.5)\""
2677             "        fill=\"url(#TestPattern)blue\" stroke=\"none\"/>"
2678             "</g>"
2679 
2680             "</svg>";
2681 
2682     SvgRenderTester t (data);
2683 
2684     t.test_standard_30px_72ppi("fill_pattern_base", false, QSize(160, 160));
2685 }
2686 
testRenderPattern_r_User_c_Obb()2687 void TestSvgParser::testRenderPattern_r_User_c_Obb()
2688 {
2689     const QString data =
2690             "<svg width=\"30px\" height=\"30px\""
2691             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
2692 
2693             "<defs>"
2694             "    <pattern id=\"TestPattern\" patternUnits=\"userSpaceOnUse\""
2695             "        patternContentUnits=\"objectBoundingBox\""
2696             "        x=\"60\" y=\"0\" width=\"30\" height=\"20\">"
2697 
2698             "        <g id=\"patternRect\">"
2699             "            <rect id=\"patternRect1\" x=\"1.5\" y=\"-0.1666\" width=\"0.25\" height=\"0.111\""
2700             "                fill=\"red\" stroke=\"none\" />"
2701 
2702             "            <rect id=\"patternRect2\" x=\"1.75\" y=\"-0.12\" width=\"0.25\" height=\"0.07\""
2703             "                fill=\"red\" stroke=\"none\" />"
2704             "        </g>"
2705 
2706             "    </pattern>"
2707             "</defs>"
2708 
2709             "<g>"
2710             "    <rect id=\"testRect\" x=\"10\" y=\"20\" width=\"40\" height=\"120\""
2711             "        transform=\"translate(40 30) scale(2 0.5)\""
2712             "        fill=\"url(#TestPattern)blue\" stroke=\"none\"/>"
2713             "</g>"
2714 
2715             "</svg>";
2716 
2717     SvgRenderTester t (data);
2718 
2719     t.test_standard_30px_72ppi("fill_pattern_base", false, QSize(160, 160));
2720 }
2721 
testRenderPattern_r_User_c_View_Rotated()2722 void TestSvgParser::testRenderPattern_r_User_c_View_Rotated()
2723 {
2724     const QString data =
2725             "<svg width=\"30px\" height=\"30px\""
2726             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
2727 
2728             "<defs>"
2729             "    <pattern id=\"TestPattern\" patternUnits=\"userSpaceOnUse\""
2730             "        viewBox=\"10 10 60 90\""
2731             "        preserveAspectRatio=\"none meet\""
2732             "        x=\"60\" y=\"0\" width=\"30\" height=\"20\""
2733             "        patternTransform=\"translate(40 10) rotate(90)\">"
2734 
2735             "        <g id=\"patternRect\">"
2736             "            <rect id=\"patternRect1\" x=\"30\" y=\"10\" width=\"20\" height=\"60\""
2737             "                fill=\"red\" stroke=\"none\" />"
2738             "            <rect id=\"patternRect2\" x=\"50\" y=\"40\" width=\"20\" height=\"30\""
2739             "                fill=\"red\" stroke=\"none\" />"
2740             "        </g>"
2741 
2742             "    </pattern>"
2743             "</defs>"
2744 
2745             "<g>"
2746             "    <rect id=\"testRect\" x=\"20\" y=\"10\" width=\"60\" height=\"90\""
2747             "        transform=\"translate(50 50) scale(2 1)\""
2748             "        fill=\"url(#TestPattern)blue\" stroke=\"none\"/>"
2749             "</g>"
2750 
2751             "</svg>";
2752 
2753     SvgRenderTester t (data);
2754 
2755     t.test_standard_30px_72ppi("fill_pattern_rotated", false, QSize(220, 160));
2756 }
2757 
testRenderPattern_r_Obb_c_View_Rotated()2758 void TestSvgParser::testRenderPattern_r_Obb_c_View_Rotated()
2759 {
2760     /**
2761      * This test case differs from any application existent in the world :(
2762      *
2763      * Chrome and Firefox premultiply the patternTransform instead of doing post-
2764      * multiplication. Photoshop forgets to multiply the reference rect on it.
2765      *
2766      * So...
2767      */
2768 
2769     const QString data =
2770             "<svg width=\"30px\" height=\"30px\""
2771             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
2772 
2773             "<defs>"
2774             "    <pattern id=\"TestPattern\" patternUnits=\"objectBoundingBox\""
2775             "        viewBox=\"10 10 60 90\""
2776             "        preserveAspectRatio=\"none meet\""
2777             "        x=\"0\" y=\"0\" width=\"0.5\" height=\"0.333\""
2778             "        patternTransform=\"translate(0 0) rotate(90)\">"
2779 
2780             "        <g id=\"patternRect\">"
2781             "            <rect id=\"patternRect1\" x=\"30\" y=\"10\" width=\"20\" height=\"60\""
2782             "                fill=\"red\" stroke=\"none\" />"
2783             "            <rect id=\"patternRect2\" x=\"50\" y=\"40\" width=\"20\" height=\"30\""
2784             "                fill=\"red\" stroke=\"none\" />"
2785             "        </g>"
2786 
2787             "    </pattern>"
2788             "</defs>"
2789 
2790             "<g>"
2791             "    <rect id=\"testRect\" x=\"20\" y=\"10\" width=\"60\" height=\"90\""
2792             "        transform=\"translate(50 50) scale(1 1)\""
2793             "        fill=\"url(#TestPattern)blue\" stroke=\"none\"/>"
2794             "</g>"
2795 
2796             "</svg>";
2797 
2798     SvgRenderTester t (data);
2799 
2800     t.test_standard_30px_72ppi("fill_pattern_rotated_odd", false, QSize(220, 160));
2801 }
2802 
2803 #include <KoPathShape.h>
2804 #include <KoColorBackground.h>
2805 #include <KoClipPath.h>
2806 #include <commands/KoShapeGroupCommand.h>
2807 
testKoClipPathRendering()2808 void TestSvgParser::testKoClipPathRendering()
2809 {
2810     QPainterPath path1;
2811     path1.addRect(QRect(5,5,15,15));
2812 
2813     QPainterPath path2;
2814     path2.addRect(QRect(10,10,15,15));
2815 
2816     QPainterPath clipPath1;
2817     clipPath1.addRect(QRect(10, 0, 10, 30));
2818 
2819     QPainterPath clipPath2;
2820     clipPath2.moveTo(0,7);
2821     clipPath2.lineTo(30,7);
2822     clipPath2.lineTo(15,30);
2823     clipPath2.lineTo(0,7);
2824 
2825     QScopedPointer<KoPathShape> shape1(KoPathShape::createShapeFromPainterPath(path1));
2826     shape1->setBackground(QSharedPointer<KoColorBackground>(new KoColorBackground(Qt::blue)));
2827 
2828     QScopedPointer<KoPathShape> shape2(KoPathShape::createShapeFromPainterPath(path2));
2829     shape2->setBackground(QSharedPointer<KoColorBackground>(new KoColorBackground(Qt::red)));
2830 
2831     QScopedPointer<KoPathShape> clipShape1(KoPathShape::createShapeFromPainterPath(clipPath1));
2832     KoClipPath *koClipPath1 = new KoClipPath({clipShape1.take()}, KoFlake::UserSpaceOnUse);
2833     koClipPath1->setClipRule(Qt::WindingFill);
2834     shape1->setClipPath(koClipPath1);
2835 
2836     QScopedPointer<KoShapeGroup> group(new KoShapeGroup());
2837     {
2838         QList<KoShape*> shapes({shape1.take(), shape2.take()});
2839 
2840         KoShapeGroupCommand cmd(group.data(), shapes, false);
2841         cmd.redo();
2842     }
2843 
2844     QScopedPointer<KoPathShape> clipShape2(KoPathShape::createShapeFromPainterPath(clipPath2));
2845     KoClipPath *koClipPath2 = new KoClipPath({clipShape2.take()}, KoFlake::UserSpaceOnUse);
2846     koClipPath2->setClipRule(Qt::WindingFill);
2847     group->setClipPath(koClipPath2);
2848 
2849     SvgRenderTester::testRender(group.take(), "load", "clip_render_test", QSize(30,30));
2850 }
2851 
testKoClipPathRelativeRendering()2852 void TestSvgParser::testKoClipPathRelativeRendering()
2853 {
2854     QPainterPath path1;
2855     path1.addRect(QRect(5,5,15,15));
2856 
2857     QPainterPath path2;
2858     path2.addRect(QRect(10,10,15,15));
2859 
2860     QPainterPath clipPath1;
2861     clipPath1.addRect(QRect(10, 0, 10, 30));
2862 
2863     QPainterPath clipPath2;
2864     clipPath2.moveTo(0,0);
2865     clipPath2.lineTo(1,0);
2866     clipPath2.lineTo(0.5,1);
2867     clipPath2.lineTo(0,0);
2868 
2869     QScopedPointer<KoPathShape> shape1(KoPathShape::createShapeFromPainterPath(path1));
2870     shape1->setBackground(QSharedPointer<KoColorBackground>(new KoColorBackground(Qt::blue)));
2871 
2872     QScopedPointer<KoPathShape> shape2(KoPathShape::createShapeFromPainterPath(path2));
2873     shape2->setBackground(QSharedPointer<KoColorBackground>(new KoColorBackground(Qt::red)));
2874 
2875     QScopedPointer<KoPathShape> clipShape1(KoPathShape::createShapeFromPainterPath(clipPath1));
2876     KoClipPath *koClipPath1 = new KoClipPath({clipShape1.take()}, KoFlake::UserSpaceOnUse);
2877     koClipPath1->setClipRule(Qt::WindingFill);
2878     shape1->setClipPath(koClipPath1);
2879 
2880     QScopedPointer<KoShapeGroup> group(new KoShapeGroup());
2881     {
2882         QList<KoShape*> shapes({shape1.take(), shape2.take()});
2883 
2884         KoShapeGroupCommand cmd(group.data(), shapes, false);
2885         cmd.redo();
2886     }
2887 
2888     QScopedPointer<KoPathShape> clipShape2(KoPathShape::createShapeFromPainterPath(clipPath2));
2889     KoClipPath *koClipPath2 = new KoClipPath({clipShape2.take()}, KoFlake::ObjectBoundingBox);
2890     koClipPath2->setClipRule(Qt::WindingFill);
2891     group->setClipPath(koClipPath2);
2892 
2893     SvgRenderTester::testRender(group.take(), "load", "relative_clip_render_test", QSize(30,30));
2894 }
2895 
testRenderClipPath_User()2896 void TestSvgParser::testRenderClipPath_User()
2897 {
2898     const QString data =
2899             "<svg width=\"30px\" height=\"30px\""
2900             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
2901 
2902             "<clipPath id=\"clip1\" clipPathUnits=\"userSpaceOnUse\">"
2903             "    <rect id=\"clipRect1\" x=\"10\" y=\"0\" width=\"10\" height=\"30\""
2904             "            fill=\"red\" stroke=\"none\" />"
2905             "    <rect id=\"clipRect1\" x=\"10\" y=\"0\" width=\"10\" height=\"30\""
2906             "            fill=\"yellow\" stroke=\"none\" />"
2907             "</clipPath>"
2908 
2909             "<clipPath id=\"clip2\" clipPathUnits=\"userSpaceOnUse\">"
2910             "    <path id=\"clipRect1\" d=\"M 0 7 L 30 7 15 30 0 7 z\""
2911             "            fill=\"red\" stroke=\"none\" />"
2912             "</clipPath>"
2913 
2914             "<g id=\"testRect\" clip-path=\"url(#clip2)\">"
2915             "    <rect id=\"testRect1\" x=\"5\" y=\"5\" width=\"15\" height=\"15\""
2916             "        fill=\"blue\" stroke=\"none\" clip-path=\"url(#clip1)\"/>"
2917 
2918             "    <rect id=\"testRect2\" x=\"10\" y=\"10\" width=\"15\" height=\"15\""
2919             "        fill=\"red\" stroke=\"none\"/>"
2920             "</g>"
2921 
2922             "</svg>";
2923 
2924     SvgRenderTester t (data);
2925 
2926     t.test_standard_30px_72ppi("clip_render_test", false);
2927 }
2928 
testRenderClipPath_Obb()2929 void TestSvgParser::testRenderClipPath_Obb()
2930 {
2931     const QString data =
2932             "<svg width=\"30px\" height=\"30px\""
2933             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
2934 
2935             "<clipPath id=\"clip1\" clipPathUnits=\"userSpaceOnUse\">"
2936             "    <rect id=\"clipRect1\" x=\"10\" y=\"0\" width=\"10\" height=\"30\""
2937             "            fill=\"red\" stroke=\"none\" />"
2938             "    <rect id=\"clipRect1\" x=\"10\" y=\"0\" width=\"10\" height=\"30\""
2939             "            fill=\"yellow\" stroke=\"none\" />"
2940             "</clipPath>"
2941 
2942             "<clipPath id=\"clip2\" clipPathUnits=\"objectBoundingBox\">"
2943             "    <path id=\"clipRect1\" d=\"M 0 0 L 1 0 0.5 1 0 0 z\""
2944             "            fill=\"red\" stroke=\"none\" />"
2945             "</clipPath>"
2946 
2947             "<g id=\"testRect\" clip-path=\"url(#clip2)\">"
2948             "    <rect id=\"testRect1\" x=\"5\" y=\"5\" width=\"15\" height=\"15\""
2949             "        fill=\"blue\" stroke=\"none\" clip-path=\"url(#clip1)\"/>"
2950 
2951             "    <rect id=\"testRect2\" x=\"10\" y=\"10\" width=\"15\" height=\"15\""
2952             "        fill=\"red\" stroke=\"none\"/>"
2953             "</g>"
2954 
2955             "</svg>";
2956 
2957     SvgRenderTester t (data);
2958 
2959     t.test_standard_30px_72ppi("relative_clip_render_test", false);
2960 }
2961 
testRenderClipPath_Obb_Transform()2962 void TestSvgParser::testRenderClipPath_Obb_Transform()
2963 {
2964     const QString data =
2965             "<svg width=\"30px\" height=\"30px\""
2966             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
2967 
2968             "<clipPath id=\"clip1\" clipPathUnits=\"userSpaceOnUse\""
2969             "    transform=\"rotate(90,15,15)\">"
2970             "    <rect id=\"clipRect1\" x=\"10\" y=\"0\" width=\"10\" height=\"30\""
2971             "            fill=\"red\" stroke=\"none\" />"
2972             "    <rect id=\"clipRect1\" x=\"10\" y=\"0\" width=\"10\" height=\"30\""
2973             "            fill=\"yellow\" stroke=\"none\" />"
2974             "</clipPath>"
2975 
2976             "<clipPath id=\"clip2\" clipPathUnits=\"objectBoundingBox\""
2977             "    transform=\"rotate(90 0.5 0.5)\">"
2978             "    <path id=\"clipRect1\" d=\"M 0 0 L 1 0 0.5 1 0 0 z\""
2979             "            fill=\"red\" stroke=\"none\" />"
2980             "</clipPath>"
2981 
2982             "<g id=\"testRect\" clip-path=\"url(#clip2)\">"
2983             "    <rect id=\"testRect1\" x=\"5\" y=\"5\" width=\"15\" height=\"15\""
2984             "        fill=\"blue\" stroke=\"none\" clip-path=\"url(#clip1)\"/>"
2985 
2986             "    <rect id=\"testRect2\" x=\"10\" y=\"10\" width=\"15\" height=\"15\""
2987             "        fill=\"red\" stroke=\"none\"/>"
2988             "</g>"
2989 
2990             "</svg>";
2991 
2992     SvgRenderTester t (data);
2993 
2994     t.test_standard_30px_72ppi("clip_render_test_rotated", false);
2995 }
2996 
testRenderClipMask_Obb()2997 void TestSvgParser::testRenderClipMask_Obb()
2998 {
2999     const QString data =
3000             "<svg width=\"30px\" height=\"30px\""
3001             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3002 
3003             "<defs>"
3004 
3005             "    <linearGradient id=\"Gradient\" gradientUnits=\"objectBoundingBox\""
3006             "        x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\">"
3007 
3008             "        <stop offset=\"0\" stop-color=\"white\" stop-opacity=\"0\" />"
3009             "        <stop offset=\"1\" stop-color=\"white\" stop-opacity=\"1\" />"
3010 
3011             "    </linearGradient>"
3012 
3013             "    <mask id=\"Mask\" maskUnits=\"objectBoundingBox\""
3014             "        maskContentUnits=\"objectBoundingBox\""
3015             "        x=\"0.2\" y=\"0.2\" width=\"0.6\" height=\"0.6\">"
3016 
3017             "        <rect x=\"0\" y=\"0\" width=\"1\" height=\"1\" fill=\"url(#Gradient)\" />"
3018 
3019             "    </mask>"
3020 
3021             "</defs>"
3022 
3023 
3024             "<g id=\"testRect\">"
3025             "    <rect id=\"testRect1\" x=\"5\" y=\"5\" width=\"15\" height=\"15\""
3026             "        fill=\"blue\" stroke=\"none\"/>"
3027 
3028             "    <rect id=\"testRect2\" x=\"10\" y=\"10\" width=\"15\" height=\"15\""
3029             "        fill=\"red\" stroke=\"none\" mask=\"url(#Mask)\" />"
3030             "</g>"
3031 
3032             "</svg>";
3033 
3034     SvgRenderTester t (data);
3035 
3036     t.test_standard_30px_72ppi("clip_mask_obb", false);
3037 }
3038 
testRenderClipMaskOnGroup_Obb()3039 void TestSvgParser::testRenderClipMaskOnGroup_Obb()
3040 {
3041     const QString data =
3042             "<svg width=\"30px\" height=\"30px\""
3043             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3044 
3045             "<defs>"
3046 
3047             "    <linearGradient id=\"Gradient\" gradientUnits=\"objectBoundingBox\""
3048             "        x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\">"
3049 
3050             "        <stop offset=\"0\" stop-color=\"white\" stop-opacity=\"0\" />"
3051             "        <stop offset=\"1\" stop-color=\"white\" stop-opacity=\"1\" />"
3052 
3053             "    </linearGradient>"
3054 
3055             "    <mask id=\"Mask\" maskUnits=\"objectBoundingBox\""
3056             "        maskContentUnits=\"objectBoundingBox\""
3057             "        x=\"0.2\" y=\"0.2\" width=\"0.6\" height=\"0.6\">"
3058 
3059             "        <rect x=\"0\" y=\"0\" width=\"1\" height=\"1\" fill=\"url(#Gradient)\" />"
3060 
3061             "    </mask>"
3062 
3063             "</defs>"
3064 
3065 
3066             "<g id=\"testRect\" mask=\"url(#Mask)\">"
3067             "    <rect id=\"testRect1\" x=\"5\" y=\"5\" width=\"15\" height=\"15\""
3068             "        fill=\"blue\" stroke=\"none\"/>"
3069 
3070             "    <rect id=\"testRect2\" x=\"10\" y=\"10\" width=\"15\" height=\"15\""
3071             "        fill=\"red\" stroke=\"none\" />"
3072             "</g>"
3073 
3074             "</svg>";
3075 
3076     SvgRenderTester t (data);
3077 
3078     t.test_standard_30px_72ppi("clip_mask_on_group_obb", false);
3079 }
3080 
fileFetcherFunc(const QString & name)3081 QByteArray fileFetcherFunc(const QString &name)
3082 {
3083     const QString fileName = TestUtil::fetchDataFileLazy(name);
3084     QFile file(fileName);
3085     KIS_ASSERT(file.exists());
3086     file.open(QIODevice::ReadOnly);
3087     return file.readAll();
3088 }
3089 
testRenderClipMask_User_Clip_Obb()3090 void TestSvgParser::testRenderClipMask_User_Clip_Obb()
3091 {
3092     const QString data =
3093             "<svg width=\"30px\" height=\"30px\""
3094             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3095 
3096             //"<defs>"
3097 
3098             "    <linearGradient id=\"Gradient\" gradientUnits=\"objectBoundingBox\""
3099             "        x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\">"
3100 
3101             "        <stop offset=\"0\" stop-color=\"white\" stop-opacity=\"0\" />"
3102             "        <stop offset=\"1\" stop-color=\"white\" stop-opacity=\"1\" />"
3103 
3104             "    </linearGradient>"
3105 
3106             "    <mask id=\"Mask\" maskUnits=\"objectBoundingBox\""
3107             "        maskContentUnits=\"userSpaceOnUse\""
3108             "        x=\"0.2\" y=\"0.2\" width=\"0.6\" height=\"0.6\">"
3109 
3110             "        <rect x=\"10\" y=\"10\" width=\"15\" height=\"15\" fill=\"url(#Gradient)\" />"
3111 
3112             "    </mask>"
3113 
3114             //"</defs>"
3115 
3116 
3117             "<g id=\"testRect\">"
3118             "    <rect id=\"testRect1\" x=\"5\" y=\"5\" width=\"15\" height=\"15\""
3119             "        fill=\"blue\" stroke=\"none\"/>"
3120 
3121             "    <rect id=\"testRect2\" x=\"10\" y=\"10\" width=\"15\" height=\"15\""
3122             "        fill=\"red\" stroke=\"none\" mask=\"url(#Mask)\" />"
3123             "</g>"
3124 
3125             "</svg>";
3126 
3127     SvgRenderTester t (data);
3128 
3129     t.test_standard_30px_72ppi("clip_mask_obb", false);
3130 }
3131 
testRenderClipMask_User_Clip_User()3132 void TestSvgParser::testRenderClipMask_User_Clip_User()
3133 {
3134     const QString data =
3135             "<svg width=\"30px\" height=\"30px\""
3136             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3137 
3138             //"<defs>"
3139 
3140             "    <linearGradient id=\"Gradient\" gradientUnits=\"objectBoundingBox\""
3141             "        x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\">"
3142 
3143             "        <stop offset=\"0\" stop-color=\"white\" stop-opacity=\"0\" />"
3144             "        <stop offset=\"1\" stop-color=\"white\" stop-opacity=\"1\" />"
3145 
3146             "    </linearGradient>"
3147 
3148             "    <mask id=\"Mask\" maskUnits=\"userSpaceOnUse\""
3149             "        maskContentUnits=\"userSpaceOnUse\""
3150             "        x=\"13\" y=\"13\" width=\"9\" height=\"9\">"
3151 
3152             "        <rect x=\"10\" y=\"10\" width=\"15\" height=\"15\" fill=\"url(#Gradient)\" />"
3153 
3154             "    </mask>"
3155 
3156             //"</defs>"
3157 
3158 
3159             "<g id=\"testRect\">"
3160             "    <rect id=\"testRect1\" x=\"5\" y=\"5\" width=\"15\" height=\"15\""
3161             "        fill=\"blue\" stroke=\"none\"/>"
3162 
3163             "    <rect id=\"testRect2\" x=\"10\" y=\"10\" width=\"15\" height=\"15\""
3164             "        fill=\"red\" stroke=\"none\" mask=\"url(#Mask)\" />"
3165             "</g>"
3166 
3167             "</svg>";
3168 
3169     SvgRenderTester t (data);
3170 
3171     t.test_standard_30px_72ppi("clip_mask_obb", false);
3172 }
3173 
testRenderImage_AspectDefault()3174 void TestSvgParser::testRenderImage_AspectDefault()
3175 {
3176     const QString data =
3177             "<svg width=\"30px\" height=\"30px\""
3178             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3179 
3180             "<g id=\"testRect\">"
3181             "    <rect id=\"testRect1\" x=\"2\" y=\"2\" width=\"26\" height=\"26\""
3182             "        fill=\"green\" stroke=\"none\"/>"
3183 
3184             "    <rect id=\"testRect1\" x=\"5\" y=\"5\" width=\"15\" height=\"10\""
3185             "        fill=\"white\" stroke=\"none\"/>"
3186 
3187 
3188             "    <image x=\"5\" y=\"5\" width=\"15\" height=\"10\""
3189             "        xlink:href=\"svg_render/testing_ref_image.png\">"
3190 
3191             "        <title>My image</title>"
3192 
3193             "    </image>"
3194 
3195             "</g>"
3196 
3197             "</svg>";
3198 
3199     SvgRenderTester t (data);
3200     t.parser.setFileFetcher(fileFetcherFunc);
3201 
3202     t.test_standard_30px_72ppi("image_aspect_default", false);
3203 }
3204 
testRenderImage_AspectNone()3205 void TestSvgParser::testRenderImage_AspectNone()
3206 {
3207     const QString data =
3208             "<svg width=\"30px\" height=\"30px\""
3209             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3210 
3211             "<g id=\"testRect\">"
3212             "    <rect id=\"testRect1\" x=\"2\" y=\"2\" width=\"26\" height=\"26\""
3213             "        fill=\"green\" stroke=\"none\"/>"
3214 
3215             "    <rect id=\"testRect1\" x=\"5\" y=\"5\" width=\"15\" height=\"10\""
3216             "        fill=\"white\" stroke=\"none\"/>"
3217 
3218 
3219             "    <image x=\"5\" y=\"5\" width=\"15\" height=\"10\""
3220             "        preserveAspectRatio=\"none\""
3221             "        xlink:href=\"svg_render/testing_ref_image.png\">"
3222 
3223             "        <title>My image</title>"
3224 
3225             "    </image>"
3226 
3227             "</g>"
3228 
3229             "</svg>";
3230 
3231     SvgRenderTester t (data);
3232     t.setFuzzyThreshold(5);
3233     t.parser.setFileFetcher(fileFetcherFunc);
3234 
3235     t.test_standard_30px_72ppi("image_aspect_none", false);
3236 }
3237 
testRenderImage_AspectMeet()3238 void TestSvgParser::testRenderImage_AspectMeet()
3239 {
3240     const QString data =
3241             "<svg width=\"30px\" height=\"30px\""
3242             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3243 
3244             "<g id=\"testRect\">"
3245             "    <rect id=\"testRect1\" x=\"2\" y=\"2\" width=\"26\" height=\"26\""
3246             "        fill=\"green\" stroke=\"none\"/>"
3247 
3248             "    <rect id=\"testRect1\" x=\"5\" y=\"5\" width=\"15\" height=\"10\""
3249             "        fill=\"white\" stroke=\"none\"/>"
3250 
3251 
3252             "    <image x=\"5\" y=\"5\" width=\"15\" height=\"10\""
3253             "        preserveAspectRatio=\"xMinYMin meet\""
3254             "        xlink:href=\"svg_render/testing_ref_image.png\">"
3255 
3256             "        <title>My image</title>"
3257 
3258             "    </image>"
3259 
3260             "</g>"
3261 
3262             "</svg>";
3263 
3264     SvgRenderTester t (data);
3265     t.parser.setFileFetcher(fileFetcherFunc);
3266 
3267     t.test_standard_30px_72ppi("image_aspect_meet", false);
3268 }
3269 
testRectShapeRoundUniformX()3270 void TestSvgParser::testRectShapeRoundUniformX()
3271 {
3272     const QString data =
3273             "<svg width=\"30px\" height=\"30px\""
3274             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3275 
3276             "    <rect id=\"testRect\" x=\"5\" y=\"5\" width=\"20\" height=\"20\""
3277             "        rx=\"5\""
3278             "        fill=\"blue\" stroke=\"none\"/>"
3279 
3280             "</svg>";
3281 
3282     SvgRenderTester t (data);
3283 
3284     t.test_standard_30px_72ppi("rect_5_5", false);
3285 }
3286 
testRectShapeRoundUniformY()3287 void TestSvgParser::testRectShapeRoundUniformY()
3288 {
3289     const QString data =
3290             "<svg width=\"30px\" height=\"30px\""
3291             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3292 
3293             "    <rect id=\"testRect\" x=\"5\" y=\"5\" width=\"20\" height=\"20\""
3294             "        rx=\"5\""
3295             "        fill=\"blue\" stroke=\"none\"/>"
3296 
3297             "</svg>";
3298 
3299     SvgRenderTester t (data);
3300 
3301     t.test_standard_30px_72ppi("rect_5_5", false);
3302 }
3303 
testRectShapeRoundXY()3304 void TestSvgParser::testRectShapeRoundXY()
3305 {
3306     const QString data =
3307             "<svg width=\"30px\" height=\"30px\""
3308             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3309 
3310             "    <rect id=\"testRect\" x=\"5\" y=\"5\" width=\"20\" height=\"20\""
3311             "        rx=\"5\" ry=\"10\""
3312             "        fill=\"blue\" stroke=\"none\"/>"
3313 
3314             "</svg>";
3315 
3316     SvgRenderTester t (data);
3317 
3318     t.test_standard_30px_72ppi("rect_5_10", false);
3319 }
3320 
testRectShapeRoundXYOverflow()3321 void TestSvgParser::testRectShapeRoundXYOverflow()
3322 {
3323     const QString data =
3324             "<svg width=\"30px\" height=\"30px\""
3325             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3326 
3327             "    <rect id=\"testRect\" x=\"5\" y=\"5\" width=\"20\" height=\"20\""
3328             "        rx=\"5\" ry=\"25\""
3329             "        fill=\"blue\" stroke=\"none\"/>"
3330 
3331             "</svg>";
3332 
3333     SvgRenderTester t (data);
3334 
3335     t.test_standard_30px_72ppi("rect_5_10", false);
3336 }
3337 
testCircleShape()3338 void TestSvgParser::testCircleShape()
3339 {
3340     const QString data =
3341             "<svg width=\"30px\" height=\"30px\""
3342             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3343 
3344             "    <circle id=\"testRect\" cx=\"15\" cy=\"15\" r=\"10\""
3345             "        fill=\"blue\" stroke=\"white\"/>"
3346 
3347             "</svg>";
3348 
3349     SvgRenderTester t (data);
3350 
3351     t.test_standard_30px_72ppi("circle", false);
3352 }
3353 
testEllipseShape()3354 void TestSvgParser::testEllipseShape()
3355 {
3356     const QString data =
3357             "<svg width=\"30px\" height=\"30px\""
3358             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3359 
3360             "    <ellipse id=\"testRect\" cx=\"15\" cy=\"15\" rx=\"10\" ry=\"5\""
3361             "        fill=\"blue\" stroke=\"white\"/>"
3362 
3363             "</svg>";
3364 
3365     SvgRenderTester t (data);
3366 
3367     t.test_standard_30px_72ppi("ellipse", false);
3368 }
3369 
testLineShape()3370 void TestSvgParser::testLineShape()
3371 {
3372     const QString data =
3373             "<svg width=\"30px\" height=\"30px\""
3374             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3375 
3376             "    <line id=\"testRect\" x1=\"5\" y1=\"5\" x2=\"25\" y2=\"15\""
3377             "        fill=\"blue\" stroke=\"white\"/>"
3378 
3379             "</svg>";
3380 
3381     SvgRenderTester t (data);
3382 
3383     t.test_standard_30px_72ppi("line", false);
3384 }
3385 
testPolylineShape()3386 void TestSvgParser::testPolylineShape()
3387 {
3388     const QString data =
3389             "<svg width=\"30px\" height=\"30px\""
3390             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3391 
3392             "    <polyline id=\"testRect\" points=\"5,5 10, 5 10,10 5,10 \n"
3393             "        5 ,15 15 , 15 15,20 20,20 20,10 25,10 25,25 5,25\""
3394             "        fill=\"red\" stroke=\"white\"/>"
3395 
3396             "</svg>";
3397 
3398     SvgRenderTester t (data);
3399 
3400     t.test_standard_30px_72ppi("polyline", false);
3401 }
3402 
testPolygonShape()3403 void TestSvgParser::testPolygonShape()
3404 {
3405     const QString data =
3406             "<svg width=\"30px\" height=\"30px\""
3407             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3408 
3409             "    <polygon id=\"testRect\" points=\"5,5 10, 5 10,10 5,10 \n"
3410             "        5 ,15 15 , 15 15,20 20,20 20,10 25,10 25,25 5,25\""
3411             "        fill=\"red\" stroke=\"white\"/>"
3412 
3413             "</svg>";
3414 
3415     SvgRenderTester t (data);
3416 
3417     t.test_standard_30px_72ppi("polygon", false);
3418 }
3419 
testPathShape()3420 void TestSvgParser::testPathShape()
3421 {
3422     const QString data =
3423             "<svg width=\"30px\" height=\"30px\""
3424             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3425 
3426             "    <path id=\"testRect\""
3427             "        d=\"M 5,5 h 5 l 0,5 L5,10 l 0,5 l10,0 v5 l 5, 0 L20, 10 l 5,0 L 25,25 L 5,25 z\""
3428             "        fill=\"red\" stroke=\"white\"/>"
3429 
3430             "</svg>";
3431 
3432     SvgRenderTester t (data);
3433 
3434     t.test_standard_30px_72ppi("polygon", false);
3435 }
3436 
testDefsHidden()3437 void TestSvgParser::testDefsHidden()
3438 {
3439     const QString data =
3440             "<svg width=\"30px\" height=\"30px\""
3441             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3442 
3443             "<g id=\"testRect\">"
3444             "    <defs>"
3445             "        <rect id=\"testRect1\" x=\"5\" y=\"5\" width=\"15\" height=\"15\""
3446             "            fill=\"blue\" stroke=\"none\"/>"
3447             "    </defs>"
3448 
3449             "    <rect id=\"testRect2\" x=\"10\" y=\"10\" width=\"15\" height=\"15\""
3450             "        fill=\"red\" stroke=\"none\"/>"
3451             "</g>"
3452 
3453             "</svg>";
3454 
3455     SvgRenderTester t (data);
3456 
3457     t.test_standard_30px_72ppi("test_defs_hidden", false);
3458 }
3459 
testDefsUseInheritance()3460 void TestSvgParser::testDefsUseInheritance()
3461 {
3462     const QString data =
3463             "<svg width=\"30px\" height=\"30px\""
3464             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3465 
3466 
3467 
3468             "<g id=\"unrenderedRect\" fill=\"green\" >"
3469             "    <defs>"
3470             "        <rect id=\"testRect1\" x=\"1\" y=\"1\" width=\"15\" height=\"15\""
3471             "            stroke=\"none\"/>"
3472             "    </defs>"
3473             "</g>"
3474 
3475 
3476             /**
3477              * NOTES:
3478              * 1) width/height attributes for <use> are not implemented yet
3479              * 2) x and y are summed up
3480              * 3) stroke="white" is overridden by the original templated object
3481              * 4) fill="green" attribute from <defs> is not inherited
3482              */
3483 
3484             "<g id=\"testRect\" fill=\"blue\" >"
3485             "    <use x=\"4\" y=\"4\" xlink:href=\"#testRect1\""
3486             "        stroke=\"white\" stroke-width=\"1\" />"
3487 
3488             "    <rect id=\"testRect2\" x=\"10\" y=\"10\" width=\"15\" height=\"15\""
3489             "        fill=\"red\" stroke=\"none\"/>"
3490             "</g>"
3491 
3492             "</svg>";
3493 
3494     SvgRenderTester t (data);
3495 
3496     t.test_standard_30px_72ppi("defs_use_inheritance", false);
3497 }
3498 
testUseWithoutDefs()3499 void TestSvgParser::testUseWithoutDefs()
3500 {
3501     const QString data =
3502             "<svg width=\"30px\" height=\"30px\""
3503             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3504 
3505             // technical rect for rendering
3506             "<g id=\"testRect\">"
3507 
3508             "<g id=\"renderedRect1\" fill=\"green\" >"
3509             "    <rect id=\"testRect1\" x=\"1\" y=\"1\" width=\"15\" height=\"15\""
3510             "        stroke=\"none\"/>"
3511             "</g>"
3512 
3513 
3514             /**
3515              * NOTES:
3516              * 1) width/height attributes for <use> are not implemented yet
3517              * 2) x and y are summed up
3518              * 3) stroke="white" is overridden by the original templated object
3519              * 4) fill="green" attribute from <defs> is not inherited
3520              */
3521 
3522             "<g id=\"renderedRect2\" fill=\"blue\" >"
3523             "    <use x=\"4\" y=\"4\" xlink:href=\"#testRect1\""
3524             "        stroke=\"white\" stroke-width=\"1\" />"
3525 
3526             "    <rect id=\"testRect2\" x=\"10\" y=\"10\" width=\"15\" height=\"15\""
3527             "        fill=\"red\" stroke=\"none\"/>"
3528             "</g>"
3529 
3530             "</g>"
3531 
3532             "</svg>";
3533 
3534     SvgRenderTester t (data);
3535 
3536     t.test_standard_30px_72ppi("use_without_defs", false);
3537 }
3538 
testMarkersAutoOrientation()3539 void TestSvgParser::testMarkersAutoOrientation()
3540 {
3541     const QString data =
3542             "<svg width=\"30px\" height=\"30px\""
3543             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3544 
3545             "<marker id=\"SimpleRectMarker\""
3546             "    orient=\"auto\" refY=\"12.5\" refX=\"12.5\" >"
3547 
3548             "    <rect id=\"markerRect\" x=\"10\" y=\"10\" width=\"5\" height=\"5\""
3549             "        fill=\"red\" stroke=\"none\"/>"
3550             "    <rect id=\"markerRect\" x=\"14\" y=\"12\" width=\"1\" height=\"1\""
3551             "        fill=\"yellow\" stroke=\"none\"/>"
3552             "    <rect id=\"markerRect\" x=\"12\" y=\"12\" width=\"1\" height=\"1\""
3553             "        fill=\"white\" stroke=\"none\"/>"
3554             "</marker>"
3555 
3556             "<path id=\"testRect\""
3557             "    style=\"fill:none;stroke:#000000;stroke-width:1px;marker-start:url(#SimpleRectMarker);marker-end:url(#SimpleRectMarker);marker-mid:url(#SimpleRectMarker)\""
3558             "    d=\"M5,15 C5,5 25,5 25,15 L15,25\"/>"
3559 
3560             "</svg>";
3561 
3562     SvgRenderTester t (data);
3563 
3564     t.test_standard_30px_72ppi("markers", false);
3565 }
3566 
testMarkersAutoOrientationScaled()3567 void TestSvgParser::testMarkersAutoOrientationScaled()
3568 {
3569     const QString data =
3570             "<svg width=\"30px\" height=\"30px\""
3571             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3572 
3573             "<marker id=\"SimpleRectMarker\""
3574             "    orient=\"auto\" refY=\"12.5\" refX=\"12.5\" >"
3575 
3576             "    <rect id=\"markerRect\" x=\"10\" y=\"10\" width=\"5\" height=\"5\""
3577             "        fill=\"red\" stroke=\"none\"/>"
3578             "    <rect id=\"markerRect\" x=\"14\" y=\"12\" width=\"1\" height=\"1\""
3579             "        fill=\"yellow\" stroke=\"none\"/>"
3580             "    <rect id=\"markerRect\" x=\"12\" y=\"12\" width=\"1\" height=\"1\""
3581             "        fill=\"white\" stroke=\"none\"/>"
3582             "</marker>"
3583 
3584             "<path id=\"testRect\""
3585             "    style=\"fill:none;stroke:#000000;stroke-width:2px;marker-start:url(#SimpleRectMarker);marker-end:url(#SimpleRectMarker);marker-mid:url(#SimpleRectMarker)\""
3586             "    d=\"M5,15 C5,5 25,5 25,15 L15,25\"/>"
3587 
3588             "</svg>";
3589 
3590     SvgRenderTester t (data);
3591 
3592     t.test_standard_30px_72ppi("markers_scaled", false);
3593 }
3594 
testMarkersAutoOrientationScaledUserCoordinates()3595 void TestSvgParser::testMarkersAutoOrientationScaledUserCoordinates()
3596 {
3597     const QString data =
3598             "<svg width=\"30px\" height=\"30px\""
3599             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3600 
3601             "<marker id=\"SimpleRectMarker\""
3602             "    markerUnits = \"userSpaceOnUse\""
3603             "    orient=\"auto\" refY=\"12.5\" refX=\"12.5\" >"
3604 
3605             "    <rect id=\"markerRect\" x=\"10\" y=\"10\" width=\"5\" height=\"5\""
3606             "        fill=\"red\" stroke=\"none\"/>"
3607             "    <rect id=\"markerRect\" x=\"14\" y=\"12\" width=\"1\" height=\"1\""
3608             "        fill=\"yellow\" stroke=\"none\"/>"
3609             "    <rect id=\"markerRect\" x=\"12\" y=\"12\" width=\"1\" height=\"1\""
3610             "        fill=\"white\" stroke=\"none\"/>"
3611             "</marker>"
3612 
3613             "<path id=\"testRect\""
3614             "    style=\"fill:none;stroke:#000000;stroke-width:2px;marker-start:url(#SimpleRectMarker);marker-end:url(#SimpleRectMarker);marker-mid:url(#SimpleRectMarker)\""
3615             "    d=\"M5,15 C5,5 25,5 25,15 L15,25\"/>"
3616 
3617             "</svg>";
3618 
3619     SvgRenderTester t (data);
3620 
3621     t.test_standard_30px_72ppi("markers_user_coordinates", false);
3622 }
3623 
testMarkersCustomOrientation()3624 void TestSvgParser::testMarkersCustomOrientation()
3625 {
3626     const QString data =
3627             "<svg width=\"30px\" height=\"30px\""
3628             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3629 
3630             "<marker id=\"SimpleRectMarker\""
3631             "    orient=\"45\" refY=\"12.5\" refX=\"12.5\" >"
3632 
3633             "    <rect id=\"markerRect\" x=\"10\" y=\"10\" width=\"5\" height=\"5\""
3634             "        fill=\"red\" stroke=\"none\"/>"
3635             "    <rect id=\"markerRect\" x=\"14\" y=\"12\" width=\"1\" height=\"1\""
3636             "        fill=\"yellow\" stroke=\"none\"/>"
3637             "    <rect id=\"markerRect\" x=\"12\" y=\"12\" width=\"1\" height=\"1\""
3638             "        fill=\"white\" stroke=\"none\"/>"
3639             "</marker>"
3640 
3641             "<path id=\"testRect\""
3642             "    style=\"fill:none;stroke:#000000;stroke-width:1px;marker-start:url(#SimpleRectMarker);marker-end:url(#SimpleRectMarker);marker-mid:url(#SimpleRectMarker)\""
3643             "    d=\"M5,15 C5,5 25,5 25,15 L15,25\"/>"
3644 
3645             "</svg>";
3646 
3647     SvgRenderTester t (data);
3648 
3649     t.test_standard_30px_72ppi("markers_custom_orientation", false);
3650 }
3651 
testMarkersDifferent()3652 void TestSvgParser::testMarkersDifferent()
3653 {
3654     const QString data =
3655             "<svg width=\"30px\" height=\"30px\""
3656             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3657 
3658             "<marker id=\"SimpleRectMarker1\""
3659             "    orient=\"auto\" refY=\"12.5\" refX=\"12.5\" >"
3660 
3661             "    <rect id=\"markerRect\" x=\"10\" y=\"10\" width=\"5\" height=\"5\""
3662             "        fill=\"red\" stroke=\"none\"/>"
3663             "    <rect id=\"markerRect\" x=\"14\" y=\"12\" width=\"1\" height=\"1\""
3664             "        fill=\"yellow\" stroke=\"none\"/>"
3665             "    <rect id=\"markerRect\" x=\"12\" y=\"12\" width=\"1\" height=\"1\""
3666             "        fill=\"white\" stroke=\"none\"/>"
3667             "</marker>"
3668 
3669             "<marker id=\"SimpleRectMarker2\""
3670             "    orient=\"auto\" refY=\"12.5\" refX=\"12.5\" >"
3671 
3672             "    <rect id=\"markerRect\" x=\"10\" y=\"10\" width=\"5\" height=\"5\""
3673             "        fill=\"green\" stroke=\"none\"/>"
3674             "    <rect id=\"markerRect\" x=\"14\" y=\"12\" width=\"1\" height=\"1\""
3675             "        fill=\"yellow\" stroke=\"none\"/>"
3676             "    <rect id=\"markerRect\" x=\"12\" y=\"12\" width=\"1\" height=\"1\""
3677             "        fill=\"white\" stroke=\"none\"/>"
3678             "</marker>"
3679 
3680             "<marker id=\"SimpleRectMarker3\""
3681             "    orient=\"auto\" refY=\"12.5\" refX=\"12.5\" >"
3682 
3683             "    <rect id=\"markerRect\" x=\"10\" y=\"10\" width=\"5\" height=\"5\""
3684             "        fill=\"blue\" stroke=\"none\"/>"
3685             "    <rect id=\"markerRect\" x=\"14\" y=\"12\" width=\"1\" height=\"1\""
3686             "        fill=\"yellow\" stroke=\"none\"/>"
3687             "    <rect id=\"markerRect\" x=\"12\" y=\"12\" width=\"1\" height=\"1\""
3688             "        fill=\"white\" stroke=\"none\"/>"
3689             "</marker>"
3690 
3691             "<path id=\"testRect\""
3692             "    style=\"fill:none;stroke:#000000;stroke-width:1px;marker-start:url(#SimpleRectMarker1);marker-end:url(#SimpleRectMarker2);marker-mid:url(#SimpleRectMarker3)\""
3693             "    d=\"M5,15 C5,5 25,5 25,15 L15,25\"/>"
3694 
3695             "</svg>";
3696 
3697     SvgRenderTester t (data);
3698 
3699     t.test_standard_30px_72ppi("markers_different", false);
3700 }
3701 
testMarkersFillAsShape()3702 void TestSvgParser::testMarkersFillAsShape()
3703 {
3704     const QString data =
3705             "<svg width=\"30px\" height=\"30px\""
3706             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3707 
3708             "<defs>"
3709             "    <linearGradient id=\"testGrad\" x1=\"0%\" y1=\"50%\" x2=\"100%\" y2=\"50%\">"
3710             "        <stop offset=\"5%\" stop-color=\"#F60\" />"
3711             "        <stop offset=\"80%\" stop-color=\"#FF6\" />"
3712             "    </linearGradient>"
3713 
3714             "    <marker id=\"SimpleRectMarker\""
3715             "        orient=\"auto\" refY=\"12.5\" refX=\"12.5\" >"
3716 
3717             "        <rect id=\"markerRect\" x=\"10\" y=\"10\" width=\"5\" height=\"5\""
3718             "            fill=\"red\" stroke=\"none\"/>"
3719             "        <rect id=\"markerRect\" x=\"14\" y=\"12\" width=\"1\" height=\"1\""
3720             "            fill=\"yellow\" stroke=\"none\"/>"
3721             "        <rect id=\"markerRect\" x=\"12\" y=\"12\" width=\"1\" height=\"1\""
3722             "            fill=\"white\" stroke=\"none\"/>"
3723             "    </marker>"
3724 
3725             "</defs>"
3726 
3727             "<path id=\"testRect\""
3728             "    style=\"fill:none;stroke:url(#testGrad) magenta;stroke-width:2px;marker-start:url(#SimpleRectMarker);marker-end:url(#SimpleRectMarker);marker-mid:url(#SimpleRectMarker);krita|marker-fill-method:auto\""
3729             "    d=\"M5,15 C5,5 25,5 25,15 L15,25\"/>"
3730             //"    d=\"M5,15 L25,15\"/>"
3731 
3732             "</svg>";
3733 
3734     SvgRenderTester t (data);
3735 
3736     t.test_standard_30px_72ppi("markers_scaled_fill_as_shape", false);
3737 }
3738 
testMarkersOnClosedPath()3739 void TestSvgParser::testMarkersOnClosedPath()
3740 {
3741     const QString data =
3742             "<svg width=\"30px\" height=\"30px\""
3743             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3744 
3745             "<marker id=\"SimpleRectMarker1\""
3746             "    orient=\"auto\" refY=\"12.5\" refX=\"12.5\" >"
3747 
3748             "    <rect id=\"markerRect\" x=\"9\" y=\"9\" width=\"7\" height=\"7\""
3749             "        fill=\"red\" stroke=\"none\"/>"
3750             "    <rect id=\"markerRect\" x=\"14\" y=\"12\" width=\"1\" height=\"1\""
3751             "        fill=\"yellow\" stroke=\"none\"/>"
3752             "    <rect id=\"markerRect\" x=\"12\" y=\"12\" width=\"1\" height=\"1\""
3753             "        fill=\"white\" stroke=\"none\"/>"
3754             "</marker>"
3755 
3756             "<marker id=\"SimpleRectMarker2\""
3757             "    orient=\"auto\" refY=\"12.5\" refX=\"12.5\" >"
3758 
3759             "    <rect id=\"markerRect\" x=\"10\" y=\"10\" width=\"5\" height=\"5\""
3760             "        fill=\"green\" stroke=\"none\"/>"
3761             "    <rect id=\"markerRect\" x=\"14\" y=\"12\" width=\"1\" height=\"1\""
3762             "        fill=\"yellow\" stroke=\"none\"/>"
3763             "    <rect id=\"markerRect\" x=\"12\" y=\"12\" width=\"1\" height=\"1\""
3764             "        fill=\"white\" stroke=\"none\"/>"
3765             "</marker>"
3766 
3767             "<marker id=\"SimpleRectMarker3\""
3768             "    orient=\"auto\" refY=\"12.5\" refX=\"12.5\" >"
3769 
3770             "    <rect id=\"markerRect\" x=\"10\" y=\"10\" width=\"5\" height=\"5\""
3771             "        fill=\"blue\" stroke=\"none\"/>"
3772             "    <rect id=\"markerRect\" x=\"14\" y=\"12\" width=\"1\" height=\"1\""
3773             "        fill=\"yellow\" stroke=\"none\"/>"
3774             "    <rect id=\"markerRect\" x=\"12\" y=\"12\" width=\"1\" height=\"1\""
3775             "        fill=\"white\" stroke=\"none\"/>"
3776             "</marker>"
3777 
3778             "<path id=\"testRect\""
3779             "    style=\"fill:none;stroke:#000000;stroke-width:1px;marker-start:url(#SimpleRectMarker1);marker-end:url(#SimpleRectMarker2);marker-mid:url(#SimpleRectMarker3)\""
3780             "    d=\"M5,15 C5,5 25,5 25,15 L15,25 z\"/>"
3781 
3782             "</svg>";
3783 
3784     SvgRenderTester t (data);
3785 
3786     t.test_standard_30px_72ppi("markers_on_closed_path", false);
3787 }
3788 
3789 
testGradientRecoveringTransform()3790 void TestSvgParser::testGradientRecoveringTransform()
3791 {
3792     // used for experimenting purposes only!
3793 
3794     QImage image(100,100,QImage::Format_ARGB32);
3795     image.fill(0);
3796     QPainter painter(&image);
3797 
3798     painter.setPen(QPen(Qt::black, 0));
3799 
3800 
3801     QLinearGradient gradient(0, 0.5, 1, 0.5);
3802     gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
3803 
3804     //QLinearGradient gradient(0, 50, 100, 50);
3805     //gradient.setCoordinateMode(QGradient::LogicalMode);
3806 
3807     gradient.setColorAt(0.0, Qt::red);
3808     gradient.setColorAt(1.0, Qt::blue);
3809 
3810     QTransform gradientTransform;
3811     gradientTransform.shear(0.2, 0);
3812 
3813     {
3814         QBrush brush(gradient);
3815         brush.setTransform(gradientTransform);
3816         painter.setBrush(brush);
3817     }
3818 
3819     QRect mainShape(3,3,94,94);
3820     painter.drawRect(mainShape);
3821 
3822     QTransform gradientToUser(mainShape.width(), 0, 0, mainShape.height(),
3823                               mainShape.x(), mainShape.y());
3824 
3825     QRect smallShape(0,0,20,20);
3826     QTransform smallShapeTransform;
3827 
3828     {
3829         smallShapeTransform =
3830             QTransform::fromTranslate(-smallShape.center().x(), -smallShape.center().y());
3831 
3832         QTransform r; r.rotate(90);
3833         smallShapeTransform *= r;
3834 
3835         smallShapeTransform *=
3836             QTransform::fromTranslate(mainShape.center().x(), mainShape.center().y());
3837     }
3838 
3839 
3840     {
3841         gradient.setCoordinateMode(QGradient::LogicalMode);
3842         QBrush brush(gradient);
3843         brush.setTransform(gradientTransform * gradientToUser * smallShapeTransform.inverted());
3844         painter.setBrush(brush);
3845         painter.setPen(Qt::NoPen);
3846     }
3847 
3848     painter.setTransform(smallShapeTransform);
3849     painter.drawRect(smallShape);
3850 
3851     //image.save("gradient_recovering_transform.png");
3852 }
3853 
testMarkersAngularUnits()3854 void TestSvgParser::testMarkersAngularUnits()
3855 {
3856     const QString data =
3857             "<svg width=\"30px\" height=\"30px\""
3858             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
3859 
3860             // start
3861             "<marker id=\"SimpleRectMarker1\""
3862             "    orient=\"45deg\" refY=\"12.5\" refX=\"12.5\" >"
3863 
3864             "    <rect id=\"markerRect\" x=\"10\" y=\"10\" width=\"5\" height=\"5\""
3865             "        fill=\"red\" stroke=\"none\"/>"
3866             "    <rect id=\"markerRect\" x=\"14\" y=\"12\" width=\"1\" height=\"1\""
3867             "        fill=\"yellow\" stroke=\"none\"/>"
3868             "    <rect id=\"markerRect\" x=\"12\" y=\"12\" width=\"1\" height=\"1\""
3869             "        fill=\"white\" stroke=\"none\"/>"
3870             "</marker>"
3871 
3872             // end
3873             "<marker id=\"SimpleRectMarker2\""
3874             "    orient=\"200grad\" refY=\"12.5\" refX=\"12.5\" >"
3875 
3876             "    <rect id=\"markerRect\" x=\"10\" y=\"10\" width=\"5\" height=\"5\""
3877             "        fill=\"green\" stroke=\"none\"/>"
3878             "    <rect id=\"markerRect\" x=\"14\" y=\"12\" width=\"1\" height=\"1\""
3879             "        fill=\"yellow\" stroke=\"none\"/>"
3880             "    <rect id=\"markerRect\" x=\"12\" y=\"12\" width=\"1\" height=\"1\""
3881             "        fill=\"white\" stroke=\"none\"/>"
3882             "</marker>"
3883 
3884             // mid
3885             "<marker id=\"SimpleRectMarker3\""
3886             "    orient=\"-1.57rad\" refY=\"12.5\" refX=\"12.5\" >"
3887 
3888             "    <rect id=\"markerRect\" x=\"10\" y=\"10\" width=\"5\" height=\"5\""
3889             "        fill=\"blue\" stroke=\"none\"/>"
3890             "    <rect id=\"markerRect\" x=\"14\" y=\"12\" width=\"1\" height=\"1\""
3891             "        fill=\"yellow\" stroke=\"none\"/>"
3892             "    <rect id=\"markerRect\" x=\"12\" y=\"12\" width=\"1\" height=\"1\""
3893             "        fill=\"white\" stroke=\"none\"/>"
3894             "</marker>"
3895 
3896             "<path id=\"testRect\""
3897             "    style=\"fill:none;stroke:#000000;stroke-width:1px;marker-start:url(#SimpleRectMarker1);marker-end:url(#SimpleRectMarker2);marker-mid:url(#SimpleRectMarker3)\""
3898             "    d=\"M5,15 C5,5 25,5 25,15 L15,25\"/>"
3899 
3900             "</svg>";
3901 
3902     SvgRenderTester t (data);
3903 
3904     t.test_standard_30px_72ppi("markers_angular_units", false);
3905 }
3906 
3907 #include "KoParameterShape.h"
3908 
testSodipodiArcShape()3909 void TestSvgParser::testSodipodiArcShape()
3910 {
3911     const QString data =
3912             "<svg width=\"30px\" height=\"30px\""
3913             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\""
3914             "    xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\""
3915             ">"
3916 
3917             "<path"
3918             "    fill=\"red\" stroke=\"black\""
3919             "    id=\"testRect\""
3920 
3921             "    sodipodi:type=\"arc\""
3922             "    sodipodi:cx=\"15.464287\""
3923             "    sodipodi:cy=\"14.517863\""
3924             "    sodipodi:rx=\"6.25\""
3925             "    sodipodi:ry=\"8.5\""
3926             "    sodipodi:start=\"5.5346039\""
3927             "    sodipodi:end=\"4.0381334\""
3928             //"    d=\"m 20.043381,8.7327624 a 6.25,8.5 0 0 1 1.053863,9.4677386 6.25,8.5 0 0 1 -6.094908,4.794113 6.25,8.5 0 0 1 -5.5086474,-5.963709 6.25,8.5 0 0 1 2.0686234,-9.1530031 l 3.901975,6.6399611 z\" />"
3929             "    d=\" some weird unparsable text \" />"
3930 
3931             "</svg>";
3932 
3933     SvgRenderTester t (data);
3934 
3935     t.test_standard_30px_72ppi("sodipodi_closed_arc", false);
3936 
3937     KoShape *shape = t.findShape("testRect");
3938     QVERIFY(dynamic_cast<KoParameterShape*>(shape));
3939 }
3940 
testSodipodiArcShapeOpen()3941 void TestSvgParser::testSodipodiArcShapeOpen()
3942 {
3943     const QString data =
3944             "<svg width=\"30px\" height=\"30px\""
3945             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\""
3946             "    xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\""
3947             ">"
3948 
3949             "<path"
3950             "    fill=\"red\" stroke=\"black\""
3951             "    id=\"testRect\""
3952 
3953             "    sodipodi:type=\"arc\""
3954             "    sodipodi:open=\"true\""
3955             "    sodipodi:cx=\"15.464287\""
3956             "    sodipodi:cy=\"14.517863\""
3957             "    sodipodi:rx=\"6.25\""
3958             "    sodipodi:ry=\"8.5\""
3959             "    sodipodi:start=\"5.5346039\""
3960             "    sodipodi:end=\"4.0381334\""
3961             //"    d=\"m 20.043381,8.7327624 a 6.25,8.5 0 0 1 1.053863,9.4677386 6.25,8.5 0 0 1 -6.094908,4.794113 6.25,8.5 0 0 1 -5.5086474,-5.963709 6.25,8.5 0 0 1 2.0686234,-9.1530031 l 3.901975,6.6399611 z\" />"
3962             "    d=\" some weird unparsable text \" />"
3963 
3964             "</svg>";
3965 
3966     SvgRenderTester t (data);
3967 
3968     t.test_standard_30px_72ppi("sodipodi_open_arc", false);
3969 
3970     KoShape *shape = t.findShape("testRect");
3971     QVERIFY(dynamic_cast<KoParameterShape*>(shape));
3972 }
3973 
testKritaChordShape()3974 void TestSvgParser::testKritaChordShape()
3975 {
3976     const QString data =
3977             "<svg width=\"30px\" height=\"30px\""
3978             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\""
3979             "    xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\""
3980             ">"
3981 
3982             "<path"
3983             "    fill=\"red\" stroke=\"black\""
3984             "    id=\"testRect\""
3985 
3986             "    krita:type=\"arc\""
3987             "    krita:arcType=\"chord\""
3988             "    krita:cx=\"15.464287\""
3989             "    krita:cy=\"14.517863\""
3990             "    krita:rx=\"6.25\""
3991             "    krita:ry=\"8.5\""
3992             "    krita:start=\"5.5346039\""
3993             "    krita:end=\"4.0381334\""
3994             //"    d=\"m 20.043381,8.7327624 a 6.25,8.5 0 0 1 1.053863,9.4677386 6.25,8.5 0 0 1 -6.094908,4.794113 6.25,8.5 0 0 1 -5.5086474,-5.963709 6.25,8.5 0 0 1 2.0686234,-9.1530031 l 3.901975,6.6399611 z\" />"
3995             "    d=\" some weird unparsable text \" />"
3996 
3997             "</svg>";
3998 
3999     SvgRenderTester t (data);
4000 
4001     t.test_standard_30px_72ppi("sodipodi_chord_arc", false);
4002 
4003     KoShape *shape = t.findShape("testRect");
4004     QVERIFY(dynamic_cast<KoParameterShape*>(shape));
4005 }
4006 
testSodipodiChordShape()4007 void TestSvgParser::testSodipodiChordShape()
4008 {
4009     const QString data =
4010             "<svg width=\"30px\" height=\"30px\""
4011             "    xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\""
4012             "    xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\""
4013             ">"
4014 
4015             "<path"
4016             "    fill=\"red\" stroke=\"black\""
4017             "    id=\"testRect\""
4018 
4019             "    sodipodi:type=\"arc\""
4020             "    sodipodi:arc-type=\"chord\""
4021             "    sodipodi:open=\"true\""
4022             "    sodipodi:cx=\"15.464287\""
4023             "    sodipodi:cy=\"14.517863\""
4024             "    sodipodi:rx=\"6.25\""
4025             "    sodipodi:ry=\"8.5\""
4026             "    sodipodi:start=\"5.5346039\""
4027             "    sodipodi:end=\"4.0381334\""
4028             //"    d=\"m 20.043381,8.7327624 a 6.25,8.5 0 0 1 1.053863,9.4677386 6.25,8.5 0 0 1 -6.094908,4.794113 6.25,8.5 0 0 1 -5.5086474,-5.963709 6.25,8.5 0 0 1 2.0686234,-9.1530031 l 3.901975,6.6399611 z\" />"
4029             "    d=\" some weird unparsable text \" />"
4030 
4031             "</svg>";
4032 
4033     SvgRenderTester t (data);
4034 
4035     t.test_standard_30px_72ppi("sodipodi_chord_arc", false);
4036 
4037     KoShape *shape = t.findShape("testRect");
4038     QVERIFY(dynamic_cast<KoParameterShape*>(shape));
4039 }
4040 
4041 
4042 QTEST_MAIN(TestSvgParser)
4043