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, °ree);
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, °ree);
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, °ree);
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