svg_loader SvgLoader: Add 'href' attribute for parser
[platform/core/graphics/tizenvg.git] / src / loaders / svg / tvgSvgLoader.cpp
1 /*
2  * Copyright (c) 2020-2021 Samsung Electronics Co., Ltd. All rights reserved.
3
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22
23 #define _USE_MATH_DEFINES       //Math Constants are not defined in Standard C/C++.
24
25 #include <fstream>
26 #include <float.h>
27 #include <math.h>
28 #include "tvgLoader.h"
29 #include "tvgXmlParser.h"
30 #include "tvgSvgLoader.h"
31 #include "tvgSvgSceneBuilder.h"
32 #include "tvgSvgUtil.h"
33
34 /************************************************************************/
35 /* Internal Class Implementation                                        */
36 /************************************************************************/
37
38 typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength);
39 typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength);
40
41
42 static char* _skipSpace(const char* str, const char* end)
43 {
44     while (((end && str < end) || (!end && *str != '\0')) && isspace(*str)) {
45         ++str;
46     }
47     return (char*) str;
48 }
49
50
51 static string* _copyId(const char* str)
52 {
53     if (!str) return nullptr;
54
55     return new string(str);
56 }
57
58
59 static const char* _skipComma(const char* content)
60 {
61     content = _skipSpace(content, nullptr);
62     if (*content == ',') return content + 1;
63     return content;
64 }
65
66
67 static bool _parseNumber(const char** content, float* number)
68 {
69     char* end = nullptr;
70
71     *number = svgUtilStrtof(*content, &end);
72     //If the start of string is not number
73     if ((*content) == end) return false;
74     //Skip comma if any
75     *content = _skipComma(end);
76     return true;
77 }
78
79 /**
80  * According to https://www.w3.org/TR/SVG/coords.html#Units
81  *
82  * TODO
83  * Since this documentation is not obvious, more clean recalculation with dpi
84  * is required, but for now default w3 constants would be used
85  */
86 static float _toFloat(const SvgParser* svgParse, const char* str, SvgParserLengthType type)
87 {
88     float parsedValue = svgUtilStrtof(str, nullptr);
89
90     if (strstr(str, "cm")) parsedValue = parsedValue * 35.43307;
91     else if (strstr(str, "mm")) parsedValue = parsedValue * 3.543307;
92     else if (strstr(str, "pt")) parsedValue = parsedValue * 1.25;
93     else if (strstr(str, "pc")) parsedValue = parsedValue * 15;
94     else if (strstr(str, "in")) parsedValue = parsedValue * 90;
95     else if (strstr(str, "%")) {
96         if (type == SvgParserLengthType::Vertical) parsedValue = (parsedValue / 100.0) * svgParse->global.h;
97         else if (type == SvgParserLengthType::Horizontal) parsedValue = (parsedValue / 100.0) * svgParse->global.w;
98         else //if other then it's radius
99         {
100             float max = svgParse->global.w;
101             if (max < svgParse->global.h)
102                 max = svgParse->global.h;
103             parsedValue = (parsedValue / 100.0) * max;
104         }
105     }
106
107     //TODO: Implement 'em', 'ex' attributes
108
109     return parsedValue;
110 }
111
112
113 static float _gradientToFloat(const SvgParser* svgParse, const char* str, SvgParserLengthType type)
114 {
115     char* end = nullptr;
116
117     float parsedValue = svgUtilStrtof(str, &end);
118     float max = 1;
119
120     /**
121     * That is according to Units in here
122     *
123     * https://www.w3.org/TR/2015/WD-SVG2-20150915/coords.html
124     */
125     if (type == SvgParserLengthType::Vertical) max = svgParse->global.h;
126     else if (type == SvgParserLengthType::Horizontal) max = svgParse->global.w;
127     else if (type == SvgParserLengthType::Other) max = sqrt(pow(svgParse->global.h, 2) + pow(svgParse->global.w, 2)) / sqrt(2.0);
128
129     if (strstr(str, "%")) parsedValue = parsedValue / 100.0;
130     else if (strstr(str, "cm")) parsedValue = parsedValue * 35.43307;
131     else if (strstr(str, "mm")) parsedValue = parsedValue * 3.543307;
132     else if (strstr(str, "pt")) parsedValue = parsedValue * 1.25;
133     else if (strstr(str, "pc")) parsedValue = parsedValue * 15;
134     else if (strstr(str, "in")) parsedValue = parsedValue * 90;
135     //TODO: Implement 'em', 'ex' attributes
136
137     //Transform into global percentage
138     parsedValue = parsedValue / max;
139
140     return parsedValue;
141 }
142
143
144 static float _toOffset(const char* str)
145 {
146     char* end = nullptr;
147     auto strEnd = str + strlen(str);
148
149     float parsedValue = svgUtilStrtof(str, &end);
150
151     end = _skipSpace(end, nullptr);
152     auto ptr = strstr(str, "%");
153
154     if (ptr) {
155         parsedValue = parsedValue / 100.0;
156         if (end != ptr || (end + 1) != strEnd) return 0;
157     } else if (end != strEnd) return 0;
158
159     return parsedValue;
160 }
161
162
163 static int _toOpacity(const char* str)
164 {
165     char* end = nullptr;
166     int a = 0;
167     float opacity = svgUtilStrtof(str, &end);
168
169     if (end && (*end == '\0')) a = lrint(opacity * 255);
170     return a;
171 }
172
173
174 #define _PARSE_TAG(Type, Name, Name1, Tags_Array, Default)                        \
175     static Type _to##Name1(const char* str)                                       \
176     {                                                                             \
177         unsigned int i;                                                           \
178                                                                                   \
179         for (i = 0; i < sizeof(Tags_Array) / sizeof(Tags_Array[0]); i++) {        \
180             if (!strcmp(str, Tags_Array[i].tag)) return Tags_Array[i].Name;       \
181         }                                                                         \
182         return Default;                                                           \
183     }
184
185
186 /* parse the line cap used during stroking a path.
187  * Value:    butt | round | square | inherit
188  * Initial:    butt
189  * https://www.w3.org/TR/SVG/painting.html
190  */
191 static constexpr struct
192 {
193     StrokeCap lineCap;
194     const char* tag;
195 } lineCapTags[] = {
196     { StrokeCap::Butt, "butt" },
197     { StrokeCap::Round, "round" },
198     { StrokeCap::Square, "square" }
199 };
200
201
202 _PARSE_TAG(StrokeCap, lineCap, LineCap, lineCapTags, StrokeCap::Butt)
203
204
205 /* parse the line join used during stroking a path.
206  * Value:   miter | round | bevel | inherit
207  * Initial:    miter
208  * https://www.w3.org/TR/SVG/painting.html
209  */
210 static constexpr struct
211 {
212     StrokeJoin lineJoin;
213     const char* tag;
214 } lineJoinTags[] = {
215     { StrokeJoin::Miter, "miter" },
216     { StrokeJoin::Round, "round" },
217     { StrokeJoin::Bevel, "bevel" }
218 };
219
220
221 _PARSE_TAG(StrokeJoin, lineJoin, LineJoin, lineJoinTags, StrokeJoin::Miter)
222
223
224 /* parse the fill rule used during filling a path.
225  * Value:   nonzero | evenodd | inherit
226  * Initial:    nonzero
227  * https://www.w3.org/TR/SVG/painting.html
228  */
229 static constexpr struct
230 {
231     FillRule fillRule;
232     const char* tag;
233 } fillRuleTags[] = {
234     { FillRule::EvenOdd, "evenodd" }
235 };
236
237
238 _PARSE_TAG(FillRule, fillRule, FillRule, fillRuleTags, FillRule::Winding)
239
240
241 /* parse the dash pattern used during stroking a path.
242  * Value:   none | <dasharray> | inherit
243  * Initial:    none
244  * https://www.w3.org/TR/SVG/painting.html
245  */
246 static inline void
247 _parseDashArray(SvgLoaderData* loader, const char *str, SvgDash* dash)
248 {
249     if (!strncmp(str, "none", 4)) return;
250
251     char *end = nullptr;
252
253     while (*str) {
254         str = _skipComma(str);
255         float parsedValue = svgUtilStrtof(str, &end);
256         if (str == end) break;
257         if (parsedValue <= 0.0f) break;
258         if (*end == '%') {
259             ++end;
260             //Refers to the diagonal length of the viewport.
261             //https://www.w3.org/TR/SVG2/coords.html#Units
262             parsedValue = (sqrt(pow(loader->svgParse->global.w, 2) + pow(loader->svgParse->global.h, 2)) / sqrt(2.0f)) * (parsedValue / 100.0f);
263         }
264         (*dash).array.push(parsedValue);
265         str = end;
266     }
267     //If dash array size is 1, it means that dash and gap size are the same.
268     if ((*dash).array.count == 1) (*dash).array.push((*dash).array.data[0]);
269 }
270
271 static string* _idFromUrl(const char* url)
272 {
273     char tmp[50];
274     int i = 0;
275
276     url = _skipSpace(url, nullptr);
277     if ((*url) == '(') {
278         ++url;
279         url = _skipSpace(url, nullptr);
280     }
281
282     if ((*url) == '#') ++url;
283
284     while ((*url) != ')') {
285         tmp[i++] = *url;
286         ++url;
287     }
288     tmp[i] = '\0';
289
290     return new string(tmp);
291 }
292
293
294 static unsigned char _parserColor(const char* value, char** end)
295 {
296     float r;
297
298     r = svgUtilStrtof(value, end);
299     *end = _skipSpace(*end, nullptr);
300     if (**end == '%') r = 255 * r / 100;
301     *end = _skipSpace(*end, nullptr);
302
303     if (r < 0 || r > 255) {
304         *end = nullptr;
305         return 0;
306     }
307
308     return lrint(r);
309 }
310
311
312 static constexpr struct
313 {
314     const char* name;
315     unsigned int value;
316 } colors[] = {
317     { "aliceblue", 0xfff0f8ff },
318     { "antiquewhite", 0xfffaebd7 },
319     { "aqua", 0xff00ffff },
320     { "aquamarine", 0xff7fffd4 },
321     { "azure", 0xfff0ffff },
322     { "beige", 0xfff5f5dc },
323     { "bisque", 0xffffe4c4 },
324     { "black", 0xff000000 },
325     { "blanchedalmond", 0xffffebcd },
326     { "blue", 0xff0000ff },
327     { "blueviolet", 0xff8a2be2 },
328     { "brown", 0xffa52a2a },
329     { "burlywood", 0xffdeb887 },
330     { "cadetblue", 0xff5f9ea0 },
331     { "chartreuse", 0xff7fff00 },
332     { "chocolate", 0xffd2691e },
333     { "coral", 0xffff7f50 },
334     { "cornflowerblue", 0xff6495ed },
335     { "cornsilk", 0xfffff8dc },
336     { "crimson", 0xffdc143c },
337     { "cyan", 0xff00ffff },
338     { "darkblue", 0xff00008b },
339     { "darkcyan", 0xff008b8b },
340     { "darkgoldenrod", 0xffb8860b },
341     { "darkgray", 0xffa9a9a9 },
342     { "darkgrey", 0xffa9a9a9 },
343     { "darkgreen", 0xff006400 },
344     { "darkkhaki", 0xffbdb76b },
345     { "darkmagenta", 0xff8b008b },
346     { "darkolivegreen", 0xff556b2f },
347     { "darkorange", 0xffff8c00 },
348     { "darkorchid", 0xff9932cc },
349     { "darkred", 0xff8b0000 },
350     { "darksalmon", 0xffe9967a },
351     { "darkseagreen", 0xff8fbc8f },
352     { "darkslateblue", 0xff483d8b },
353     { "darkslategray", 0xff2f4f4f },
354     { "darkslategrey", 0xff2f4f4f },
355     { "darkturquoise", 0xff00ced1 },
356     { "darkviolet", 0xff9400d3 },
357     { "deeppink", 0xffff1493 },
358     { "deepskyblue", 0xff00bfff },
359     { "dimgray", 0xff696969 },
360     { "dimgrey", 0xff696969 },
361     { "dodgerblue", 0xff1e90ff },
362     { "firebrick", 0xffb22222 },
363     { "floralwhite", 0xfffffaf0 },
364     { "forestgreen", 0xff228b22 },
365     { "fuchsia", 0xffff00ff },
366     { "gainsboro", 0xffdcdcdc },
367     { "ghostwhite", 0xfff8f8ff },
368     { "gold", 0xffffd700 },
369     { "goldenrod", 0xffdaa520 },
370     { "gray", 0xff808080 },
371     { "grey", 0xff808080 },
372     { "green", 0xff008000 },
373     { "greenyellow", 0xffadff2f },
374     { "honeydew", 0xfff0fff0 },
375     { "hotpink", 0xffff69b4 },
376     { "indianred", 0xffcd5c5c },
377     { "indigo", 0xff4b0082 },
378     { "ivory", 0xfffffff0 },
379     { "khaki", 0xfff0e68c },
380     { "lavender", 0xffe6e6fa },
381     { "lavenderblush", 0xfffff0f5 },
382     { "lawngreen", 0xff7cfc00 },
383     { "lemonchiffon", 0xfffffacd },
384     { "lightblue", 0xffadd8e6 },
385     { "lightcoral", 0xfff08080 },
386     { "lightcyan", 0xffe0ffff },
387     { "lightgoldenrodyellow", 0xfffafad2 },
388     { "lightgray", 0xffd3d3d3 },
389     { "lightgrey", 0xffd3d3d3 },
390     { "lightgreen", 0xff90ee90 },
391     { "lightpink", 0xffffb6c1 },
392     { "lightsalmon", 0xffffa07a },
393     { "lightseagreen", 0xff20b2aa },
394     { "lightskyblue", 0xff87cefa },
395     { "lightslategray", 0xff778899 },
396     { "lightslategrey", 0xff778899 },
397     { "lightsteelblue", 0xffb0c4de },
398     { "lightyellow", 0xffffffe0 },
399     { "lime", 0xff00ff00 },
400     { "limegreen", 0xff32cd32 },
401     { "linen", 0xfffaf0e6 },
402     { "magenta", 0xffff00ff },
403     { "maroon", 0xff800000 },
404     { "mediumaquamarine", 0xff66cdaa },
405     { "mediumblue", 0xff0000cd },
406     { "mediumorchid", 0xffba55d3 },
407     { "mediumpurple", 0xff9370d8 },
408     { "mediumseagreen", 0xff3cb371 },
409     { "mediumslateblue", 0xff7b68ee },
410     { "mediumspringgreen", 0xff00fa9a },
411     { "mediumturquoise", 0xff48d1cc },
412     { "mediumvioletred", 0xffc71585 },
413     { "midnightblue", 0xff191970 },
414     { "mintcream", 0xfff5fffa },
415     { "mistyrose", 0xffffe4e1 },
416     { "moccasin", 0xffffe4b5 },
417     { "navajowhite", 0xffffdead },
418     { "navy", 0xff000080 },
419     { "oldlace", 0xfffdf5e6 },
420     { "olive", 0xff808000 },
421     { "olivedrab", 0xff6b8e23 },
422     { "orange", 0xffffa500 },
423     { "orangered", 0xffff4500 },
424     { "orchid", 0xffda70d6 },
425     { "palegoldenrod", 0xffeee8aa },
426     { "palegreen", 0xff98fb98 },
427     { "paleturquoise", 0xffafeeee },
428     { "palevioletred", 0xffd87093 },
429     { "papayawhip", 0xffffefd5 },
430     { "peachpuff", 0xffffdab9 },
431     { "peru", 0xffcd853f },
432     { "pink", 0xffffc0cb },
433     { "plum", 0xffdda0dd },
434     { "powderblue", 0xffb0e0e6 },
435     { "purple", 0xff800080 },
436     { "red", 0xffff0000 },
437     { "rosybrown", 0xffbc8f8f },
438     { "royalblue", 0xff4169e1 },
439     { "saddlebrown", 0xff8b4513 },
440     { "salmon", 0xfffa8072 },
441     { "sandybrown", 0xfff4a460 },
442     { "seagreen", 0xff2e8b57 },
443     { "seashell", 0xfffff5ee },
444     { "sienna", 0xffa0522d },
445     { "silver", 0xffc0c0c0 },
446     { "skyblue", 0xff87ceeb },
447     { "slateblue", 0xff6a5acd },
448     { "slategray", 0xff708090 },
449     { "slategrey", 0xff708090 },
450     { "snow", 0xfffffafa },
451     { "springgreen", 0xff00ff7f },
452     { "steelblue", 0xff4682b4 },
453     { "tan", 0xffd2b48c },
454     { "teal", 0xff008080 },
455     { "thistle", 0xffd8bfd8 },
456     { "tomato", 0xffff6347 },
457     { "turquoise", 0xff40e0d0 },
458     { "violet", 0xffee82ee },
459     { "wheat", 0xfff5deb3 },
460     { "white", 0xffffffff },
461     { "whitesmoke", 0xfff5f5f5 },
462     { "yellow", 0xffffff00 },
463     { "yellowgreen", 0xff9acd32 }
464 };
465
466
467 static void _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, string** ref)
468 {
469     unsigned int len = strlen(str);
470     char *red, *green, *blue;
471     unsigned char tr, tg, tb;
472
473     if (len == 4 && str[0] == '#') {
474         //Case for "#456" should be interprete as "#445566"
475         if (isxdigit(str[1]) && isxdigit(str[2]) && isxdigit(str[3])) {
476             char tmp[3] = { '\0', '\0', '\0' };
477             tmp[0] = str[1];
478             tmp[1] = str[1];
479             *r = strtol(tmp, nullptr, 16);
480             tmp[0] = str[2];
481             tmp[1] = str[2];
482             *g = strtol(tmp, nullptr, 16);
483             tmp[0] = str[3];
484             tmp[1] = str[3];
485             *b = strtol(tmp, nullptr, 16);
486         }
487     } else if (len == 7 && str[0] == '#') {
488         if (isxdigit(str[1]) && isxdigit(str[2]) && isxdigit(str[3]) && isxdigit(str[4]) && isxdigit(str[5]) && isxdigit(str[6])) {
489             char tmp[3] = { '\0', '\0', '\0' };
490             tmp[0] = str[1];
491             tmp[1] = str[2];
492             *r = strtol(tmp, nullptr, 16);
493             tmp[0] = str[3];
494             tmp[1] = str[4];
495             *g = strtol(tmp, nullptr, 16);
496             tmp[0] = str[5];
497             tmp[1] = str[6];
498             *b = strtol(tmp, nullptr, 16);
499         }
500     } else if (len >= 10 && (str[0] == 'r' || str[0] == 'R') && (str[1] == 'g' || str[1] == 'G') && (str[2] == 'b' || str[2] == 'B') && str[3] == '(' && str[len - 1] == ')') {
501         tr = _parserColor(str + 4, &red);
502         if (red && *red == ',') {
503             tg = _parserColor(red + 1, &green);
504             if (green && *green == ',') {
505                 tb = _parserColor(green + 1, &blue);
506                 if (blue && blue[0] == ')' && blue[1] == '\0') {
507                     *r = tr;
508                     *g = tg;
509                     *b = tb;
510                 }
511             }
512         }
513     } else if (len >= 3 && !strncmp(str, "url", 3)) {
514         *ref = _idFromUrl((const char*)(str + 3));
515     } else {
516         //Handle named color
517         for (unsigned int i = 0; i < (sizeof(colors) / sizeof(colors[0])); i++) {
518             if (!strcasecmp(colors[i].name, str)) {
519                 *r = (((uint8_t*)(&(colors[i].value)))[2]);
520                 *g = (((uint8_t*)(&(colors[i].value)))[1]);
521                 *b = (((uint8_t*)(&(colors[i].value)))[0]);
522                 return;
523             }
524         }
525     }
526 }
527
528
529 static char* _parseNumbersArray(char* str, float* points, int* ptCount, int len)
530 {
531     int count = 0;
532     char* end = nullptr;
533
534     str = _skipSpace(str, nullptr);
535     while ((count < len) && (isdigit(*str) || *str == '-' || *str == '+' || *str == '.')) {
536         points[count++] = svgUtilStrtof(str, &end);
537         str = end;
538         str = _skipSpace(str, nullptr);
539         if (*str == ',') ++str;
540         //Eat the rest of space
541         str = _skipSpace(str, nullptr);
542     }
543     *ptCount = count;
544     return str;
545 }
546
547
548 enum class MatrixState {
549     Unknown,
550     Matrix,
551     Translate,
552     Rotate,
553     Scale,
554     SkewX,
555     SkewY
556 };
557
558
559 #define MATRIX_DEF(Name, Value)     \
560     {                               \
561 #Name, sizeof(#Name), Value \
562     }
563
564
565 static constexpr struct
566 {
567     const char* tag;
568     int sz;
569     MatrixState state;
570 } matrixTags[] = {
571     MATRIX_DEF(matrix, MatrixState::Matrix),
572     MATRIX_DEF(translate, MatrixState::Translate),
573     MATRIX_DEF(rotate, MatrixState::Rotate),
574     MATRIX_DEF(scale, MatrixState::Scale),
575     MATRIX_DEF(skewX, MatrixState::SkewX),
576     MATRIX_DEF(skewY, MatrixState::SkewY)
577 };
578
579
580 static void _matrixCompose(const Matrix* m1, const Matrix* m2, Matrix* dst)
581 {
582     auto a11 = (m1->e11 * m2->e11) + (m1->e12 * m2->e21) + (m1->e13 * m2->e31);
583     auto a12 = (m1->e11 * m2->e12) + (m1->e12 * m2->e22) + (m1->e13 * m2->e32);
584     auto a13 = (m1->e11 * m2->e13) + (m1->e12 * m2->e23) + (m1->e13 * m2->e33);
585
586     auto a21 = (m1->e21 * m2->e11) + (m1->e22 * m2->e21) + (m1->e23 * m2->e31);
587     auto a22 = (m1->e21 * m2->e12) + (m1->e22 * m2->e22) + (m1->e23 * m2->e32);
588     auto a23 = (m1->e21 * m2->e13) + (m1->e22 * m2->e23) + (m1->e23 * m2->e33);
589
590     auto a31 = (m1->e31 * m2->e11) + (m1->e32 * m2->e21) + (m1->e33 * m2->e31);
591     auto a32 = (m1->e31 * m2->e12) + (m1->e32 * m2->e22) + (m1->e33 * m2->e32);
592     auto a33 = (m1->e31 * m2->e13) + (m1->e32 * m2->e23) + (m1->e33 * m2->e33);
593
594     dst->e11 = a11;
595     dst->e12 = a12;
596     dst->e13 = a13;
597     dst->e21 = a21;
598     dst->e22 = a22;
599     dst->e23 = a23;
600     dst->e31 = a31;
601     dst->e32 = a32;
602     dst->e33 = a33;
603 }
604
605
606 /* parse transform attribute
607  * https://www.w3.org/TR/SVG/coords.html#TransformAttribute
608  */
609 static Matrix* _parseTransformationMatrix(const char* value)
610 {
611     const int POINT_CNT = 8;
612
613     auto matrix = (Matrix*)malloc(sizeof(Matrix));
614     if (!matrix) return nullptr;
615     *matrix = {1, 0, 0, 0, 1, 0, 0, 0, 1};
616
617     float points[POINT_CNT];
618     int ptCount = 0;
619     char* str = (char*)value;
620     char* end = str + strlen(str);
621
622     while (str < end) {
623         auto state = MatrixState::Unknown;
624
625         if (isspace(*str) || (*str == ',')) {
626             ++str;
627             continue;
628         }
629         for (unsigned int i = 0; i < sizeof(matrixTags) / sizeof(matrixTags[0]); i++) {
630             if (!strncmp(matrixTags[i].tag, str, matrixTags[i].sz - 1)) {
631                 state = matrixTags[i].state;
632                 str += (matrixTags[i].sz - 1);
633                 break;
634             }
635         }
636         if (state == MatrixState::Unknown) goto error;
637
638         str = _skipSpace(str, end);
639         if (*str != '(') goto error;
640         ++str;
641         str = _parseNumbersArray(str, points, &ptCount, POINT_CNT);
642         if (*str != ')') goto error;
643         ++str;
644
645         if (state == MatrixState::Matrix) {
646             if (ptCount != 6) goto error;
647             Matrix tmp = {points[0], points[2], points[4], points[1], points[3], points[5], 0, 0, 1};
648             _matrixCompose(matrix, &tmp, matrix);
649         } else if (state == MatrixState::Translate) {
650             if (ptCount == 1) {
651                 Matrix tmp = {1, 0, points[0], 0, 1, 0, 0, 0, 1};
652                 _matrixCompose(matrix, &tmp, matrix);
653             } else if (ptCount == 2) {
654                 Matrix tmp = {1, 0, points[0], 0, 1, points[1], 0, 0, 1};
655                 _matrixCompose(matrix, &tmp, matrix);
656             } else goto error;
657         } else if (state == MatrixState::Rotate) {
658             //Transform to signed.
659             points[0] = fmod(points[0], 360);
660             if (points[0] < 0) points[0] += 360;
661             auto c = cosf(points[0] * (M_PI / 180.0));
662             auto s = sinf(points[0] * (M_PI / 180.0));
663             if (ptCount == 1) {
664                 Matrix tmp = { c, -s, 0, s, c, 0, 0, 0, 1 };
665                 _matrixCompose(matrix, &tmp, matrix);
666             } else if (ptCount == 3) {
667                 Matrix tmp = { 1, 0, points[1], 0, 1, points[2], 0, 0, 1 };
668                 _matrixCompose(matrix, &tmp, matrix);
669                 tmp = { c, -s, 0, s, c, 0, 0, 0, 1 };
670                 _matrixCompose(matrix, &tmp, matrix);
671                 tmp = { 1, 0, -points[1], 0, 1, -points[2], 0, 0, 1 };
672                 _matrixCompose(matrix, &tmp, matrix);
673             } else {
674                 goto error;
675             }
676         } else if (state == MatrixState::Scale) {
677             if (ptCount < 1 || ptCount > 2) goto error;
678             auto sx = points[0];
679             auto sy = sx;
680             if (ptCount == 2) sy = points[1];
681             Matrix tmp = { sx, 0, 0, 0, sy, 0, 0, 0, 1 };
682             _matrixCompose(matrix, &tmp, matrix);
683         }
684     }
685     return matrix;
686 error:
687     if (matrix) free(matrix);
688     return nullptr;
689 }
690
691
692 #define LENGTH_DEF(Name, Value)     \
693     {                               \
694 #Name, sizeof(#Name), Value \
695     }
696
697
698 static constexpr struct
699 {
700     const char* tag;
701     int sz;
702     SvgLengthType type;
703 } lengthTags[] = {
704     LENGTH_DEF(%, SvgLengthType::Percent),
705     LENGTH_DEF(px, SvgLengthType::Px),
706     LENGTH_DEF(pc, SvgLengthType::Pc),
707     LENGTH_DEF(pt, SvgLengthType::Pt),
708     LENGTH_DEF(mm, SvgLengthType::Mm),
709     LENGTH_DEF(cm, SvgLengthType::Cm),
710     LENGTH_DEF(in, SvgLengthType::In)
711 };
712
713
714 static float _parseLength(const char* str, SvgLengthType* type)
715 {
716     float value;
717     int sz = strlen(str);
718
719     *type = SvgLengthType::Px;
720     for (unsigned int i = 0; i < sizeof(lengthTags) / sizeof(lengthTags[0]); i++) {
721         if (lengthTags[i].sz - 1 == sz && !strncmp(lengthTags[i].tag, str, sz)) *type = lengthTags[i].type;
722     }
723     value = svgUtilStrtof(str, nullptr);
724     return value;
725 }
726
727
728 static bool _parseStyleAttr(void* data, const char* key, const char* value);
729 static bool _parseStyleAttr(void* data, const char* key, const char* value, bool style);
730
731
732 static bool _attrParseSvgNode(void* data, const char* key, const char* value)
733 {
734     SvgLoaderData* loader = (SvgLoaderData*)data;
735     SvgNode* node = loader->svgParse->node;
736     SvgDocNode* doc = &(node->node.doc);
737     SvgLengthType type;
738
739     //TODO: handle length unit.
740     if (!strcmp(key, "width")) {
741         doc->w = _parseLength(value, &type);
742     } else if (!strcmp(key, "height")) {
743         doc->h = _parseLength(value, &type);
744     } else if (!strcmp(key, "viewBox")) {
745         if (_parseNumber(&value, &doc->vx)) {
746             if (_parseNumber(&value, &doc->vy)) {
747                 if (_parseNumber(&value, &doc->vw)) {
748                     _parseNumber(&value, &doc->vh);
749                     loader->svgParse->global.h = doc->vh;
750                 }
751                 loader->svgParse->global.w = doc->vw;
752             }
753             loader->svgParse->global.y = doc->vy;
754         }
755         loader->svgParse->global.x = doc->vx;
756     } else if (!strcmp(key, "preserveAspectRatio")) {
757         if (!strcmp(value, "none")) doc->preserveAspect = false;
758     } else if (!strcmp(key, "style")) {
759         return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
760     }
761 #ifdef THORVG_LOG_ENABLED
762     else if (!strcmp(key, "x") || !strcmp(key, "y")) {
763         if (0.0f == _parseLength(value, &type)) TVGLOG("SVG", "Unsupported attributes used [Elements type: Svg][Attribute: %s][Value: %s]", key, value);
764     }
765 #endif
766     else {
767         return _parseStyleAttr(loader, key, value, false);
768     }
769     return true;
770 }
771
772
773 //https://www.w3.org/TR/SVGTiny12/painting.html#SpecifyingPaint
774 static void _handlePaintAttr(SvgPaint* paint, const char* value)
775 {
776     if (!strcmp(value, "none")) {
777         //No paint property
778         paint->none = true;
779         return;
780     }
781     paint->none = false;
782     if (!strcmp(value, "currentColor")) {
783         paint->curColor = true;
784         return;
785     }
786     _toColor(value, &paint->color.r, &paint->color.g, &paint->color.b, &paint->url);
787 }
788
789
790 static void _handleColorAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
791 {
792     SvgStyleProperty* style = node->style;
793     style->curColorSet = true;
794     _toColor(value, &style->color.r, &style->color.g, &style->color.b, nullptr);
795 }
796
797
798 static void _handleFillAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
799 {
800     SvgStyleProperty* style = node->style;
801     style->fill.flags = (SvgFillFlags)((int)style->fill.flags | (int)SvgFillFlags::Paint);
802     _handlePaintAttr(&style->fill.paint, value);
803 }
804
805
806 static void _handleStrokeAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
807 {
808     SvgStyleProperty* style = node->style;
809     style->stroke.flags = (SvgStrokeFlags)((int)style->stroke.flags | (int)SvgStrokeFlags::Paint);
810     _handlePaintAttr(&style->stroke.paint, value);
811 }
812
813
814 static void _handleStrokeOpacityAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
815 {
816     node->style->stroke.flags = (SvgStrokeFlags)((int)node->style->stroke.flags | (int)SvgStrokeFlags::Opacity);
817     node->style->stroke.opacity = _toOpacity(value);
818 }
819
820 static void _handleStrokeDashArrayAttr(SvgLoaderData* loader, SvgNode* node, const char* value)
821 {
822     node->style->stroke.flags = (SvgStrokeFlags)((int)node->style->stroke.flags | (int)SvgStrokeFlags::Dash);
823     _parseDashArray(loader, value, &node->style->stroke.dash);
824 }
825
826 static void _handleStrokeWidthAttr(SvgLoaderData* loader, SvgNode* node, const char* value)
827 {
828     node->style->stroke.flags = (SvgStrokeFlags)((int)node->style->stroke.flags | (int)SvgStrokeFlags::Width);
829     node->style->stroke.width = _toFloat(loader->svgParse, value, SvgParserLengthType::Horizontal);
830 }
831
832
833 static void _handleStrokeLineCapAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
834 {
835     node->style->stroke.flags = (SvgStrokeFlags)((int)node->style->stroke.flags | (int)SvgStrokeFlags::Cap);
836     node->style->stroke.cap = _toLineCap(value);
837 }
838
839
840 static void _handleStrokeLineJoinAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
841 {
842     node->style->stroke.flags = (SvgStrokeFlags)((int)node->style->stroke.flags | (int)SvgStrokeFlags::Join);
843     node->style->stroke.join = _toLineJoin(value);
844 }
845
846
847 static void _handleFillRuleAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
848 {
849     node->style->fill.flags = (SvgFillFlags)((int)node->style->fill.flags | (int)SvgFillFlags::FillRule);
850     node->style->fill.fillRule = _toFillRule(value);
851 }
852
853
854 static void _handleOpacityAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
855 {
856     node->style->opacity = _toOpacity(value);
857 }
858
859
860 static void _handleFillOpacityAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
861 {
862     node->style->fill.flags = (SvgFillFlags)((int)node->style->fill.flags | (int)SvgFillFlags::Opacity);
863     node->style->fill.opacity = _toOpacity(value);
864 }
865
866
867 static void _handleTransformAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
868 {
869     node->transform = _parseTransformationMatrix(value);
870 }
871
872
873 static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
874 {
875     SvgStyleProperty* style = node->style;
876     int len = strlen(value);
877     if (len >= 3 && !strncmp(value, "url", 3)) {
878         if (style->clipPath.url) delete(style->clipPath.url);
879         style->clipPath.url = _idFromUrl((const char*)(value + 3));
880     }
881 }
882
883
884 static void _handleMaskAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
885 {
886     SvgStyleProperty* style = node->style;
887     int len = strlen(value);
888     if (len >= 3 && !strncmp(value, "url", 3)) {
889         if (style->mask.url) delete(style->mask.url);
890         style->mask.url = _idFromUrl((const char*)(value + 3));
891     }
892 }
893
894
895 static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
896 {
897     //TODO : The display attribute can have various values as well as "none".
898     //       The default is "inline" which means visible and "none" means invisible.
899     //       Depending on the type of node, additional functionality may be required.
900     //       refer to https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/display
901     if (!strcmp(value, "none")) node->display = false;
902     else node->display = true;
903 }
904
905
906 typedef void (*styleMethod)(SvgLoaderData* loader, SvgNode* node, const char* value);
907
908 #define STYLE_DEF(Name, Name1, Flag) { #Name, sizeof(#Name), _handle##Name1##Attr, Flag }
909
910
911 static constexpr struct
912 {
913     const char* tag;
914     int sz;
915     styleMethod tagHandler;
916     SvgStyleFlags flag;
917 } styleTags[] = {
918     STYLE_DEF(color, Color, SvgStyleFlags::Color),
919     STYLE_DEF(fill, Fill, SvgStyleFlags::Fill),
920     STYLE_DEF(fill-rule, FillRule, SvgStyleFlags::FillRule),
921     STYLE_DEF(fill-opacity, FillOpacity, SvgStyleFlags::FillOpacity),
922     STYLE_DEF(opacity, Opacity, SvgStyleFlags::Opacity),
923     STYLE_DEF(stroke, Stroke, SvgStyleFlags::Stroke),
924     STYLE_DEF(stroke-width, StrokeWidth, SvgStyleFlags::StrokeWidth),
925     STYLE_DEF(stroke-linejoin, StrokeLineJoin, SvgStyleFlags::StrokeLineJoin),
926     STYLE_DEF(stroke-linecap, StrokeLineCap, SvgStyleFlags::StrokeLineCap),
927     STYLE_DEF(stroke-opacity, StrokeOpacity, SvgStyleFlags::StrokeOpacity),
928     STYLE_DEF(stroke-dasharray, StrokeDashArray, SvgStyleFlags::StrokeDashArray),
929     STYLE_DEF(transform, Transform, SvgStyleFlags::Transform),
930     STYLE_DEF(clip-path, ClipPath, SvgStyleFlags::ClipPath),
931     STYLE_DEF(mask, Mask, SvgStyleFlags::Mask),
932     STYLE_DEF(display, Display, SvgStyleFlags::Display)
933 };
934
935
936 static bool _parseStyleAttr(void* data, const char* key, const char* value, bool style)
937 {
938     SvgLoaderData* loader = (SvgLoaderData*)data;
939     SvgNode* node = loader->svgParse->node;
940     int sz;
941     if (!key || !value) return false;
942
943     //Trim the white space
944     key = _skipSpace(key, nullptr);
945     value = _skipSpace(value, nullptr);
946
947     sz = strlen(key);
948     for (unsigned int i = 0; i < sizeof(styleTags) / sizeof(styleTags[0]); i++) {
949         if (styleTags[i].sz - 1 == sz && !strncmp(styleTags[i].tag, key, sz)) {
950             if (style) {
951                 styleTags[i].tagHandler(loader, node, value);
952                 node->style->flags = (SvgStyleFlags)((int)node->style->flags | (int)styleTags[i].flag);
953             } else if (!((int)node->style->flags & (int)styleTags[i].flag)) {
954                 styleTags[i].tagHandler(loader, node, value);
955             }
956             return true;
957         }
958     }
959
960     return false;
961 }
962
963
964 static bool _parseStyleAttr(void* data, const char* key, const char* value)
965 {
966     return _parseStyleAttr(data, key, value, true);
967 }
968
969
970 /* parse g node
971  * https://www.w3.org/TR/SVG/struct.html#Groups
972  */
973 static bool _attrParseGNode(void* data, const char* key, const char* value)
974 {
975     SvgLoaderData* loader = (SvgLoaderData*)data;
976     SvgNode* node = loader->svgParse->node;
977
978     if (!strcmp(key, "style")) {
979         return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
980     } else if (!strcmp(key, "transform")) {
981         node->transform = _parseTransformationMatrix(value);
982     } else if (!strcmp(key, "id")) {
983         if (node->id && value) delete node->id;
984         node->id = _copyId(value);
985     } else if (!strcmp(key, "clip-path")) {
986         _handleClipPathAttr(loader, node, value);
987     } else if (!strcmp(key, "mask")) {
988         _handleMaskAttr(loader, node, value);
989     } else {
990         return _parseStyleAttr(loader, key, value, false);
991     }
992     return true;
993 }
994
995
996 /* parse clipPath node
997  * https://www.w3.org/TR/SVG/struct.html#Groups
998  */
999 static bool _attrParseClipPathNode(void* data, const char* key, const char* value)
1000 {
1001     SvgLoaderData* loader = (SvgLoaderData*)data;
1002     SvgNode* node = loader->svgParse->node;
1003
1004     if (!strcmp(key, "style")) {
1005         return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
1006     } else if (!strcmp(key, "transform")) {
1007         node->transform = _parseTransformationMatrix(value);
1008     } else if (!strcmp(key, "id")) {
1009         if (node->id && value) delete node->id;
1010         node->id = _copyId(value);
1011     } else {
1012         return _parseStyleAttr(loader, key, value, false);
1013     }
1014     return true;
1015 }
1016
1017
1018 static bool _attrParseMaskNode(void* data, const char* key, const char* value)
1019 {
1020     SvgLoaderData* loader = (SvgLoaderData*)data;
1021     SvgNode* node = loader->svgParse->node;
1022
1023     if (!strcmp(key, "style")) {
1024         return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
1025     } else if (!strcmp(key, "transform")) {
1026         node->transform = _parseTransformationMatrix(value);
1027     } else if (!strcmp(key, "id")) {
1028         if (node->id && value) delete node->id;
1029         node->id = _copyId(value);
1030     } else {
1031         return _parseStyleAttr(loader, key, value, false);
1032     }
1033     return true;
1034 }
1035
1036
1037 static SvgNode* _createNode(SvgNode* parent, SvgNodeType type)
1038 {
1039     SvgNode* node = (SvgNode*)calloc(1, sizeof(SvgNode));
1040
1041     if (!node) return nullptr;
1042
1043     //Default fill property
1044     node->style = (SvgStyleProperty*)calloc(1, sizeof(SvgStyleProperty));
1045
1046     if (!node->style) {
1047         free(node);
1048         return nullptr;
1049     }
1050
1051     //Update the default value of stroke and fill
1052     //https://www.w3.org/TR/SVGTiny12/painting.html#SpecifyingPaint
1053     node->style->fill.paint.none = false;
1054     //Default fill opacity is 1
1055     node->style->fill.opacity = 255;
1056     node->style->opacity = 255;
1057     //Default current color is not set
1058     node->style->fill.paint.curColor = false;
1059     node->style->curColorSet = false;
1060     //Default fill rule is nonzero
1061     node->style->fill.fillRule = FillRule::Winding;
1062
1063     //Default stroke is none
1064     node->style->stroke.paint.none = true;
1065     //Default stroke opacity is 1
1066     node->style->stroke.opacity = 255;
1067     //Default stroke current color is not set
1068     node->style->stroke.paint.curColor = false;
1069     //Default stroke width is 1
1070     node->style->stroke.width = 1;
1071     //Default line cap is butt
1072     node->style->stroke.cap = StrokeCap::Butt;
1073     //Default line join is miter
1074     node->style->stroke.join = StrokeJoin::Miter;
1075     node->style->stroke.scale = 1.0;
1076
1077     //Default display is true("inline").
1078     node->display = true;
1079
1080     node->parent = parent;
1081     node->type = type;
1082
1083     if (parent) parent->child.push(node);
1084     return node;
1085 }
1086
1087
1088 static SvgNode* _createDefsNode(TVG_UNUSED SvgLoaderData* loader, TVG_UNUSED SvgNode* parent, const char* buf, unsigned bufLength)
1089 {
1090     if (loader->def && loader->doc->node.doc.defs) return loader->def;
1091     SvgNode* node = _createNode(nullptr, SvgNodeType::Defs);
1092
1093     loader->def = node;
1094     loader->doc->node.doc.defs = node;
1095     return node;
1096 }
1097
1098
1099 static SvgNode* _createGNode(TVG_UNUSED SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
1100 {
1101     loader->svgParse->node = _createNode(parent, SvgNodeType::G);
1102     if (!loader->svgParse->node) return nullptr;
1103
1104     simpleXmlParseAttributes(buf, bufLength, _attrParseGNode, loader);
1105     return loader->svgParse->node;
1106 }
1107
1108
1109 static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
1110 {
1111     loader->svgParse->node = _createNode(parent, SvgNodeType::Doc);
1112     if (!loader->svgParse->node) return nullptr;
1113     SvgDocNode* doc = &(loader->svgParse->node->node.doc);
1114
1115     loader->svgParse->global.w = 0;
1116     loader->svgParse->global.h = 0;
1117
1118     doc->preserveAspect = true;
1119     simpleXmlParseAttributes(buf, bufLength, _attrParseSvgNode, loader);
1120
1121     if (loader->svgParse->global.w == 0) {
1122         if (doc->w < FLT_EPSILON) loader->svgParse->global.w = 1;
1123         else loader->svgParse->global.w = doc->w;
1124     }
1125     if (loader->svgParse->global.h == 0) {
1126         if (doc->h < FLT_EPSILON) loader->svgParse->global.h = 1;
1127         else loader->svgParse->global.h =doc->h;
1128     }
1129
1130     return loader->svgParse->node;
1131 }
1132
1133
1134 static SvgNode* _createMaskNode(SvgLoaderData* loader, SvgNode* parent, TVG_UNUSED const char* buf, TVG_UNUSED unsigned bufLength)
1135 {
1136     loader->svgParse->node = _createNode(parent, SvgNodeType::Mask);
1137     if (!loader->svgParse->node) return nullptr;
1138
1139     simpleXmlParseAttributes(buf, bufLength, _attrParseMaskNode, loader);
1140
1141     return loader->svgParse->node;
1142 }
1143
1144
1145 static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
1146 {
1147     loader->svgParse->node = _createNode(parent, SvgNodeType::ClipPath);
1148
1149     if (!loader->svgParse->node) return nullptr;
1150
1151     loader->svgParse->node->display = false;
1152
1153     simpleXmlParseAttributes(buf, bufLength, _attrParseClipPathNode, loader);
1154
1155     return loader->svgParse->node;
1156 }
1157
1158 static bool _attrParsePathNode(void* data, const char* key, const char* value)
1159 {
1160     SvgLoaderData* loader = (SvgLoaderData*)data;
1161     SvgNode* node = loader->svgParse->node;
1162     SvgPathNode* path = &(node->node.path);
1163
1164     if (!strcmp(key, "d")) {
1165         //Temporary: need to copy
1166         path->path = _copyId(value);
1167     } else if (!strcmp(key, "style")) {
1168         return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
1169     } else if (!strcmp(key, "clip-path")) {
1170         _handleClipPathAttr(loader, node, value);
1171     } else if (!strcmp(key, "mask")) {
1172         _handleMaskAttr(loader, node, value);
1173     } else if (!strcmp(key, "id")) {
1174         if (node->id && value) delete node->id;
1175         node->id = _copyId(value);
1176     } else {
1177         return _parseStyleAttr(loader, key, value, false);
1178     }
1179     return true;
1180 }
1181
1182
1183 static SvgNode* _createPathNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
1184 {
1185     loader->svgParse->node = _createNode(parent, SvgNodeType::Path);
1186
1187     if (!loader->svgParse->node) return nullptr;
1188
1189     simpleXmlParseAttributes(buf, bufLength, _attrParsePathNode, loader);
1190
1191     return loader->svgParse->node;
1192 }
1193
1194
1195 static constexpr struct
1196 {
1197     const char* tag;
1198     SvgParserLengthType type;
1199     int sz;
1200     size_t offset;
1201 } circleTags[] = {
1202     {"cx", SvgParserLengthType::Horizontal, sizeof("cx"), offsetof(SvgCircleNode, cx)},
1203     {"cy", SvgParserLengthType::Vertical, sizeof("cy"), offsetof(SvgCircleNode, cy)},
1204     {"r", SvgParserLengthType::Other, sizeof("r"), offsetof(SvgCircleNode, r)}
1205 };
1206
1207
1208 /* parse the attributes for a circle element.
1209  * https://www.w3.org/TR/SVG/shapes.html#CircleElement
1210  */
1211 static bool _attrParseCircleNode(void* data, const char* key, const char* value)
1212 {
1213     SvgLoaderData* loader = (SvgLoaderData*)data;
1214     SvgNode* node = loader->svgParse->node;
1215     SvgCircleNode* circle = &(node->node.circle);
1216     unsigned char* array;
1217     int sz = strlen(key);
1218
1219     array = (unsigned char*)circle;
1220     for (unsigned int i = 0; i < sizeof(circleTags) / sizeof(circleTags[0]); i++) {
1221         if (circleTags[i].sz - 1 == sz && !strncmp(circleTags[i].tag, key, sz)) {
1222             *((float*)(array + circleTags[i].offset)) = _toFloat(loader->svgParse, value, circleTags[i].type);
1223             return true;
1224         }
1225     }
1226
1227     if (!strcmp(key, "style")) {
1228         return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
1229     } else if (!strcmp(key, "clip-path")) {
1230         _handleClipPathAttr(loader, node, value);
1231     } else if (!strcmp(key, "mask")) {
1232         _handleMaskAttr(loader, node, value);
1233     } else if (!strcmp(key, "id")) {
1234         if (node->id && value) delete node->id;
1235         node->id = _copyId(value);
1236     } else {
1237         return _parseStyleAttr(loader, key, value, false);
1238     }
1239     return true;
1240 }
1241
1242
1243 static SvgNode* _createCircleNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
1244 {
1245     loader->svgParse->node = _createNode(parent, SvgNodeType::Circle);
1246
1247     if (!loader->svgParse->node) return nullptr;
1248
1249     simpleXmlParseAttributes(buf, bufLength, _attrParseCircleNode, loader);
1250     return loader->svgParse->node;
1251 }
1252
1253
1254 static constexpr struct
1255 {
1256     const char* tag;
1257     SvgParserLengthType type;
1258     int sz;
1259     size_t offset;
1260 } ellipseTags[] = {
1261     {"cx", SvgParserLengthType::Horizontal, sizeof("cx"), offsetof(SvgEllipseNode, cx)},
1262     {"cy", SvgParserLengthType::Vertical, sizeof("cy"), offsetof(SvgEllipseNode, cy)},
1263     {"rx", SvgParserLengthType::Horizontal, sizeof("rx"), offsetof(SvgEllipseNode, rx)},
1264     {"ry", SvgParserLengthType::Vertical, sizeof("ry"), offsetof(SvgEllipseNode, ry)}
1265 };
1266
1267
1268 /* parse the attributes for an ellipse element.
1269  * https://www.w3.org/TR/SVG/shapes.html#EllipseElement
1270  */
1271 static bool _attrParseEllipseNode(void* data, const char* key, const char* value)
1272 {
1273     SvgLoaderData* loader = (SvgLoaderData*)data;
1274     SvgNode* node = loader->svgParse->node;
1275     SvgEllipseNode* ellipse = &(node->node.ellipse);
1276     unsigned char* array;
1277     int sz = strlen(key);
1278
1279     array = (unsigned char*)ellipse;
1280     for (unsigned int i = 0; i < sizeof(ellipseTags) / sizeof(ellipseTags[0]); i++) {
1281         if (ellipseTags[i].sz - 1 == sz && !strncmp(ellipseTags[i].tag, key, sz)) {
1282             *((float*)(array + ellipseTags[i].offset)) = _toFloat(loader->svgParse, value, ellipseTags[i].type);
1283             return true;
1284         }
1285     }
1286
1287     if (!strcmp(key, "id")) {
1288         if (node->id && value) delete node->id;
1289         node->id = _copyId(value);
1290     } else if (!strcmp(key, "style")) {
1291         return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
1292     } else if (!strcmp(key, "clip-path")) {
1293         _handleClipPathAttr(loader, node, value);
1294     } else if (!strcmp(key, "mask")) {
1295         _handleMaskAttr(loader, node, value);
1296     } else {
1297         return _parseStyleAttr(loader, key, value, false);
1298     }
1299     return true;
1300 }
1301
1302
1303 static SvgNode* _createEllipseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
1304 {
1305     loader->svgParse->node = _createNode(parent, SvgNodeType::Ellipse);
1306
1307     if (!loader->svgParse->node) return nullptr;
1308
1309     simpleXmlParseAttributes(buf, bufLength, _attrParseEllipseNode, loader);
1310     return loader->svgParse->node;
1311 }
1312
1313
1314 static bool _attrParsePolygonPoints(const char* str, float** points, int* ptCount)
1315 {
1316     float tmp[50];
1317     int tmpCount = 0;
1318     int count = 0;
1319     float num;
1320     float *pointArray = nullptr, *tmpArray;
1321
1322     while (_parseNumber(&str, &num)) {
1323         tmp[tmpCount++] = num;
1324         if (tmpCount == 50) {
1325             tmpArray = (float*)realloc(pointArray, (count + tmpCount) * sizeof(float));
1326             if (!tmpArray) goto error_alloc;
1327             pointArray = tmpArray;
1328             memcpy(&pointArray[count], tmp, tmpCount * sizeof(float));
1329             count += tmpCount;
1330             tmpCount = 0;
1331         }
1332     }
1333
1334     if (tmpCount > 0) {
1335         tmpArray = (float*)realloc(pointArray, (count + tmpCount) * sizeof(float));
1336         if (!tmpArray) goto error_alloc;
1337         pointArray = tmpArray;
1338         memcpy(&pointArray[count], tmp, tmpCount * sizeof(float));
1339         count += tmpCount;
1340     }
1341     *ptCount = count;
1342     *points = pointArray;
1343     return true;
1344
1345 error_alloc:
1346     return false;
1347 }
1348
1349
1350 /* parse the attributes for a polygon element.
1351  * https://www.w3.org/TR/SVG/shapes.html#PolylineElement
1352  */
1353 static bool _attrParsePolygonNode(void* data, const char* key, const char* value)
1354 {
1355     SvgLoaderData* loader = (SvgLoaderData*)data;
1356     SvgNode* node = loader->svgParse->node;
1357     SvgPolygonNode* polygon = nullptr;
1358
1359     if (node->type == SvgNodeType::Polygon) polygon = &(node->node.polygon);
1360     else polygon = &(node->node.polyline);
1361
1362     if (!strcmp(key, "points")) {
1363         return _attrParsePolygonPoints(value, &polygon->points, &polygon->pointsCount);
1364     } else if (!strcmp(key, "style")) {
1365         return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
1366     } else if (!strcmp(key, "clip-path")) {
1367         _handleClipPathAttr(loader, node, value);
1368     } else if (!strcmp(key, "mask")) {
1369         _handleMaskAttr(loader, node, value);
1370     } else if (!strcmp(key, "id")) {
1371         if (node->id && value) delete node->id;
1372         node->id = _copyId(value);
1373     } else {
1374         return _parseStyleAttr(loader, key, value, false);
1375     }
1376     return true;
1377 }
1378
1379
1380 static SvgNode* _createPolygonNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
1381 {
1382     loader->svgParse->node = _createNode(parent, SvgNodeType::Polygon);
1383
1384     if (!loader->svgParse->node) return nullptr;
1385
1386     simpleXmlParseAttributes(buf, bufLength, _attrParsePolygonNode, loader);
1387     return loader->svgParse->node;
1388 }
1389
1390
1391 static SvgNode* _createPolylineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
1392 {
1393     loader->svgParse->node = _createNode(parent, SvgNodeType::Polyline);
1394
1395     if (!loader->svgParse->node) return nullptr;
1396
1397     simpleXmlParseAttributes(buf, bufLength, _attrParsePolygonNode, loader);
1398     return loader->svgParse->node;
1399 }
1400
1401 static constexpr struct
1402 {
1403     const char* tag;
1404     SvgParserLengthType type;
1405     int sz;
1406     size_t offset;
1407 } rectTags[] = {
1408     {"x", SvgParserLengthType::Horizontal, sizeof("x"), offsetof(SvgRectNode, x)},
1409     {"y", SvgParserLengthType::Vertical, sizeof("y"), offsetof(SvgRectNode, y)},
1410     {"width", SvgParserLengthType::Horizontal, sizeof("width"), offsetof(SvgRectNode, w)},
1411     {"height", SvgParserLengthType::Vertical, sizeof("height"), offsetof(SvgRectNode, h)},
1412     {"rx", SvgParserLengthType::Horizontal, sizeof("rx"), offsetof(SvgRectNode, rx)},
1413     {"ry", SvgParserLengthType::Vertical, sizeof("ry"), offsetof(SvgRectNode, ry)}
1414 };
1415
1416
1417 /* parse the attributes for a rect element.
1418  * https://www.w3.org/TR/SVG/shapes.html#RectElement
1419  */
1420 static bool _attrParseRectNode(void* data, const char* key, const char* value)
1421 {
1422     SvgLoaderData* loader = (SvgLoaderData*)data;
1423     SvgNode* node = loader->svgParse->node;
1424     SvgRectNode* rect = &(node->node.rect);
1425     unsigned char* array;
1426     bool ret = true;
1427     int sz = strlen(key);
1428
1429     array = (unsigned char*)rect;
1430     for (unsigned int i = 0; i < sizeof(rectTags) / sizeof(rectTags[0]); i++) {
1431         if (rectTags[i].sz - 1 == sz && !strncmp(rectTags[i].tag, key, sz)) {
1432             *((float*)(array + rectTags[i].offset)) = _toFloat(loader->svgParse, value, rectTags[i].type);
1433
1434             //Case if only rx or ry is declared
1435             if (!strncmp(rectTags[i].tag, "rx", sz)) rect->hasRx = true;
1436             if (!strncmp(rectTags[i].tag, "ry", sz)) rect->hasRy = true;
1437
1438             if ((rect->rx > FLT_EPSILON) && (rect->ry <= FLT_EPSILON) && rect->hasRx && !rect->hasRy) rect->ry = rect->rx;
1439             if ((rect->ry > FLT_EPSILON) && (rect->rx <= FLT_EPSILON) && !rect->hasRx && rect->hasRy) rect->rx = rect->ry;
1440             return ret;
1441         }
1442     }
1443
1444     if (!strcmp(key, "id")) {
1445         if (node->id && value) delete node->id;
1446         node->id = _copyId(value);
1447     } else if (!strcmp(key, "style")) {
1448         ret = simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
1449     } else if (!strcmp(key, "clip-path")) {
1450         _handleClipPathAttr(loader, node, value);
1451     } else if (!strcmp(key, "mask")) {
1452         _handleMaskAttr(loader, node, value);
1453     } else {
1454         ret = _parseStyleAttr(loader, key, value, false);
1455     }
1456
1457     return ret;
1458 }
1459
1460
1461 static SvgNode* _createRectNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
1462 {
1463     loader->svgParse->node = _createNode(parent, SvgNodeType::Rect);
1464
1465     if (!loader->svgParse->node) return nullptr;
1466
1467     loader->svgParse->node->node.rect.hasRx = loader->svgParse->node->node.rect.hasRy = false;
1468
1469     simpleXmlParseAttributes(buf, bufLength, _attrParseRectNode, loader);
1470     return loader->svgParse->node;
1471 }
1472
1473
1474 static constexpr struct
1475 {
1476     const char* tag;
1477     SvgParserLengthType type;
1478     int sz;
1479     size_t offset;
1480 } lineTags[] = {
1481     {"x1", SvgParserLengthType::Horizontal, sizeof("x1"), offsetof(SvgLineNode, x1)},
1482     {"y1", SvgParserLengthType::Vertical, sizeof("y1"), offsetof(SvgLineNode, y1)},
1483     {"x2", SvgParserLengthType::Horizontal, sizeof("x2"), offsetof(SvgLineNode, x2)},
1484     {"y2", SvgParserLengthType::Vertical, sizeof("y2"), offsetof(SvgLineNode, y2)}
1485 };
1486
1487
1488 /* parse the attributes for a line element.
1489  * https://www.w3.org/TR/SVG/shapes.html#LineElement
1490  */
1491 static bool _attrParseLineNode(void* data, const char* key, const char* value)
1492 {
1493     SvgLoaderData* loader = (SvgLoaderData*)data;
1494     SvgNode* node = loader->svgParse->node;
1495     SvgLineNode* line = &(node->node.line);
1496     unsigned char* array;
1497     int sz = strlen(key);
1498
1499     array = (unsigned char*)line;
1500     for (unsigned int i = 0; i < sizeof(lineTags) / sizeof(lineTags[0]); i++) {
1501         if (lineTags[i].sz - 1 == sz && !strncmp(lineTags[i].tag, key, sz)) {
1502             *((float*)(array + lineTags[i].offset)) = _toFloat(loader->svgParse, value, lineTags[i].type);
1503             return true;
1504         }
1505     }
1506
1507     if (!strcmp(key, "id")) {
1508         if (node->id && value) delete node->id;
1509         node->id = _copyId(value);
1510     } else if (!strcmp(key, "style")) {
1511         return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
1512     } else if (!strcmp(key, "clip-path")) {
1513         _handleClipPathAttr(loader, node, value);
1514     } else if (!strcmp(key, "mask")) {
1515         _handleMaskAttr(loader, node, value);
1516     } else {
1517         return _parseStyleAttr(loader, key, value, false);
1518     }
1519     return true;
1520 }
1521
1522
1523 static SvgNode* _createLineNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
1524 {
1525     loader->svgParse->node = _createNode(parent, SvgNodeType::Line);
1526
1527     if (!loader->svgParse->node) return nullptr;
1528
1529     simpleXmlParseAttributes(buf, bufLength, _attrParseLineNode, loader);
1530     return loader->svgParse->node;
1531 }
1532
1533
1534 static string* _idFromHref(const char* href)
1535 {
1536     href = _skipSpace(href, nullptr);
1537     if ((*href) == '#') href++;
1538     return new string(href);
1539 }
1540
1541
1542 static constexpr struct
1543 {
1544     const char* tag;
1545     SvgParserLengthType type;
1546     int sz;
1547     size_t offset;
1548 } imageTags[] = {
1549     {"x", SvgParserLengthType::Horizontal, sizeof("x"), offsetof(SvgRectNode, x)},
1550     {"y", SvgParserLengthType::Vertical, sizeof("y"), offsetof(SvgRectNode, y)},
1551     {"width", SvgParserLengthType::Horizontal, sizeof("width"), offsetof(SvgRectNode, w)},
1552     {"height", SvgParserLengthType::Vertical, sizeof("height"), offsetof(SvgRectNode, h)},
1553 };
1554
1555
1556 /* parse the attributes for a image element.
1557  * https://www.w3.org/TR/SVG/embedded.html#ImageElement
1558  */
1559 static bool _attrParseImageNode(void* data, const char* key, const char* value)
1560 {
1561     SvgLoaderData* loader = (SvgLoaderData*)data;
1562     SvgNode* node = loader->svgParse->node;
1563     SvgImageNode* image = &(node->node.image);
1564     unsigned char* array;
1565     int sz = strlen(key);
1566
1567     array = (unsigned char*)image;
1568     for (unsigned int i = 0; i < sizeof(imageTags) / sizeof(imageTags[0]); i++) {
1569         if (imageTags[i].sz - 1 == sz && !strncmp(imageTags[i].tag, key, sz)) {
1570             *((float*)(array + imageTags[i].offset)) = _toFloat(loader->svgParse, value, imageTags[i].type);
1571             return true;
1572         }
1573     }
1574
1575     if (!strcmp(key, "href") || !strcmp(key, "xlink:href")) {
1576         image->href = _idFromHref(value);
1577     } else if (!strcmp(key, "id")) {
1578         if (node->id && value) delete node->id;
1579         node->id = _copyId(value);
1580     } else if (!strcmp(key, "style")) {
1581         return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader);
1582     } else if (!strcmp(key, "clip-path")) {
1583         _handleClipPathAttr(loader, node, value);
1584     } else if (!strcmp(key, "mask")) {
1585         _handleMaskAttr(loader, node, value);
1586     } else {
1587         return _parseStyleAttr(loader, key, value);
1588     }
1589     return true;
1590 }
1591
1592
1593 static SvgNode* _createImageNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
1594 {
1595     loader->svgParse->node = _createNode(parent, SvgNodeType::Image);
1596
1597     if (!loader->svgParse->node) return nullptr;
1598
1599     simpleXmlParseAttributes(buf, bufLength, _attrParseImageNode, loader);
1600     return loader->svgParse->node;
1601 }
1602
1603
1604 static SvgNode* _getDefsNode(SvgNode* node)
1605 {
1606     if (!node) return nullptr;
1607
1608     while (node->parent != nullptr) {
1609         node = node->parent;
1610     }
1611
1612     if (node->type == SvgNodeType::Doc) return node->node.doc.defs;
1613
1614     return nullptr;
1615 }
1616
1617
1618 static SvgNode* _findChildById(const SvgNode* node, const char* id)
1619 {
1620     if (!node) return nullptr;
1621
1622     auto child = node->child.data;
1623     for (uint32_t i = 0; i < node->child.count; ++i, ++child) {
1624         if (((*child)->id != nullptr) && !strcmp((*child)->id->c_str(), id)) return (*child);
1625     }
1626     return nullptr;
1627 }
1628
1629 static SvgNode* _findNodeById(SvgNode *node, string* id)
1630 {
1631     SvgNode* result = nullptr;
1632     if (node->id && !node->id->compare(*id)) return node;
1633
1634     if (node->child.count > 0) {
1635         auto child = node->child.data;
1636         for (uint32_t i = 0; i < node->child.count; ++i, ++child) {
1637             result = _findNodeById(*child, id);
1638             if (result) break;
1639         }
1640     }
1641     return result;
1642 }
1643
1644 static void _cloneGradStops(Array<Fill::ColorStop>& dst, const Array<Fill::ColorStop>& src)
1645 {
1646     for (uint32_t i = 0; i < src.count; ++i) {
1647         dst.push(src.data[i]);
1648     }
1649 }
1650
1651
1652 static SvgStyleGradient* _cloneGradient(SvgStyleGradient* from)
1653 {
1654     if (!from) return nullptr;
1655
1656     auto grad = new SvgStyleGradient;
1657     if (!grad) return nullptr;
1658
1659     grad->type = from->type;
1660     grad->id = from->id ? _copyId(from->id->c_str()) : nullptr;
1661     grad->ref = from->ref ? _copyId(from->ref->c_str()) : nullptr;
1662     grad->spread = from->spread;
1663     grad->usePercentage = from->usePercentage;
1664     grad->userSpace = from->userSpace;
1665
1666     if (from->transform) {
1667         grad->transform = (Matrix*)calloc(1, sizeof(Matrix));
1668         if (grad->transform) memcpy(grad->transform, from->transform, sizeof(Matrix));
1669     }
1670
1671     if (grad->type == SvgGradientType::Linear) {
1672         grad->linear = (SvgLinearGradient*)calloc(1, sizeof(SvgLinearGradient));
1673         if (!grad->linear) goto error_grad_alloc;
1674         memcpy(grad->linear, from->linear, sizeof(SvgLinearGradient));
1675     } else if (grad->type == SvgGradientType::Radial) {
1676         grad->radial = (SvgRadialGradient*)calloc(1, sizeof(SvgRadialGradient));
1677         if (!grad->radial) goto error_grad_alloc;
1678         memcpy(grad->radial, from->radial, sizeof(SvgRadialGradient));
1679     }
1680
1681     _cloneGradStops(grad->stops, from->stops);
1682
1683     return grad;
1684
1685 error_grad_alloc:
1686     if (grad) delete(grad);
1687     return nullptr;
1688 }
1689
1690
1691 static void _copyAttr(SvgNode* to, const SvgNode* from)
1692 {
1693     //Copy matrix attribute
1694     if (from->transform) {
1695         to->transform = (Matrix*)malloc(sizeof(Matrix));
1696         if (to->transform) *to->transform = *from->transform;
1697     }
1698     //Copy style attribute
1699     *to->style = *from->style;
1700     if (from->style->fill.paint.url) to->style->fill.paint.url = new string(from->style->fill.paint.url->c_str());
1701     if (from->style->stroke.paint.url) to->style->stroke.paint.url = new string(from->style->stroke.paint.url->c_str());
1702     if (from->style->clipPath.url) to->style->clipPath.url = new string(from->style->clipPath.url->c_str());
1703     if (from->style->mask.url) to->style->mask.url = new string(from->style->mask.url->c_str());
1704
1705     //Copy node attribute
1706     switch (from->type) {
1707         case SvgNodeType::Circle: {
1708             to->node.circle.cx = from->node.circle.cx;
1709             to->node.circle.cy = from->node.circle.cy;
1710             to->node.circle.r = from->node.circle.r;
1711             break;
1712         }
1713         case SvgNodeType::Ellipse: {
1714             to->node.ellipse.cx = from->node.ellipse.cx;
1715             to->node.ellipse.cy = from->node.ellipse.cy;
1716             to->node.ellipse.rx = from->node.ellipse.rx;
1717             to->node.ellipse.ry = from->node.ellipse.ry;
1718             break;
1719         }
1720         case SvgNodeType::Rect: {
1721             to->node.rect.x = from->node.rect.x;
1722             to->node.rect.y = from->node.rect.y;
1723             to->node.rect.w = from->node.rect.w;
1724             to->node.rect.h = from->node.rect.h;
1725             to->node.rect.rx = from->node.rect.rx;
1726             to->node.rect.ry = from->node.rect.ry;
1727             to->node.rect.hasRx = from->node.rect.hasRx;
1728             to->node.rect.hasRy = from->node.rect.hasRy;
1729             break;
1730         }
1731         case SvgNodeType::Line: {
1732             to->node.line.x1 = from->node.line.x1;
1733             to->node.line.y1 = from->node.line.y1;
1734             to->node.line.x2 = from->node.line.x2;
1735             to->node.line.y2 = from->node.line.y2;
1736             break;
1737         }
1738         case SvgNodeType::Path: {
1739             if (from->node.path.path) to->node.path.path = new string(from->node.path.path->c_str());
1740             break;
1741         }
1742         case SvgNodeType::Polygon: {
1743             to->node.polygon.pointsCount = from->node.polygon.pointsCount;
1744             to->node.polygon.points = (float*)malloc(to->node.polygon.pointsCount * sizeof(float));
1745             memcpy(to->node.polygon.points, from->node.polygon.points, to->node.polygon.pointsCount * sizeof(float));
1746             break;
1747         }
1748         case SvgNodeType::Polyline: {
1749             to->node.polyline.pointsCount = from->node.polyline.pointsCount;
1750             to->node.polyline.points = (float*)malloc(to->node.polyline.pointsCount * sizeof(float));
1751             memcpy(to->node.polyline.points, from->node.polyline.points, to->node.polyline.pointsCount * sizeof(float));
1752             break;
1753         }
1754         case SvgNodeType::Image: {
1755             to->node.image.x = from->node.image.x;
1756             to->node.image.y = from->node.image.y;
1757             to->node.image.w = from->node.image.w;
1758             to->node.image.h = from->node.image.h;
1759             if (from->node.image.href) to->node.image.href = new string(from->node.image.href->c_str());
1760             break;
1761         }
1762         default: {
1763             break;
1764         }
1765     }
1766 }
1767
1768
1769 static void _cloneNode(SvgNode* from, SvgNode* parent)
1770 {
1771     SvgNode* newNode;
1772     if (!from || !parent) return;
1773
1774     newNode = _createNode(parent, from->type);
1775
1776     if (!newNode) return;
1777
1778     _copyAttr(newNode, from);
1779
1780     auto child = from->child.data;
1781     for (uint32_t i = 0; i < from->child.count; ++i, ++child) {
1782         _cloneNode(*child, newNode);
1783     }
1784 }
1785
1786
1787 static void _postponeCloneNode(SvgLoaderData* loader, SvgNode *node, string* id) {
1788     SvgNodeIdPair nodeIdPair;
1789     nodeIdPair.node = node;
1790     nodeIdPair.id = id;
1791     loader->cloneNodes.push(nodeIdPair);
1792 }
1793
1794
1795 static void _clonePostponedNodes(Array<SvgNodeIdPair>* cloneNodes) {
1796     for (uint32_t i = 0; i < cloneNodes->count; ++i) {
1797         SvgNodeIdPair nodeIdPair = cloneNodes->data[i];
1798         SvgNode *defs = _getDefsNode(nodeIdPair.node);
1799         SvgNode *nodeFrom = _findChildById(defs, nodeIdPair.id->c_str());
1800         _cloneNode(nodeFrom, nodeIdPair.node);
1801         delete nodeIdPair.id;
1802     }
1803 }
1804
1805
1806 static bool _attrParseUseNode(void* data, const char* key, const char* value)
1807 {
1808     SvgLoaderData* loader = (SvgLoaderData*)data;
1809     SvgNode *defs, *nodeFrom, *node = loader->svgParse->node;
1810     string* id;
1811
1812     if (!strcmp(key, "href") || !strcmp(key, "xlink:href")) {
1813         id = _idFromHref(value);
1814         defs = _getDefsNode(node);
1815         nodeFrom = _findChildById(defs, id->c_str());
1816         if (nodeFrom) {
1817             _cloneNode(nodeFrom, node);
1818             delete id;
1819         } else {
1820             //some svg export software include <defs> element at the end of the file
1821             //if so the 'from' element won't be found now and we have to repeat finding
1822             //after the whole file is parsed
1823             _postponeCloneNode(loader, node, id);
1824         }
1825     } else if (!strcmp(key, "clip-path")) {
1826         _handleClipPathAttr(loader, node, value);
1827     } else if (!strcmp(key, "mask")) {
1828         _handleMaskAttr(loader, node, value);
1829     } else {
1830         return _attrParseGNode(data, key, value);
1831     }
1832     return true;
1833 }
1834
1835
1836 static SvgNode* _createUseNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength)
1837 {
1838     loader->svgParse->node = _createNode(parent, SvgNodeType::Use);
1839
1840     if (!loader->svgParse->node) return nullptr;
1841
1842     simpleXmlParseAttributes(buf, bufLength, _attrParseUseNode, loader);
1843     return loader->svgParse->node;
1844 }
1845
1846 //TODO: Implement 'text' primitive
1847 static constexpr struct
1848 {
1849     const char* tag;
1850     int sz;
1851     FactoryMethod tagHandler;
1852 } graphicsTags[] = {
1853     {"use", sizeof("use"), _createUseNode},
1854     {"circle", sizeof("circle"), _createCircleNode},
1855     {"ellipse", sizeof("ellipse"), _createEllipseNode},
1856     {"path", sizeof("path"), _createPathNode},
1857     {"polygon", sizeof("polygon"), _createPolygonNode},
1858     {"rect", sizeof("rect"), _createRectNode},
1859     {"polyline", sizeof("polyline"), _createPolylineNode},
1860     {"line", sizeof("line"), _createLineNode},
1861     {"image", sizeof("image"), _createImageNode}
1862 };
1863
1864
1865 static constexpr struct
1866 {
1867     const char* tag;
1868     int sz;
1869     FactoryMethod tagHandler;
1870 } groupTags[] = {
1871     {"defs", sizeof("defs"), _createDefsNode},
1872     {"g", sizeof("g"), _createGNode},
1873     {"svg", sizeof("svg"), _createSvgNode},
1874     {"mask", sizeof("mask"), _createMaskNode},
1875     {"clipPath", sizeof("clipPath"), _createClipPathNode}
1876 };
1877
1878
1879 #define FIND_FACTORY(Short_Name, Tags_Array)                                           \
1880     static FactoryMethod                                                               \
1881         _find##Short_Name##Factory(const char* name)                                   \
1882     {                                                                                  \
1883         unsigned int i;                                                                \
1884         int sz = strlen(name);                                                         \
1885                                                                                        \
1886         for (i = 0; i < sizeof(Tags_Array) / sizeof(Tags_Array[0]); i++) {             \
1887             if (Tags_Array[i].sz - 1 == sz && !strncmp(Tags_Array[i].tag, name, sz)) { \
1888                 return Tags_Array[i].tagHandler;                                       \
1889             }                                                                          \
1890         }                                                                              \
1891         return nullptr;                                                                \
1892     }
1893
1894 FIND_FACTORY(Group, groupTags)
1895 FIND_FACTORY(Graphics, graphicsTags)
1896
1897
1898 FillSpread _parseSpreadValue(const char* value)
1899 {
1900     auto spread = FillSpread::Pad;
1901
1902     if (!strcmp(value, "reflect")) {
1903         spread = FillSpread::Reflect;
1904     } else if (!strcmp(value, "repeat")) {
1905         spread = FillSpread::Repeat;
1906     }
1907
1908     return spread;
1909 }
1910
1911
1912 static void _handleRadialCxAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value)
1913 {
1914     radial->cx = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal);
1915     if (!loader->svgParse->gradient.parsedFx) radial->fx = radial->cx;
1916 }
1917
1918
1919 static void _handleRadialCyAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value)
1920 {
1921     radial->cy = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical);
1922     if (!loader->svgParse->gradient.parsedFy) radial->fy = radial->cy;
1923 }
1924
1925
1926 static void _handleRadialFxAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value)
1927 {
1928     radial->fx = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal);
1929     loader->svgParse->gradient.parsedFx = true;
1930 }
1931
1932
1933 static void _handleRadialFyAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value)
1934 {
1935     radial->fy = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical);
1936     loader->svgParse->gradient.parsedFy = true;
1937 }
1938
1939
1940 static void _handleRadialRAttr(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value)
1941 {
1942     radial->r = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Other);
1943 }
1944
1945
1946 static void _recalcRadialCxAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace)
1947 {
1948     if (!userSpace) radial->cx = radial->cx * loader->svgParse->global.w;
1949 }
1950
1951
1952 static void _recalcRadialCyAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace)
1953 {
1954     if (!userSpace) radial->cy = radial->cy * loader->svgParse->global.h;
1955 }
1956
1957
1958 static void _recalcRadialFxAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace)
1959 {
1960     if (!userSpace) radial->fx = radial->fx * loader->svgParse->global.w;
1961 }
1962
1963
1964 static void _recalcRadialFyAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace)
1965 {
1966     if (!userSpace) radial->fy = radial->fy * loader->svgParse->global.h;
1967 }
1968
1969
1970 static void _recalcRadialRAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace)
1971 {
1972     if (!userSpace) radial->r = radial->r * (sqrt(pow(loader->svgParse->global.h, 2) + pow(loader->svgParse->global.w, 2)) / sqrt(2.0));
1973 }
1974
1975
1976 typedef void (*radialMethod)(SvgLoaderData* loader, SvgRadialGradient* radial, const char* value);
1977 typedef void (*radialMethodRecalc)(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace);
1978
1979
1980 #define RADIAL_DEF(Name, Name1)                                                          \
1981     {                                                                                    \
1982 #Name, sizeof(#Name), _handleRadial##Name1##Attr, _recalcRadial##Name1##Attr             \
1983     }
1984
1985
1986 static constexpr struct
1987 {
1988     const char* tag;
1989     int sz;
1990     radialMethod tagHandler;
1991     radialMethodRecalc tagRecalc;
1992 } radialTags[] = {
1993     RADIAL_DEF(cx, Cx),
1994     RADIAL_DEF(cy, Cy),
1995     RADIAL_DEF(fx, Fx),
1996     RADIAL_DEF(fy, Fy),
1997     RADIAL_DEF(r, R)
1998 };
1999
2000
2001 static bool _attrParseRadialGradientNode(void* data, const char* key, const char* value)
2002 {
2003     SvgLoaderData* loader = (SvgLoaderData*)data;
2004     SvgStyleGradient* grad = loader->svgParse->styleGrad;
2005     SvgRadialGradient* radial = grad->radial;
2006     int sz = strlen(key);
2007
2008     for (unsigned int i = 0; i < sizeof(radialTags) / sizeof(radialTags[0]); i++) {
2009         if (radialTags[i].sz - 1 == sz && !strncmp(radialTags[i].tag, key, sz)) {
2010             radialTags[i].tagHandler(loader, radial, value);
2011             return true;
2012         }
2013     }
2014
2015     if (!strcmp(key, "id")) {
2016         grad->id = _copyId(value);
2017     } else if (!strcmp(key, "spreadMethod")) {
2018         grad->spread = _parseSpreadValue(value);
2019     } else if (!strcmp(key, "href") || !strcmp(key, "xlink:href")) {
2020         grad->ref = _idFromHref(value);
2021     } else if (!strcmp(key, "gradientUnits") && !strcmp(value, "userSpaceOnUse")) {
2022         grad->userSpace = true;
2023     } else if (!strcmp(key, "gradientTransform")) {
2024         grad->transform = _parseTransformationMatrix(value);
2025     } else {
2026         return false;
2027     }
2028
2029     return true;
2030 }
2031
2032
2033 static SvgStyleGradient* _createRadialGradient(SvgLoaderData* loader, const char* buf, unsigned bufLength)
2034 {
2035     auto grad = new SvgStyleGradient;
2036     if (!grad) return nullptr;
2037
2038     loader->svgParse->styleGrad = grad;
2039
2040     grad->type = SvgGradientType::Radial;
2041     grad->userSpace = false;
2042     grad->radial = (SvgRadialGradient*)calloc(1, sizeof(SvgRadialGradient));
2043     if (!grad->radial) {
2044         delete(grad);
2045         return nullptr;
2046     }
2047     /**
2048     * Default values of gradient transformed into global percentage
2049     */
2050     grad->radial->cx = 0.5f / loader->svgParse->global.w;
2051     grad->radial->cy = 0.5f / loader->svgParse->global.h;
2052     grad->radial->fx = 0.5f / loader->svgParse->global.w;
2053     grad->radial->fy = 0.5f / loader->svgParse->global.h;
2054     grad->radial->r = 0.5f / (sqrt(pow(loader->svgParse->global.h, 2) + pow(loader->svgParse->global.w, 2)) / sqrt(2.0f));
2055
2056     loader->svgParse->gradient.parsedFx = false;
2057     loader->svgParse->gradient.parsedFy = false;
2058     simpleXmlParseAttributes(buf, bufLength,
2059         _attrParseRadialGradientNode, loader);
2060
2061     for (unsigned int i = 0; i < sizeof(radialTags) / sizeof(radialTags[0]); i++) {
2062         radialTags[i].tagRecalc(loader, grad->radial, grad->userSpace);
2063     }
2064
2065     grad->usePercentage = true;
2066
2067     return loader->svgParse->styleGrad;
2068 }
2069
2070
2071 static bool _attrParseStopsStyle(void* data, const char* key, const char* value)
2072 {
2073     SvgLoaderData* loader = (SvgLoaderData*)data;
2074     auto stop = &loader->svgParse->gradStop;
2075
2076     if (!strcmp(key, "stop-opacity")) {
2077         stop->a = _toOpacity(value);
2078         loader->svgParse->flags = (SvgStopStyleFlags)((int)loader->svgParse->flags | (int)SvgStopStyleFlags::StopOpacity);
2079     } else if (!strcmp(key, "stop-color")) {
2080         _toColor(value, &stop->r, &stop->g, &stop->b, nullptr);
2081         loader->svgParse->flags = (SvgStopStyleFlags)((int)loader->svgParse->flags | (int)SvgStopStyleFlags::StopColor);
2082     } else {
2083         return false;
2084     }
2085
2086     return true;
2087 }
2088
2089
2090 static bool _attrParseStops(void* data, const char* key, const char* value)
2091 {
2092     SvgLoaderData* loader = (SvgLoaderData*)data;
2093     auto stop = &loader->svgParse->gradStop;
2094
2095     if (!strcmp(key, "offset")) {
2096         stop->offset = _toOffset(value);
2097     } else if (!strcmp(key, "stop-opacity")) {
2098         if (!((int)loader->svgParse->flags & (int)SvgStopStyleFlags::StopOpacity)) {
2099             stop->a = _toOpacity(value);
2100         }
2101     } else if (!strcmp(key, "stop-color")) {
2102         if (!((int)loader->svgParse->flags & (int)SvgStopStyleFlags::StopColor)) {
2103             _toColor(value, &stop->r, &stop->g, &stop->b, nullptr);
2104         }
2105     } else if (!strcmp(key, "style")) {
2106         simpleXmlParseW3CAttribute(value, _attrParseStopsStyle, data);
2107     } else {
2108         return false;
2109     }
2110
2111     return true;
2112 }
2113
2114
2115 static void _handleLinearX1Attr(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value)
2116 {
2117     linear->x1 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal);
2118 }
2119
2120
2121 static void _handleLinearY1Attr(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value)
2122 {
2123     linear->y1 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical);
2124 }
2125
2126
2127 static void _handleLinearX2Attr(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value)
2128 {
2129     linear->x2 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Horizontal);
2130 }
2131
2132
2133 static void _handleLinearY2Attr(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value)
2134 {
2135     linear->y2 = _gradientToFloat(loader->svgParse, value, SvgParserLengthType::Vertical);
2136 }
2137
2138
2139 static void _recalcLinearX1Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace)
2140 {
2141     if (!userSpace) linear->x1 = linear->x1 * loader->svgParse->global.w;
2142 }
2143
2144
2145 static void _recalcLinearY1Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace)
2146 {
2147     if (!userSpace) linear->y1 = linear->y1 * loader->svgParse->global.h;
2148 }
2149
2150
2151 static void _recalcLinearX2Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace)
2152 {
2153     if (!userSpace) linear->x2 = linear->x2 * loader->svgParse->global.w;
2154 }
2155
2156
2157 static void _recalcLinearY2Attr(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace)
2158 {
2159     if (!userSpace) linear->y2 = linear->y2 * loader->svgParse->global.h;
2160 }
2161
2162
2163 typedef void (*Linear_Method)(SvgLoaderData* loader, SvgLinearGradient* linear, const char* value);
2164 typedef void (*Linear_Method_Recalc)(SvgLoaderData* loader, SvgLinearGradient* linear, bool userSpace);
2165
2166
2167 #define LINEAR_DEF(Name, Name1)                                                          \
2168     {                                                                                    \
2169 #Name, sizeof(#Name), _handleLinear##Name1##Attr, _recalcLinear##Name1##Attr \
2170     }
2171
2172
2173 static constexpr struct
2174 {
2175     const char* tag;
2176     int sz;
2177     Linear_Method tagHandler;
2178     Linear_Method_Recalc tagRecalc;
2179 } linear_tags[] = {
2180     LINEAR_DEF(x1, X1),
2181     LINEAR_DEF(y1, Y1),
2182     LINEAR_DEF(x2, X2),
2183     LINEAR_DEF(y2, Y2)
2184 };
2185
2186
2187 static bool _attrParseLinearGradientNode(void* data, const char* key, const char* value)
2188 {
2189     SvgLoaderData* loader = (SvgLoaderData*)data;
2190     SvgStyleGradient* grad = loader->svgParse->styleGrad;
2191     SvgLinearGradient* linear = grad->linear;
2192     int sz = strlen(key);
2193
2194     for (unsigned int i = 0; i < sizeof(linear_tags) / sizeof(linear_tags[0]); i++) {
2195         if (linear_tags[i].sz - 1 == sz && !strncmp(linear_tags[i].tag, key, sz)) {
2196             linear_tags[i].tagHandler(loader, linear, value);
2197             return true;
2198         }
2199     }
2200
2201     if (!strcmp(key, "id")) {
2202         grad->id = _copyId(value);
2203     } else if (!strcmp(key, "spreadMethod")) {
2204         grad->spread = _parseSpreadValue(value);
2205     } else if (!strcmp(key, "href") || !strcmp(key, "xlink:href")) {
2206         grad->ref = _idFromHref(value);
2207     } else if (!strcmp(key, "gradientUnits") && !strcmp(value, "userSpaceOnUse")) {
2208         grad->userSpace = true;
2209     } else if (!strcmp(key, "gradientTransform")) {
2210         grad->transform = _parseTransformationMatrix(value);
2211     } else {
2212         return false;
2213     }
2214
2215     return true;
2216 }
2217
2218
2219 static SvgStyleGradient* _createLinearGradient(SvgLoaderData* loader, const char* buf, unsigned bufLength)
2220 {
2221     auto grad = new SvgStyleGradient;
2222     if (!grad) return nullptr;
2223
2224     loader->svgParse->styleGrad = grad;
2225
2226     grad->type = SvgGradientType::Linear;
2227     grad->userSpace = false;
2228     grad->linear = (SvgLinearGradient*)calloc(1, sizeof(SvgLinearGradient));
2229     if (!grad->linear) {
2230         delete(grad);
2231         return nullptr;
2232     }
2233     /**
2234     * Default value of x2 is 100% - transformed to the global percentage
2235     */
2236     grad->linear->x2 = 1.0f / loader->svgParse->global.w;
2237     simpleXmlParseAttributes(buf, bufLength, _attrParseLinearGradientNode, loader);
2238
2239     for (unsigned int i = 0; i < sizeof(linear_tags) / sizeof(linear_tags[0]); i++) {
2240         linear_tags[i].tagRecalc(loader, grad->linear, grad->userSpace);
2241     }
2242
2243     grad->usePercentage = true;
2244
2245     return loader->svgParse->styleGrad;
2246 }
2247
2248
2249 #define GRADIENT_DEF(Name, Name1)            \
2250     {                                        \
2251 #Name, sizeof(#Name), _create##Name1         \
2252     }
2253
2254
2255 /**
2256  * For all Gradients lengths would be calculated into percentages related to
2257  * canvas width and height.
2258  *
2259  * if user then recalculate actual pixels into percentages
2260  */
2261 static constexpr struct
2262 {
2263     const char* tag;
2264     int sz;
2265     GradientFactoryMethod tagHandler;
2266 } gradientTags[] = {
2267     GRADIENT_DEF(linearGradient, LinearGradient),
2268     GRADIENT_DEF(radialGradient, RadialGradient)
2269 };
2270
2271
2272 static GradientFactoryMethod _findGradientFactory(const char* name)
2273 {
2274     int sz = strlen(name);
2275
2276     for (unsigned int i = 0; i < sizeof(gradientTags) / sizeof(gradientTags[0]); i++) {
2277         if (gradientTags[i].sz - 1 == sz && !strncmp(gradientTags[i].tag, name, sz)) {
2278             return gradientTags[i].tagHandler;
2279         }
2280     }
2281     return nullptr;
2282 }
2283
2284
2285 static constexpr struct
2286 {
2287     const char* tag;
2288     size_t sz;
2289 } popArray[] = {
2290     {"g", sizeof("g")},
2291     {"svg", sizeof("svg")},
2292     {"defs", sizeof("defs")},
2293     {"mask", sizeof("mask")},
2294     {"clipPath", sizeof("clipPath")}
2295 };
2296
2297
2298 static void _svgLoaderParerXmlClose(SvgLoaderData* loader, const char* content)
2299 {
2300     content = _skipSpace(content, nullptr);
2301
2302     for (unsigned int i = 0; i < sizeof(popArray) / sizeof(popArray[0]); i++) {
2303         if (!strncmp(content, popArray[i].tag, popArray[i].sz - 1)) {
2304             loader->stack.pop();
2305             break;
2306         }
2307     }
2308
2309     loader->level--;
2310 }
2311
2312
2313 static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, unsigned int length, bool empty)
2314 {
2315     const char* attrs = nullptr;
2316     int attrsLength = 0;
2317     int sz = length;
2318     char tagName[20] = "";
2319     FactoryMethod method;
2320     GradientFactoryMethod gradientMethod;
2321     SvgNode *node = nullptr, *parent = nullptr;
2322     loader->level++;
2323     attrs = simpleXmlFindAttributesTag(content, length);
2324
2325     if (!attrs) {
2326         //Parse the empty tag
2327         attrs = content;
2328         while ((attrs != nullptr) && *attrs != '>') attrs++;
2329     }
2330
2331     if (attrs) {
2332         //Find out the tag name starting from content till sz length
2333         sz = attrs - content;
2334         while ((sz > 0) && (isspace(content[sz - 1]))) sz--;
2335         if ((unsigned)sz >= sizeof(tagName)) return;
2336         strncpy(tagName, content, sz);
2337         tagName[sz] = '\0';
2338         attrsLength = length - sz;
2339     }
2340
2341     if ((method = _findGroupFactory(tagName))) {
2342         //Group
2343         if (!loader->doc) {
2344             if (strcmp(tagName, "svg")) return; //Not a valid svg document
2345             node = method(loader, nullptr, attrs, attrsLength);
2346             loader->doc = node;
2347         } else {
2348             if (!strcmp(tagName, "svg")) return; //Already loaded <svg>(SvgNodeType::Doc) tag
2349             if (loader->stack.count > 0) parent = loader->stack.data[loader->stack.count - 1];
2350             else parent = loader->doc;
2351             node = method(loader, parent, attrs, attrsLength);
2352         }
2353
2354         if (!node) return;
2355         if (node->type != SvgNodeType::Defs || !empty) {
2356             loader->stack.push(node);
2357         }
2358     } else if ((method = _findGraphicsFactory(tagName))) {
2359         if (loader->stack.count > 0) parent = loader->stack.data[loader->stack.count - 1];
2360         else parent = loader->doc;
2361         node = method(loader, parent, attrs, attrsLength);
2362     } else if ((gradientMethod = _findGradientFactory(tagName))) {
2363         SvgStyleGradient* gradient;
2364         gradient = gradientMethod(loader, attrs, attrsLength);
2365         //FIXME: The current parsing structure does not distinguish end tags.
2366         //       There is no way to know if the currently parsed gradient is in defs.
2367         //       If a gradient is declared outside of defs after defs is set, it is included in the gradients of defs.
2368         //       But finally, the loader has a gradient style list regardless of defs.
2369         //       This is only to support this when multiple gradients are declared, even if no defs are declared.
2370         //       refer to: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs
2371         if (loader->def && loader->doc->node.doc.defs) {
2372             loader->def->node.defs.gradients.push(gradient);
2373         } else {
2374             loader->gradients.push(gradient);
2375         }
2376         loader->latestGradient = gradient;
2377     } else if (!strcmp(tagName, "stop")) {
2378         if (!loader->latestGradient) {
2379             TVGLOG("SVG", "Stop element is used outside of the Gradient element");
2380             return;
2381         }
2382         /* default value for opacity */
2383         loader->svgParse->gradStop = {0.0f, 0, 0, 0, 255};
2384         simpleXmlParseAttributes(attrs, attrsLength, _attrParseStops, loader);
2385         loader->latestGradient->stops.push(loader->svgParse->gradStop);
2386     } else if (!isIgnoreUnsupportedLogElements(tagName)) {
2387         TVGLOG("SVG", "Unsupported elements used [Elements: %s]", tagName);
2388     }
2389 }
2390
2391
2392 static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content, unsigned int length)
2393 {
2394     SvgLoaderData* loader = (SvgLoaderData*)data;
2395
2396     switch (type) {
2397         case SimpleXMLType::Open: {
2398             _svgLoaderParserXmlOpen(loader, content, length, false);
2399             break;
2400         }
2401         case SimpleXMLType::OpenEmpty: {
2402             _svgLoaderParserXmlOpen(loader, content, length, true);
2403             break;
2404         }
2405         case SimpleXMLType::Close: {
2406             _svgLoaderParerXmlClose(loader, content);
2407             break;
2408         }
2409         case SimpleXMLType::Data:
2410         case SimpleXMLType::CData:
2411         case SimpleXMLType::DoctypeChild: {
2412             break;
2413         }
2414         case SimpleXMLType::Ignored:
2415         case SimpleXMLType::Comment:
2416         case SimpleXMLType::Doctype: {
2417             break;
2418         }
2419         default: {
2420             break;
2421         }
2422     }
2423
2424     return true;
2425 }
2426
2427
2428 static void _styleInherit(SvgStyleProperty* child, const SvgStyleProperty* parent)
2429 {
2430     if (parent == nullptr) return;
2431     //Inherit the property of parent if not present in child.
2432     //Fill
2433     if (!((int)child->fill.flags & (int)SvgFillFlags::Paint)) {
2434         child->fill.paint.color = parent->fill.paint.color;
2435         child->fill.paint.none = parent->fill.paint.none;
2436         child->fill.paint.curColor = parent->fill.paint.curColor;
2437         if (parent->fill.paint.url) child->fill.paint.url = _copyId(parent->fill.paint.url->c_str());
2438     } else if (child->fill.paint.curColor && !child->curColorSet) {
2439         child->color = parent->color;
2440     }
2441     if (!((int)child->fill.flags & (int)SvgFillFlags::Opacity)) {
2442         child->fill.opacity = parent->fill.opacity;
2443     }
2444     if (!((int)child->fill.flags & (int)SvgFillFlags::FillRule)) {
2445         child->fill.fillRule = parent->fill.fillRule;
2446     }
2447     //Stroke
2448     if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Paint)) {
2449         child->stroke.paint.color = parent->stroke.paint.color;
2450         child->stroke.paint.none = parent->stroke.paint.none;
2451         child->stroke.paint.curColor = parent->stroke.paint.curColor;
2452         child->stroke.paint.url = parent->stroke.paint.url ? _copyId(parent->stroke.paint.url->c_str()) : nullptr;
2453     } else if (child->stroke.paint.curColor && !child->curColorSet) {
2454         child->color = parent->color;
2455     }
2456     if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Opacity)) {
2457         child->stroke.opacity = parent->stroke.opacity;
2458     }
2459     if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Width)) {
2460         child->stroke.width = parent->stroke.width;
2461     }
2462     if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Dash)) {
2463         if (parent->stroke.dash.array.count > 0) {
2464             child->stroke.dash.array.clear();
2465             child->stroke.dash.array.reserve(parent->stroke.dash.array.count);
2466             for (uint32_t i = 0; i < parent->stroke.dash.array.count; ++i) {
2467                 child->stroke.dash.array.push(parent->stroke.dash.array.data[i]);
2468             }
2469         }
2470     }
2471     if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Cap)) {
2472         child->stroke.cap = parent->stroke.cap;
2473     }
2474     if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Join)) {
2475         child->stroke.join = parent->stroke.join;
2476     }
2477 }
2478
2479
2480 static void _inefficientNodeCheck(TVG_UNUSED SvgNode* node){
2481 #ifdef THORVG_LOG_ENABLED
2482     auto type = simpleXmlNodeTypeToString(node->type);
2483
2484     if (!node->display && node->type != SvgNodeType::ClipPath) TVGLOG("SVG", "Inefficient elements used [Display is none][Node Type : %s]", type);
2485     if (node->style->opacity == 0) TVGLOG("SVG", "Inefficient elements used [Opacity is zero][Node Type : %s]", type);
2486     if (node->style->fill.opacity == 0 && node->style->stroke.opacity == 0) TVGLOG("SVG", "Inefficient elements used [Fill opacity and stroke opacity are zero][Node Type : %s]", type);
2487
2488     switch (node->type) {
2489         case SvgNodeType::Path: {
2490             if (!node->node.path.path || node->node.path.path->empty()) TVGLOG("SVG", "Inefficient elements used [Empty path][Node Type : %s]", type);
2491             break;
2492         }
2493         case SvgNodeType::Ellipse: {
2494             if (node->node.ellipse.rx == 0 && node->node.ellipse.ry == 0) TVGLOG("SVG", "Inefficient elements used [Size is zero][Node Type : %s]", type);
2495             break;
2496         }
2497         case SvgNodeType::Polygon:
2498         case SvgNodeType::Polyline: {
2499             if (node->node.polygon.pointsCount < 2) TVGLOG("SVG", "Inefficient elements used [Invalid Polygon][Node Type : %s]", type);
2500             break;
2501         }
2502         case SvgNodeType::Circle: {
2503             if (node->node.circle.r == 0) TVGLOG("SVG", "Inefficient elements used [Size is zero][Node Type : %s]", type);
2504             break;
2505         }
2506         case SvgNodeType::Rect: {
2507             if (node->node.rect.w == 0 && node->node.rect.h) TVGLOG("SVG", "Inefficient elements used [Size is zero][Node Type : %s]", type);
2508             break;
2509         }
2510         case SvgNodeType::Line: {
2511             if (node->node.line.x1 == node->node.line.x2 && node->node.line.y1 == node->node.line.y2) TVGLOG("SVG", "Inefficient elements used [Size is zero][Node Type : %s]", type);
2512             break;
2513         }
2514         default: break;
2515     }
2516 #endif
2517 }
2518
2519
2520 static void _updateStyle(SvgNode* node, SvgStyleProperty* parentStyle)
2521 {
2522     _styleInherit(node->style, parentStyle);
2523     _inefficientNodeCheck(node);
2524
2525     auto child = node->child.data;
2526     for (uint32_t i = 0; i < node->child.count; ++i, ++child) {
2527         _updateStyle(*child, node->style);
2528     }
2529 }
2530
2531
2532 static SvgStyleGradient* _gradientDup(Array<SvgStyleGradient*>* gradients, const string* id)
2533 {
2534     SvgStyleGradient* result = nullptr;
2535
2536     auto gradList = gradients->data;
2537
2538     for (uint32_t i = 0; i < gradients->count; ++i) {
2539         if (!((*gradList)->id->compare(*id))) {
2540             result = _cloneGradient(*gradList);
2541             break;
2542         }
2543         ++gradList;
2544     }
2545
2546     if (result && result->ref) {
2547         gradList = gradients->data;
2548         for (uint32_t i = 0; i < gradients->count; ++i) {
2549             if (!((*gradList)->id->compare(*result->ref))) {
2550                 if (result->stops.count == 0) {
2551                     _cloneGradStops(result->stops, (*gradList)->stops);
2552                 }
2553                 //TODO: Properly inherit other property
2554                 break;
2555             }
2556             ++gradList;
2557         }
2558     }
2559
2560     return result;
2561 }
2562
2563
2564 static void _updateGradient(SvgNode* node, Array<SvgStyleGradient*>* gradients)
2565 {
2566     if (node->child.count > 0) {
2567         auto child = node->child.data;
2568         for (uint32_t i = 0; i < node->child.count; ++i, ++child) {
2569             _updateGradient(*child, gradients);
2570         }
2571     } else {
2572         if (node->style->fill.paint.url) {
2573             if (node->style->fill.paint.gradient) delete(node->style->fill.paint.gradient);
2574             node->style->fill.paint.gradient = _gradientDup(gradients, node->style->fill.paint.url);
2575         }
2576         if (node->style->stroke.paint.url) {
2577             if (node->style->stroke.paint.gradient) delete(node->style->stroke.paint.gradient);
2578             node->style->stroke.paint.gradient = _gradientDup(gradients, node->style->stroke.paint.url);
2579         }
2580     }
2581 }
2582
2583
2584 static void _updateComposite(SvgNode* node, SvgNode* root)
2585 {
2586     if (node->style->clipPath.url && !node->style->clipPath.node) {
2587         SvgNode *findResult = _findNodeById(root, node->style->clipPath.url);
2588         if (findResult) node->style->clipPath.node = findResult;
2589     }
2590     if (node->style->mask.url && !node->style->mask.node) {
2591         SvgNode *findResult = _findNodeById(root, node->style->mask.url);
2592         if (findResult) node->style->mask.node = findResult;
2593     }
2594     if (node->child.count > 0) {
2595         auto child = node->child.data;
2596         for (uint32_t i = 0; i < node->child.count; ++i, ++child) {
2597             _updateComposite(*child, root);
2598         }
2599     }
2600 }
2601
2602
2603 static void _freeNodeStyle(SvgStyleProperty* style)
2604 {
2605     if (!style) return;
2606
2607     //style->clipPath.node and style->mask.node has only the addresses of node. Therefore, node is released from _freeNode.
2608     delete(style->clipPath.url);
2609     delete(style->mask.url);
2610
2611     if (style->fill.paint.gradient) delete(style->fill.paint.gradient);
2612     if (style->stroke.paint.gradient) delete(style->stroke.paint.gradient);
2613     delete(style->fill.paint.url);
2614     delete(style->stroke.paint.url);
2615     style->stroke.dash.array.reset();
2616     free(style);
2617 }
2618
2619
2620 static void _freeNode(SvgNode* node)
2621 {
2622     if (!node) return;
2623
2624     auto child = node->child.data;
2625     for (uint32_t i = 0; i < node->child.count; ++i, ++child) {
2626         _freeNode(*child);
2627     }
2628     node->child.reset();
2629
2630     delete node->id;
2631     free(node->transform);
2632     _freeNodeStyle(node->style);
2633     switch (node->type) {
2634          case SvgNodeType::Path: {
2635              delete node->node.path.path;
2636              break;
2637          }
2638          case SvgNodeType::Polygon: {
2639              free(node->node.polygon.points);
2640              break;
2641          }
2642          case SvgNodeType::Polyline: {
2643              free(node->node.polyline.points);
2644              break;
2645          }
2646          case SvgNodeType::Doc: {
2647              _freeNode(node->node.doc.defs);
2648              break;
2649          }
2650          case SvgNodeType::Defs: {
2651              auto gradients = node->node.defs.gradients.data;
2652              for (size_t i = 0; i < node->node.defs.gradients.count; ++i) {
2653                  delete(*gradients);
2654                  ++gradients;
2655              }
2656              node->node.defs.gradients.reset();
2657              break;
2658          }
2659          case SvgNodeType::Image: {
2660              delete node->node.image.href;
2661              break;
2662          }
2663          default: {
2664              break;
2665          }
2666     }
2667     free(node);
2668 }
2669
2670
2671 static bool _svgLoaderParserForValidCheckXmlOpen(SvgLoaderData* loader, const char* content, unsigned int length)
2672 {
2673     const char* attrs = nullptr;
2674     int sz = length;
2675     char tagName[20] = "";
2676     FactoryMethod method;
2677     SvgNode *node = nullptr;
2678     int attrsLength = 0;
2679     loader->level++;
2680     attrs = simpleXmlFindAttributesTag(content, length);
2681
2682     if (!attrs) {
2683         //Parse the empty tag
2684         attrs = content;
2685         while ((attrs != nullptr) && *attrs != '>') attrs++;
2686     }
2687
2688     if (attrs) {
2689         sz = attrs - content;
2690         while ((sz > 0) && (isspace(content[sz - 1]))) sz--;
2691         if ((unsigned)sz >= sizeof(tagName)) return false;
2692         strncpy(tagName, content, sz);
2693         tagName[sz] = '\0';
2694         attrsLength = length - sz;
2695     }
2696
2697     if ((method = _findGroupFactory(tagName))) {
2698         if (!loader->doc) {
2699             if (strcmp(tagName, "svg")) return true; //Not a valid svg document
2700             node = method(loader, nullptr, attrs, attrsLength);
2701             loader->doc = node;
2702             loader->stack.push(node);
2703             return false;
2704         }
2705     }
2706     return true;
2707 }
2708
2709
2710 static bool _svgLoaderParserForValidCheck(void* data, SimpleXMLType type, const char* content, unsigned int length)
2711 {
2712     SvgLoaderData* loader = (SvgLoaderData*)data;
2713     bool res = true;;
2714
2715     switch (type) {
2716         case SimpleXMLType::Open:
2717         case SimpleXMLType::OpenEmpty: {
2718             //If 'res' is false, it means <svg> tag is found.
2719             res = _svgLoaderParserForValidCheckXmlOpen(loader, content, length);
2720             break;
2721         }
2722         default: {
2723             break;
2724         }
2725     }
2726
2727     return res;
2728 }
2729
2730
2731 void SvgLoader::clear()
2732 {
2733     if (copy) free((char*)content);
2734     size = 0;
2735     content = nullptr;
2736     copy = false;
2737 }
2738
2739
2740 /************************************************************************/
2741 /* External Class Implementation                                        */
2742 /************************************************************************/
2743
2744 SvgLoader::SvgLoader()
2745 {
2746 }
2747
2748
2749 SvgLoader::~SvgLoader()
2750 {
2751     close();
2752 }
2753
2754
2755 void SvgLoader::run(unsigned tid)
2756 {
2757     if (!simpleXmlParse(content, size, true, _svgLoaderParser, &(loaderData))) return;
2758
2759     if (loaderData.doc) {
2760         _updateStyle(loaderData.doc, nullptr);
2761         auto defs = loaderData.doc->node.doc.defs;
2762         if (defs) _updateGradient(loaderData.doc, &defs->node.defs.gradients);
2763
2764         if (loaderData.gradients.count > 0) _updateGradient(loaderData.doc, &loaderData.gradients);
2765
2766         _updateComposite(loaderData.doc, loaderData.doc);
2767         if (defs) _updateComposite(loaderData.doc, defs);
2768
2769         if (loaderData.cloneNodes.count > 0) _clonePostponedNodes(&loaderData.cloneNodes);
2770     }
2771     root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh);
2772 };
2773
2774
2775 bool SvgLoader::header()
2776 {
2777     //For valid check, only <svg> tag is parsed first.
2778     //If the <svg> tag is found, the loaded file is valid and stores viewbox information.
2779     //After that, the remaining content data is parsed in order with async.
2780     loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser));
2781     if (!loaderData.svgParse) return false;
2782
2783     loaderData.svgParse->flags = SvgStopStyleFlags::StopDefault;
2784
2785     simpleXmlParse(content, size, true, _svgLoaderParserForValidCheck, &(loaderData));
2786
2787     if (loaderData.doc && loaderData.doc->type == SvgNodeType::Doc) {
2788         //Return the brief resource info such as viewbox:
2789         vx = loaderData.doc->node.doc.vx;
2790         vy = loaderData.doc->node.doc.vy;
2791         w = vw = loaderData.doc->node.doc.vw;
2792         h = vh = loaderData.doc->node.doc.vh;
2793
2794         //Override size
2795         if (loaderData.doc->node.doc.w > 0) {
2796             w = loaderData.doc->node.doc.w;
2797             if (vw < FLT_EPSILON) vw = w;
2798         }
2799         if (loaderData.doc->node.doc.h > 0) {
2800             h = loaderData.doc->node.doc.h;
2801             if (vh < FLT_EPSILON) vh = h;
2802         }
2803
2804         preserveAspect = loaderData.doc->node.doc.preserveAspect;
2805     } else {
2806         TVGLOG("SVG", "No SVG File. There is no <svg/>");
2807         return false;
2808     }
2809
2810     return true;
2811 }
2812
2813
2814 bool SvgLoader::open(const char* data, uint32_t size, bool copy)
2815 {
2816     clear();
2817
2818     if (copy) {
2819         content = (char*)malloc(size);
2820         if (!content) return false;
2821         memcpy((char*)content, data, size);
2822     } else content = data;
2823
2824     this->size = size;
2825     this->copy = copy;
2826
2827     return header();
2828 }
2829
2830
2831 bool SvgLoader::open(const string& path)
2832 {
2833     clear();
2834
2835     ifstream f;
2836     f.open(path);
2837
2838     if (!f.is_open()) return false;
2839
2840     getline(f, filePath, '\0');
2841     f.close();
2842
2843     if (filePath.empty()) return false;
2844
2845     content = filePath.c_str();
2846     size = filePath.size();
2847
2848     return header();
2849 }
2850
2851
2852 bool SvgLoader::resize(Paint* paint, float w, float h)
2853 {
2854     if (!paint) return false;
2855
2856     auto sx = w / vw;
2857     auto sy = h / vh;
2858
2859     if (preserveAspect) {
2860         //Scale
2861         auto scale = sx < sy ? sx : sy;
2862         paint->scale(scale);
2863         //Align
2864         auto vx = this->vx * scale;
2865         auto vy = this->vy * scale;
2866         auto vw = this->vw * scale;
2867         auto vh = this->vh * scale;
2868         if (vw > vh) vy -= (h - vh) * 0.5f;
2869         else vx -= (w - vw) * 0.5f;
2870         paint->translate(-vx, -vy);
2871     } else {
2872         //Align
2873         auto vx = this->vx * sx;
2874         auto vy = this->vy * sy;
2875         auto vw = this->vw * sx;
2876         auto vh = this->vh * sy;
2877         if (vw > vh) vy -= (h - vh) * 0.5f;
2878         else vx -= (w - vw) * 0.5f;
2879
2880         Matrix m = {sx, 0, -vx, 0, sy, -vy, 0, 0, 1};
2881         paint->transform(m);
2882     }
2883     return true;
2884 }
2885
2886
2887 bool SvgLoader::read()
2888 {
2889     if (!content || size == 0) return false;
2890
2891     TaskScheduler::request(this);
2892
2893     return true;
2894 }
2895
2896
2897 bool SvgLoader::close()
2898 {
2899     this->done();
2900
2901     if (loaderData.svgParse) {
2902         free(loaderData.svgParse);
2903         loaderData.svgParse = nullptr;
2904     }
2905     auto gradients = loaderData.gradients.data;
2906     for (size_t i = 0; i < loaderData.gradients.count; ++i) {
2907         delete(*gradients);
2908         ++gradients;
2909     }
2910     loaderData.gradients.reset();
2911
2912     _freeNode(loaderData.doc);
2913     loaderData.doc = nullptr;
2914     loaderData.stack.reset();
2915
2916     clear();
2917
2918     return true;
2919 }
2920
2921
2922 unique_ptr<Paint> SvgLoader::paint()
2923 {
2924     this->done();
2925     if (root) return move(root);
2926     else return nullptr;
2927 }