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