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