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