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