1 /**
2  * @file lv_svg_parser.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_svg_parser.h"
10 #if LV_USE_SVG
11 
12 #include "../../../lvgl.h"
13 #include <ctype.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <math.h>
17 
18 /*********************
19 *      DEFINES
20 *********************/
21 #ifndef M_PI
22     #define M_PI 3.1415926f
23 #endif
24 
25 #define MAP_LEN(m) sizeof((m)) / sizeof((m[0]))
26 
27 #define CHECK_AND_RESIZE_ATTRS(a) \
28     do { \
29         if((lv_array_size(&(a)) + 1) > lv_array_capacity(&(a))) { \
30             lv_array_resize(&(a), (a).capacity << 1); \
31         } \
32     } while(0)
33 
34 /**********************
35 *      TYPEDEFS
36 **********************/
37 static const struct _lv_svg_tag_map {
38     const char * name;
39     uint32_t name_len;
40     lv_svg_tag_t tag;
41 } _svg_tag_map[] = {
42     {"svg", 3, LV_SVG_TAG_SVG},
43     {"use", 3, LV_SVG_TAG_USE},
44     {"g", 1, LV_SVG_TAG_G},
45     {"path", 4, LV_SVG_TAG_PATH},
46     {"rect", 4, LV_SVG_TAG_RECT},
47     {"circle", 6, LV_SVG_TAG_CIRCLE},
48     {"ellipse", 7, LV_SVG_TAG_ELLIPSE},
49     {"line", 4, LV_SVG_TAG_LINE},
50     {"polyline", 8, LV_SVG_TAG_POLYLINE},
51     {"polygon", 7, LV_SVG_TAG_POLYGON},
52     {"solidColor", 10, LV_SVG_TAG_SOLID_COLOR},
53     {"linearGradient", 14, LV_SVG_TAG_LINEAR_GRADIENT},
54     {"radialGradient", 14, LV_SVG_TAG_RADIAL_GRADIENT},
55     {"stop", 4, LV_SVG_TAG_STOP},
56     {"defs", 4, LV_SVG_TAG_DEFS},
57     {"image", 5, LV_SVG_TAG_IMAGE},
58 #if LV_USE_SVG_ANIMATION
59     {"mpath", 5, LV_SVG_TAG_MPATH},
60     {"set", 3, LV_SVG_TAG_SET},
61     {"animate", 7, LV_SVG_TAG_ANIMATE},
62     {"animateColor", 12, LV_SVG_TAG_ANIMATE_COLOR},
63     {"animateTransform", 16, LV_SVG_TAG_ANIMATE_TRANSFORM},
64     {"animateMotion", 13, LV_SVG_TAG_ANIMATE_MOTION},
65 #endif
66     {"text", 4, LV_SVG_TAG_TEXT},
67     {"tspan", 5, LV_SVG_TAG_TSPAN},
68     {"textArea", 8, LV_SVG_TAG_TEXT_AREA},
69 };
70 
71 static const struct _lv_svg_attr_map {
72     const char * name;
73     uint32_t name_len;
74     lv_svg_attr_type_t attr;
75 } _svg_attr_map[] = {
76     {"id", 2, LV_SVG_ATTR_ID},
77     {"xml:id", 6, LV_SVG_ATTR_XML_ID},
78     {"version", 7, LV_SVG_ATTR_VERSION},
79     {"baseProfile", 11, LV_SVG_ATTR_BASE_PROFILE},
80     {"viewBox", 7, LV_SVG_ATTR_VIEWBOX},
81     {"preserveAspectRatio", 19, LV_SVG_ATTR_PRESERVE_ASPECT_RATIO},
82     {"viewport-fill", 13, LV_SVG_ATTR_VIEWPORT_FILL},
83     {"viewport-fill-opacity", 21, LV_SVG_ATTR_VIEWPORT_FILL_OPACITY},
84     {"display", 7, LV_SVG_ATTR_DISPLAY},
85     {"visibility", 10, LV_SVG_ATTR_VISIBILITY},
86     {"x", 1, LV_SVG_ATTR_X},
87     {"y", 1, LV_SVG_ATTR_Y},
88     {"width", 5, LV_SVG_ATTR_WIDTH},
89     {"height", 6, LV_SVG_ATTR_HEIGHT},
90     {"rx", 2, LV_SVG_ATTR_RX},
91     {"ry", 2, LV_SVG_ATTR_RY},
92     {"cx", 2, LV_SVG_ATTR_CX},
93     {"cy", 2, LV_SVG_ATTR_CY},
94     {"r", 1, LV_SVG_ATTR_R},
95     {"x1", 2, LV_SVG_ATTR_X1},
96     {"y1", 2, LV_SVG_ATTR_Y1},
97     {"x2", 2, LV_SVG_ATTR_X2},
98     {"y2", 2, LV_SVG_ATTR_Y2},
99     {"points", 6, LV_SVG_ATTR_POINTS},
100     {"d", 1, LV_SVG_ATTR_D},
101     {"pathLength", 10, LV_SVG_ATTR_PATH_LENGTH},
102     {"xlink:href", 10, LV_SVG_ATTR_XLINK_HREF},
103     {"fill", 4, LV_SVG_ATTR_FILL},
104     {"fill-rule", 9, LV_SVG_ATTR_FILL_RULE},
105     {"fill-opacity", 12, LV_SVG_ATTR_FILL_OPACITY},
106     {"stroke", 6, LV_SVG_ATTR_STROKE},
107     {"stroke-width", 12, LV_SVG_ATTR_STROKE_WIDTH},
108     {"stroke-linecap", 14, LV_SVG_ATTR_STROKE_LINECAP},
109     {"stroke-linejoin", 15, LV_SVG_ATTR_STROKE_LINEJOIN},
110     {"stroke-miterlimit", 17, LV_SVG_ATTR_STROKE_MITER_LIMIT},
111     {"stroke-dasharray", 16, LV_SVG_ATTR_STROKE_DASH_ARRAY},
112     {"stroke-dashoffset", 17, LV_SVG_ATTR_STROKE_DASH_OFFSET},
113     {"stroke-opacity", 14, LV_SVG_ATTR_STROKE_OPACITY},
114     {"opacity", 7, LV_SVG_ATTR_OPACITY},
115     {"solid-color", 11, LV_SVG_ATTR_SOLID_COLOR},
116     {"solid-opacity", 13, LV_SVG_ATTR_SOLID_OPACITY},
117     {"gradientUnits", 13, LV_SVG_ATTR_GRADIENT_UNITS},
118     {"offset", 6, LV_SVG_ATTR_GRADIENT_STOP_OFFSET},
119     {"stop-color", 10, LV_SVG_ATTR_GRADIENT_STOP_COLOR},
120     {"stop-opacity", 12, LV_SVG_ATTR_GRADIENT_STOP_OPACITY},
121     {"font-family", 11, LV_SVG_ATTR_FONT_FAMILY},
122     {"font-style", 10, LV_SVG_ATTR_FONT_STYLE},
123     {"font-variant", 12, LV_SVG_ATTR_FONT_VARIANT},
124     {"font-weight", 11, LV_SVG_ATTR_FONT_WEIGHT},
125     {"font-size", 9, LV_SVG_ATTR_FONT_SIZE},
126     {"transform", 9, LV_SVG_ATTR_TRANSFORM},
127     {"text-anchor", 11, LV_SVG_ATTR_TEXT_ANCHOR},
128 #if LV_USE_SVG_ANIMATION
129     {"attributeName", 13, LV_SVG_ATTR_ATTRIBUTE_NAME},
130     {"attributeType", 13, LV_SVG_ATTR_ATTRIBUTE_TYPE},
131     {"begin", 5, LV_SVG_ATTR_BEGIN},
132     {"end", 3, LV_SVG_ATTR_END},
133     {"dur", 3, LV_SVG_ATTR_DUR},
134     {"min", 3, LV_SVG_ATTR_MIN},
135     {"max", 3, LV_SVG_ATTR_MAX},
136     {"restart", 7, LV_SVG_ATTR_RESTART},
137     {"repeatCount", 11, LV_SVG_ATTR_REPEAT_COUNT},
138     {"repeatDur", 9, LV_SVG_ATTR_REPEAT_DUR},
139     {"calcMode", 8, LV_SVG_ATTR_CALC_MODE},
140     {"values", 6, LV_SVG_ATTR_VALUES},
141     {"keyTimes", 8, LV_SVG_ATTR_KEY_TIMES},
142     {"keySplines", 10, LV_SVG_ATTR_KEY_SPLINES},
143     {"keyPoints", 9, LV_SVG_ATTR_KEY_POINTS},
144     {"from", 4, LV_SVG_ATTR_FROM},
145     {"to", 2, LV_SVG_ATTR_TO},
146     {"by", 2, LV_SVG_ATTR_BY},
147     {"additive", 8, LV_SVG_ATTR_ADDITIVE},
148     {"accumulate", 10, LV_SVG_ATTR_ACCUMULATE},
149     {"path", 4, LV_SVG_ATTR_PATH},
150     {"rotate", 6, LV_SVG_ATTR_ROTATE},
151     {"type", 4, LV_SVG_ATTR_TRANSFORM_TYPE},
152 #endif
153 };
154 
155 static const struct _lv_svg_attr_aspect_ratio_map {
156     const char * name;
157     uint32_t align;
158 } _svg_attr_aspect_ratio_map[] = {
159     {"xMinYMin", LV_SVG_ASPECT_RATIO_XMIN_YMIN},
160     {"xMidYMin", LV_SVG_ASPECT_RATIO_XMID_YMIN},
161     {"xMaxYMin", LV_SVG_ASPECT_RATIO_XMAX_YMIN},
162     {"xMinYMid", LV_SVG_ASPECT_RATIO_XMIN_YMID},
163     {"xMidYMid", LV_SVG_ASPECT_RATIO_XMID_YMID},
164     {"xMaxYMid", LV_SVG_ASPECT_RATIO_XMAX_YMID},
165     {"xMinYMax", LV_SVG_ASPECT_RATIO_XMIN_YMAX},
166     {"xMidYMax", LV_SVG_ASPECT_RATIO_XMID_YMAX},
167     {"xMaxYMax", LV_SVG_ASPECT_RATIO_XMAX_YMAX},
168 };
169 
170 static const struct _lv_svg_color_map {
171     const char * name;
172     uint32_t name_len;
173     uint32_t color;
174 } _svg_color_map[] = {
175     {"aliceblue", 9, 0xf0f8ff},
176     {"antiquewhite", 12, 0xfaebd7},
177     {"aqua", 4, 0x00ffff},
178     {"aquamarine", 10, 0x7fffd4},
179     {"azure", 5, 0xf0ffff},
180     {"beige", 5, 0xf5f5dc},
181     {"bisque", 6, 0xffe4c4},
182     {"black", 5, 0x000000},
183     {"blanchedalmond", 14, 0xffebcd},
184     {"blue", 4, 0x0000ff},
185     {"blueviolet", 10, 0x8a2be2},
186     {"brown", 5, 0xa52a2a},
187     {"burlywood", 9, 0xdeb887},
188     {"cadetblue", 9, 0x5f9ea0},
189     {"chartreuse", 10, 0x7fff00},
190     {"chocolate", 9, 0xd2691e},
191     {"coral", 5, 0xff7f50},
192     {"cornflowerblue", 14, 0x6495ed},
193     {"cornsilk", 8, 0xfff8dc},
194     {"crimson", 7, 0xdc143c},
195     {"cyan", 4, 0x00ffff},
196     {"darkblue", 8, 0x00008b},
197     {"darkcyan", 8, 0x008b8b},
198     {"darkgoldenrod", 13, 0xb8860b},
199     {"darkgray", 8, 0xa9a9a9},
200     {"darkgrey", 8, 0xa9a9a9},
201     {"darkgreen", 9, 0x006400},
202     {"darkkhaki", 9, 0xbdb76b},
203     {"darkmagenta", 11, 0x8b008b},
204     {"darkolivegreen", 14, 0x556b2f},
205     {"darkorange", 10, 0xff8c00},
206     {"darkorchid", 10, 0x9932cc},
207     {"darkred", 7, 0x8b0000},
208     {"darksalmon", 10, 0xe9967a},
209     {"darkseagreen", 12, 0x8fbc8f},
210     {"darkslateblue", 13, 0x483d8b},
211     {"darkslategray", 13, 0x2f4f4f},
212     {"darkslategrey", 13, 0x2f4f4f},
213     {"darkturquoise", 13, 0x00ced1},
214     {"darkviolet", 10, 0x9400d3},
215     {"deeppink", 8, 0xff1493},
216     {"deepskyblue", 11, 0x00bfff},
217     {"dimgray", 7, 0x696969},
218     {"dimgrey", 7, 0x696969},
219     {"dodgerblue", 10, 0x1e90ff},
220     {"firebrick", 9, 0xb22222},
221     {"floralwhite", 11, 0xfffaf0},
222     {"forestgreen", 11, 0x228b22},
223     {"fuchsia", 7, 0xff00ff},
224     {"gainsboro", 9, 0xdcdcdc},
225     {"ghostwhite", 10, 0xf8f8ff},
226     {"gold", 4, 0xffd700},
227     {"goldenrod", 9, 0xdaa520},
228     {"gray", 4, 0x808080},
229     {"grey", 4, 0x808080},
230     {"green", 5, 0x008000},
231     {"greenyellow", 11, 0xadff2f},
232     {"honeydew", 8, 0xf0fff0},
233     {"hotpink", 7, 0xff69b4},
234     {"indianred", 9, 0xcd5c5c},
235     {"indigo", 6, 0x4b0082},
236     {"ivory", 5, 0xfffff0},
237     {"khaki", 5, 0xf0e68c},
238     {"lavender", 8, 0xe6e6fa},
239     {"lavenderblush", 13, 0xfff0f5},
240     {"lawngreen", 9, 0x7cfc00},
241     {"lemonchiffon", 12, 0xfffacd},
242     {"lightblue", 9, 0xadd8e6},
243     {"lightcoral", 10, 0xf08080},
244     {"lightcyan", 9, 0xe0ffff},
245     {"lightgoldenrodyellow", 20, 0xfafad2},
246     {"lightgray", 9, 0xd3d3d3},
247     {"lightgrey", 9, 0xd3d3d3},
248     {"lightgreen", 10, 0x90ee90},
249     {"lightpink", 9, 0xffb6c1},
250     {"lightsalmon", 11, 0xffa07a},
251     {"lightseagreen", 13, 0x20b2aa},
252     {"lightskyblue", 12, 0x87cefa},
253     {"lightslategray", 14, 0x778899},
254     {"lightslategrey", 14, 0x778899},
255     {"lightsteelblue", 14, 0xb0c4de},
256     {"lightyellow", 11, 0xffffe0},
257     {"lime", 4, 0x00ff00},
258     {"limegreen", 9, 0x32cd32},
259     {"linen", 5, 0xfaf0e6},
260     {"magenta", 7, 0xff00ff},
261     {"maroon", 6, 0x800000},
262     {"mediumaquamarine", 16, 0x66cdaa},
263     {"mediumblue", 10, 0x0000cd},
264     {"mediumorchid", 12, 0xba55d3},
265     {"mediumpurple", 12, 0x9370d8},
266     {"mediumseagreen", 14, 0x3cb371},
267     {"mediumslateblue", 15, 0x7b68ee},
268     {"mediumspringgreen", 17, 0x00fa9a},
269     {"mediumturquoise", 15, 0x48d1cc},
270     {"mediumvioletred", 15, 0xc71585},
271     {"midnightblue", 12, 0x191970},
272     {"mintcream", 9, 0xf5fffa},
273     {"mistyrose", 9, 0xffe4e1},
274     {"moccasin", 8, 0xffe4b5},
275     {"navajowhite", 11, 0xffdead},
276     {"navy", 4, 0x000080},
277     {"oldlace", 7, 0xfdf5e6},
278     {"olive", 5, 0x808000},
279     {"olivedrab", 9, 0x6b8e23},
280     {"orange", 6, 0xffa500},
281     {"orangered", 9, 0xff4500},
282     {"orchid", 6, 0xda70d6},
283     {"palegoldenrod", 13, 0xeee8aa},
284     {"palegreen", 9, 0x98fb98},
285     {"paleturquoise", 13, 0xafeeee},
286     {"palevioletred", 13, 0xd87093},
287     {"papayawhip", 10, 0xffefd5},
288     {"peachpuff", 9, 0xffdab9},
289     {"peru", 4, 0xcd853f},
290     {"pink", 4, 0xffc0cb},
291     {"plum", 4, 0xdda0dd},
292     {"powderblue", 10, 0xb0e0e6},
293     {"purple", 6, 0x800080},
294     {"red", 3, 0xff0000},
295     {"rosybrown", 9, 0xbc8f8f},
296     {"royalblue", 9, 0x4169e1},
297     {"saddlebrown", 11, 0x8b4513},
298     {"salmon", 6, 0xfa8072},
299     {"sandybrown", 10, 0xf4a460},
300     {"seagreen", 8, 0x2e8b57},
301     {"seashell", 8, 0xfff5ee},
302     {"sienna", 6, 0xa0522d},
303     {"silver", 6, 0xc0c0c0},
304     {"skyblue", 7, 0x87ceeb},
305     {"slateblue", 9, 0x6a5acd},
306     {"slategray", 9, 0x708090},
307     {"slategrey", 9, 0x708090},
308     {"snow", 4, 0xfffafa},
309     {"springgreen", 11, 0x00ff7f},
310     {"steelblue", 9, 0x4682b4},
311     {"tan", 3, 0xd2b48c},
312     {"teal", 4, 0x008080},
313     {"thistle", 7, 0xd8bfd8},
314     {"tomato", 6, 0xff6347},
315     {"turquoise", 9, 0x40e0d0},
316     {"violet", 6, 0xee82ee},
317     {"wheat", 5, 0xf5deb3},
318     {"white", 5, 0xffffff},
319     {"whitesmoke", 10, 0xf5f5f5},
320     {"yellow", 6, 0xffff00},
321     {"yellowgreen", 11, 0x9acd32},
322 };
323 
324 /**********************
325  *  STATIC PROTOTYPES
326  **********************/
327 
_get_svg_tag_type(const _lv_svg_token_t * token)328 static lv_svg_tag_t _get_svg_tag_type(const _lv_svg_token_t * token)
329 {
330     uint32_t len = MAP_LEN(_svg_tag_map);
331     uint32_t token_len = SVG_TOKEN_LEN(token);
332 
333     for(uint32_t i = 0; i < len; i++) {
334         if(token_len == _svg_tag_map[i].name_len && strncmp(_svg_tag_map[i].name, token->start, token_len) == 0) {
335             return _svg_tag_map[i].tag;
336         }
337     }
338     return LV_SVG_TAG_INVALID;
339 }
340 
_process_end_tag(_lv_svg_parser_t * parser,lv_svg_tag_t tag,const _lv_svg_token_t * token)341 static bool _process_end_tag(_lv_svg_parser_t * parser, lv_svg_tag_t tag, const _lv_svg_token_t * token)
342 {
343     if(parser->state == LV_SVG_PARSER_IGNORE) {
344         uint32_t len = SVG_TOKEN_LEN(token);
345         if((parser->ignore_len == len) && strncmp(parser->ignore_name, token->start, len) == 0) {
346             parser->state = LV_SVG_PARSER_PROCESS;
347             lv_free(parser->ignore_name);
348             parser->ignore_name = NULL;
349             parser->ignore_len = 0;
350         }
351         return true;
352     }
353 
354     if(parser->cur_node->type != tag) {
355         LV_LOG_ERROR("svg tag does not match in pairs!");
356         return false;
357     }
358 
359     if(parser->cur_node != parser->doc_root) {
360         parser->cur_node = (lv_svg_node_t *)LV_TREE_NODE(parser->cur_node)->parent;
361     }
362     return true;
363 }
364 
_get_svg_attr_type(const char * attr_start,const char * attr_end)365 static lv_svg_attr_type_t _get_svg_attr_type(const char * attr_start, const char * attr_end)
366 {
367     uint32_t len = MAP_LEN(_svg_attr_map);
368     uint32_t attr_len = attr_end - attr_start;
369 
370     for(uint32_t i = 0; i < len; i++) {
371         if(attr_len == _svg_attr_map[i].name_len && strncmp(_svg_attr_map[i].name, attr_start, attr_len) == 0) {
372             return _svg_attr_map[i].attr;
373         }
374     }
375     return LV_SVG_ATTR_INVALID;
376 }
377 
_process_string(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)378 static void _process_string(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start, const char * val_end)
379 {
380     CHECK_AND_RESIZE_ATTRS(node->attrs);
381 
382     node->attrs.size++;
383     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
384     attr->id = type;
385     attr->val_type = LV_SVG_ATTR_VALUE_PTR;
386     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
387 
388     uint32_t len = val_end - val_start;
389     char * str = lv_malloc(len + 1);
390     LV_ASSERT_MALLOC(str);
391     lv_memcpy(str, val_start, len);
392     str[len] = '\0';
393     attr->value.sval = str;
394 }
395 
_process_xlink(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)396 static void _process_xlink(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start, const char * val_end)
397 {
398     CHECK_AND_RESIZE_ATTRS(node->attrs);
399 
400     node->attrs.size++;
401     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
402     attr->id = type;
403     attr->val_type = LV_SVG_ATTR_VALUE_PTR;
404     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
405 
406     if(*val_start == '#') {
407         val_start++;
408     }
409 
410     uint32_t len = val_end - val_start;
411     char * str = lv_malloc(len + 1);
412     LV_ASSERT_MALLOC(str);
413     lv_memcpy(str, val_start, len);
414     str[len] = '\0';
415     attr->value.sval = str;
416 }
417 
_is_number_begin(char ch)418 static bool _is_number_begin(char ch)
419 {
420     return ch != 0 && strchr("0123456789+-.", ch) != NULL;
421 }
422 
_skip_space(const char * str,const char * str_end)423 static const char * _skip_space(const char * str, const char * str_end)
424 {
425     while((str < str_end) && isspace(*str)) {
426         ++str;
427     }
428     return str;
429 }
430 
_is_separators(char c)431 static bool _is_separators(char c)
432 {
433     return  c == ',' || c == '\t' || c == '\n' || c == '\r';
434 }
435 
_skip_space_and_separators(const char * str,const char * str_end)436 static const char * _skip_space_and_separators(const char * str, const char * str_end)
437 {
438     while((str < str_end) && (isspace(*str) || _is_separators(*str))) {
439         ++str;
440     }
441     return str;
442 }
443 
_parse_number(const char * str,const char * str_end,float * val)444 static const char * _parse_number(const char * str, const char * str_end, float * val)
445 {
446     if(!str) {
447         return NULL;
448     }
449     // skip loading
450     while((str < str_end) && !_is_number_begin(*str)) {
451         ++str;
452     }
453 
454     if(str == str_end) { // parse fail
455         return NULL;
456     }
457 
458     char * end = NULL;
459     *val = strtof(str, &end);
460     return end;
461 }
462 
_parse_length(const char * str,const char * str_end,int32_t dpi,float * val)463 static const char * _parse_length(const char * str, const char * str_end, int32_t dpi, float * val)
464 {
465     str = _parse_number(str, str_end, val);
466     if(str) {
467         uint32_t len = str_end - str;
468         if(len > 0) {
469             if(len == 1 && (*str == '%')) {
470                 // percentage
471                 *val *= 0.01f;
472             }
473             else if(len == 2) {
474                 if(str[0] == 'p' && str[1] == 't') { // pt
475                     *val = *val / 72.0f * (float)dpi;
476                 }
477                 else if(str[0] == 'p' && str[1] == 'c') {   // pc
478                     *val = *val / 6.0f * (float)dpi;
479                 }
480                 else if(str[0] == 'i' && str[1] == 'n') {   // in
481                     *val = *val * (float)dpi;
482                 }
483                 else if(str[0] == 'm' && str[1] == 'm') {   // mm
484                     *val = *val / 25.4f * (float)dpi;
485                 }
486                 else if(str[0] == 'c' && str[1] == 'm') {   // cm
487                     *val = *val / 2.54f * (float)dpi;
488                 }
489                 else if(str[0] == 'e' && str[1] == 'm') {   // em
490                     *val = *val * 16.0f; // FIXME: browser default font size
491                 }
492                 else if(str[0] == 'e' && str[1] == 'x') {   // ex
493                     *val = *val * 16.0f * 0.52f;
494                 }
495             }
496         }
497         str += len;
498     }
499     return str;
500 }
501 
_parse_color(const char * str,const char * str_end,uint32_t * val)502 static const char * _parse_color(const char * str, const char * str_end, uint32_t * val)
503 {
504     if(!str) {
505         return NULL;
506     }
507 
508     const char * ptr = str;
509     while((ptr < str_end) && (*ptr != ')')) { // calc letters end
510         ++ptr;
511     }
512 
513     uint32_t len = ptr - str;
514     uint8_t r = 0, g = 0, b = 0;
515 
516     if(*str == '#') {
517         if(len == 4) { // three digit hex format '#rgb'
518             if(isxdigit(str[1]) && isxdigit(str[2]) && isxdigit(str[3])) {
519                 char st[3] = {0};
520                 st[0] = st[1] = str[1];
521                 r = (uint8_t)strtol(st, NULL, 16);
522                 st[0] = st[1] = str[2];
523                 g = (uint8_t)strtol(st, NULL, 16);
524                 st[0] = st[1] = str[3];
525                 b = (uint8_t)strtol(st, NULL, 16);
526             }
527         }
528         else if(len == 7) {    // six digit hex format '#rrggbb'
529             if(isxdigit(str[1]) && isxdigit(str[2]) && isxdigit(str[3])
530                && isxdigit(str[4]) && isxdigit(str[5]) && isxdigit(str[6])) {
531                 char st[3] = {0};
532                 st[0] = str[1];
533                 st[1] = str[2];
534                 r = (uint8_t)strtol(st, NULL, 16);
535                 st[0] = str[3];
536                 st[1] = str[4];
537                 g = (uint8_t)strtol(st, NULL, 16);
538                 st[0] = str[5];
539                 st[1] = str[6];
540                 b = (uint8_t)strtol(st, NULL, 16);
541             }
542         }
543         // make color
544         *val = (r << 16) + (g << 8) + b;
545     }
546     else if(len > 4 && strncmp(str, "rgb(", 4) == 0) {
547         str += 4;
548         bool valid_color = true;
549         float vals[3] = {0};
550 
551         for(int i = 0; i < 3; i++) {
552             str = _parse_number(str, ptr, &vals[i]);
553             if(!str) valid_color = false;
554 
555             if(*str == '%') {
556                 vals[i] *= 2.56f;
557             }
558         }
559 
560         if(valid_color) {
561             r = (uint8_t)vals[0];
562             g = (uint8_t)vals[1];
563             b = (uint8_t)vals[2];
564         }
565         // make color
566         *val = (r << 16) + (g << 8) + b;
567     }
568     else {   // color keyword
569         uint32_t map_len = MAP_LEN(_svg_color_map);
570         for(uint32_t i = 0; i < map_len; i++) {
571             if(len == _svg_color_map[i].name_len && strncmp(_svg_color_map[i].name, str, len) == 0) {
572                 *val = _svg_color_map[i].color;
573             }
574         }
575     }
576     return ++ptr;
577 }
578 
_multiply_matrix(lv_svg_matrix_t * matrix,const lv_svg_matrix_t * mul)579 static void _multiply_matrix(lv_svg_matrix_t * matrix, const lv_svg_matrix_t * mul)
580 {
581     // TODO: use NEON to optimize this function on ARM architecture.
582     lv_svg_matrix_t tmp;
583 
584     for(int y = 0; y < 3; y++) {
585         for(int x = 0; x < 3; x++) {
586             tmp.m[y][x] = (matrix->m[y][0] * mul->m[0][x])
587                           + (matrix->m[y][1] * mul->m[1][x])
588                           + (matrix->m[y][2] * mul->m[2][x]);
589         }
590     }
591 
592     lv_memcpy(matrix, &tmp, sizeof(lv_svg_matrix_t));
593 }
594 
_parse_matrix(const char * str,const char * str_end,lv_svg_transform_type_t type,lv_svg_matrix_t * matrix)595 static const char * _parse_matrix(const char * str, const char * str_end, lv_svg_transform_type_t type,
596                                   lv_svg_matrix_t * matrix)
597 {
598     // skip loading
599     while((str < str_end) && *str != '(') {
600         ++str;
601     }
602 
603     if(str == str_end) { // parse fail
604         return str;
605     }
606 
607     const char * ptr = str;
608     switch(type) {
609         case LV_SVG_TRANSFORM_TYPE_MATRIX: {
610                 float vals[6] = {0};
611                 for(int i = 0; i < 6; i++) {
612                     ptr = _parse_number(ptr, str_end, &vals[i]);
613                     if(!ptr) return str;
614                     str = ptr;
615                 }
616 
617                 lv_svg_matrix_t mt = {{
618                         {vals[0], vals[2], vals[4]},
619                         {vals[1], vals[3], vals[5]},
620                         {0.0f, 0.0f, 1.0f},
621                     }
622                 };
623 
624                 _multiply_matrix(matrix, &mt);
625             }
626             break;
627         case LV_SVG_TRANSFORM_TYPE_TRANSLATE: {
628                 float tx = 0.0f, ty = 0.0f;
629                 ptr = _parse_number(ptr, str_end, &tx);
630                 if(!ptr) return str;
631                 str = ptr;
632 
633                 ptr = _skip_space(ptr, str_end);
634                 if(*ptr != ')') {
635                     ptr = _parse_number(ptr, str_end, &ty);
636                     if(ptr) str = ptr;
637                 }
638 
639                 lv_svg_matrix_t tlm = {{
640                         {1.0f, 0.0f, tx},
641                         {0.0f, 1.0f, ty},
642                         {0.0f, 0.0f, 1.0f},
643                     }
644                 };
645 
646                 _multiply_matrix(matrix, &tlm);
647             }
648             break;
649         case LV_SVG_TRANSFORM_TYPE_ROTATE: {
650                 float degree = 0.0f, cx = 0.0f, cy = 0.0f;
651                 bool trans = false;
652 
653                 ptr = _parse_number(ptr, str_end, &degree);
654                 if(!ptr) return str;
655                 str = ptr;
656 
657                 ptr = _skip_space(ptr, str_end);
658                 if(*ptr != ')') {
659                     ptr = _parse_number(ptr, str_end, &cx);
660                     ptr = _parse_number(ptr, str_end, &cy);
661                     if(ptr) {
662                         trans = true;
663                         str = ptr;
664                     }
665                 }
666 
667                 float radian = degree / 180.0f * (float)M_PI;
668                 float cos_r = cosf(radian);
669                 float sin_r = sinf(radian);
670 
671                 lv_svg_matrix_t rtm = {{
672                         {cos_r, -sin_r, 0.0f},
673                         {sin_r, cos_r, 0.0f},
674                         {0.0f, 0.0f, 1.0f},
675                     }
676                 };
677 
678                 if(!trans) {
679                     _multiply_matrix(matrix, &rtm);
680                 }
681                 else {
682                     lv_svg_matrix_t tlm = {{
683                             {1.0f, 0.0f, cx},
684                             {0.0f, 1.0f, cy},
685                             {0.0f, 0.0f, 1.0f},
686                         }
687                     };
688 
689                     _multiply_matrix(matrix, &tlm);
690                     _multiply_matrix(matrix, &rtm);
691 
692                     tlm.m[0][2] = -cx;
693                     tlm.m[1][2] = -cy;
694                     _multiply_matrix(matrix, &tlm);
695                 }
696             }
697             break;
698         case LV_SVG_TRANSFORM_TYPE_SCALE: {
699                 float sx = 0.0f, sy = 0.0f;
700                 ptr = _parse_number(ptr, str_end, &sx);
701                 if(!ptr) return str;
702                 str = ptr;
703 
704                 sy = sx;
705 
706                 ptr = _skip_space(ptr, str_end);
707                 if(*ptr != ')') {
708                     ptr = _parse_number(ptr, str_end, &sy);
709                     if(ptr) str = ptr;
710                 }
711 
712                 lv_svg_matrix_t scm = {{
713                         {sx, 0.0f, 0.0f},
714                         {0.0f, sy, 0.0f},
715                         {0.0f, 0.0f, 1.0f},
716                     }
717                 };
718 
719                 _multiply_matrix(matrix, &scm);
720             }
721             break;
722         case LV_SVG_TRANSFORM_TYPE_SKEW_X: {
723                 float degree = 0.0f;
724                 ptr = _parse_number(ptr, str_end, &degree);
725                 if(!ptr) return str;
726                 str = ptr;
727 
728                 float radian = degree / 180.0f * (float)M_PI;
729                 float tan = tanf(radian);
730 
731                 lv_svg_matrix_t skm = {{
732                         {1.0f, tan, 0.0f},
733                         {0.0f, 1.0f, 0.0f},
734                         {0.0f, 0.0f, 1.0f},
735                     }
736                 };
737 
738                 _multiply_matrix(matrix, &skm);
739             }
740             break;
741         case LV_SVG_TRANSFORM_TYPE_SKEW_Y: {
742                 float degree = 0.0f;
743                 ptr = _parse_number(ptr, str_end, &degree);
744                 if(!ptr) return str;
745                 str = ptr;
746 
747                 float radian = degree / 180.0f * (float)M_PI;
748                 float tan = tanf(radian);
749 
750                 lv_svg_matrix_t skm = {{
751                         {1.0f, 0.0f, 0.0f},
752                         {tan, 1.0f, 0.0f},
753                         {0.0f, 0.0f, 1.0f},
754                     }
755                 };
756 
757                 _multiply_matrix(matrix, &skm);
758             }
759             break;
760     }
761     return str;
762 }
763 
_process_view_box(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)764 static void _process_view_box(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
765                               const char * val_end)
766 {
767     CHECK_AND_RESIZE_ATTRS(node->attrs);
768 
769     node->attrs.size++;
770     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
771     attr->id = type;
772     attr->val_type = LV_SVG_ATTR_VALUE_PTR;
773     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
774 
775     uint32_t len = val_end - val_start;
776     if(len >= 4 && strncmp(val_start, "none", 4) == 0) {
777         attr->val_type = LV_SVG_ATTR_VALUE_DATA;
778         attr->class_type = LV_SVG_ATTR_VALUE_NONE;
779         return;
780     }
781 
782     float * vals = lv_malloc_zeroed(sizeof(float) * 4);
783     LV_ASSERT_MALLOC(vals);
784     const char * ptr = val_start;
785     for(int i = 0; i < 4; i++) {
786         ptr = _parse_number(ptr, val_end, &vals[i]);
787         if(!ptr) {
788             attr->val_type = LV_SVG_ATTR_VALUE_DATA;
789             attr->class_type = LV_SVG_ATTR_VALUE_NONE;
790             lv_free(vals);
791             return;
792         }
793     }
794     attr->value.val = vals;
795 }
796 
_process_points_value(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)797 static void _process_points_value(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
798                                   const char * val_end)
799 {
800     CHECK_AND_RESIZE_ATTRS(node->attrs);
801 
802     node->attrs.size++;
803     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
804     attr->id = type;
805     attr->val_type = LV_SVG_ATTR_VALUE_PTR;
806     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
807 
808     uint32_t list_cap = 4;
809     lv_svg_attr_values_list_t * list = lv_malloc(sizeof(lv_svg_point_t) * list_cap + sizeof(uint32_t));
810     LV_ASSERT_MALLOC(list);
811 
812     float val_number = 0.0f;
813     const char * ptr = val_start;
814     uint32_t point_cnt = 0;
815 
816     while(ptr < val_end) {
817         if(point_cnt == list_cap) {
818             list_cap = list_cap << 1;
819             list = (lv_svg_attr_values_list_t *)lv_realloc(list, sizeof(lv_svg_point_t) * list_cap + sizeof(uint32_t));
820             LV_ASSERT_MALLOC(list);
821         }
822         lv_svg_point_t * pt = (lv_svg_point_t *)(&list->data) + point_cnt;
823         val_number = 0.0f;
824         ptr = _parse_number(ptr, val_end, &val_number);
825         pt->x = val_number;
826         val_number = 0.0f;
827         ptr = _parse_number(ptr, val_end, &val_number);
828         pt->y = val_number;
829         if(!ptr) break;
830         ++point_cnt;
831     }
832 
833     list->length = point_cnt;
834     attr->value.val = list;
835 }
836 
_get_path_point_count(char cmd)837 static int _get_path_point_count(char cmd)
838 {
839     switch(cmd) {
840         case 'M':
841         case 'm':
842         case 'L':
843         case 'l':
844         case 'H':
845         case 'h':
846         case 'V':
847         case 'v':
848         case 'Z':
849         case 'z':
850             return 1;
851         case 'C':
852         case 'c':
853         case 'S':
854         case 's':
855             return 3;
856         case 'Q':
857         case 'q':
858         case 'T':
859         case 't':
860             return 2;
861         default:
862             return 0;
863     }
864 }
865 
_is_relative_cmd(char cmd)866 static bool _is_relative_cmd(char cmd)
867 {
868     switch(cmd) {
869         case 'm':
870         case 'l':
871         case 'h':
872         case 'v':
873         case 'c':
874         case 's':
875         case 'q':
876         case 't':
877         case 'z':
878             return true;
879         case 'M':
880         case 'L':
881         case 'H':
882         case 'V':
883         case 'C':
884         case 'S':
885         case 'Q':
886         case 'T':
887         case 'Z':
888         default:
889             return false;
890     }
891 }
892 
_is_path_cmd(char ch)893 static bool _is_path_cmd(char ch)
894 {
895     return ch != 0 && strchr("MLHVCSQTZmlhvcsqtz", ch) != NULL;
896 }
897 
_process_path_value(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)898 static void _process_path_value(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
899                                 const char * val_end)
900 {
901     CHECK_AND_RESIZE_ATTRS(node->attrs);
902 
903     node->attrs.size++;
904     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
905     attr->id = type;
906     attr->val_type = LV_SVG_ATTR_VALUE_PTR;
907     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
908 
909     uint32_t list_cap = 4;
910     uint32_t list_size = sizeof(lv_svg_point_t) * list_cap + sizeof(uint32_t) * list_cap + sizeof(uint32_t);
911     lv_svg_attr_values_list_t * list = lv_malloc(list_size);
912     LV_ASSERT_MALLOC(list);
913 
914     uint32_t cmd_cnt = 0;
915     uint32_t cur_size = 0;
916     char cur_cmd = 0;
917     lv_svg_point_t cur_point = {0, 0};
918     lv_svg_point_t cur_ctrlPoint = {0, 0};
919     lv_svg_point_t first_point = {0, 0};
920 
921     const char * ptr = val_start;
922     uint8_t * data_ptr = (uint8_t *)(&list->data);
923 
924     while(ptr < val_end) {
925         ptr = _skip_space_and_separators(ptr, val_end);
926         if(ptr == val_end) break;
927 
928         char ch = *ptr;
929         if(_is_number_begin(ch)) {
930             if(cur_cmd != 0) {
931                 if(cur_cmd == 'M') {
932                     ch = 'L';
933                 }
934                 else if(cur_cmd == 'm') {
935                     ch = 'l';
936                 }
937                 else {
938                     ch = cur_cmd;
939                 }
940             }
941             else {
942                 break;
943             }
944         }
945         else if(_is_path_cmd(ch)) {
946             ++ptr;
947         }
948         else {
949             break;
950         }
951 
952         int point_count = _get_path_point_count(ch);
953         uint32_t mem_inc = sizeof(lv_svg_point_t) * point_count + sizeof(uint32_t);
954 
955         if((cur_size + mem_inc) > (list_size - sizeof(uint32_t))) {
956             list_cap = list_cap << 1;
957             list_size = sizeof(lv_svg_point_t) * list_cap + sizeof(uint32_t) * list_cap + sizeof(uint32_t);
958             list = (lv_svg_attr_values_list_t *)lv_realloc(list, list_size);
959             LV_ASSERT_MALLOC(list);
960         }
961 
962         data_ptr = (uint8_t *)(&list->data) + cur_size;
963         lv_svg_attr_path_value_t * path_seg = (lv_svg_attr_path_value_t *)data_ptr;
964 
965         bool relative = _is_relative_cmd(ch);
966 
967         switch(ch) {
968             case 'm':
969             case 'M': {
970                     lv_svg_point_t * point = (lv_svg_point_t *)(&path_seg->data);
971                     float xval = 0.0f;
972                     ptr = _parse_number(ptr, val_end, &xval);
973                     float yval = 0.0f;
974                     ptr = _parse_number(ptr, val_end, &yval);
975                     if(relative) {
976                         xval += cur_point.x;
977                         yval += cur_point.y;
978                     }
979                     path_seg->cmd = LV_SVG_PATH_CMD_MOVE_TO;
980                     point->x = xval;
981                     point->y = yval;
982                     cur_point.x = xval;
983                     cur_point.y = yval;
984                     first_point.x = xval;
985                     first_point.y = yval;
986                 }
987                 break;
988             case 'L':
989             case 'l': {
990                     lv_svg_point_t * point = (lv_svg_point_t *)(&path_seg->data);
991                     float xval = 0.0f;
992                     ptr = _parse_number(ptr, val_end, &xval);
993                     float yval = 0.0f;
994                     ptr = _parse_number(ptr, val_end, &yval);
995                     if(relative) {
996                         xval += cur_point.x;
997                         yval += cur_point.y;
998                     }
999                     path_seg->cmd = LV_SVG_PATH_CMD_LINE_TO;
1000                     point->x = xval;
1001                     point->y = yval;
1002                     cur_point.x = xval;
1003                     cur_point.y = yval;
1004                 }
1005                 break;
1006             case 'H':
1007             case 'h': {
1008                     lv_svg_point_t * point = (lv_svg_point_t *)(&path_seg->data);
1009                     float xval = 0.0f;
1010                     ptr = _parse_number(ptr, val_end, &xval);
1011                     if(relative) {
1012                         xval += cur_point.x;
1013                     }
1014                     path_seg->cmd = LV_SVG_PATH_CMD_LINE_TO;
1015                     point->x = xval;
1016                     point->y = cur_point.y;
1017                     cur_point.x = xval;
1018                 }
1019                 break;
1020             case 'V':
1021             case 'v': {
1022                     lv_svg_point_t * point = (lv_svg_point_t *)(&path_seg->data);
1023                     float yval = 0.0f;
1024                     ptr = _parse_number(ptr, val_end, &yval);
1025                     if(relative) {
1026                         yval += cur_point.y;
1027                     }
1028                     path_seg->cmd = LV_SVG_PATH_CMD_LINE_TO;
1029                     point->x = cur_point.x;
1030                     point->y = yval;
1031                     cur_point.y = yval;
1032                 }
1033                 break;
1034             case 'C':
1035             case 'c': {
1036                     lv_svg_point_t * point = (lv_svg_point_t *)(&path_seg->data);
1037                     for(int i = 0; i < 3; i++) {
1038                         float xval = 0.0f;
1039                         ptr = _parse_number(ptr, val_end, &xval);
1040                         float yval = 0.0f;
1041                         ptr = _parse_number(ptr, val_end, &yval);
1042                         if(relative) {
1043                             xval += cur_point.x;
1044                             yval += cur_point.y;
1045                         }
1046                         path_seg->cmd = LV_SVG_PATH_CMD_CURVE_TO;
1047                         point[i].x = xval;
1048                         point[i].y = yval;
1049                     }
1050 
1051                     cur_ctrlPoint.x = point[1].x;
1052                     cur_ctrlPoint.y = point[1].y;
1053                     cur_point.x = point[2].x;
1054                     cur_point.y = point[2].y;
1055                 }
1056                 break;
1057             case 'S':
1058             case 's': {
1059                     lv_svg_point_t * point = (lv_svg_point_t *)(&path_seg->data);
1060 
1061                     if(cur_cmd == 'C' || cur_cmd == 'c' || cur_cmd == 'S' || cur_cmd == 's') {
1062                         point[0].x = cur_point.x * 2 - cur_ctrlPoint.x;
1063                         point[0].y = cur_point.y * 2 - cur_ctrlPoint.y;
1064                     }
1065                     else {
1066                         point[0].x = cur_point.x;
1067                         point[0].y = cur_point.y;
1068                     }
1069 
1070                     for(int i = 1; i < 3; i++) {
1071                         float xval = 0.0f;
1072                         ptr = _parse_number(ptr, val_end, &xval);
1073                         float yval = 0.0f;
1074                         ptr = _parse_number(ptr, val_end, &yval);
1075                         if(relative) {
1076                             xval += cur_point.x;
1077                             yval += cur_point.y;
1078                         }
1079                         path_seg->cmd = LV_SVG_PATH_CMD_CURVE_TO;
1080                         point[i].x = xval;
1081                         point[i].y = yval;
1082                     }
1083 
1084                     cur_ctrlPoint.x = point[1].x;
1085                     cur_ctrlPoint.y = point[1].y;
1086                     cur_point.x = point[2].x;
1087                     cur_point.y = point[2].y;
1088                 }
1089                 break;
1090             case 'Q':
1091             case 'q': {
1092                     lv_svg_point_t * point = (lv_svg_point_t *)(&path_seg->data);
1093                     for(int i = 0; i < 2; i++) {
1094                         float xval = 0.0f;
1095                         ptr = _parse_number(ptr, val_end, &xval);
1096                         float yval = 0.0f;
1097                         ptr = _parse_number(ptr, val_end, &yval);
1098                         if(relative) {
1099                             xval += cur_point.x;
1100                             yval += cur_point.y;
1101                         }
1102                         path_seg->cmd = LV_SVG_PATH_CMD_QUAD_TO;
1103                         point[i].x = xval;
1104                         point[i].y = yval;
1105                     }
1106 
1107                     cur_ctrlPoint.x = point[0].x;
1108                     cur_ctrlPoint.y = point[0].y;
1109                     cur_point.x = point[1].x;
1110                     cur_point.y = point[1].y;
1111                 }
1112                 break;
1113             case 'T':
1114             case 't': {
1115                     lv_svg_point_t * point = (lv_svg_point_t *)(&path_seg->data);
1116                     if(cur_cmd == 'Q' || cur_cmd == 'q' || cur_cmd == 'T' || cur_cmd == 't') {
1117                         point[0].x = cur_point.x * 2 - cur_ctrlPoint.x;
1118                         point[0].y = cur_point.y * 2 - cur_ctrlPoint.y;
1119                     }
1120                     else {
1121                         point[0].x = cur_point.x;
1122                         point[0].y = cur_point.y;
1123                     }
1124 
1125                     for(int i = 1; i < 2; i++) {
1126                         float xval = 0.0f;
1127                         ptr = _parse_number(ptr, val_end, &xval);
1128                         float yval = 0.0f;
1129                         ptr = _parse_number(ptr, val_end, &yval);
1130                         if(relative) {
1131                             xval += cur_point.x;
1132                             yval += cur_point.y;
1133                         }
1134                         path_seg->cmd = LV_SVG_PATH_CMD_QUAD_TO;
1135                         point[i].x = xval;
1136                         point[i].y = yval;
1137                     }
1138 
1139                     cur_ctrlPoint.x = point[0].x;
1140                     cur_ctrlPoint.y = point[0].y;
1141                     cur_point.x = point[1].x;
1142                     cur_point.y = point[1].y;
1143                 }
1144                 break;
1145             case 'Z':
1146             case 'z': {
1147                     path_seg->cmd = LV_SVG_PATH_CMD_CLOSE;
1148                     cur_point.x = first_point.x;
1149                     cur_point.y = first_point.y;
1150                 }
1151                 break;
1152         }
1153 
1154         if(!ptr) break;
1155         cur_size += mem_inc;
1156         cur_cmd = ch;
1157         ++cmd_cnt;
1158     }
1159 
1160     list->length = cmd_cnt;
1161     attr->value.val = list;
1162 }
1163 
_process_gradient_units(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)1164 static void _process_gradient_units(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
1165                                     const char * val_end)
1166 {
1167     CHECK_AND_RESIZE_ATTRS(node->attrs);
1168 
1169     node->attrs.size++;
1170     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
1171     attr->id = type;
1172     attr->val_type = LV_SVG_ATTR_VALUE_DATA;
1173     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
1174 
1175     uint32_t len = val_end - val_start;
1176     int32_t val = 0;
1177 
1178     if(len == 14 && strncmp(val_start, "userSpaceOnUse", 14) == 0) {
1179         val = LV_SVG_GRADIENT_UNITS_USER_SPACE;
1180     }
1181     else {
1182         val = LV_SVG_GRADIENT_UNITS_OBJECT;
1183     }
1184     attr->value.ival = val;
1185 }
1186 
_process_paint_dasharray(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)1187 static void _process_paint_dasharray(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
1188                                      const char * val_end)
1189 {
1190     CHECK_AND_RESIZE_ATTRS(node->attrs);
1191 
1192     node->attrs.size++;
1193     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
1194     attr->id = type;
1195     attr->val_type = LV_SVG_ATTR_VALUE_DATA;
1196     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
1197 
1198     uint32_t len = val_end - val_start;
1199 
1200     if(len >= 4 && strncmp(val_start, "none", 4) == 0) {
1201         attr->class_type = LV_SVG_ATTR_VALUE_NONE;
1202         return;
1203     }
1204     else if(len >= 7 && strncmp(val_start, "inherit", 7) == 0) {
1205         attr->class_type = LV_SVG_ATTR_VALUE_INHERIT;
1206         return;
1207     }
1208     else {
1209         attr->val_type = LV_SVG_ATTR_VALUE_PTR;
1210 
1211         uint32_t list_cap = 4;
1212         lv_svg_attr_values_list_t * list = lv_malloc(sizeof(float) * list_cap + sizeof(uint32_t));
1213         LV_ASSERT_MALLOC(list);
1214 
1215         uint32_t count = 0;
1216         const char * ptr = val_start;
1217 
1218         while(ptr < val_end) {
1219             if(count == list_cap) {
1220                 list_cap = list_cap << 1;
1221                 list = lv_realloc(list, sizeof(float) * list_cap + sizeof(uint32_t));
1222                 LV_ASSERT_MALLOC(list);
1223             }
1224             float * val = (float *)(&list->data) + count;
1225             ptr = _parse_number(ptr, val_end, val);
1226             if(!ptr) break;
1227             ++count;
1228         }
1229 
1230         list->length = count;
1231         attr->value.val = list;
1232     }
1233 }
1234 
_process_font_attrs(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end,int32_t dpi)1235 static void _process_font_attrs(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
1236                                 const char * val_end, int32_t dpi)
1237 {
1238     CHECK_AND_RESIZE_ATTRS(node->attrs);
1239 
1240     node->attrs.size++;
1241     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
1242     attr->id = type;
1243     attr->val_type = LV_SVG_ATTR_VALUE_DATA;
1244     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
1245 
1246     uint32_t len = val_end - val_start;
1247 
1248     if(len >= 7 && strncmp(val_start, "inherit", 7) == 0) {
1249         attr->class_type = LV_SVG_ATTR_VALUE_INHERIT;
1250         return;
1251     }
1252 
1253     if(type == LV_SVG_ATTR_FONT_SIZE && _is_number_begin(*val_start)) {
1254         float val_number = 0.0f;
1255         val_start = _parse_length(val_start, val_end, dpi, &val_number);
1256         attr->value.fval = val_number;
1257     }
1258     else {
1259         attr->val_type = LV_SVG_ATTR_VALUE_PTR;
1260 
1261         char * str = lv_malloc(len + 1);
1262         LV_ASSERT_MALLOC(str);
1263         lv_memcpy(str, val_start, len);
1264         str[len] = '\0';
1265         attr->value.sval = str;
1266     }
1267 }
1268 
_process_paint_attrs(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)1269 static void _process_paint_attrs(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
1270                                  const char * val_end)
1271 {
1272     CHECK_AND_RESIZE_ATTRS(node->attrs);
1273 
1274     node->attrs.size++;
1275     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
1276     attr->id = type;
1277     attr->val_type = LV_SVG_ATTR_VALUE_DATA;
1278     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
1279 
1280     uint32_t len = val_end - val_start;
1281 
1282     if(len >= 7 && strncmp(val_start, "inherit", 7) == 0) {
1283         attr->class_type = LV_SVG_ATTR_VALUE_INHERIT;
1284         return;
1285     }
1286 
1287     if(type == LV_SVG_ATTR_FILL_RULE) {
1288         int32_t val = 0;
1289         if(strncmp(val_start, "evenodd", 7) == 0) {
1290             val = LV_SVG_FILL_EVENODD;
1291         }
1292         else {
1293             val = LV_SVG_FILL_NONZERO;
1294         }
1295         attr->value.ival = val;
1296     }
1297     else if(type == LV_SVG_ATTR_STROKE_LINECAP) {
1298         int32_t val = 0;
1299         if(strncmp(val_start, "round", 5) == 0) {
1300             val = LV_SVG_LINE_CAP_ROUND;
1301         }
1302         else if(strncmp(val_start, "square", 6) == 0) {
1303             val = LV_SVG_LINE_CAP_SQUARE;
1304         }
1305         else {
1306             val = LV_SVG_LINE_CAP_BUTT;
1307         }
1308         attr->value.ival = val;
1309     }
1310     else if(type == LV_SVG_ATTR_STROKE_LINEJOIN) {
1311         int32_t val = 0;
1312         if(strncmp(val_start, "round", 5) == 0) {
1313             val = LV_SVG_LINE_JOIN_ROUND;
1314         }
1315         else if(strncmp(val_start, "bevel", 5) == 0) {
1316             val = LV_SVG_LINE_JOIN_BEVEL;
1317         }
1318         else {
1319             val = LV_SVG_LINE_JOIN_MITER;
1320         }
1321         attr->value.ival = val;
1322     }
1323     else if(type == LV_SVG_ATTR_STROKE_WIDTH) {
1324         float val = 1.0f;
1325         val_start = _parse_number(val_start, val_end, &val);
1326         if(val < 0.0f) {
1327             val = 0.0f;
1328         }
1329         attr->value.fval = val;
1330     }
1331     else if(type == LV_SVG_ATTR_STROKE_MITER_LIMIT) {
1332         float val = 4.0f;
1333         val_start = _parse_number(val_start, val_end, &val);
1334         if(val < 1.0f) {
1335             val = 1.0f;
1336         }
1337         attr->value.ival = (int32_t)val;
1338     }
1339     else if(type == LV_SVG_ATTR_STROKE_DASH_OFFSET) {
1340         float val = 0.0f;
1341         val_start = _parse_number(val_start, val_end, &val);
1342         attr->value.fval = val;
1343     }
1344     else if(type == LV_SVG_ATTR_GRADIENT_STOP_OFFSET) {
1345         float val = 0.0f;
1346         val_start = _parse_number(val_start, val_end, &val);
1347         attr->value.fval = val;
1348     }
1349 }
1350 
_process_paint(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)1351 static void _process_paint(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
1352                            const char * val_end)
1353 {
1354     CHECK_AND_RESIZE_ATTRS(node->attrs);
1355 
1356     node->attrs.size++;
1357     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
1358     attr->id = type;
1359     attr->val_type = LV_SVG_ATTR_VALUE_DATA;
1360     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
1361 
1362     uint32_t len = val_end - val_start;
1363     if(len >= 4 && strncmp(val_start, "none", 4) == 0) {
1364         attr->class_type = LV_SVG_ATTR_VALUE_NONE;
1365         return;
1366     }
1367     else if(len >= 7 && strncmp(val_start, "inherit", 7) == 0) {
1368         attr->class_type = LV_SVG_ATTR_VALUE_INHERIT;
1369         return;
1370     }
1371     else if(len > 4 && strncmp(val_start, "url(", 4) == 0) {
1372         // parse url
1373         const char * ptr = val_start + 4;
1374         const char * url_start = NULL;
1375         const char * url_end = NULL;
1376 
1377         ptr = _skip_space(ptr, val_end);
1378         if(ptr == val_end) {
1379             attr->class_type = LV_SVG_ATTR_VALUE_NONE;
1380             return;
1381         }
1382 
1383         if(*ptr == '#') {
1384             url_start = ptr + 1;
1385         }
1386 
1387         while((ptr < val_end) && !isspace(*ptr) && *ptr != ')') {
1388             ++ptr;
1389         }
1390 
1391         url_end = ptr;
1392         if(url_start && url_end) {
1393             attr->val_type = LV_SVG_ATTR_VALUE_PTR;
1394             len = url_end - url_start;
1395             char * node_id = lv_malloc(len + 1);
1396             LV_ASSERT_MALLOC(node_id);
1397             lv_memcpy(node_id, url_start, len);
1398             node_id[len] = '\0';
1399             attr->value.sval = node_id;
1400         }
1401         return;
1402     }
1403     else {
1404 #if LV_USE_SVG_ANIMATION
1405         if(len == 6) {
1406             if(strncmp(val_start, "freeze", 6) == 0) {
1407                 attr->value.ival = LV_SVG_ANIM_FREEZE;
1408                 return;
1409             }
1410             else if(strncmp(val_start, "remove", 6) == 0) {
1411                 attr->value.ival = LV_SVG_ANIM_REMOVE;
1412                 return;
1413             }
1414         }
1415 #endif
1416         // parse color
1417         uint32_t color = 0;
1418         _parse_color(val_start, val_end, &color);
1419         attr->value.uval = color;
1420         return;
1421     }
1422 }
1423 
_process_opacity_value(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)1424 static void _process_opacity_value(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
1425                                    const char * val_end)
1426 {
1427     CHECK_AND_RESIZE_ATTRS(node->attrs);
1428 
1429     node->attrs.size++;
1430     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
1431     attr->id = type;
1432     attr->val_type = LV_SVG_ATTR_VALUE_DATA;
1433     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
1434 
1435     uint32_t len = val_end - val_start;
1436 
1437     if(len >= 7 && strncmp(val_start, "inherit", 7) == 0) {
1438         attr->class_type = LV_SVG_ATTR_VALUE_INHERIT;
1439         return;
1440     }
1441 
1442     float val_number = 1.0f;
1443     val_start = _parse_number(val_start, val_end, &val_number);
1444 
1445     if(val_number < 0.0f) val_number = 0.0f;
1446     else if(val_number > 1.0f) val_number = 1.0f;
1447 
1448     attr->value.fval = val_number;
1449 }
1450 
_process_length_value(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end,int32_t dpi)1451 static void _process_length_value(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
1452                                   const char * val_end, int32_t dpi)
1453 {
1454     CHECK_AND_RESIZE_ATTRS(node->attrs);
1455 
1456     node->attrs.size++;
1457     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
1458     attr->id = type;
1459     attr->val_type = LV_SVG_ATTR_VALUE_DATA;
1460     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
1461 
1462     float val_number = 0.0f;
1463     val_start = _parse_length(val_start, val_end, dpi, &val_number);
1464     attr->value.fval = val_number;
1465 }
1466 
_process_transform(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)1467 static void _process_transform(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
1468                                const char * val_end)
1469 {
1470     CHECK_AND_RESIZE_ATTRS(node->attrs);
1471 
1472     node->attrs.size++;
1473     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
1474     attr->id = type;
1475     attr->val_type = LV_SVG_ATTR_VALUE_PTR;
1476     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
1477 
1478     uint32_t len = val_end - val_start;
1479     if(len >= 4 && strncmp(val_start, "none", 4) == 0) {
1480         attr->val_type = LV_SVG_ATTR_VALUE_DATA;
1481         attr->class_type = LV_SVG_ATTR_VALUE_NONE;
1482         return;
1483     }
1484 
1485     lv_svg_matrix_t * matrix = lv_malloc_zeroed(sizeof(lv_svg_matrix_t));
1486     LV_ASSERT_MALLOC(matrix);
1487     matrix->m[0][0] = matrix->m[1][1] = matrix->m[2][2] = 1.0f; // identity
1488 
1489     const char * ptr = val_start;
1490     while(ptr < val_end) {
1491         ptr = _skip_space(ptr, val_end);
1492         if(ptr == val_end) break;
1493 
1494         len = val_end - ptr;
1495 
1496         if(len >= 9 && strncmp(ptr, "translate", 9) == 0) {
1497             ptr = _parse_matrix(ptr, val_end, LV_SVG_TRANSFORM_TYPE_TRANSLATE, matrix);
1498         }
1499         else if(len >= 6 && strncmp(ptr, "matrix", 6) == 0) {
1500             ptr = _parse_matrix(ptr, val_end, LV_SVG_TRANSFORM_TYPE_MATRIX, matrix);
1501         }
1502         else if(len >= 6 && strncmp(ptr, "rotate", 6) == 0) {
1503             ptr = _parse_matrix(ptr, val_end, LV_SVG_TRANSFORM_TYPE_ROTATE, matrix);
1504         }
1505         else if(len >= 5 && strncmp(ptr, "scale", 5) == 0) {
1506             ptr = _parse_matrix(ptr, val_end, LV_SVG_TRANSFORM_TYPE_SCALE, matrix);
1507         }
1508         else if(len >= 5 && strncmp(ptr, "skewX", 5) == 0) {
1509             ptr = _parse_matrix(ptr, val_end, LV_SVG_TRANSFORM_TYPE_SKEW_X, matrix);
1510         }
1511         else if(len >= 5 && strncmp(ptr, "skewY", 5) == 0) {
1512             ptr = _parse_matrix(ptr, val_end, LV_SVG_TRANSFORM_TYPE_SKEW_Y, matrix);
1513         }
1514 
1515         ++ptr;
1516     }
1517     attr->value.val = matrix;
1518 }
1519 
_process_preserve_aspect_ratio(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)1520 static void _process_preserve_aspect_ratio(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
1521                                            const char * val_end)
1522 {
1523     CHECK_AND_RESIZE_ATTRS(node->attrs);
1524 
1525     node->attrs.size++;
1526     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
1527     attr->id = type;
1528     attr->val_type = LV_SVG_ATTR_VALUE_DATA;
1529     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
1530 
1531     lv_svg_aspect_ratio_t ratio = LV_SVG_ASPECT_RATIO_XMID_YMID;
1532     uint32_t len = MAP_LEN(_svg_attr_aspect_ratio_map);
1533 
1534     for(uint32_t i = 0; i < len; i++) {
1535         if(strncmp(_svg_attr_aspect_ratio_map[i].name, val_start, 8) == 0) {
1536             ratio = _svg_attr_aspect_ratio_map[i].align;
1537             val_start += 8;
1538             break;
1539         }
1540         else if(strncmp("none", val_start, 4) == 0) {
1541             ratio = LV_SVG_ASPECT_RATIO_NONE;
1542             val_start += 4;
1543             break;
1544         }
1545     }
1546 
1547     if(ratio != LV_SVG_ASPECT_RATIO_NONE) {
1548         len = val_end - val_start;
1549         if(len > 4) {
1550             val_start = _skip_space(val_start, val_end);
1551             if(strncmp(val_start, "meet", 4) == 0) {
1552                 ratio |= LV_SVG_ASPECT_RATIO_OPT_MEET;
1553             }
1554             else if(strncmp(val_start, "slice", 5) == 0) {
1555                 ratio |= LV_SVG_ASPECT_RATIO_OPT_SLICE;
1556             }
1557         }
1558     }
1559     attr->value.uval = ratio;
1560 }
1561 
1562 #if LV_USE_SVG_ANIMATION
1563 typedef void(*_parse_list_cb)(lv_svg_node_t * node, lv_svg_attr_t * attr, const char * val_start, const char * val_end,
1564                               int32_t dpi, void * data);
1565 
_parse_anim_value_list(lv_svg_node_t * node,lv_svg_attr_t * attr,const char * val_start,const char * val_end,int32_t dpi,_parse_list_cb cb,void * data)1566 static uint32_t _parse_anim_value_list(lv_svg_node_t * node, lv_svg_attr_t * attr, const char * val_start,
1567                                        const char * val_end, int32_t dpi, _parse_list_cb cb, void * data)
1568 {
1569     uint32_t count = 0;
1570     val_start = _skip_space(val_start, val_end);
1571     const char * ptr = val_start;
1572 
1573     while(ptr != val_end) {
1574         if(*ptr == ';') {
1575             cb(node, attr, val_start, ptr, dpi, data);
1576             val_start = ++ptr;
1577             val_start = _skip_space(val_start, val_end);
1578             count++;
1579         }
1580         else {
1581             ++ptr;
1582         }
1583     }
1584     if(val_start < val_end) {
1585         cb(node, attr, val_start, ptr, dpi, data);
1586         count++;
1587     }
1588     return count;
1589 }
1590 
_parse_clock_time(const char * str,const char * str_end,float * val)1591 static const char * _parse_clock_time(const char * str, const char * str_end, float * val)
1592 {
1593     str = _parse_number(str, str_end, val);
1594     if(str) {
1595         uint32_t len = str_end - str;
1596         if(len > 0) {
1597             if(len >= 2 && str[0] == 'm' && str[1] == 's') {
1598                 *val = roundf(*val);
1599             }
1600             else {
1601                 *val = roundf(*val * 1000.0f);
1602             }
1603         }
1604         else {
1605             *val = roundf(*val * 1000.0f);
1606         }
1607         str += len;
1608         return str;
1609     }
1610     *val = roundf(*val * 1000.0f);
1611     return str;
1612 }
1613 
_process_clock_time(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)1614 static void _process_clock_time(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
1615                                 const char * val_end)
1616 {
1617     CHECK_AND_RESIZE_ATTRS(node->attrs);
1618 
1619     node->attrs.size++;
1620     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
1621     attr->id = type;
1622     attr->val_type = LV_SVG_ATTR_VALUE_DATA;
1623     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
1624 
1625     uint32_t len = val_end - val_start;
1626     if(len == 10 && strncmp(val_start, "indefinite", 10) == 0) {
1627         attr->value.fval = 0.0f;
1628         return;
1629     }
1630 
1631     float val_number = 0.0f;
1632     val_start = _parse_clock_time(val_start, val_end, &val_number);
1633     attr->value.fval = val_number; // ms
1634 }
1635 
_process_anim_attr_number(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)1636 static void _process_anim_attr_number(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
1637                                       const char * val_end)
1638 {
1639     CHECK_AND_RESIZE_ATTRS(node->attrs);
1640 
1641     node->attrs.size++;
1642     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
1643     attr->id = type;
1644     attr->val_type = LV_SVG_ATTR_VALUE_DATA;
1645     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
1646 
1647     if(type == LV_SVG_ATTR_REPEAT_COUNT) {
1648         uint32_t len = val_end - val_start;
1649         if(len == 10 && strncmp(val_start, "indefinite", 10) == 0) {
1650             attr->value.uval = 0;
1651             return;
1652         }
1653 
1654         float val_number = 0.0f;
1655         val_start = _parse_number(val_start, val_end, &val_number);
1656         attr->value.uval = (uint32_t)val_number;
1657     }
1658     else {   // LV_SVG_ATTR_ROTATE
1659         uint32_t len = val_end - val_start;
1660         if(len == 4 && strncmp(val_start, "auto", 4) == 0) {
1661             attr->class_type =
1662                 LV_SVG_ATTR_VALUE_INHERIT; // rotated over time by the angle of the direction (i.e., directional tangent vector) of the motion path
1663             attr->value.fval = 0.0f;
1664             return;
1665         }
1666         else if(len == 12 && strncmp(val_start, "auto-reverse", 12) == 0) {
1667             attr->class_type =
1668                 LV_SVG_ATTR_VALUE_INHERIT; // rotated over time by the angle of the direction (i.e., directional tangent vector) of the motion path plus 180 degrees.
1669             attr->value.fval = 180.0f;
1670             return;
1671         }
1672 
1673         float val_number = 0.0f;
1674         val_start = _parse_number(val_start, val_end, &val_number);
1675         attr->value.fval = val_number;
1676     }
1677 }
1678 
_process_anim_attr_names(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)1679 static void _process_anim_attr_names(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
1680                                      const char * val_end)
1681 {
1682     CHECK_AND_RESIZE_ATTRS(node->attrs);
1683 
1684     node->attrs.size++;
1685     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
1686     attr->id = type;
1687     attr->val_type = LV_SVG_ATTR_VALUE_DATA;
1688     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
1689     attr->value.ival = _get_svg_attr_type(val_start, val_end);
1690 }
1691 
_process_anim_attr_options(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end)1692 static void _process_anim_attr_options(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
1693                                        const char * val_end)
1694 {
1695     CHECK_AND_RESIZE_ATTRS(node->attrs);
1696 
1697     node->attrs.size++;
1698     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
1699     attr->id = type;
1700     attr->val_type = LV_SVG_ATTR_VALUE_DATA;
1701     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
1702 
1703     uint32_t len = val_end - val_start;
1704     switch(type) {
1705         case LV_SVG_ATTR_RESTART: {
1706                 if(len == 6 && strncmp(val_start, "always", 6) == 0) {
1707                     attr->value.ival = LV_SVG_ANIM_RESTART_ALWAYS;
1708                     return;
1709                 }
1710                 else if(len == 13 && strncmp(val_start, "whenNotActive", 13) == 0) {
1711                     attr->value.ival = LV_SVG_ANIM_RESTART_WHEN_NOT_ACTIVE;
1712                     return;
1713                 }
1714                 else if(len == 5 && strncmp(val_start, "never", 5) == 0) {
1715                     attr->value.ival = LV_SVG_ANIM_RESTART_NEVER;
1716                     return;
1717                 }
1718             }
1719             break;
1720         case LV_SVG_ATTR_CALC_MODE: {
1721                 if(len == 6 && strncmp(val_start, "linear", 6) == 0) {
1722                     attr->value.ival = LV_SVG_ANIM_CALC_MODE_LINEAR;
1723                     return;
1724                 }
1725                 else if(len == 5 && strncmp(val_start, "paced", 5) == 0) {
1726                     attr->value.ival = LV_SVG_ANIM_CALC_MODE_PACED;
1727                     return;
1728                 }
1729                 else if(len == 6 && strncmp(val_start, "spline", 6) == 0) {
1730                     attr->value.ival = LV_SVG_ANIM_CALC_MODE_SPLINE;
1731                     return;
1732                 }
1733                 else if(len == 8 && strncmp(val_start, "discrete", 8) == 0) {
1734                     attr->value.ival = LV_SVG_ANIM_CALC_MODE_DISCRETE;
1735                     return;
1736                 }
1737             }
1738             break;
1739         case LV_SVG_ATTR_ADDITIVE: {
1740                 if(len == 7 && strncmp(val_start, "replace", 7) == 0) {
1741                     attr->value.ival = LV_SVG_ANIM_ADDITIVE_REPLACE;
1742                     return;
1743                 }
1744                 else if(len == 3 && strncmp(val_start, "sum", 3) == 0) {
1745                     attr->value.ival = LV_SVG_ANIM_ADDITIVE_SUM;
1746                     return;
1747                 }
1748             }
1749             break;
1750         case LV_SVG_ATTR_ACCUMULATE: {
1751                 if(len == 4 && strncmp(val_start, "none", 4) == 0) {
1752                     attr->value.ival = LV_SVG_ANIM_ACCUMULATE_NONE;
1753                     return;
1754                 }
1755                 else if(len == 3 && strncmp(val_start, "sum", 3) == 0) {
1756                     attr->value.ival = LV_SVG_ANIM_ACCUMULATE_SUM;
1757                     return;
1758                 }
1759             }
1760             break;
1761         case LV_SVG_ATTR_TRANSFORM_TYPE: {
1762                 if(len == 9 && strncmp(val_start, "translate", 9) == 0) {
1763                     attr->value.ival = LV_SVG_TRANSFORM_TYPE_TRANSLATE;
1764                     return;
1765                 }
1766                 else if(len == 5 && strncmp(val_start, "scale", 5) == 0) {
1767                     attr->value.ival = LV_SVG_TRANSFORM_TYPE_SCALE;
1768                     return;
1769                 }
1770                 else if(len == 6 && strncmp(val_start, "rotate", 6) == 0) {
1771                     attr->value.ival = LV_SVG_TRANSFORM_TYPE_ROTATE;
1772                     return;
1773                 }
1774                 else if(len == 5 && strncmp(val_start, "skewX", 5) == 0) {
1775                     attr->value.ival = LV_SVG_TRANSFORM_TYPE_SKEW_X;
1776                     return;
1777                 }
1778                 else if(len == 5 && strncmp(val_start, "skewY", 5) == 0) {
1779                     attr->value.ival = LV_SVG_TRANSFORM_TYPE_SKEW_Y;
1780                     return;
1781                 }
1782             }
1783             break;
1784     }
1785     attr->value.ival = 0;
1786 }
1787 
_parse_anim_value(lv_svg_node_t * node,lv_svg_attr_t * attr,const char * val_start,const char * val_end,int32_t dpi)1788 static void _parse_anim_value(lv_svg_node_t * node, lv_svg_attr_t * attr, const char * val_start, const char * val_end,
1789                               int32_t dpi)
1790 {
1791     if(node->type == LV_SVG_TAG_ANIMATE || node->type == LV_SVG_TAG_SET) {
1792         float val_number = 0.0f;
1793         val_start = _parse_length(val_start, val_end, dpi, &val_number);
1794         attr->value.fval = val_number;
1795     }
1796     else if(node->type == LV_SVG_TAG_ANIMATE_COLOR) {
1797         uint32_t color = 0;
1798         val_start = _parse_color(val_start, val_end, &color);
1799         attr->value.uval = color;
1800     }
1801     else if(node->type == LV_SVG_TAG_ANIMATE_TRANSFORM) {
1802         attr->val_type = LV_SVG_ATTR_VALUE_PTR;
1803         lv_svg_attr_values_list_t * list = lv_malloc(sizeof(float) * 4 + sizeof(uint32_t));
1804         LV_ASSERT_MALLOC(list);
1805 
1806         float val_number = 0.0f;
1807         uint32_t cnt = 0;
1808         const char * ptr = val_start;
1809 
1810         while((ptr < val_end) && (cnt < 3)) {
1811             float * val = (float *)(&list->data) + cnt;
1812 
1813             val_number = 0.0f;
1814             ptr = _parse_number(ptr, val_end, &val_number);
1815             *val = val_number;
1816 
1817             if(!ptr) break;
1818             ++cnt;
1819         }
1820 
1821         list->length = cnt;
1822         attr->value.val = list;
1823     }
1824     else if(node->type == LV_SVG_TAG_ANIMATE_MOTION) {
1825         attr->val_type = LV_SVG_ATTR_VALUE_PTR;
1826         lv_svg_attr_values_list_t * list = lv_malloc(sizeof(lv_svg_point_t) + sizeof(uint32_t));
1827         LV_ASSERT_MALLOC(list);
1828 
1829         lv_svg_point_t * pt = (lv_svg_point_t *)(&list->data);
1830 
1831         float val_number = 0.0f;
1832         val_start = _parse_number(val_start, val_end, &val_number);
1833         pt->x = val_number;
1834         val_number = 0.0f;
1835         val_start = _parse_number(val_start, val_end, &val_number);
1836         pt->y = val_number;
1837 
1838         list->length = 1;
1839         attr->value.val = list;
1840     }
1841 }
1842 
1843 struct _parse_value_list_context {
1844     uint32_t mem_size;
1845     uint32_t list_count;
1846     lv_svg_attr_values_list_t * list;
1847 };
1848 
1849 struct _transform_values_list {
1850     uint32_t length;
1851     float data[4];
1852 };
1853 
1854 #define GET_NEXT_VALUE_PTR(ptr, ctx, type) \
1855     do { \
1856         lv_svg_attr_values_list_t * list = ctx->list; \
1857         if(!list) { \
1858             ctx->mem_size = sizeof(type) * 4 + sizeof(uint32_t);\
1859             ctx->list = lv_malloc_zeroed(ctx->mem_size); \
1860             LV_ASSERT_MALLOC(ctx->list); \
1861             ptr = (type *)(&(ctx->list->data)); \
1862             ctx->list_count = 1; \
1863         } else { \
1864             uint32_t mem = sizeof(type) * (ctx->list_count + 1) + sizeof(uint32_t); \
1865             if(ctx->mem_size < mem) { \
1866                 ctx->mem_size = (ctx->list_count << 1) * sizeof(type) + sizeof(uint32_t); \
1867                 ctx->list = (lv_svg_attr_values_list_t *)lv_realloc(ctx->list, ctx->mem_size); \
1868                 LV_ASSERT_MALLOC(ctx->list); \
1869             } \
1870             ptr = (type *)(&(ctx->list->data)) + ctx->list_count; \
1871             ctx->list_count++; \
1872         } \
1873     } while(0)
1874 
_anim_values_cb(lv_svg_node_t * node,lv_svg_attr_t * attr,const char * val_start,const char * val_end,int32_t dpi,void * data)1875 static void _anim_values_cb(lv_svg_node_t * node, lv_svg_attr_t * attr, const char * val_start, const char * val_end,
1876                             int32_t dpi, void * data)
1877 {
1878     LV_UNUSED(attr);
1879     struct _parse_value_list_context * ctx = (struct _parse_value_list_context *)data;
1880 
1881     if(node->type == LV_SVG_TAG_ANIMATE || node->type == LV_SVG_TAG_SET) {
1882         float * val_number = NULL;
1883         GET_NEXT_VALUE_PTR(val_number, ctx, float);
1884         val_start = _parse_length(val_start, val_end, dpi, val_number);
1885     }
1886     else if(node->type == LV_SVG_TAG_ANIMATE_COLOR) {
1887         uint32_t * color = NULL;
1888         GET_NEXT_VALUE_PTR(color, ctx, uint32_t);
1889         val_start = _parse_color(val_start, val_end, color);
1890     }
1891     else if(node->type == LV_SVG_TAG_ANIMATE_TRANSFORM) {
1892         struct _transform_values_list * trans_vals = NULL;
1893         GET_NEXT_VALUE_PTR(trans_vals, ctx, struct _transform_values_list);
1894 
1895         uint32_t cnt = 0;
1896         const char * ptr = val_start;
1897 
1898         while((ptr < val_end) && (cnt < 3)) {
1899             float * val = &(trans_vals->data[cnt]);
1900             ptr = _parse_number(ptr, val_end, val);
1901             if(!ptr) break;
1902             ++cnt;
1903         }
1904 
1905         trans_vals->length = cnt;
1906     }
1907     else if(node->type == LV_SVG_TAG_ANIMATE_MOTION) {
1908         lv_svg_point_t * point = NULL;
1909         GET_NEXT_VALUE_PTR(point, ctx, lv_svg_point_t);
1910         val_start = _parse_number(val_start, val_end, &point->x);
1911         val_start = _parse_number(val_start, val_end, &point->y);
1912     }
1913     ctx->list->length = ctx->list_count;
1914 }
1915 
_anim_keys_cb(lv_svg_node_t * node,lv_svg_attr_t * attr,const char * val_start,const char * val_end,int32_t dpi,void * data)1916 static void _anim_keys_cb(lv_svg_node_t * node, lv_svg_attr_t * attr, const char * val_start, const char * val_end,
1917                           int32_t dpi, void * data)
1918 {
1919     LV_UNUSED(node);
1920     LV_UNUSED(attr);
1921     LV_UNUSED(dpi);
1922     struct _parse_value_list_context * ctx = (struct _parse_value_list_context *)data;
1923 
1924     float * val_number = NULL;
1925     GET_NEXT_VALUE_PTR(val_number, ctx, float);
1926     val_start = _parse_number(val_start, val_end, val_number);
1927 
1928     ctx->list->length = ctx->list_count;
1929 }
1930 
_anim_key_splines_cb(lv_svg_node_t * node,lv_svg_attr_t * attr,const char * val_start,const char * val_end,int32_t dpi,void * data)1931 static void _anim_key_splines_cb(lv_svg_node_t * node, lv_svg_attr_t * attr, const char * val_start,
1932                                  const char * val_end, int32_t dpi, void * data)
1933 {
1934     LV_UNUSED(node);
1935     LV_UNUSED(attr);
1936     LV_UNUSED(dpi);
1937     struct _parse_value_list_context * ctx = (struct _parse_value_list_context *)data;
1938 
1939     lv_svg_point_t * point = NULL;
1940     GET_NEXT_VALUE_PTR(point, ctx, lv_svg_point_t);
1941     val_start = _parse_number(val_start, val_end, &point->x);
1942     val_start = _parse_number(val_start, val_end, &point->y);
1943 
1944     GET_NEXT_VALUE_PTR(point, ctx, lv_svg_point_t);
1945     val_start = _parse_number(val_start, val_end, &point->x);
1946     val_start = _parse_number(val_start, val_end, &point->y);
1947 
1948     ctx->list->length = ctx->list_count;
1949 }
1950 
_anim_begin_end_cb(lv_svg_node_t * node,lv_svg_attr_t * attr,const char * val_start,const char * val_end,int32_t dpi,void * data)1951 static void _anim_begin_end_cb(lv_svg_node_t * node, lv_svg_attr_t * attr, const char * val_start,
1952                                const char * val_end, int32_t dpi, void * data)
1953 {
1954     LV_UNUSED(node);
1955     LV_UNUSED(attr);
1956     LV_UNUSED(dpi);
1957     struct _parse_value_list_context * ctx = (struct _parse_value_list_context *)data;
1958 
1959     // offset-value
1960     float * val_number = NULL;
1961     GET_NEXT_VALUE_PTR(val_number, ctx, float);
1962     val_start = _parse_clock_time(val_start, val_end, val_number);
1963 
1964     //FIXME: not support begin-end type
1965     // syncbase-value
1966     // event-value
1967     // repeat-value
1968     // accessKey-value
1969     // indefinite
1970 
1971     ctx->list->length = ctx->list_count;
1972 }
1973 
_process_anim_attr_values(lv_svg_node_t * node,lv_svg_attr_type_t type,const char * val_start,const char * val_end,int32_t dpi)1974 static void _process_anim_attr_values(lv_svg_node_t * node, lv_svg_attr_type_t type, const char * val_start,
1975                                       const char * val_end, int32_t dpi)
1976 {
1977     CHECK_AND_RESIZE_ATTRS(node->attrs);
1978 
1979     node->attrs.size++;
1980     lv_svg_attr_t * attr = lv_array_at(&node->attrs, node->attrs.size - 1);
1981     attr->id = type;
1982     attr->val_type = LV_SVG_ATTR_VALUE_DATA;
1983     attr->class_type = LV_SVG_ATTR_VALUE_INITIAL;
1984 
1985     if(type == LV_SVG_ATTR_VALUES) {
1986         attr->val_type = LV_SVG_ATTR_VALUE_PTR;
1987         struct _parse_value_list_context ctx = {.mem_size = 0, .list_count = 0, .list = NULL};
1988         _parse_anim_value_list(node, attr, val_start, val_end, dpi, _anim_values_cb, &ctx);
1989         attr->value.val = ctx.list;
1990     }
1991     else if(type == LV_SVG_ATTR_KEY_TIMES || type == LV_SVG_ATTR_KEY_POINTS) {
1992         attr->val_type = LV_SVG_ATTR_VALUE_PTR;
1993         struct _parse_value_list_context ctx = {.mem_size = 0, .list_count = 0, .list = NULL};
1994         _parse_anim_value_list(node, attr, val_start, val_end, dpi, _anim_keys_cb, &ctx);
1995         attr->value.val = ctx.list;
1996     }
1997     else if(type == LV_SVG_ATTR_KEY_SPLINES) {
1998         attr->val_type = LV_SVG_ATTR_VALUE_PTR;
1999         struct _parse_value_list_context ctx = {.mem_size = 0, .list_count = 0, .list = NULL};
2000         _parse_anim_value_list(node, attr, val_start, val_end, dpi, _anim_key_splines_cb, &ctx);
2001         attr->value.val = ctx.list;
2002     }
2003     else if(type == LV_SVG_ATTR_BEGIN || type == LV_SVG_ATTR_END) {
2004         attr->val_type = LV_SVG_ATTR_VALUE_PTR;
2005         struct _parse_value_list_context ctx = {.mem_size = 0, .list_count = 0, .list = NULL};
2006         _parse_anim_value_list(node, attr, val_start, val_end, dpi, _anim_begin_end_cb, &ctx);
2007         attr->value.val = ctx.list;
2008     }
2009     else {
2010         _parse_anim_value(node, attr, val_start, val_end, dpi);
2011     }
2012 }
2013 
2014 #endif
2015 
_process_attrs_tag(_lv_svg_parser_t * parser,lv_svg_node_t * node,const _lv_svg_token_t * token)2016 static void _process_attrs_tag(_lv_svg_parser_t * parser, lv_svg_node_t * node, const _lv_svg_token_t * token)
2017 {
2018     uint32_t len = lv_array_size(&token->attrs);
2019     for(uint32_t i = 0; i < len; i++) {
2020         _lv_svg_token_attr_t * tok_attr = lv_array_at(&token->attrs, i);
2021         lv_svg_attr_type_t type = _get_svg_attr_type(tok_attr->name_start, tok_attr->name_end);
2022 
2023         tok_attr->value_start = _skip_space(tok_attr->value_start, tok_attr->value_end);
2024         uint32_t value_len = tok_attr->value_end - tok_attr->value_start;
2025         if(value_len == 0) {
2026             continue; // skip empty value attribute
2027         }
2028 
2029         if(type == LV_SVG_ATTR_XML_ID || type == LV_SVG_ATTR_ID) { // get xml:id
2030             char * str = lv_malloc(value_len + 1);
2031             LV_ASSERT_MALLOC(str);
2032             lv_memcpy(str, tok_attr->value_start, value_len);
2033             str[value_len] = '\0';
2034             node->xml_id = str;
2035             continue;
2036         }
2037 
2038         switch(type) {
2039             case LV_SVG_ATTR_VERSION:
2040             case LV_SVG_ATTR_BASE_PROFILE:
2041                 _process_string(node, type, tok_attr->value_start, tok_attr->value_end);
2042                 break;
2043             case LV_SVG_ATTR_VIEWBOX:
2044                 _process_view_box(node, type, tok_attr->value_start, tok_attr->value_end);
2045                 break;
2046             case LV_SVG_ATTR_PRESERVE_ASPECT_RATIO:
2047                 _process_preserve_aspect_ratio(node, type, tok_attr->value_start, tok_attr->value_end);
2048                 break;
2049             case LV_SVG_ATTR_X:
2050             case LV_SVG_ATTR_Y:
2051             case LV_SVG_ATTR_WIDTH:
2052             case LV_SVG_ATTR_HEIGHT:
2053             case LV_SVG_ATTR_RX:
2054             case LV_SVG_ATTR_RY:
2055             case LV_SVG_ATTR_CX:
2056             case LV_SVG_ATTR_CY:
2057             case LV_SVG_ATTR_R:
2058             case LV_SVG_ATTR_X1:
2059             case LV_SVG_ATTR_Y1:
2060             case LV_SVG_ATTR_X2:
2061             case LV_SVG_ATTR_Y2:
2062             case LV_SVG_ATTR_PATH_LENGTH:
2063                 _process_length_value(node, type, tok_attr->value_start, tok_attr->value_end, parser->dpi);
2064                 break;
2065             case LV_SVG_ATTR_OPACITY:
2066             case LV_SVG_ATTR_FILL_OPACITY:
2067             case LV_SVG_ATTR_STROKE_OPACITY:
2068             case LV_SVG_ATTR_SOLID_OPACITY:
2069             case LV_SVG_ATTR_VIEWPORT_FILL_OPACITY:
2070             case LV_SVG_ATTR_GRADIENT_STOP_OPACITY:
2071                 _process_opacity_value(node, type, tok_attr->value_start, tok_attr->value_end);
2072                 break;
2073             case LV_SVG_ATTR_POINTS:
2074                 _process_points_value(node, type, tok_attr->value_start, tok_attr->value_end);
2075                 break;
2076             case LV_SVG_ATTR_D:
2077 #if LV_USE_SVG_ANIMATION
2078             case LV_SVG_ATTR_PATH:
2079 #endif
2080                 _process_path_value(node, type, tok_attr->value_start, tok_attr->value_end);
2081                 break;
2082             case LV_SVG_ATTR_TRANSFORM:
2083                 _process_transform(node, type, tok_attr->value_start, tok_attr->value_end);
2084                 break;
2085             case LV_SVG_ATTR_FILL:
2086             case LV_SVG_ATTR_STROKE:
2087             case LV_SVG_ATTR_VIEWPORT_FILL:
2088             case LV_SVG_ATTR_SOLID_COLOR:
2089             case LV_SVG_ATTR_GRADIENT_STOP_COLOR:
2090                 _process_paint(node, type, tok_attr->value_start, tok_attr->value_end);
2091                 break;
2092             case LV_SVG_ATTR_FILL_RULE:
2093             case LV_SVG_ATTR_STROKE_LINECAP:
2094             case LV_SVG_ATTR_STROKE_LINEJOIN:
2095             case LV_SVG_ATTR_STROKE_WIDTH:
2096             case LV_SVG_ATTR_STROKE_MITER_LIMIT:
2097             case LV_SVG_ATTR_STROKE_DASH_OFFSET:
2098             case LV_SVG_ATTR_GRADIENT_STOP_OFFSET:
2099                 _process_paint_attrs(node, type, tok_attr->value_start, tok_attr->value_end);
2100                 break;
2101             case LV_SVG_ATTR_STROKE_DASH_ARRAY:
2102                 _process_paint_dasharray(node, type, tok_attr->value_start, tok_attr->value_end);
2103                 break;
2104             case LV_SVG_ATTR_GRADIENT_UNITS:
2105                 _process_gradient_units(node, type, tok_attr->value_start, tok_attr->value_end);
2106                 break;
2107             case LV_SVG_ATTR_FONT_FAMILY:
2108             case LV_SVG_ATTR_FONT_STYLE:
2109             case LV_SVG_ATTR_FONT_VARIANT:
2110             case LV_SVG_ATTR_FONT_WEIGHT:
2111             case LV_SVG_ATTR_FONT_SIZE:
2112                 _process_font_attrs(node, type, tok_attr->value_start, tok_attr->value_end, parser->dpi);
2113                 break;
2114             case LV_SVG_ATTR_XLINK_HREF:
2115                 _process_xlink(node, type, tok_attr->value_start, tok_attr->value_end);
2116                 break;
2117 #if LV_USE_SVG_ANIMATION
2118             case LV_SVG_ATTR_DUR:
2119             case LV_SVG_ATTR_MIN:
2120             case LV_SVG_ATTR_MAX:
2121             case LV_SVG_ATTR_REPEAT_DUR:
2122                 _process_clock_time(node, type, tok_attr->value_start, tok_attr->value_end);
2123                 break;
2124             case LV_SVG_ATTR_ATTRIBUTE_NAME:
2125                 _process_anim_attr_names(node, type, tok_attr->value_start, tok_attr->value_end);
2126                 break;
2127             case LV_SVG_ATTR_FROM:
2128             case LV_SVG_ATTR_TO:
2129             case LV_SVG_ATTR_BY:
2130             case LV_SVG_ATTR_VALUES:
2131             case LV_SVG_ATTR_KEY_TIMES:
2132             case LV_SVG_ATTR_KEY_POINTS:
2133             case LV_SVG_ATTR_KEY_SPLINES:
2134             case LV_SVG_ATTR_BEGIN:
2135             case LV_SVG_ATTR_END:
2136                 _process_anim_attr_values(node, type, tok_attr->value_start, tok_attr->value_end, parser->dpi);
2137                 break;
2138             case LV_SVG_ATTR_ROTATE:
2139             case LV_SVG_ATTR_REPEAT_COUNT:
2140                 _process_anim_attr_number(node, type, tok_attr->value_start, tok_attr->value_end);
2141                 break;
2142             case LV_SVG_ATTR_RESTART:
2143             case LV_SVG_ATTR_CALC_MODE:
2144             case LV_SVG_ATTR_ADDITIVE:
2145             case LV_SVG_ATTR_ACCUMULATE:
2146             case LV_SVG_ATTR_TRANSFORM_TYPE:
2147                 _process_anim_attr_options(node, type, tok_attr->value_start, tok_attr->value_end);
2148                 break;
2149             case LV_SVG_ATTR_ATTRIBUTE_TYPE:
2150 #endif
2151             case LV_SVG_ATTR_DISPLAY:
2152             case LV_SVG_ATTR_VISIBILITY:
2153             case LV_SVG_ATTR_TEXT_ANCHOR:
2154                 // not support yet
2155                 break;
2156         }
2157     }
2158 }
2159 
_process_begin_tag(_lv_svg_parser_t * parser,lv_svg_tag_t tag,const _lv_svg_token_t * token)2160 static bool _process_begin_tag(_lv_svg_parser_t * parser, lv_svg_tag_t tag, const _lv_svg_token_t * token)
2161 {
2162     if(parser->state == LV_SVG_PARSER_IGNORE) {
2163         // ignore ignored tokens
2164         return true;
2165     }
2166 
2167     if(token->type == LV_SVG_TOKEN_CONTENT) {
2168         uint32_t len = SVG_TOKEN_LEN(token);
2169         char * content = lv_malloc(len + 1);
2170         LV_ASSERT_MALLOC(content);
2171         lv_memcpy(content, token->start, len);
2172         content[len] = '\0';
2173         lv_svg_node_t * node = lv_svg_node_create(parser->cur_node);
2174         node->xml_id = content;
2175         node->type = LV_SVG_TAG_CONTENT;
2176         return true;
2177     }
2178 
2179     // begin invalid tag
2180     if(tag == LV_SVG_TAG_INVALID) {
2181         if(!token->flat) {
2182             parser->state = LV_SVG_PARSER_IGNORE;
2183             uint32_t len = SVG_TOKEN_LEN(token);
2184             parser->ignore_name = lv_malloc(len + 1);
2185             LV_ASSERT_MALLOC(parser->ignore_name);
2186             parser->ignore_len = len;
2187             lv_memcpy(parser->ignore_name, token->start, len);
2188             parser->ignore_name[len] = '\0';
2189         }
2190         return true;
2191     }
2192 
2193     // create new node
2194     lv_svg_node_t * node = lv_svg_node_create(parser->cur_node);
2195     node->type = tag;
2196     _process_attrs_tag(parser, node, token);
2197 
2198     if(!parser->doc_root) { // root node
2199         parser->doc_root = node;
2200     }
2201     if(!token->flat) { // FIXME: not leaf node
2202         parser->cur_node = node;
2203     }
2204     return true;
2205 }
2206 
2207 /**********************
2208  *   GLOBAL FUNCTIONS
2209  **********************/
_lv_svg_parser_init(_lv_svg_parser_t * parser)2210 void _lv_svg_parser_init(_lv_svg_parser_t * parser)
2211 {
2212     LV_ASSERT_NULL(parser);
2213     lv_memzero(parser, sizeof(_lv_svg_parser_t));
2214     parser->state = LV_SVG_PARSER_PROCESS;
2215     parser->ignore_name = NULL;
2216     parser->ignore_len = 0;
2217     parser->dpi = 96; // FIXME: Is it right ?
2218     parser->doc_root = NULL;
2219     parser->cur_node = NULL;
2220 }
2221 
_lv_svg_parser_deinit(_lv_svg_parser_t * parser)2222 void _lv_svg_parser_deinit(_lv_svg_parser_t * parser)
2223 {
2224     LV_ASSERT_NULL(parser);
2225     if(parser->ignore_name) {
2226         lv_free(parser->ignore_name);
2227         parser->ignore_name = NULL;
2228         parser->ignore_len = 0;
2229     }
2230 
2231     if(parser->doc_root) {
2232         lv_svg_node_delete(parser->doc_root);
2233     }
2234     parser->doc_root = parser->cur_node = NULL;
2235 }
2236 
_lv_svg_parser_is_finish(_lv_svg_parser_t * parser)2237 bool _lv_svg_parser_is_finish(_lv_svg_parser_t * parser)
2238 {
2239     LV_ASSERT_NULL(parser);
2240     return (parser->doc_root != NULL)
2241            && (parser->cur_node == parser->doc_root)
2242            && (parser->state != LV_SVG_PARSER_IGNORE);
2243 }
2244 
_lv_svg_parser_token(_lv_svg_parser_t * parser,const _lv_svg_token_t * token)2245 bool _lv_svg_parser_token(_lv_svg_parser_t * parser, const _lv_svg_token_t * token)
2246 {
2247     LV_ASSERT_NULL(parser);
2248     LV_ASSERT_NULL(token);
2249     lv_svg_tag_t tag = _get_svg_tag_type(token);
2250 
2251     if(parser->doc_root == NULL) {
2252         if(!(tag == LV_SVG_TAG_SVG && token->type == LV_SVG_TOKEN_BEGIN)) {
2253             LV_LOG_ERROR("root element in svg document must be <svg>!");
2254             return false;
2255         }
2256     }
2257 
2258     if(token->type == LV_SVG_TOKEN_END) {
2259         return _process_end_tag(parser, tag, token);
2260     }
2261 
2262     return _process_begin_tag(parser, tag, token);
2263 }
2264 
2265 #if LV_USE_SVG_DEBUG
2266 #include <stdio.h>
_lv_svg_dump_tree(lv_svg_node_t * root,int depth)2267 void _lv_svg_dump_tree(lv_svg_node_t * root, int depth)
2268 {
2269     if(!root) {
2270         return;
2271     }
2272 
2273     for(int i = 0; i < depth; i++) {
2274         printf("  ");
2275     }
2276     if(root->type == LV_SVG_TAG_CONTENT) {
2277         printf("content: [%s]\n", root->xml_id);
2278     }
2279     else {
2280         printf("tag <%s>", _svg_tag_map[root->type - 1].name);
2281         if(root->xml_id) {
2282             printf(" - id [%s]", root->xml_id);
2283         }
2284         printf("\n");
2285     }
2286 
2287     uint32_t len = lv_array_size(&root->attrs);
2288     for(uint32_t i = 0; i < len; i++) {
2289         for(int j = 0; j < depth; j++) {
2290             printf("  ");
2291         }
2292         lv_svg_attr_t * attr = lv_array_at(&root->attrs, i);
2293         printf("   attr <%s>\n", _svg_attr_map[attr->id - 1].name);
2294     }
2295 
2296     lv_tree_node_t * tree_root = (lv_tree_node_t *)root;
2297 
2298     for(uint32_t i = 0; i < tree_root->child_cnt; i++) {
2299         ++depth;
2300         _lv_svg_dump_tree((lv_svg_node_t *)tree_root->children[i], depth);
2301         --depth;
2302     }
2303 }
2304 #endif /*LV_USE_SVG_DEBUG*/
2305 
2306 /**********************
2307  *   STATIC FUNCTIONS
2308  **********************/
2309 #endif /*LV_USE_SVG*/
2310