1 /**
2  * @file lv_svg_render.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "../../../lvgl.h"
11 #include "lv_svg_render.h"
12 #if LV_USE_SVG
13 
14 #include "../../misc/lv_text_private.h"
15 #include <math.h>
16 #include <string.h>
17 
18 #if LV_USE_FREETYPE
19     #include "../../libs/freetype/lv_freetype_private.h"
20 #endif
21 
22 /*********************
23 *      DEFINES
24 *********************/
25 #ifndef M_PI
26     #define M_PI 3.1415926f
27 #endif
28 
29 #define MIN(a,b) (((a)<(b))?(a):(b))
30 #define MAX(a,b) (((a)>(b))?(a):(b))
31 #define ABS(a) fabsf(a)
32 
33 #define CALC_BOUNDS(p, bounds) \
34     do { \
35         if((p).x < (bounds).x1) (bounds).x1 = (int32_t)(p).x; \
36         if((p).y < (bounds).y1) (bounds).y1 = (int32_t)(p).y; \
37         if((p).x > (bounds).x2) (bounds).x2 = (int32_t)(p).x; \
38         if((p).y > (bounds).y2) (bounds).y2 = (int32_t)(p).y; \
39     } while(0)
40 
41 #define PCT_TO_PX(v, base) ((v) > 1 ? (v) : ((v) * (base)))
42 
43 enum {
44     _RENDER_NORMAL = 0,
45     _RENDER_IN_DEFS = 1,
46     _RENDER_IN_GROUP = 2,
47 };
48 
49 enum {
50     _RENDER_ATTR_FILL         = (4 << 1),
51     _RENDER_ATTR_FILL_RULE    = (4 << 2),
52     _RENDER_ATTR_FILL_OPACITY = (4 << 3),
53     _RENDER_ATTR_STROKE       = (4 << 4),
54     _RENDER_ATTR_STROKE_OPACITY = (4 << 5),
55     _RENDER_ATTR_STROKE_WIDTH   = (4 << 6),
56     _RENDER_ATTR_STROKE_LINECAP = (4 << 7),
57     _RENDER_ATTR_STROKE_LINEJOIN    = (4 << 8),
58     _RENDER_ATTR_STROKE_MITER_LIMIT = (4 << 9),
59     _RENDER_ATTR_STROKE_DASH_ARRAY  = (4 << 10),
60 };
61 
62 /**********************
63 *      TYPEDEFS
64 **********************/
65 static void _set_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr);
66 static void _init_draw_dsc(lv_vector_draw_dsc_t * dsc);
67 static void _deinit_draw_dsc(lv_vector_draw_dsc_t * dsc);
68 static void _copy_draw_dsc(lv_vector_draw_dsc_t * dst, const lv_vector_draw_dsc_t * src);
69 static void _prepare_render(const lv_svg_render_obj_t * obj, lv_vector_dsc_t * dsc);
70 static void _special_render(const lv_svg_render_obj_t * obj, lv_vector_dsc_t * dsc);
71 #if LV_USE_FREETYPE
72     static void _freetype_outline_cb(lv_event_t * e);
73 #endif
74 
75 typedef struct {
76     lv_svg_render_obj_t base;
77     float width;
78     float height;
79     bool viewport_fill;
80 } lv_svg_render_viewport_t;
81 
82 typedef struct {
83     lv_svg_render_obj_t base;
84     lv_array_t items;
85 } lv_svg_render_group_t;
86 
87 typedef struct {
88     lv_svg_render_obj_t base;
89     float x;
90     float y;
91     char * xlink;
92 } lv_svg_render_use_t;
93 
94 typedef struct {
95     lv_svg_render_obj_t base;
96     lv_color_t color;
97     float opacity;
98 } lv_svg_render_solid_t;
99 
100 typedef struct {
101     lv_svg_render_obj_t base;
102     lv_vector_gradient_t dsc;
103     lv_svg_gradient_units_t units;
104 } lv_svg_render_gradient_t;
105 
106 typedef struct {
107     lv_svg_render_obj_t base;
108     float x;
109     float y;
110     float width;
111     float height;
112     float rx;
113     float ry;
114 } lv_svg_render_rect_t;
115 
116 typedef struct {
117     lv_svg_render_obj_t base;
118     float cx;
119     float cy;
120     float r;
121 } lv_svg_render_circle_t;
122 
123 typedef struct {
124     lv_svg_render_obj_t base;
125     float cx;
126     float cy;
127     float rx;
128     float ry;
129 } lv_svg_render_ellipse_t;
130 
131 typedef struct {
132     lv_svg_render_obj_t base;
133     float x1;
134     float y1;
135     float x2;
136     float y2;
137 } lv_svg_render_line_t;
138 
139 typedef struct {
140     lv_svg_render_obj_t base;
141     lv_vector_path_t * path;
142     lv_area_t bounds;
143 } lv_svg_render_poly_t;
144 
145 typedef struct {
146     lv_svg_render_obj_t base;
147     float x;
148     float y;
149     float width;
150     float height;
151     lv_draw_image_dsc_t img_dsc;
152     lv_svg_aspect_ratio_t ratio;
153 } lv_svg_render_image_t;
154 
155 #if LV_USE_FREETYPE
156 typedef struct {
157     lv_svg_render_obj_t base;
158     lv_array_t contents;
159     char * family;
160     float size;
161     lv_freetype_font_style_t style;
162     lv_font_t * font;
163     float x;
164     float y;
165     lv_vector_path_t * path;
166     lv_area_t bounds;
167 } lv_svg_render_text_t;
168 
169 typedef struct _lv_svg_render_content {
170     lv_svg_render_obj_t base;
171     void (*render_content)(const struct _lv_svg_render_content * content,
172                            lv_vector_dsc_t * dsc, lv_matrix_t * matrix);
173     uint32_t * letters;
174     uint32_t count;
175 } lv_svg_render_content_t;
176 
177 typedef struct {
178     lv_svg_render_content_t base;
179     char * family;
180     float size;
181     lv_freetype_font_style_t style;
182     lv_font_t * font;
183     lv_vector_path_t * path;
184     lv_area_t bounds;
185 } lv_svg_render_tspan_t;
186 #endif
187 
188 struct _lv_svg_draw_dsc {
189     struct _lv_svg_draw_dsc * next;
190     lv_vector_draw_dsc_t dsc;
191     const char * fill_ref;
192     const char * stroke_ref;
193 };
194 
195 struct _lv_svg_drawing_builder_state {
196     const lv_svg_node_t * doc;
197     struct _lv_svg_draw_dsc * draw_dsc;
198     int in_group_deps;
199     bool in_defs;
200 #if LV_USE_FREETYPE
201     bool in_text;
202     lv_svg_node_t * cur_text;
203 #endif
204     lv_svg_render_obj_t * list;
205     lv_svg_render_obj_t * tail;
206 };
207 
208 /**********************
209  *  STATIC VARIABLES
210  **********************/
211 static lv_svg_render_hal_t hal_funcs = {NULL};
212 
213 /**********************
214  *  STATIC PROTOTYPES
215  **********************/
lv_svg_render_init(const lv_svg_render_hal_t * hal)216 void lv_svg_render_init(const lv_svg_render_hal_t * hal)
217 {
218     if(hal) {
219         hal_funcs = *hal;
220 #if LV_USE_FREETYPE
221         lv_freetype_outline_add_event(_freetype_outline_cb, LV_EVENT_ALL, NULL);
222 #endif
223     }
224 }
225 
_lv_svg_draw_dsc_create(void)226 static struct _lv_svg_draw_dsc * _lv_svg_draw_dsc_create(void)
227 {
228     struct _lv_svg_draw_dsc * dsc = lv_malloc_zeroed(sizeof(struct _lv_svg_draw_dsc));
229     LV_ASSERT_MALLOC(dsc);
230     _init_draw_dsc(&(dsc->dsc));
231     return dsc;
232 }
233 
_lv_svg_draw_dsc_delete(struct _lv_svg_draw_dsc * dsc)234 static void _lv_svg_draw_dsc_delete(struct _lv_svg_draw_dsc * dsc)
235 {
236     while(dsc) {
237         struct _lv_svg_draw_dsc * cur = dsc;
238         dsc = dsc->next;
239         _deinit_draw_dsc(&(cur->dsc));
240         lv_free(cur);
241     }
242 }
243 
_lv_svg_draw_dsc_push(struct _lv_svg_draw_dsc * dsc)244 static struct _lv_svg_draw_dsc * _lv_svg_draw_dsc_push(struct _lv_svg_draw_dsc * dsc)
245 {
246     if(!dsc) return NULL;
247     struct _lv_svg_draw_dsc * cur = lv_malloc_zeroed(sizeof(struct _lv_svg_draw_dsc));
248     LV_ASSERT_MALLOC(cur);
249     _copy_draw_dsc(&(cur->dsc), &(dsc->dsc));
250     cur->fill_ref = dsc->fill_ref;
251     cur->stroke_ref = dsc->stroke_ref;
252     cur->next = dsc;
253     return cur;
254 }
255 
_lv_svg_draw_dsc_pop(struct _lv_svg_draw_dsc * dsc)256 static struct _lv_svg_draw_dsc * _lv_svg_draw_dsc_pop(struct _lv_svg_draw_dsc * dsc)
257 {
258     if(!dsc) return NULL;
259     struct _lv_svg_draw_dsc * cur = dsc->next;
260     lv_free(dsc);
261     return cur;
262 }
263 
_set_viewport_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)264 static void _set_viewport_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
265 {
266     lv_svg_render_viewport_t * view = (lv_svg_render_viewport_t *)obj;
267     switch(attr->id) {
268         case LV_SVG_ATTR_WIDTH:
269             view->width = attr->value.fval;
270             break;
271         case LV_SVG_ATTR_HEIGHT:
272             view->height = attr->value.fval;
273             break;
274         case LV_SVG_ATTR_VIEWBOX: {
275                 if(attr->class_type == LV_SVG_ATTR_VALUE_INITIAL) {
276                     float * vals = attr->value.val;
277                     float scale_x = 1.0f;
278                     float scale_y = 1.0f;
279                     float trans_x = vals[0];
280                     float trans_y = vals[1];
281 
282                     if(view->width > 0 && vals[2] > 0) {
283                         scale_x = view->width / vals[2];
284                     }
285                     if(view->height > 0 && vals[3] > 0) {
286                         scale_y = view->height / vals[3];
287                     }
288 
289                     lv_matrix_scale(&obj->matrix, scale_x, scale_y);
290                     lv_matrix_translate(&obj->matrix, -trans_x, -trans_y);
291                 }
292             }
293             break;
294         case LV_SVG_ATTR_VIEWPORT_FILL: {
295                 if(attr->class_type == LV_SVG_ATTR_VALUE_INITIAL
296                    && attr->val_type == LV_SVG_ATTR_VALUE_DATA) {
297                     dsc->fill_dsc.color = lv_color_to_32(lv_color_hex(attr->value.uval), 0xFF);
298                     view->viewport_fill = true;
299                 }
300                 else if(attr->class_type == LV_SVG_ATTR_VALUE_NONE) {
301                     view->viewport_fill = false;
302                 }
303             }
304             break;
305         case LV_SVG_ATTR_VIEWPORT_FILL_OPACITY: {
306                 if(attr->class_type == LV_SVG_ATTR_VALUE_INITIAL) {
307                     dsc->fill_dsc.opa = (lv_opa_t)(attr->value.fval * 255.0f);
308                 }
309             }
310             break;
311     }
312 }
313 
_set_use_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)314 static void _set_use_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
315 {
316     _set_attr(obj, dsc, attr);
317     lv_svg_render_use_t * use = (lv_svg_render_use_t *)obj;
318     switch(attr->id) {
319         case LV_SVG_ATTR_X:
320             use->x = attr->value.fval;
321             break;
322         case LV_SVG_ATTR_Y:
323             use->y = attr->value.fval;
324             break;
325         case LV_SVG_ATTR_XLINK_HREF: {
326                 if(use->xlink) lv_free(use->xlink);
327                 use->xlink = lv_strdup(attr->value.sval);
328             }
329             break;
330     }
331 }
332 
_set_solid_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)333 static void _set_solid_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
334 {
335     LV_UNUSED(dsc);
336     lv_svg_render_solid_t * solid = (lv_svg_render_solid_t *)obj;
337     switch(attr->id) {
338         case LV_SVG_ATTR_SOLID_COLOR:
339             solid->color = lv_color_hex(attr->value.uval);
340             break;
341         case LV_SVG_ATTR_SOLID_OPACITY:
342             solid->opacity = attr->value.fval;
343             break;
344     }
345 }
346 
_set_gradient_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)347 static void _set_gradient_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
348 {
349     LV_UNUSED(dsc);
350     lv_svg_render_gradient_t * grad = (lv_svg_render_gradient_t *)obj;
351     switch(attr->id) {
352         case LV_SVG_ATTR_CX:
353             grad->dsc.cx = attr->value.fval;
354             break;
355         case LV_SVG_ATTR_CY:
356             grad->dsc.cy = attr->value.fval;
357             break;
358         case LV_SVG_ATTR_R:
359             grad->dsc.cr = attr->value.fval;
360             break;
361         case LV_SVG_ATTR_X1:
362             grad->dsc.x1 = attr->value.fval;
363             break;
364         case LV_SVG_ATTR_Y1:
365             grad->dsc.y1 = attr->value.fval;
366             break;
367         case LV_SVG_ATTR_X2:
368             grad->dsc.x2 = attr->value.fval;
369             break;
370         case LV_SVG_ATTR_Y2:
371             grad->dsc.y2 = attr->value.fval;
372             break;
373         case LV_SVG_ATTR_GRADIENT_UNITS:
374             grad->units = attr->value.ival;
375             break;
376     }
377 }
378 
_set_rect_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)379 static void _set_rect_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
380 {
381     _set_attr(obj, dsc, attr);
382     lv_svg_render_rect_t * rect = (lv_svg_render_rect_t *)obj;
383     switch(attr->id) {
384         case LV_SVG_ATTR_X:
385             rect->x = attr->value.fval;
386             break;
387         case LV_SVG_ATTR_Y:
388             rect->y = attr->value.fval;
389             break;
390         case LV_SVG_ATTR_WIDTH:
391             rect->width = attr->value.fval;
392             break;
393         case LV_SVG_ATTR_HEIGHT:
394             rect->height = attr->value.fval;
395             break;
396         case LV_SVG_ATTR_RX:
397             rect->rx = attr->value.fval;
398             break;
399         case LV_SVG_ATTR_RY:
400             rect->ry = attr->value.fval;
401             break;
402     }
403 }
404 
_set_circle_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)405 static void _set_circle_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
406 {
407     _set_attr(obj, dsc, attr);
408     lv_svg_render_circle_t * circle = (lv_svg_render_circle_t *)obj;
409     switch(attr->id) {
410         case LV_SVG_ATTR_CX:
411             circle->cx = attr->value.fval;
412             break;
413         case LV_SVG_ATTR_CY:
414             circle->cy = attr->value.fval;
415             break;
416         case LV_SVG_ATTR_R:
417             circle->r = attr->value.fval;
418             break;
419     }
420 }
421 
_set_ellipse_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)422 static void _set_ellipse_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
423 {
424     _set_attr(obj, dsc, attr);
425     lv_svg_render_ellipse_t * ellipse = (lv_svg_render_ellipse_t *)obj;
426     switch(attr->id) {
427         case LV_SVG_ATTR_CX:
428             ellipse->cx = attr->value.fval;
429             break;
430         case LV_SVG_ATTR_CY:
431             ellipse->cy = attr->value.fval;
432             break;
433         case LV_SVG_ATTR_RX:
434             ellipse->rx = attr->value.fval;
435             break;
436         case LV_SVG_ATTR_RY:
437             ellipse->ry = attr->value.fval;
438             break;
439     }
440 }
441 
_set_line_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)442 static void _set_line_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
443 {
444     _set_attr(obj, dsc, attr);
445     lv_svg_render_line_t * line = (lv_svg_render_line_t *)obj;
446     switch(attr->id) {
447         case LV_SVG_ATTR_X1:
448             line->x1 = attr->value.fval;
449             break;
450         case LV_SVG_ATTR_Y1:
451             line->y1 = attr->value.fval;
452             break;
453         case LV_SVG_ATTR_X2:
454             line->x2 = attr->value.fval;
455             break;
456         case LV_SVG_ATTR_Y2:
457             line->y2 = attr->value.fval;
458             break;
459     }
460 }
461 
_set_polyline_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)462 static void _set_polyline_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
463 {
464     _set_attr(obj, dsc, attr);
465     lv_svg_render_poly_t * poly = (lv_svg_render_poly_t *)obj;
466     if(attr->id == LV_SVG_ATTR_POINTS) {
467         lv_vector_path_clear(poly->path);
468         lv_svg_attr_values_list_t * vals = (lv_svg_attr_values_list_t *)(attr->value.val);
469         uint32_t len = vals->length;
470         lv_svg_point_t * points = (lv_svg_point_t *)(&vals->data);
471 
472         CALC_BOUNDS(points[0], poly->bounds);
473         lv_fpoint_t pt = {points[0].x, points[0].y};
474         lv_vector_path_move_to(poly->path, &pt);
475         for(uint32_t i = 1; i < len; i++) {
476             pt.x = points[i].x;
477             pt.y = points[i].y;
478             lv_vector_path_line_to(poly->path, &pt);
479             CALC_BOUNDS(pt, poly->bounds);
480         }
481     }
482 }
483 
_set_polygen_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)484 static void _set_polygen_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
485 {
486     _set_polyline_attr(obj, dsc, attr);
487     lv_svg_render_poly_t * poly = (lv_svg_render_poly_t *)obj;
488     if(attr->id == LV_SVG_ATTR_POINTS) {
489         lv_vector_path_close(poly->path);
490     }
491 }
492 
_get_path_seg_size(uint32_t cmd)493 static size_t _get_path_seg_size(uint32_t cmd)
494 {
495     switch(cmd) {
496         case LV_SVG_PATH_CMD_MOVE_TO:
497         case LV_SVG_PATH_CMD_LINE_TO:
498         case LV_SVG_PATH_CMD_CLOSE:
499             return sizeof(lv_svg_point_t) + sizeof(uint32_t);
500         case LV_SVG_PATH_CMD_QUAD_TO:
501             return sizeof(lv_svg_point_t) * 2 + sizeof(uint32_t);
502         case LV_SVG_PATH_CMD_CURVE_TO:
503             return sizeof(lv_svg_point_t) * 3 + sizeof(uint32_t);
504         default:
505             return 0;
506     }
507 }
508 
_set_path_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)509 static void _set_path_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
510 {
511     _set_attr(obj, dsc, attr);
512     lv_svg_render_poly_t * poly = (lv_svg_render_poly_t *)obj;
513     if(attr->id == LV_SVG_ATTR_D) {
514         lv_vector_path_clear(poly->path);
515         lv_svg_attr_values_list_t * vals = (lv_svg_attr_values_list_t *)(attr->value.val);
516         uint32_t len = vals->length;
517         uint8_t * data_ptr = (uint8_t *)(&vals->data);
518 
519         for(uint32_t i = 0; i < len; i++) {
520             lv_svg_attr_path_value_t * path_seg = (lv_svg_attr_path_value_t *)data_ptr;
521             uint32_t cmd = path_seg->cmd;
522             lv_svg_point_t * points = (lv_svg_point_t *)(&path_seg->data);
523             switch(cmd) {
524                 case LV_SVG_PATH_CMD_MOVE_TO: {
525                         lv_fpoint_t pt = {points[0].x, points[0].y};
526                         lv_vector_path_move_to(poly->path, &pt);
527                         CALC_BOUNDS(pt, poly->bounds);
528                     }
529                     break;
530                 case LV_SVG_PATH_CMD_LINE_TO: {
531                         lv_fpoint_t pt = {points[0].x, points[0].y};
532                         lv_vector_path_line_to(poly->path, &pt);
533                         CALC_BOUNDS(pt, poly->bounds);
534                     }
535                     break;
536                 case LV_SVG_PATH_CMD_QUAD_TO: {
537                         lv_fpoint_t pt[2] = {
538                             {points[0].x, points[0].y},
539                             {points[1].x, points[1].y}
540                         };
541                         lv_vector_path_quad_to(poly->path, &pt[0], &pt[1]);
542                         CALC_BOUNDS(pt[0], poly->bounds);
543                         CALC_BOUNDS(pt[1], poly->bounds);
544                     }
545                     break;
546                 case LV_SVG_PATH_CMD_CURVE_TO: {
547                         lv_fpoint_t pt[3] = {
548                             {points[0].x, points[0].y},
549                             {points[1].x, points[1].y},
550                             {points[2].x, points[2].y}
551                         };
552                         lv_vector_path_cubic_to(poly->path, &pt[0], &pt[1], &pt[2]);
553                         CALC_BOUNDS(pt[0], poly->bounds);
554                         CALC_BOUNDS(pt[1], poly->bounds);
555                         CALC_BOUNDS(pt[2], poly->bounds);
556                     }
557                     break;
558                 case LV_SVG_PATH_CMD_CLOSE: {
559                         lv_vector_path_close(poly->path);
560                     }
561                     break;
562             }
563             size_t mem_inc = _get_path_seg_size(cmd);
564             data_ptr += mem_inc;
565         }
566     }
567 }
568 
569 #if LV_USE_FREETYPE
570 #define SET_FONT_ATTRS(obj, attr) \
571     do { \
572         switch(attr->id) { \
573             case LV_SVG_ATTR_FONT_FAMILY: { \
574                     if(attr->val_type == LV_SVG_ATTR_VALUE_PTR) { \
575                         if((obj)->font) { \
576                             lv_freetype_font_delete((obj)->font); \
577                             (obj)->font = NULL; \
578                         } \
579                         lv_vector_path_clear((obj)->path); \
580                         if((obj)->family) lv_free((obj)->family); \
581                         (obj)->family = lv_strdup(attr->value.sval); \
582                     } \
583                 } \
584                 break; \
585             case LV_SVG_ATTR_FONT_SIZE: \
586                 if(attr->class_type == LV_SVG_ATTR_VALUE_INITIAL) { \
587                     if(attr->val_type == LV_SVG_ATTR_VALUE_DATA) { \
588                         if((obj)->font) { \
589                             lv_freetype_font_delete((obj)->font); \
590                             (obj)->font = NULL; \
591                         } \
592                         (obj)->size = attr->value.fval; \
593                         lv_vector_path_clear((obj)->path); \
594                     } \
595                 } \
596                 break; \
597             case LV_SVG_ATTR_FONT_STYLE: \
598                 if(attr->class_type == LV_SVG_ATTR_VALUE_INITIAL) { \
599                     if(attr->val_type == LV_SVG_ATTR_VALUE_PTR) { \
600                         if((obj)->font) { \
601                             lv_freetype_font_delete((obj)->font); \
602                             (obj)->font = NULL; \
603                         } \
604                         lv_vector_path_clear((obj)->path); \
605                         if(strncmp(attr->value.sval, "italic", 6) == 0) { \
606                             (obj)->style = LV_FREETYPE_FONT_STYLE_ITALIC; \
607                         } \
608                     } \
609                 } \
610                 break; \
611             case LV_SVG_ATTR_FONT_WEIGHT: \
612                 if(attr->class_type == LV_SVG_ATTR_VALUE_INITIAL) { \
613                     if(attr->val_type == LV_SVG_ATTR_VALUE_PTR) { \
614                         if((obj)->font) { \
615                             lv_freetype_font_delete((obj)->font); \
616                             (obj)->font = NULL; \
617                         } \
618                         lv_vector_path_clear((obj)->path); \
619                         if(strncmp(attr->value.sval, "bold", 4) == 0) { \
620                             (obj)->style = LV_FREETYPE_FONT_STYLE_BOLD; \
621                         } \
622                     } \
623                 } \
624                 break; \
625             case LV_SVG_ATTR_FONT_VARIANT: \
626                 if(attr->class_type == LV_SVG_ATTR_VALUE_INITIAL) { \
627                     if(attr->val_type == LV_SVG_ATTR_VALUE_PTR) { \
628                         if((obj)->font) { \
629                             lv_freetype_font_delete((obj)->font); \
630                             (obj)->font = NULL; \
631                         } \
632                         lv_vector_path_clear((obj)->path); \
633                         if(strncmp(attr->value.sval, "small-caps", 10) == 0) { \
634                             (obj)->size /= 2; \
635                         } \
636                     } \
637                 } \
638                 break; \
639         } \
640     } while(0)
641 
_set_tspan_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)642 static void _set_tspan_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
643 {
644     _set_attr(obj, dsc, attr);
645     lv_svg_render_tspan_t * tspan = (lv_svg_render_tspan_t *)obj;
646 
647     SET_FONT_ATTRS(tspan, attr);
648 }
649 
_set_text_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)650 static void _set_text_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
651 {
652     _set_attr(obj, dsc, attr);
653     lv_svg_render_text_t * text = (lv_svg_render_text_t *)obj;
654 
655     SET_FONT_ATTRS(text, attr);
656 
657     switch(attr->id) {
658         case LV_SVG_ATTR_X:
659             text->x = attr->value.fval;
660             break;
661         case LV_SVG_ATTR_Y:
662             text->y = attr->value.fval;
663             break;
664     }
665 }
666 #endif
667 
_set_image_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)668 static void _set_image_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
669 {
670     _set_attr(obj, dsc, attr);
671     lv_svg_render_image_t * image = (lv_svg_render_image_t *)obj;
672     switch(attr->id) {
673         case LV_SVG_ATTR_X:
674             image->x = attr->value.fval;
675             break;
676         case LV_SVG_ATTR_Y:
677             image->y = attr->value.fval;
678             break;
679         case LV_SVG_ATTR_HEIGHT:
680             image->height = attr->value.fval;
681             break;
682         case LV_SVG_ATTR_WIDTH:
683             image->width = attr->value.fval;
684             break;
685         case LV_SVG_ATTR_OPACITY:
686             image->img_dsc.opa = (lv_opa_t)(attr->value.fval * 255.0f);
687             break;
688         case LV_SVG_ATTR_XLINK_HREF: {
689                 const char * xlink = attr->value.sval;
690                 if(hal_funcs.load_image) {
691                     hal_funcs.load_image(xlink, &image->img_dsc);
692                 }
693             }
694             break;
695         case LV_SVG_ATTR_PRESERVE_ASPECT_RATIO: {
696                 if(attr->class_type == LV_SVG_ATTR_VALUE_INITIAL) {
697                     image->ratio = attr->value.uval;
698                 }
699             }
700             break;
701     }
702 }
703 
_set_attr(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_attr_t * attr)704 static void _set_attr(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr)
705 {
706     LV_UNUSED(obj);
707     switch(attr->id) {
708         case LV_SVG_ATTR_FILL: {
709                 if(attr->class_type == LV_SVG_ATTR_VALUE_NONE) {
710                     dsc->fill_dsc.opa = LV_OPA_0;
711                     obj->flags |= _RENDER_ATTR_FILL_OPACITY;
712                     obj->flags |= _RENDER_ATTR_FILL;
713                     return;
714                 }
715                 else if(attr->class_type == LV_SVG_ATTR_VALUE_INHERIT) {
716                     obj->flags &= ~_RENDER_ATTR_FILL;
717                     return;
718                 }
719                 else {
720                     if(obj->fill_ref) {
721                         lv_free(obj->fill_ref);
722                         obj->fill_ref = NULL;
723                     }
724                     if(attr->val_type == LV_SVG_ATTR_VALUE_PTR) {
725                         obj->fill_ref = lv_strdup(attr->value.sval);
726                     }
727                     else {   // color
728                         dsc->fill_dsc.style = LV_VECTOR_DRAW_STYLE_SOLID;
729                         dsc->fill_dsc.color = lv_color_to_32(lv_color_hex(attr->value.uval), 0xFF);
730                     }
731                     obj->flags |= _RENDER_ATTR_FILL;
732                     if(obj->dsc.fill_dsc.opa == LV_OPA_0) {
733                         dsc->fill_dsc.opa = LV_OPA_COVER;
734                         obj->flags |= _RENDER_ATTR_FILL_OPACITY;
735                     }
736                 }
737             }
738             break;
739         case LV_SVG_ATTR_STROKE: {
740                 if(attr->class_type == LV_SVG_ATTR_VALUE_NONE) {
741                     dsc->stroke_dsc.opa = LV_OPA_0;
742                     obj->flags |= _RENDER_ATTR_STROKE_OPACITY;
743                     obj->flags |= _RENDER_ATTR_STROKE;
744                     return;
745                 }
746                 else if(attr->class_type == LV_SVG_ATTR_VALUE_INHERIT) {
747                     obj->flags &= ~_RENDER_ATTR_STROKE;
748                     return;
749                 }
750                 else {
751                     if(obj->stroke_ref) {
752                         lv_free(obj->stroke_ref);
753                         obj->stroke_ref = NULL;
754                     }
755                     if(attr->val_type == LV_SVG_ATTR_VALUE_PTR) {
756                         obj->stroke_ref = lv_strdup(attr->value.sval);
757                     }
758                     else {   // color
759                         dsc->stroke_dsc.style = LV_VECTOR_DRAW_STYLE_SOLID;
760                         dsc->stroke_dsc.color = lv_color_to_32(lv_color_hex(attr->value.uval), 0xFF);
761                     }
762                 }
763 
764                 obj->flags |= _RENDER_ATTR_STROKE;
765                 if(obj->dsc.stroke_dsc.opa == LV_OPA_0) {
766                     dsc->stroke_dsc.opa = LV_OPA_COVER;
767                     obj->flags |= _RENDER_ATTR_STROKE_OPACITY;
768                 }
769             }
770             break;
771         case LV_SVG_ATTR_FILL_OPACITY: {
772                 if(attr->class_type == LV_SVG_ATTR_VALUE_INHERIT) {
773                     obj->flags &= ~_RENDER_ATTR_FILL_OPACITY;
774                     return;
775                 }
776                 dsc->fill_dsc.opa = (lv_opa_t)(attr->value.fval * 255.0f);
777                 obj->flags |= _RENDER_ATTR_FILL_OPACITY;
778             }
779             break;
780         case LV_SVG_ATTR_STROKE_OPACITY: {
781                 if(attr->class_type == LV_SVG_ATTR_VALUE_INHERIT) {
782                     obj->flags &= ~_RENDER_ATTR_STROKE_OPACITY;
783                     return;
784                 }
785                 dsc->stroke_dsc.opa = (lv_opa_t)(attr->value.fval * 255.0f);
786                 obj->flags |= _RENDER_ATTR_STROKE_OPACITY;
787             }
788             break;
789         case LV_SVG_ATTR_FILL_RULE: {
790                 if(attr->class_type == LV_SVG_ATTR_VALUE_INHERIT) {
791                     obj->flags &= ~_RENDER_ATTR_FILL_RULE;
792                     return;
793                 }
794                 dsc->fill_dsc.fill_rule = attr->value.ival;
795                 obj->flags |= _RENDER_ATTR_FILL_RULE;
796             }
797             break;
798         case LV_SVG_ATTR_STROKE_WIDTH: {
799                 if(attr->class_type == LV_SVG_ATTR_VALUE_INHERIT) {
800                     obj->flags &= ~_RENDER_ATTR_STROKE_WIDTH;
801                     return;
802                 }
803                 dsc->stroke_dsc.width = attr->value.fval;
804                 obj->flags |= _RENDER_ATTR_STROKE_WIDTH;
805             }
806             break;
807         case LV_SVG_ATTR_STROKE_LINECAP: {
808                 if(attr->class_type == LV_SVG_ATTR_VALUE_INHERIT) {
809                     obj->flags &= ~_RENDER_ATTR_STROKE_LINECAP;
810                     return;
811                 }
812                 dsc->stroke_dsc.cap = attr->value.ival;
813                 obj->flags |= _RENDER_ATTR_STROKE_LINECAP;
814             }
815             break;
816         case LV_SVG_ATTR_STROKE_LINEJOIN: {
817                 if(attr->class_type == LV_SVG_ATTR_VALUE_INHERIT) {
818                     obj->flags &= ~_RENDER_ATTR_STROKE_LINEJOIN;
819                     return;
820                 }
821                 dsc->stroke_dsc.join = attr->value.ival;
822                 obj->flags |= _RENDER_ATTR_STROKE_LINEJOIN;
823             }
824             break;
825         case LV_SVG_ATTR_STROKE_MITER_LIMIT: {
826                 if(attr->class_type == LV_SVG_ATTR_VALUE_INHERIT) {
827                     obj->flags &= ~_RENDER_ATTR_STROKE_MITER_LIMIT;
828                     return;
829                 }
830                 dsc->stroke_dsc.miter_limit = attr->value.ival;
831                 obj->flags |= _RENDER_ATTR_STROKE_MITER_LIMIT;
832             }
833             break;
834         case LV_SVG_ATTR_STROKE_DASH_ARRAY: {
835                 if(attr->class_type == LV_SVG_ATTR_VALUE_NONE) {
836                     lv_array_clear(&(dsc->stroke_dsc.dash_pattern));
837                     obj->flags |= _RENDER_ATTR_STROKE_DASH_ARRAY;
838                     return;
839                 }
840                 else if(attr->class_type == LV_SVG_ATTR_VALUE_INHERIT) {
841                     obj->flags &= ~_RENDER_ATTR_STROKE_DASH_ARRAY;
842                     return;
843                 }
844                 else {
845                     lv_array_t * dash_array = &(dsc->stroke_dsc.dash_pattern);
846 
847                     lv_svg_attr_values_list_t * vals = (lv_svg_attr_values_list_t *)(attr->value.val);
848                     uint32_t len = vals->length;
849                     float * dashs = (float *)(&vals->data);
850                     lv_array_clear(dash_array);
851 
852                     obj->flags |= _RENDER_ATTR_STROKE_DASH_ARRAY;
853                     if(len) {
854                         if(lv_array_capacity(dash_array) == 0) {
855                             lv_array_init(dash_array, len, sizeof(float));
856                         }
857                         else {
858                             lv_array_resize(dash_array, len);
859                         }
860                         for(uint32_t i = 0; i < len; i++) {
861                             lv_array_push_back(dash_array, (uint8_t *)(&dashs[i]));
862                         }
863                     }
864                 }
865             }
866             break;
867         case LV_SVG_ATTR_TRANSFORM: {
868                 if(attr->class_type == LV_SVG_ATTR_VALUE_NONE) {
869                     return;
870                 }
871                 lv_memcpy(&(obj->matrix), attr->value.val, sizeof(lv_matrix_t));
872             }
873             break;
874         case LV_SVG_ATTR_STROKE_DASH_OFFSET:
875             // not support yet
876             break;
877     }
878 }
879 
_set_solid_ref(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_render_obj_t * target_obj,bool fill)880 static void _set_solid_ref(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc,
881                            const lv_svg_render_obj_t * target_obj, bool fill)
882 {
883     LV_UNUSED(target_obj);
884     lv_svg_render_solid_t * solid = (lv_svg_render_solid_t *)obj;
885     if(fill) {
886         dsc->fill_dsc.style = LV_VECTOR_DRAW_STYLE_SOLID;
887         dsc->fill_dsc.color = lv_color_to_32(solid->color, 0xFF);
888         dsc->fill_dsc.opa = (lv_opa_t)(solid->opacity * 255.0f);
889     }
890     else {
891         dsc->stroke_dsc.style = LV_VECTOR_DRAW_STYLE_SOLID;
892         dsc->stroke_dsc.color = lv_color_to_32(solid->color, 0xFF);
893         dsc->stroke_dsc.opa = (lv_opa_t)(solid->opacity * 255.0f);
894     }
895 }
896 
_set_gradient_ref(lv_svg_render_obj_t * obj,lv_vector_draw_dsc_t * dsc,const lv_svg_render_obj_t * target_obj,bool fill)897 static void _set_gradient_ref(lv_svg_render_obj_t * obj, lv_vector_draw_dsc_t * dsc,
898                               const lv_svg_render_obj_t * target_obj, bool fill)
899 {
900     if(!target_obj->get_bounds) {
901         return;
902     }
903 
904     lv_svg_render_gradient_t * grad = (lv_svg_render_gradient_t *)obj;
905     lv_vector_gradient_t * grad_dsc = NULL;
906     lv_matrix_t * mtx = NULL;
907 
908     if(fill) {
909         dsc->fill_dsc.style = LV_VECTOR_DRAW_STYLE_GRADIENT;
910         grad_dsc = &dsc->fill_dsc.gradient;
911         mtx = &dsc->fill_dsc.matrix;
912     }
913     else {
914         dsc->stroke_dsc.style = LV_VECTOR_DRAW_STYLE_GRADIENT;
915         grad_dsc = &dsc->stroke_dsc.gradient;
916         mtx = &dsc->stroke_dsc.matrix;
917     }
918 
919     lv_memcpy(grad_dsc, &grad->dsc, sizeof(lv_vector_gradient_t));
920 
921     lv_area_t bounds = {0, 0, 0, 0};
922     target_obj->get_bounds(target_obj, &bounds);
923 
924     int32_t w = bounds.x2 - bounds.x1;
925     int32_t h = bounds.y2 - bounds.y1;
926     if(grad->dsc.style == LV_VECTOR_GRADIENT_STYLE_RADIAL) {
927         if(grad->units == LV_SVG_GRADIENT_UNITS_OBJECT) {
928             grad_dsc->cx = PCT_TO_PX(grad_dsc->cx, w);
929             grad_dsc->cy = PCT_TO_PX(grad_dsc->cy, h);
930             grad_dsc->cr = PCT_TO_PX(grad_dsc->cr, MAX(w, h));
931             lv_matrix_translate(mtx, bounds.x1, bounds.y1);
932         }
933     }
934     else {   // LV_VECTOR_GRADIENT_STYLE_LINEAR
935         if(grad->units == LV_SVG_GRADIENT_UNITS_OBJECT) {
936             grad_dsc->x1 = PCT_TO_PX(grad_dsc->x1, w);
937             grad_dsc->y1 = PCT_TO_PX(grad_dsc->y1, h);
938             grad_dsc->x2 = PCT_TO_PX(grad_dsc->x2, w);
939             grad_dsc->y2 = PCT_TO_PX(grad_dsc->y2, h);
940             lv_matrix_translate(mtx, bounds.x1, bounds.y1);
941         }
942     }
943 }
944 
_init_draw_dsc(lv_vector_draw_dsc_t * dsc)945 static void _init_draw_dsc(lv_vector_draw_dsc_t * dsc)
946 {
947     lv_vector_fill_dsc_t * fill_dsc = &(dsc->fill_dsc);
948     fill_dsc->style = LV_VECTOR_DRAW_STYLE_SOLID;
949     fill_dsc->color = lv_color_to_32(lv_color_black(), 0xFF);
950     fill_dsc->opa = LV_OPA_COVER;
951     fill_dsc->fill_rule = LV_VECTOR_FILL_NONZERO;
952     lv_matrix_identity(&(fill_dsc->matrix)); // identity matrix
953 
954     lv_vector_stroke_dsc_t * stroke_dsc = &(dsc->stroke_dsc);
955     stroke_dsc->style = LV_VECTOR_DRAW_STYLE_SOLID;
956     stroke_dsc->color = lv_color_to_32(lv_color_black(), 0xFF);
957     stroke_dsc->opa = LV_OPA_0; // default no stroke
958     stroke_dsc->width = 1.0f;
959     stroke_dsc->cap = LV_VECTOR_STROKE_CAP_BUTT;
960     stroke_dsc->join = LV_VECTOR_STROKE_JOIN_MITER;
961     stroke_dsc->miter_limit = 4.0f;
962     lv_matrix_identity(&(stroke_dsc->matrix)); // identity matrix
963 
964     dsc->blend_mode = LV_VECTOR_BLEND_SRC_OVER;
965     lv_matrix_identity(&(dsc->matrix)); // identity matrix
966 }
967 
_deinit_draw_dsc(lv_vector_draw_dsc_t * dsc)968 static void _deinit_draw_dsc(lv_vector_draw_dsc_t * dsc)
969 {
970     lv_array_deinit(&(dsc->stroke_dsc.dash_pattern));
971 }
972 
_copy_draw_dsc(lv_vector_draw_dsc_t * dst,const lv_vector_draw_dsc_t * src)973 static void _copy_draw_dsc(lv_vector_draw_dsc_t * dst, const lv_vector_draw_dsc_t * src)
974 {
975     lv_memcpy(&dst->fill_dsc, &src->fill_dsc, sizeof(lv_vector_fill_dsc_t));
976 
977     dst->stroke_dsc.style = src->stroke_dsc.style;
978     dst->stroke_dsc.color = src->stroke_dsc.color;
979     dst->stroke_dsc.opa = src->stroke_dsc.opa;
980     dst->stroke_dsc.width = src->stroke_dsc.width;
981     dst->stroke_dsc.cap = src->stroke_dsc.cap;
982     dst->stroke_dsc.join = src->stroke_dsc.join;
983     dst->stroke_dsc.miter_limit = src->stroke_dsc.miter_limit;
984     lv_array_copy(&(dst->stroke_dsc.dash_pattern), &(src->stroke_dsc.dash_pattern));
985     lv_memcpy(&(dst->stroke_dsc.gradient), &(src->stroke_dsc.gradient), sizeof(lv_vector_gradient_t));
986     lv_memcpy(&(dst->stroke_dsc.matrix), &(src->stroke_dsc.matrix), sizeof(lv_matrix_t));
987 
988     dst->blend_mode = src->blend_mode;
989 }
990 
_copy_draw_dsc_from_ref(lv_vector_dsc_t * dsc,const lv_svg_render_obj_t * obj)991 static void _copy_draw_dsc_from_ref(lv_vector_dsc_t * dsc, const lv_svg_render_obj_t * obj)
992 {
993     lv_vector_draw_dsc_t * dst = &(dsc->current_dsc);
994     if(obj->fill_ref) {
995         lv_svg_render_obj_t * list = obj->head;
996         while(list) {
997             if(list->id) {
998                 if(strcmp(obj->fill_ref, list->id) == 0) {
999                     list->set_paint_ref(list, dst, obj, true);
1000                     break;
1001                 }
1002             }
1003             list = list->next;
1004         }
1005     }
1006 
1007     if(obj->stroke_ref) {
1008         lv_svg_render_obj_t * list = obj->head;
1009         while(list) {
1010             if(list->id) {
1011                 if(strcmp(obj->stroke_ref, list->id) == 0) {
1012                     list->set_paint_ref(list, dst, obj, false);
1013                     break;
1014                 }
1015             }
1016             list = list->next;
1017         }
1018     }
1019 }
1020 
_set_render_attrs(lv_svg_render_obj_t * obj,const lv_svg_node_t * node,struct _lv_svg_drawing_builder_state * state)1021 static void _set_render_attrs(lv_svg_render_obj_t * obj, const lv_svg_node_t * node,
1022                               struct _lv_svg_drawing_builder_state * state)
1023 {
1024     if((node->type != LV_SVG_TAG_CONTENT) && node->xml_id) {
1025         obj->id = lv_strdup(node->xml_id);
1026     }
1027     if(obj->init) {
1028         obj->init(obj, node);
1029     }
1030     if(state->draw_dsc->fill_ref) {
1031         obj->fill_ref = lv_strdup(state->draw_dsc->fill_ref);
1032     }
1033     if(state->draw_dsc->stroke_ref) {
1034         obj->stroke_ref = lv_strdup(state->draw_dsc->stroke_ref);
1035     }
1036 
1037     uint32_t len = lv_array_size(&node->attrs);
1038     for(uint32_t i = 0; i < len; i++) {
1039         lv_svg_attr_t * attr = lv_array_at(&node->attrs, i);
1040         obj->set_attr(obj, &(state->draw_dsc->dsc), attr);
1041     }
1042     if(node->type == LV_SVG_TAG_G) { // only <g> need store it
1043         state->draw_dsc->fill_ref = obj->fill_ref;
1044         state->draw_dsc->stroke_ref = obj->stroke_ref;
1045     }
1046     obj->head = state->list;
1047 }
1048 
1049 // init functions
1050 
_init_obj(lv_svg_render_obj_t * obj,const lv_svg_node_t * node)1051 static void _init_obj(lv_svg_render_obj_t * obj, const lv_svg_node_t * node)
1052 {
1053     LV_UNUSED(node);
1054     lv_matrix_identity(&obj->matrix);
1055 }
1056 
_init_viewport(lv_svg_render_obj_t * obj,const lv_svg_node_t * node)1057 static void _init_viewport(lv_svg_render_obj_t * obj, const lv_svg_node_t * node)
1058 {
1059     _init_obj(obj, node);
1060     lv_svg_render_viewport_t * view = (lv_svg_render_viewport_t *)obj;
1061     view->viewport_fill = false;
1062 }
1063 
_init_group(lv_svg_render_obj_t * obj,const lv_svg_node_t * node)1064 static void _init_group(lv_svg_render_obj_t * obj, const lv_svg_node_t * node)
1065 {
1066     _init_obj(obj, node);
1067     lv_svg_render_group_t * group = (lv_svg_render_group_t *)obj;
1068     lv_array_init(&group->items, LV_TREE_NODE(node)->child_cnt, sizeof(lv_svg_render_obj_t *));
1069 }
1070 
_init_image(lv_svg_render_obj_t * obj,const lv_svg_node_t * node)1071 static void _init_image(lv_svg_render_obj_t * obj, const lv_svg_node_t * node)
1072 {
1073     _init_obj(obj, node);
1074     lv_svg_render_image_t * image = (lv_svg_render_image_t *)obj;
1075     lv_draw_image_dsc_init(&image->img_dsc);
1076     image->ratio = LV_SVG_ASPECT_RATIO_XMID_YMID | LV_SVG_ASPECT_RATIO_OPT_MEET;
1077 }
1078 
_init_poly(lv_svg_render_obj_t * obj,const lv_svg_node_t * node)1079 static void _init_poly(lv_svg_render_obj_t * obj, const lv_svg_node_t * node)
1080 {
1081     _init_obj(obj, node);
1082     lv_svg_render_poly_t * poly = (lv_svg_render_poly_t *)obj;
1083     poly->path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);
1084     lv_area_set(&poly->bounds, 0, 0, 0, 0);
1085 }
1086 
1087 #if LV_USE_FREETYPE
_init_text(lv_svg_render_obj_t * obj,const lv_svg_node_t * node)1088 static void _init_text(lv_svg_render_obj_t * obj, const lv_svg_node_t * node)
1089 {
1090     _init_obj(obj, node);
1091     lv_svg_render_text_t * text = (lv_svg_render_text_t *)obj;
1092     text->family = lv_strdup("sans-serif");
1093     text->size = 16.0f;
1094     text->style = LV_FREETYPE_FONT_STYLE_NORMAL;
1095     text->font = NULL;
1096     text->x = text->y = 0.0f;
1097     lv_array_init(&text->contents, LV_TREE_NODE(node)->child_cnt, sizeof(lv_svg_render_obj_t *));
1098     text->path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);
1099 }
1100 
_init_content(lv_svg_render_obj_t * obj,const lv_svg_node_t * node)1101 static void _init_content(lv_svg_render_obj_t * obj, const lv_svg_node_t * node)
1102 {
1103     _init_obj(obj, node);
1104     lv_svg_render_content_t * content = (lv_svg_render_content_t *)obj;
1105     const char * str = node->xml_id;
1106     content->count = lv_text_get_encoded_length(str);
1107     content->letters = lv_malloc(sizeof(uint32_t) * content->count);
1108     LV_ASSERT_MALLOC(content->letters);
1109     uint32_t offset = 0;
1110     for(uint32_t i = 0; i < content->count; i++) {
1111         content->letters[i] = lv_text_encoded_next(str, &offset);
1112     }
1113 }
1114 
_init_tspan(lv_svg_render_obj_t * obj,const lv_svg_node_t * node)1115 static void _init_tspan(lv_svg_render_obj_t * obj, const lv_svg_node_t * node)
1116 {
1117     _init_obj(obj, node);
1118     lv_svg_render_tspan_t * span = (lv_svg_render_tspan_t *)obj;
1119     lv_svg_node_t * parent = LV_SVG_NODE(LV_TREE_NODE(node)->parent);
1120     if(parent->type != LV_SVG_TAG_TEXT) {
1121         return;
1122     }
1123 
1124     lv_svg_render_text_t * text = (lv_svg_render_text_t *)parent->render_obj;
1125     span->family = lv_strdup(text->family);
1126     span->size = text->size;
1127     span->style = text->style;
1128     span->path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);
1129 
1130     lv_svg_node_t * content_node = LV_SVG_NODE(LV_TREE_NODE(node)->children[0]);
1131     _init_content(obj, content_node);
1132 }
1133 #endif
1134 
_init_gradient(lv_svg_render_obj_t * obj,const lv_svg_node_t * node)1135 static void _init_gradient(lv_svg_render_obj_t * obj, const lv_svg_node_t * node)
1136 {
1137     _init_obj(obj, node);
1138     lv_svg_render_gradient_t * grad = (lv_svg_render_gradient_t *)obj;
1139     grad->units = LV_SVG_GRADIENT_UNITS_OBJECT;
1140     grad->dsc.cx = 0.5f;
1141     grad->dsc.cy = 0.5f;
1142     grad->dsc.cr = 0.5f;
1143     grad->dsc.x1 = 0.0f;
1144     grad->dsc.y1 = 0.0f;
1145     grad->dsc.x2 = 1.0f;
1146     grad->dsc.y2 = 0.0f;
1147     grad->dsc.spread = LV_VECTOR_GRADIENT_SPREAD_PAD;
1148 
1149     uint32_t count = LV_TREE_NODE(node)->child_cnt;
1150     uint32_t stop_count = 0;
1151 
1152     for(uint32_t i = 0; i < count; i++) {
1153         lv_svg_node_t * child_node = LV_SVG_NODE_CHILD(node, i);
1154         uint32_t len = lv_array_size(&child_node->attrs);
1155 
1156         bool is_stop = false;
1157         lv_color_t stop_color = lv_color_black();
1158         lv_opa_t stop_opa = LV_OPA_COVER;
1159         uint8_t stop_frac = 0;
1160 
1161         for(uint32_t j = 0; j < len; j++) {
1162             lv_svg_attr_t * attr = lv_array_at(&child_node->attrs, j);
1163             switch(attr->id) {
1164                 case LV_SVG_ATTR_GRADIENT_STOP_COLOR: {
1165                         stop_color = lv_color_hex(attr->value.uval);
1166                         is_stop = true;
1167                     }
1168                     break;
1169                 case LV_SVG_ATTR_GRADIENT_STOP_OPACITY: {
1170                         stop_opa = (lv_opa_t)(attr->value.fval * 255.0f);
1171                         is_stop = true;
1172                     }
1173                     break;
1174                 case LV_SVG_ATTR_GRADIENT_STOP_OFFSET: {
1175                         stop_frac = (uint8_t)(attr->value.fval * 255.0f);
1176                         is_stop = true;
1177                     }
1178                     break;
1179             }
1180         }
1181 
1182         if(is_stop) {
1183             grad->dsc.stops[stop_count].opa = stop_opa;
1184             grad->dsc.stops[stop_count].frac = stop_frac;
1185             grad->dsc.stops[stop_count].color = stop_color;
1186             stop_count++;
1187         }
1188 
1189         if(stop_count == LV_GRADIENT_MAX_STOPS) {
1190             break;
1191         }
1192     }
1193     grad->dsc.stops_count = stop_count;
1194 }
1195 
_setup_matrix(lv_matrix_t * matrix,lv_vector_dsc_t * dsc,const lv_svg_render_obj_t * obj)1196 static void _setup_matrix(lv_matrix_t * matrix, lv_vector_dsc_t * dsc, const lv_svg_render_obj_t * obj)
1197 {
1198     lv_memcpy(matrix, &dsc->current_dsc.matrix, sizeof(lv_matrix_t));
1199     lv_matrix_multiply(&dsc->current_dsc.matrix, &obj->matrix);
1200 }
1201 
_restore_matrix(lv_matrix_t * matrix,lv_vector_dsc_t * dsc)1202 static void _restore_matrix(lv_matrix_t * matrix, lv_vector_dsc_t * dsc)
1203 {
1204     lv_memcpy(&dsc->current_dsc.matrix, matrix, sizeof(lv_matrix_t));
1205 }
1206 
_prepare_render(const lv_svg_render_obj_t * obj,lv_vector_dsc_t * dsc)1207 static void _prepare_render(const lv_svg_render_obj_t * obj, lv_vector_dsc_t * dsc)
1208 {
1209     _copy_draw_dsc(&(dsc->current_dsc), &(obj->dsc));
1210 }
1211 
_special_render(const lv_svg_render_obj_t * obj,lv_vector_dsc_t * dsc)1212 static void _special_render(const lv_svg_render_obj_t * obj, lv_vector_dsc_t * dsc)
1213 {
1214     const lv_vector_draw_dsc_t * src = &(obj->dsc);
1215     lv_vector_draw_dsc_t * dst = &(dsc->current_dsc);
1216 
1217     if(obj->flags & _RENDER_ATTR_FILL) {
1218         lv_memcpy(&(dst->fill_dsc), &(src->fill_dsc), sizeof(lv_vector_fill_dsc_t));
1219         dst->blend_mode = src->blend_mode;
1220     }
1221 
1222     if(obj->flags & _RENDER_ATTR_FILL_OPACITY) {
1223         dst->fill_dsc.opa = src->fill_dsc.opa;
1224     }
1225 
1226     if(obj->flags & _RENDER_ATTR_FILL_RULE) {
1227         dst->fill_dsc.fill_rule = src->fill_dsc.fill_rule;
1228     }
1229 
1230     if(obj->flags & _RENDER_ATTR_STROKE) {
1231         dst->stroke_dsc.style = src->stroke_dsc.style;
1232         dst->stroke_dsc.color = src->stroke_dsc.color;
1233         lv_memcpy(&(dst->stroke_dsc.gradient), &(src->stroke_dsc.gradient), sizeof(lv_vector_gradient_t));
1234         lv_memcpy(&(dst->stroke_dsc.matrix), &(src->stroke_dsc.matrix), sizeof(lv_matrix_t));
1235         dst->blend_mode = src->blend_mode;
1236     }
1237 
1238     if(obj->flags & _RENDER_ATTR_STROKE_OPACITY) {
1239         dst->stroke_dsc.opa = src->stroke_dsc.opa;
1240     }
1241 
1242     if(obj->flags & _RENDER_ATTR_STROKE_WIDTH) {
1243         dst->stroke_dsc.width = src->stroke_dsc.width;
1244     }
1245     if(obj->flags & _RENDER_ATTR_STROKE_LINECAP) {
1246         dst->stroke_dsc.cap = src->stroke_dsc.cap;
1247     }
1248     if(obj->flags & _RENDER_ATTR_STROKE_LINEJOIN) {
1249         dst->stroke_dsc.join = src->stroke_dsc.join;
1250     }
1251     if(obj->flags & _RENDER_ATTR_STROKE_MITER_LIMIT) {
1252         dst->stroke_dsc.miter_limit = src->stroke_dsc.miter_limit;
1253     }
1254     if(obj->flags & _RENDER_ATTR_STROKE_DASH_ARRAY) {
1255         lv_array_copy(&(dst->stroke_dsc.dash_pattern), &(src->stroke_dsc.dash_pattern));
1256     }
1257 }
1258 
1259 // render functions
_render_viewport(const lv_svg_render_obj_t * obj,lv_vector_dsc_t * dsc,const lv_matrix_t * matrix)1260 static void _render_viewport(const lv_svg_render_obj_t * obj, lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
1261 {
1262     LV_UNUSED(matrix);
1263 
1264     lv_svg_render_viewport_t * view = (lv_svg_render_viewport_t *)obj;
1265     lv_matrix_multiply(&dsc->current_dsc.matrix, &obj->matrix);
1266     if(view->viewport_fill) {
1267         lv_area_t rc = {0, 0, (int32_t)view->width, (int32_t)view->height};
1268         lv_vector_clear_area(dsc, &rc);
1269     }
1270 }
1271 
_render_rect(const lv_svg_render_obj_t * obj,lv_vector_dsc_t * dsc,const lv_matrix_t * matrix)1272 static void _render_rect(const lv_svg_render_obj_t * obj, lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
1273 {
1274     lv_matrix_t mtx;
1275     _setup_matrix(&mtx, dsc, obj);
1276 
1277     if(matrix) {
1278         lv_matrix_multiply(&dsc->current_dsc.matrix, matrix);
1279     }
1280 
1281     lv_svg_render_rect_t * rect = (lv_svg_render_rect_t *)obj;
1282 
1283     if(rect->rx > 0 && rect->ry == 0) rect->ry = rect->rx;
1284     else if(rect->ry > 0 && rect->rx == 0) rect->rx = rect->ry;
1285 
1286     lv_vector_path_t * path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);
1287     lv_area_t rc = {(int32_t)rect->x, (int32_t)rect->y, (int32_t)(rect->x + rect->width), (int32_t)(rect->y + rect->height)};
1288     lv_vector_path_append_rect(path, &rc, rect->rx, rect->ry);
1289 
1290     _copy_draw_dsc_from_ref(dsc, obj);
1291     lv_vector_dsc_add_path(dsc, path);
1292     lv_vector_path_delete(path);
1293 
1294     _restore_matrix(&mtx, dsc);
1295 }
1296 
_render_circle(const lv_svg_render_obj_t * obj,lv_vector_dsc_t * dsc,const lv_matrix_t * matrix)1297 static void _render_circle(const lv_svg_render_obj_t * obj, lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
1298 {
1299     lv_matrix_t mtx;
1300     _setup_matrix(&mtx, dsc, obj);
1301 
1302     if(matrix) {
1303         lv_matrix_multiply(&dsc->current_dsc.matrix, matrix);
1304     }
1305 
1306     lv_svg_render_circle_t * circle = (lv_svg_render_circle_t *)obj;
1307     lv_vector_path_t * path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);
1308     lv_fpoint_t cp = {circle->cx, circle->cy};
1309     lv_vector_path_append_circle(path, &cp, circle->r, circle->r);
1310 
1311     _copy_draw_dsc_from_ref(dsc, obj);
1312     lv_vector_dsc_add_path(dsc, path);
1313     lv_vector_path_delete(path);
1314 
1315     _restore_matrix(&mtx, dsc);
1316 }
1317 
_render_ellipse(const lv_svg_render_obj_t * obj,lv_vector_dsc_t * dsc,const lv_matrix_t * matrix)1318 static void _render_ellipse(const lv_svg_render_obj_t * obj, lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
1319 {
1320     lv_matrix_t mtx;
1321     _setup_matrix(&mtx, dsc, obj);
1322 
1323     if(matrix) {
1324         lv_matrix_multiply(&dsc->current_dsc.matrix, matrix);
1325     }
1326 
1327     lv_svg_render_ellipse_t * ellipse = (lv_svg_render_ellipse_t *)obj;
1328     lv_vector_path_t * path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);
1329     lv_fpoint_t cp = {ellipse->cx, ellipse->cy};
1330     lv_vector_path_append_circle(path, &cp, ellipse->rx, ellipse->ry);
1331 
1332     _copy_draw_dsc_from_ref(dsc, obj);
1333     lv_vector_dsc_add_path(dsc, path);
1334     lv_vector_path_delete(path);
1335 
1336     _restore_matrix(&mtx, dsc);
1337 }
1338 
_render_line(const lv_svg_render_obj_t * obj,lv_vector_dsc_t * dsc,const lv_matrix_t * matrix)1339 static void _render_line(const lv_svg_render_obj_t * obj, lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
1340 {
1341     lv_matrix_t mtx;
1342     _setup_matrix(&mtx, dsc, obj);
1343 
1344     if(matrix) {
1345         lv_matrix_multiply(&dsc->current_dsc.matrix, matrix);
1346     }
1347 
1348     lv_svg_render_line_t * line = (lv_svg_render_line_t *)obj;
1349     lv_vector_path_t * path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);
1350     lv_fpoint_t sp = {line->x1, line->y1};
1351     lv_vector_path_move_to(path, &sp);
1352     lv_fpoint_t ep = {line->x2, line->y2};
1353     lv_vector_path_line_to(path, &ep);
1354 
1355     _copy_draw_dsc_from_ref(dsc, obj);
1356     lv_vector_dsc_add_path(dsc, path);
1357     lv_vector_path_delete(path);
1358 
1359     _restore_matrix(&mtx, dsc);
1360 }
1361 
_render_poly(const lv_svg_render_obj_t * obj,lv_vector_dsc_t * dsc,const lv_matrix_t * matrix)1362 static void _render_poly(const lv_svg_render_obj_t * obj, lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
1363 {
1364     lv_matrix_t mtx;
1365     _setup_matrix(&mtx, dsc, obj);
1366 
1367     if(matrix) {
1368         lv_matrix_multiply(&dsc->current_dsc.matrix, matrix);
1369     }
1370 
1371     lv_svg_render_poly_t * poly = (lv_svg_render_poly_t *)obj;
1372 
1373     _copy_draw_dsc_from_ref(dsc, obj);
1374     lv_vector_dsc_add_path(dsc, poly->path);
1375 
1376     _restore_matrix(&mtx, dsc);
1377 }
1378 
_render_group(const lv_svg_render_obj_t * obj,lv_vector_dsc_t * dsc,const lv_matrix_t * matrix)1379 static void _render_group(const lv_svg_render_obj_t * obj, lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
1380 {
1381     lv_svg_render_group_t * group = (lv_svg_render_group_t *)obj;
1382 
1383     lv_matrix_t mtx;
1384     _setup_matrix(&mtx, dsc, obj);
1385 
1386     struct _lv_svg_draw_dsc save_dsc;
1387     lv_memzero(&save_dsc, sizeof(struct _lv_svg_draw_dsc));
1388 
1389     for(uint32_t i = 0; i < group->items.size; i++) {
1390         lv_svg_render_obj_t * list = *((lv_svg_render_obj_t **)lv_array_at(&group->items, i));
1391 
1392         if(list->render && (list->flags & _RENDER_IN_GROUP)) {
1393             _copy_draw_dsc(&(save_dsc.dsc), &(dsc->current_dsc));
1394             _special_render(list, dsc);
1395             list->render(list, dsc, matrix);
1396             _copy_draw_dsc(&(dsc->current_dsc), &(save_dsc.dsc));
1397         }
1398     }
1399 
1400     _restore_matrix(&mtx, dsc);
1401 }
1402 
_render_image(const lv_svg_render_obj_t * obj,lv_vector_dsc_t * dsc,const lv_matrix_t * matrix)1403 static void _render_image(const lv_svg_render_obj_t * obj, lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
1404 {
1405     lv_matrix_t imtx;
1406     _setup_matrix(&imtx, dsc, obj);
1407 
1408     if(matrix) {
1409         lv_matrix_multiply(&dsc->current_dsc.matrix, matrix);
1410     }
1411 
1412     lv_svg_render_image_t * image = (lv_svg_render_image_t *)obj;
1413     if(!image->img_dsc.header.w || !image->img_dsc.header.h || !image->img_dsc.src) {
1414         return;
1415     }
1416 
1417     lv_vector_path_t * path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);
1418     lv_area_t rc = {(int32_t)image->x, (int32_t)image->y, (int32_t)(image->x + image->width), (int32_t)(image->y + image->height)};
1419     lv_vector_path_append_rect(path, &rc, 0, 0);
1420 
1421     lv_matrix_t mtx;
1422     lv_matrix_identity(&mtx);
1423 
1424     float img_w = (float)image->img_dsc.header.w;
1425     float img_h = (float)image->img_dsc.header.h;
1426     float scale_x = image->width / img_w;
1427     float scale_y = image->height / img_h;
1428     float scale = 1.0f;
1429 
1430     if((image->ratio & 0x1) == LV_SVG_ASPECT_RATIO_OPT_SLICE) {
1431         scale = MAX(scale_x, scale_y);
1432     }
1433     else if((image->ratio & 0x1) == LV_SVG_ASPECT_RATIO_OPT_MEET) {
1434         scale = MIN(scale_x, scale_y);
1435     }
1436 
1437     uint32_t align = image->ratio & ~0x1;
1438 
1439     switch(align) {
1440         case LV_SVG_ASPECT_RATIO_NONE:
1441             lv_matrix_scale(&mtx, scale_x, scale_y);
1442             break;
1443         case LV_SVG_ASPECT_RATIO_XMIN_YMIN:
1444             lv_matrix_scale(&mtx, scale, scale);
1445             break;
1446         case LV_SVG_ASPECT_RATIO_XMID_YMIN: {
1447                 float tx = (image->width - img_w * scale) / 2;
1448                 lv_matrix_translate(&mtx, tx, 0);
1449                 lv_matrix_scale(&mtx, scale, scale);
1450             }
1451             break;
1452         case LV_SVG_ASPECT_RATIO_XMAX_YMIN: {
1453                 float tx = image->width - img_w * scale;
1454                 lv_matrix_translate(&mtx, tx, 0);
1455                 lv_matrix_scale(&mtx, scale, scale);
1456             }
1457             break;
1458         case LV_SVG_ASPECT_RATIO_XMIN_YMID: {
1459                 float ty = (image->height - img_h * scale) / 2;
1460                 lv_matrix_translate(&mtx, 0, ty);
1461                 lv_matrix_scale(&mtx, scale, scale);
1462             }
1463             break;
1464         case LV_SVG_ASPECT_RATIO_XMID_YMID: {
1465                 float tx = (image->width - img_w * scale) / 2;
1466                 float ty = (image->height - img_h * scale) / 2;
1467                 lv_matrix_translate(&mtx, tx, ty);
1468                 lv_matrix_scale(&mtx, scale, scale);
1469             }
1470             break;
1471         case LV_SVG_ASPECT_RATIO_XMAX_YMID: {
1472                 float tx = image->width - img_w * scale;
1473                 float ty = (image->height - img_h * scale) / 2;
1474                 lv_matrix_translate(&mtx, tx, ty);
1475                 lv_matrix_scale(&mtx, scale, scale);
1476             }
1477             break;
1478         case LV_SVG_ASPECT_RATIO_XMIN_YMAX: {
1479                 float ty = image->height - img_h * scale;
1480                 lv_matrix_translate(&mtx, 0, ty);
1481                 lv_matrix_scale(&mtx, scale, scale);
1482             }
1483             break;
1484         case LV_SVG_ASPECT_RATIO_XMID_YMAX: {
1485                 float tx = (image->width - img_w * scale) / 2;
1486                 float ty = image->height - img_h * scale;
1487                 lv_matrix_translate(&mtx, tx, ty);
1488                 lv_matrix_scale(&mtx, scale, scale);
1489             }
1490             break;
1491         case LV_SVG_ASPECT_RATIO_XMAX_YMAX: {
1492                 float tx = image->width - img_w * scale;
1493                 float ty = image->height - img_h * scale;
1494                 lv_matrix_translate(&mtx, tx, ty);
1495                 lv_matrix_scale(&mtx, scale, scale);
1496             }
1497             break;
1498     }
1499 
1500     lv_vector_dsc_set_fill_transform(dsc, &mtx);
1501     lv_vector_dsc_set_fill_image(dsc, &image->img_dsc);
1502 
1503     _copy_draw_dsc_from_ref(dsc, obj);
1504     lv_vector_dsc_add_path(dsc, path);
1505     lv_vector_path_delete(path);
1506 
1507     _restore_matrix(&imtx, dsc);
1508 }
1509 
_render_use(const lv_svg_render_obj_t * obj,lv_vector_dsc_t * dsc,const lv_matrix_t * matrix)1510 static void _render_use(const lv_svg_render_obj_t * obj, lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
1511 {
1512     LV_UNUSED(matrix);
1513     lv_matrix_t imtx;
1514     _setup_matrix(&imtx, dsc, obj);
1515 
1516     lv_svg_render_use_t * use = (lv_svg_render_use_t *)obj;
1517 
1518     lv_matrix_t mtx;
1519     lv_matrix_identity(&mtx);
1520     lv_matrix_translate(&mtx, use->x, use->y);
1521 
1522     lv_svg_render_obj_t * list = obj->head;
1523     while(list) {
1524         if(list->id) {
1525             if(strcmp(use->xlink, list->id) == 0) {
1526                 if(list->render) {
1527                     _prepare_render(list, dsc);
1528                     _special_render(obj, dsc);
1529                     list->render(list, dsc, &mtx);
1530                 }
1531                 break;
1532             }
1533         }
1534         list = list->next;
1535     }
1536 
1537     _restore_matrix(&imtx, dsc);
1538 }
1539 
1540 #if LV_USE_FREETYPE
_render_text(const lv_svg_render_obj_t * obj,lv_vector_dsc_t * dsc,const lv_matrix_t * matrix)1541 static void _render_text(const lv_svg_render_obj_t * obj, lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
1542 {
1543     lv_svg_render_text_t * text = (lv_svg_render_text_t *)obj;
1544     if(!text->font) {
1545         if(!hal_funcs.get_font_path) {
1546             return;
1547         }
1548         const char * font_path = hal_funcs.get_font_path(text->family);
1549         if(!font_path) {
1550             return;
1551         }
1552         text->font = lv_freetype_font_create(font_path, LV_FREETYPE_FONT_RENDER_MODE_OUTLINE, (uint32_t)text->size,
1553                                              text->style);
1554     }
1555 
1556     if(!text->font || !lv_freetype_is_outline_font(text->font)) {
1557         LV_LOG_ERROR("svg current font is not outline font!");
1558         return;
1559     }
1560 
1561     lv_matrix_t tmtx;
1562     _setup_matrix(&tmtx, dsc, obj);
1563 
1564     if(matrix) {
1565         lv_matrix_multiply(&dsc->current_dsc.matrix, matrix);
1566     }
1567 
1568     if(lv_array_size(&text->path->ops) == 0) { /* empty path */
1569         lv_vector_path_t * glyph_path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);
1570         // draw text contents and spans
1571         lv_matrix_t mtx;
1572         lv_matrix_identity(&mtx);
1573         lv_matrix_translate(&mtx, text->x, text->y);
1574         for(uint32_t i = 0; i < lv_array_size(&text->contents); i++) {
1575             lv_svg_render_obj_t * ptext = *((lv_svg_render_obj_t **)lv_array_at(&text->contents, i));
1576             lv_svg_render_content_t * content = (lv_svg_render_content_t *)ptext;
1577 
1578             if(content->render_content) {
1579                 content->render_content(content, dsc, &mtx);
1580             }
1581             else {
1582                 float scale = text->size / 128.0f;
1583                 for(uint32_t j = 0; j < content->count; j++) {
1584                     uint32_t letter = content->letters[j];
1585                     lv_font_glyph_dsc_t g;
1586                     lv_font_get_glyph_dsc(text->font, &g, letter, '\0');
1587                     lv_vector_path_t * p = (lv_vector_path_t *)lv_font_get_glyph_bitmap(&g, NULL);
1588                     lv_vector_path_clear(glyph_path);
1589                     lv_vector_path_copy(glyph_path, p);
1590                     uint32_t letter_w = g.box_w > 0 ? g.box_w : g.adv_w;
1591 
1592                     lv_matrix_t scale_matrix = mtx;
1593                     lv_matrix_translate(&mtx, g.ofs_x, 0);
1594                     lv_matrix_scale(&scale_matrix, scale, scale);
1595                     lv_matrix_transform_path(&scale_matrix, glyph_path);
1596 
1597                     lv_vector_path_append_path(text->path, glyph_path);
1598                     text->font->release_glyph(text->font, &g);
1599                     lv_matrix_translate(&mtx, letter_w, 0);
1600                 }
1601             }
1602         }
1603         lv_vector_path_delete(glyph_path);
1604         lv_vector_path_get_bounding(text->path, &text->bounds);
1605     }
1606 
1607     _copy_draw_dsc_from_ref(dsc, obj);
1608     lv_vector_dsc_add_path(dsc, text->path);
1609 
1610     _restore_matrix(&tmtx, dsc);
1611 }
1612 
_render_span(const lv_svg_render_content_t * content,lv_vector_dsc_t * dsc,lv_matrix_t * matrix)1613 static void _render_span(const lv_svg_render_content_t * content, lv_vector_dsc_t * dsc, lv_matrix_t * matrix)
1614 {
1615     lv_svg_render_obj_t * obj = (lv_svg_render_obj_t *)content;
1616 
1617     lv_svg_render_tspan_t * span = (lv_svg_render_tspan_t *)content;
1618     if(!span->font) {
1619         if(!hal_funcs.get_font_path) {
1620             return;
1621         }
1622         const char * font_path = hal_funcs.get_font_path(span->family);
1623         if(!font_path) {
1624             return;
1625         }
1626         span->font = lv_freetype_font_create(font_path, LV_FREETYPE_FONT_RENDER_MODE_OUTLINE, (uint32_t)span->size,
1627                                              span->style);
1628     }
1629 
1630     if(!span->font || !lv_freetype_is_outline_font(span->font)) {
1631         LV_LOG_ERROR("svg current font is not outline font!");
1632         return;
1633     }
1634 
1635     struct _lv_svg_draw_dsc save_dsc;
1636     lv_memzero(&save_dsc, sizeof(struct _lv_svg_draw_dsc));
1637     _copy_draw_dsc(&(save_dsc.dsc), &(dsc->current_dsc));
1638 
1639     _copy_draw_dsc(&(dsc->current_dsc), &(obj->dsc));
1640 
1641     if(lv_array_size(&span->path->ops) == 0) { /* empty path */
1642         lv_vector_path_t * glyph_path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);
1643         // draw text contents and spans
1644         lv_matrix_t * mtx = matrix;
1645 
1646         float scale = span->size / 128.0f;
1647         for(uint32_t j = 0; j < content->count; j++) {
1648             uint32_t letter = content->letters[j];
1649             lv_font_glyph_dsc_t g;
1650             lv_font_get_glyph_dsc(span->font, &g, letter, '\0');
1651             lv_vector_path_t * p = (lv_vector_path_t *)lv_font_get_glyph_bitmap(&g, NULL);
1652             lv_vector_path_clear(glyph_path);
1653             lv_vector_path_copy(glyph_path, p);
1654             uint32_t letter_w = g.box_w > 0 ? g.box_w : g.adv_w;
1655 
1656             lv_matrix_t scale_matrix = *mtx;
1657             lv_matrix_translate(mtx, g.ofs_x, 0);
1658             lv_matrix_scale(&scale_matrix, scale, scale);
1659             lv_matrix_transform_path(&scale_matrix, glyph_path);
1660 
1661             lv_vector_path_append_path(span->path, glyph_path);
1662             span->font->release_glyph(span->font, &g);
1663             lv_matrix_translate(mtx, letter_w, 0);
1664         }
1665         lv_vector_path_delete(glyph_path);
1666         lv_vector_path_get_bounding(span->path, &span->bounds);
1667     }
1668     _copy_draw_dsc_from_ref(dsc, obj);
1669     lv_vector_dsc_add_path(dsc, span->path);
1670 
1671     _copy_draw_dsc(&(dsc->current_dsc), &(save_dsc.dsc));
1672 }
1673 #endif
1674 
1675 // get bounds functions
1676 
_get_rect_bounds(const lv_svg_render_obj_t * obj,lv_area_t * area)1677 static void _get_rect_bounds(const lv_svg_render_obj_t * obj, lv_area_t * area)
1678 {
1679     lv_svg_render_rect_t * rect = (lv_svg_render_rect_t *)obj;
1680     area->x1 = (int32_t)rect->x;
1681     area->y1 = (int32_t)rect->y;
1682     area->x2 = (int32_t)(rect->x + rect->width);
1683     area->y2 = (int32_t)(rect->y + rect->height);
1684 }
1685 
_get_circle_bounds(const lv_svg_render_obj_t * obj,lv_area_t * area)1686 static void _get_circle_bounds(const lv_svg_render_obj_t * obj, lv_area_t * area)
1687 {
1688     lv_svg_render_circle_t * circle = (lv_svg_render_circle_t *)obj;
1689     area->x1 = (int32_t)(circle->cx - circle->r);
1690     area->y1 = (int32_t)(circle->cy - circle->r);
1691     area->x2 = (int32_t)(circle->cx + circle->r);
1692     area->y2 = (int32_t)(circle->cy + circle->r);
1693 }
1694 
_get_ellipse_bounds(const lv_svg_render_obj_t * obj,lv_area_t * area)1695 static void _get_ellipse_bounds(const lv_svg_render_obj_t * obj, lv_area_t * area)
1696 {
1697     lv_svg_render_ellipse_t * ellipse = (lv_svg_render_ellipse_t *)obj;
1698     area->x1 = (int32_t)(ellipse->cx - ellipse->rx);
1699     area->y1 = (int32_t)(ellipse->cy - ellipse->ry);
1700     area->x2 = (int32_t)(ellipse->cx + ellipse->rx);
1701     area->y2 = (int32_t)(ellipse->cy + ellipse->ry);
1702 }
1703 
_get_line_bounds(const lv_svg_render_obj_t * obj,lv_area_t * area)1704 static void _get_line_bounds(const lv_svg_render_obj_t * obj, lv_area_t * area)
1705 {
1706     lv_svg_render_line_t * line = (lv_svg_render_line_t *)obj;
1707     area->x1 = (int32_t)(line->x1);
1708     area->y1 = (int32_t)(line->y1);
1709     area->x2 = (int32_t)(line->x2);
1710     area->y2 = (int32_t)(line->y2);
1711 }
1712 
_get_poly_bounds(const lv_svg_render_obj_t * obj,lv_area_t * area)1713 static void _get_poly_bounds(const lv_svg_render_obj_t * obj, lv_area_t * area)
1714 {
1715     lv_svg_render_poly_t * poly = (lv_svg_render_poly_t *)obj;
1716     lv_area_copy(area, &poly->bounds);
1717 }
1718 
1719 #if LV_USE_FREETYPE
_get_text_bounds(const lv_svg_render_obj_t * obj,lv_area_t * area)1720 static void _get_text_bounds(const lv_svg_render_obj_t * obj, lv_area_t * area)
1721 {
1722     lv_svg_render_text_t * text = (lv_svg_render_text_t *)obj;
1723     lv_area_copy(area, &text->bounds);
1724 }
1725 
_get_tspan_bounds(const lv_svg_render_obj_t * obj,lv_area_t * area)1726 static void _get_tspan_bounds(const lv_svg_render_obj_t * obj, lv_area_t * area)
1727 {
1728     lv_svg_render_tspan_t * tspan = (lv_svg_render_tspan_t *)obj;
1729     lv_area_copy(area, &tspan->bounds);
1730 }
1731 #endif
1732 
1733 // destroy functions
_destroy_poly(lv_svg_render_obj_t * obj)1734 static void _destroy_poly(lv_svg_render_obj_t * obj)
1735 {
1736     lv_svg_render_poly_t * poly = (lv_svg_render_poly_t *)obj;
1737     lv_vector_path_delete(poly->path);
1738 }
1739 
_destroy_use(lv_svg_render_obj_t * obj)1740 static void _destroy_use(lv_svg_render_obj_t * obj)
1741 {
1742     lv_svg_render_use_t * use = (lv_svg_render_use_t *)obj;
1743     if(use->xlink) {
1744         lv_free(use->xlink);
1745     }
1746 }
1747 
_destroy_group(lv_svg_render_obj_t * obj)1748 static void _destroy_group(lv_svg_render_obj_t * obj)
1749 {
1750     lv_svg_render_group_t * group = (lv_svg_render_group_t *)obj;
1751     lv_array_deinit(&group->items);
1752 }
1753 
1754 #if LV_USE_FREETYPE
_destroy_text(lv_svg_render_obj_t * obj)1755 static void _destroy_text(lv_svg_render_obj_t * obj)
1756 {
1757     lv_svg_render_text_t * text = (lv_svg_render_text_t *)obj;
1758     if(text->font) {
1759         lv_freetype_font_delete(text->font);
1760     }
1761     if(text->family) {
1762         lv_free(text->family);
1763     }
1764     lv_array_deinit(&text->contents);
1765     lv_vector_path_delete(text->path);
1766 }
1767 
_destroy_content(lv_svg_render_obj_t * obj)1768 static void _destroy_content(lv_svg_render_obj_t * obj)
1769 {
1770     lv_svg_render_content_t * content = (lv_svg_render_content_t *)obj;
1771     if(content->letters) {
1772         lv_free(content->letters);
1773     }
1774 }
1775 
_destroy_tspan(lv_svg_render_obj_t * obj)1776 static void _destroy_tspan(lv_svg_render_obj_t * obj)
1777 {
1778     lv_svg_render_tspan_t * span = (lv_svg_render_tspan_t *)obj;
1779     if(span->font) {
1780         lv_freetype_font_delete(span->font);
1781     }
1782 
1783     if(span->family) {
1784         lv_free(span->family);
1785     }
1786 
1787     _destroy_content(obj);
1788     lv_vector_path_delete(span->path);
1789 }
1790 
1791 #endif
1792 
_lv_svg_render_create(const lv_svg_node_t * node,struct _lv_svg_drawing_builder_state * state)1793 static lv_svg_render_obj_t * _lv_svg_render_create(const lv_svg_node_t * node,
1794                                                    struct _lv_svg_drawing_builder_state * state)
1795 {
1796     switch(node->type) {
1797         case LV_SVG_TAG_SVG: {
1798                 lv_svg_render_viewport_t * view = lv_malloc_zeroed(sizeof(lv_svg_render_viewport_t));
1799                 LV_ASSERT_MALLOC(view);
1800                 view->base.init = _init_viewport;
1801                 view->base.render = _render_viewport;
1802                 view->base.set_attr = _set_viewport_attr;
1803                 _set_render_attrs(LV_SVG_RENDER_OBJ(view), node, state);
1804                 return LV_SVG_RENDER_OBJ(view);
1805             }
1806         case LV_SVG_TAG_RECT: {
1807                 lv_svg_render_rect_t * rect = lv_malloc_zeroed(sizeof(lv_svg_render_rect_t));
1808                 LV_ASSERT_MALLOC(rect);
1809                 rect->base.init = _init_obj;
1810                 rect->base.render = _render_rect;
1811                 rect->base.set_attr = _set_rect_attr;
1812                 rect->base.get_bounds = _get_rect_bounds;
1813                 _set_render_attrs(LV_SVG_RENDER_OBJ(rect), node, state);
1814                 return LV_SVG_RENDER_OBJ(rect);
1815             }
1816         case LV_SVG_TAG_CIRCLE: {
1817                 lv_svg_render_circle_t * circle = lv_malloc_zeroed(sizeof(lv_svg_render_circle_t));
1818                 LV_ASSERT_MALLOC(circle);
1819                 circle->base.init = _init_obj;
1820                 circle->base.render = _render_circle;
1821                 circle->base.set_attr = _set_circle_attr;
1822                 circle->base.get_bounds = _get_circle_bounds;
1823                 _set_render_attrs(LV_SVG_RENDER_OBJ(circle), node, state);
1824                 return LV_SVG_RENDER_OBJ(circle);
1825             }
1826         case LV_SVG_TAG_ELLIPSE: {
1827                 lv_svg_render_ellipse_t * ellipse = lv_malloc_zeroed(sizeof(lv_svg_render_ellipse_t));
1828                 LV_ASSERT_MALLOC(ellipse);
1829                 ellipse->base.init = _init_obj;
1830                 ellipse->base.render = _render_ellipse;
1831                 ellipse->base.set_attr = _set_ellipse_attr;
1832                 ellipse->base.get_bounds = _get_ellipse_bounds;
1833                 _set_render_attrs(LV_SVG_RENDER_OBJ(ellipse), node, state);
1834                 return LV_SVG_RENDER_OBJ(ellipse);
1835             }
1836         case LV_SVG_TAG_LINE: {
1837                 lv_svg_render_line_t * line = lv_malloc_zeroed(sizeof(lv_svg_render_line_t));
1838                 LV_ASSERT_MALLOC(line);
1839                 line->base.init = _init_obj;
1840                 line->base.render = _render_line;
1841                 line->base.set_attr = _set_line_attr;
1842                 line->base.get_bounds = _get_line_bounds;
1843                 _set_render_attrs(LV_SVG_RENDER_OBJ(line), node, state);
1844                 return LV_SVG_RENDER_OBJ(line);
1845             }
1846         case LV_SVG_TAG_POLYLINE: {
1847                 lv_svg_render_poly_t * poly = lv_malloc_zeroed(sizeof(lv_svg_render_poly_t));
1848                 LV_ASSERT_MALLOC(poly);
1849                 poly->base.init = _init_poly;
1850                 poly->base.render = _render_poly;
1851                 poly->base.set_attr = _set_polyline_attr;
1852                 poly->base.get_bounds = _get_poly_bounds;
1853                 poly->base.destroy = _destroy_poly;
1854                 _set_render_attrs(LV_SVG_RENDER_OBJ(poly), node, state);
1855                 return LV_SVG_RENDER_OBJ(poly);
1856             }
1857         case LV_SVG_TAG_POLYGON: {
1858                 lv_svg_render_poly_t * poly = lv_malloc_zeroed(sizeof(lv_svg_render_poly_t));
1859                 LV_ASSERT_MALLOC(poly);
1860                 poly->base.init = _init_poly;
1861                 poly->base.render = _render_poly;
1862                 poly->base.set_attr = _set_polygen_attr;
1863                 poly->base.get_bounds = _get_poly_bounds;
1864                 poly->base.destroy = _destroy_poly;
1865                 _set_render_attrs(LV_SVG_RENDER_OBJ(poly), node, state);
1866                 return LV_SVG_RENDER_OBJ(poly);
1867             }
1868         case LV_SVG_TAG_PATH: {
1869                 lv_svg_render_poly_t * poly = lv_malloc_zeroed(sizeof(lv_svg_render_poly_t));
1870                 LV_ASSERT_MALLOC(poly);
1871                 poly->base.init = _init_poly;
1872                 poly->base.render = _render_poly;
1873                 poly->base.set_attr = _set_path_attr;
1874                 poly->base.get_bounds = _get_poly_bounds;
1875                 poly->base.destroy = _destroy_poly;
1876                 _set_render_attrs(LV_SVG_RENDER_OBJ(poly), node, state);
1877                 return LV_SVG_RENDER_OBJ(poly);
1878             }
1879 #if LV_USE_FREETYPE
1880         case LV_SVG_TAG_TEXT: {
1881                 lv_svg_render_text_t * txt = lv_malloc_zeroed(sizeof(lv_svg_render_text_t));
1882                 LV_ASSERT_MALLOC(txt);
1883                 txt->base.init = _init_text;
1884                 txt->base.set_attr = _set_text_attr;
1885                 txt->base.render = _render_text;
1886                 txt->base.get_bounds = _get_text_bounds;
1887                 txt->base.destroy = _destroy_text;
1888                 _set_render_attrs(LV_SVG_RENDER_OBJ(txt), node, state);
1889                 return LV_SVG_RENDER_OBJ(txt);
1890             }
1891         case LV_SVG_TAG_TSPAN: {
1892                 lv_svg_render_tspan_t * span = lv_malloc_zeroed(sizeof(lv_svg_render_tspan_t));
1893                 LV_ASSERT_MALLOC(span);
1894                 lv_svg_render_content_t * content = (lv_svg_render_content_t *)span;
1895                 content->render_content = _render_span;
1896                 content->base.init = _init_tspan;
1897                 content->base.set_attr = _set_tspan_attr;
1898                 content->base.get_bounds = _get_tspan_bounds;
1899                 content->base.destroy = _destroy_tspan;
1900                 _set_render_attrs(LV_SVG_RENDER_OBJ(span), node, state);
1901                 return LV_SVG_RENDER_OBJ(span);
1902             }
1903         case LV_SVG_TAG_CONTENT: {
1904                 lv_svg_render_content_t * content = lv_malloc_zeroed(sizeof(lv_svg_render_content_t));
1905                 LV_ASSERT_MALLOC(content);
1906                 content->base.init = _init_content;
1907                 content->base.destroy = _destroy_content;
1908                 _set_render_attrs(LV_SVG_RENDER_OBJ(content), node, state);
1909                 return LV_SVG_RENDER_OBJ(content);
1910             }
1911 #endif
1912         case LV_SVG_TAG_IMAGE: {
1913                 lv_svg_render_image_t * image = lv_malloc_zeroed(sizeof(lv_svg_render_image_t));
1914                 LV_ASSERT_MALLOC(image);
1915                 image->base.init = _init_image;
1916                 image->base.render = _render_image;
1917                 image->base.set_attr = _set_image_attr;
1918                 _set_render_attrs(LV_SVG_RENDER_OBJ(image), node, state);
1919                 return LV_SVG_RENDER_OBJ(image);
1920             }
1921         case LV_SVG_TAG_USE: {
1922                 lv_svg_render_use_t * use = lv_malloc_zeroed(sizeof(lv_svg_render_use_t));
1923                 LV_ASSERT_MALLOC(use);
1924                 use->base.init = _init_obj;
1925                 use->base.set_attr = _set_use_attr;
1926                 use->base.render = _render_use;
1927                 use->base.destroy = _destroy_use;
1928                 _set_render_attrs(LV_SVG_RENDER_OBJ(use), node, state);
1929                 return LV_SVG_RENDER_OBJ(use);
1930             }
1931         case LV_SVG_TAG_SOLID_COLOR: {
1932                 lv_svg_render_solid_t * solid = lv_malloc_zeroed(sizeof(lv_svg_render_solid_t));
1933                 LV_ASSERT_MALLOC(solid);
1934                 solid->base.init = _init_obj;
1935                 solid->base.set_attr = _set_solid_attr;
1936                 solid->base.set_paint_ref = _set_solid_ref;
1937                 _set_render_attrs(LV_SVG_RENDER_OBJ(solid), node, state);
1938                 return LV_SVG_RENDER_OBJ(solid);
1939             }
1940         case LV_SVG_TAG_RADIAL_GRADIENT:
1941         case LV_SVG_TAG_LINEAR_GRADIENT: {
1942                 lv_svg_render_gradient_t * grad = lv_malloc_zeroed(sizeof(lv_svg_render_gradient_t));
1943                 LV_ASSERT_MALLOC(grad);
1944                 grad->base.init = _init_gradient;
1945                 grad->base.set_attr = _set_gradient_attr;
1946                 grad->base.set_paint_ref = _set_gradient_ref;
1947                 if(node->type == LV_SVG_TAG_LINEAR_GRADIENT) {
1948                     grad->dsc.style = LV_VECTOR_GRADIENT_STYLE_LINEAR;
1949                 }
1950                 else {   // radial gradient
1951                     grad->dsc.style = LV_VECTOR_GRADIENT_STYLE_RADIAL;
1952                 }
1953                 _set_render_attrs(LV_SVG_RENDER_OBJ(grad), node, state);
1954                 return LV_SVG_RENDER_OBJ(grad);
1955             }
1956         case LV_SVG_TAG_G: {
1957                 lv_svg_render_group_t * group = lv_malloc_zeroed(sizeof(lv_svg_render_group_t));
1958                 LV_ASSERT_MALLOC(group);
1959                 group->base.init = _init_group;
1960                 group->base.set_attr = _set_attr;
1961                 group->base.render = _render_group;
1962                 group->base.destroy = _destroy_group;
1963                 _set_render_attrs(LV_SVG_RENDER_OBJ(group), node, state);
1964                 return LV_SVG_RENDER_OBJ(group);
1965             }
1966         default:
1967             return NULL;
1968     }
1969 }
1970 
_lv_svg_doc_walk_cb(const lv_tree_node_t * node,void * data)1971 static bool _lv_svg_doc_walk_cb(const lv_tree_node_t * node, void * data)
1972 {
1973     struct _lv_svg_drawing_builder_state * state = (struct _lv_svg_drawing_builder_state *)data;
1974     lv_svg_render_obj_t * obj = _lv_svg_render_create(LV_SVG_NODE(node), state);
1975     if(!obj) {
1976         return true;
1977     }
1978 
1979     if(state->in_defs) {
1980         obj->flags |= _RENDER_IN_DEFS;
1981     }
1982     if(state->in_group_deps > 0) {
1983         obj->flags |= _RENDER_IN_GROUP;
1984     }
1985 
1986     if(state->list == NULL) {
1987         state->list = obj;
1988         state->tail = obj;
1989     }
1990     else {
1991         state->tail->next = obj;
1992         state->tail = obj;
1993     }
1994     LV_SVG_NODE(node)->render_obj = obj;
1995     return true;
1996 }
1997 
_lv_svg_doc_walk_before_cb(const lv_tree_node_t * node,void * data)1998 static bool _lv_svg_doc_walk_before_cb(const lv_tree_node_t * node, void * data)
1999 {
2000     struct _lv_svg_drawing_builder_state * state = (struct _lv_svg_drawing_builder_state *)data;
2001     lv_svg_node_t * svg_node = LV_SVG_NODE(node);
2002 #if LV_USE_FREETYPE
2003     if(svg_node->type == LV_SVG_TAG_TEXT) {
2004         state->in_text = true;
2005         state->cur_text = svg_node;
2006     }
2007 #endif
2008     if(svg_node->type == LV_SVG_TAG_DEFS) {
2009         state->in_defs = true;
2010     }
2011 
2012     if(svg_node->type == LV_SVG_TAG_G) {
2013         state->in_group_deps++;
2014     }
2015     state->draw_dsc = _lv_svg_draw_dsc_push(state->draw_dsc);
2016     return true;
2017 }
2018 
_lv_svg_doc_walk_after_cb(const lv_tree_node_t * node,void * data)2019 static void _lv_svg_doc_walk_after_cb(const lv_tree_node_t * node, void * data)
2020 {
2021     struct _lv_svg_drawing_builder_state * state = (struct _lv_svg_drawing_builder_state *)data;
2022     lv_svg_node_t * svg_node = LV_SVG_NODE(node);
2023     if(svg_node->render_obj) {
2024         _copy_draw_dsc(&(LV_SVG_NODE(node)->render_obj->dsc), &(state->draw_dsc->dsc));
2025     }
2026 #if LV_USE_FREETYPE
2027     if(state->in_text) {
2028         if(svg_node->type == LV_SVG_TAG_TSPAN || svg_node->type == LV_SVG_TAG_CONTENT) {
2029             if(LV_TREE_NODE(svg_node)->parent == LV_TREE_NODE(state->cur_text)) {
2030                 lv_svg_render_text_t * text = (lv_svg_render_text_t *)state->cur_text->render_obj;
2031                 if((lv_array_size(&text->contents) + 1) > lv_array_capacity(&text->contents)) {
2032                     lv_array_resize(&text->contents, text->contents.capacity << 1);
2033                 }
2034                 lv_array_push_back(&text->contents, (uint8_t *)(&svg_node->render_obj));
2035             }
2036         }
2037     }
2038     if(svg_node->type == LV_SVG_TAG_TEXT) {
2039         state->in_text = false;
2040         state->cur_text = NULL;
2041     }
2042 #endif
2043     if(svg_node->type == LV_SVG_TAG_G) {
2044         lv_svg_render_group_t * group = (lv_svg_render_group_t *)svg_node->render_obj;
2045         uint32_t count = LV_TREE_NODE(node)->child_cnt;
2046         for(uint32_t i = 0; i < count; i++) {
2047             lv_svg_node_t * child = LV_SVG_NODE_CHILD(node, i);
2048             if(child->render_obj) { // not defs
2049                 lv_array_push_back(&group->items, (uint8_t *)(&child->render_obj));
2050             }
2051         }
2052 
2053         state->in_group_deps--;
2054         if(state->in_group_deps == 0) {
2055             group->base.flags &= ~_RENDER_IN_GROUP;
2056         }
2057     }
2058     if(svg_node->type == LV_SVG_TAG_DEFS) {
2059         state->in_defs = false;
2060     }
2061     state->draw_dsc = _lv_svg_draw_dsc_pop(state->draw_dsc);
2062 }
2063 
2064 #if LV_USE_FREETYPE
_freetype_outline_cb(lv_event_t * e)2065 static void _freetype_outline_cb(lv_event_t * e)
2066 {
2067     lv_event_code_t code = lv_event_get_code(e);
2068     lv_freetype_outline_event_param_t * param = lv_event_get_param(e);
2069     switch(code) {
2070         case LV_EVENT_CREATE:
2071             param->outline = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);
2072             break;
2073         case LV_EVENT_DELETE:
2074             lv_vector_path_delete(param->outline);
2075             break;
2076         case LV_EVENT_INSERT: {
2077                 if(param->type == LV_FREETYPE_OUTLINE_MOVE_TO) {
2078                     lv_fpoint_t pt = {0};
2079                     pt.x = LV_FREETYPE_F26DOT6_TO_FLOAT(param->to.x);
2080                     pt.y = -LV_FREETYPE_F26DOT6_TO_FLOAT(param->to.y);
2081                     lv_vector_path_move_to(param->outline, &pt);
2082                 }
2083                 else if(param->type == LV_FREETYPE_OUTLINE_LINE_TO) {
2084                     lv_fpoint_t pt = {0};
2085                     pt.x = LV_FREETYPE_F26DOT6_TO_FLOAT(param->to.x);
2086                     pt.y = -LV_FREETYPE_F26DOT6_TO_FLOAT(param->to.y);
2087                     lv_vector_path_line_to(param->outline, &pt);
2088                 }
2089                 else if(param->type == LV_FREETYPE_OUTLINE_CUBIC_TO) {
2090                     lv_fpoint_t pt[3] = {0};
2091                     pt[0].x = LV_FREETYPE_F26DOT6_TO_FLOAT(param->control1.x);
2092                     pt[0].y = -LV_FREETYPE_F26DOT6_TO_FLOAT(param->control1.y);
2093                     pt[1].x = LV_FREETYPE_F26DOT6_TO_FLOAT(param->control2.x);
2094                     pt[1].y = -LV_FREETYPE_F26DOT6_TO_FLOAT(param->control2.y);
2095                     pt[2].x = LV_FREETYPE_F26DOT6_TO_FLOAT(param->to.x);
2096                     pt[2].y = -LV_FREETYPE_F26DOT6_TO_FLOAT(param->to.y);
2097                     lv_vector_path_cubic_to(param->outline, &pt[0], &pt[1], &pt[2]);
2098                 }
2099                 else if(param->type == LV_FREETYPE_OUTLINE_CONIC_TO) {
2100                     lv_fpoint_t pt[2] = {0};
2101                     pt[0].x = LV_FREETYPE_F26DOT6_TO_FLOAT(param->control1.x);
2102                     pt[0].y = -LV_FREETYPE_F26DOT6_TO_FLOAT(param->control1.y);
2103                     pt[1].x = LV_FREETYPE_F26DOT6_TO_FLOAT(param->to.x);
2104                     pt[1].y = -LV_FREETYPE_F26DOT6_TO_FLOAT(param->to.y);
2105                     lv_vector_path_quad_to(param->outline, &pt[0], &pt[1]);
2106                 }
2107                 else if(param->type == LV_FREETYPE_OUTLINE_END) {
2108                     lv_vector_path_close(param->outline);
2109                 }
2110             }
2111             break;
2112         default:
2113             LV_LOG_WARN("unknown event code: %d", code);
2114             break;
2115     }
2116 }
2117 #endif
2118 /**********************
2119  *   GLOBAL FUNCTIONS
2120  **********************/
2121 
lv_svg_render_create(const lv_svg_node_t * svg_doc)2122 lv_svg_render_obj_t * lv_svg_render_create(const lv_svg_node_t * svg_doc)
2123 {
2124     if(!svg_doc) {
2125         return NULL;
2126     }
2127 
2128     struct _lv_svg_draw_dsc * dsc = _lv_svg_draw_dsc_create();
2129     struct _lv_svg_drawing_builder_state state = {
2130         .doc = svg_doc,
2131         .draw_dsc = dsc,
2132         .in_group_deps = 0,
2133         .in_defs = false,
2134 #if LV_USE_FREETYPE
2135         .in_text = false,
2136         .cur_text = NULL,
2137 #endif
2138         .list = NULL, .tail = NULL
2139     };
2140 
2141     lv_tree_walk(LV_TREE_NODE(svg_doc), LV_TREE_WALK_PRE_ORDER, _lv_svg_doc_walk_cb, _lv_svg_doc_walk_before_cb,
2142                  _lv_svg_doc_walk_after_cb, &state);
2143     _lv_svg_draw_dsc_delete(dsc);
2144     return state.list;
2145 }
2146 
lv_svg_render_delete(lv_svg_render_obj_t * list)2147 void lv_svg_render_delete(lv_svg_render_obj_t * list)
2148 {
2149     while(list) {
2150         lv_svg_render_obj_t * obj = list;
2151         list = list->next;
2152 
2153         _deinit_draw_dsc(&(obj->dsc));
2154 
2155         if(obj->destroy) {
2156             obj->destroy(obj);
2157         }
2158         if(obj->id) {
2159             lv_free(obj->id);
2160         }
2161         if(obj->fill_ref) {
2162             lv_free(obj->fill_ref);
2163         }
2164         if(obj->stroke_ref) {
2165             lv_free(obj->stroke_ref);
2166         }
2167         lv_free(obj);
2168     }
2169 }
2170 
lv_draw_svg_render(lv_vector_dsc_t * dsc,const lv_svg_render_obj_t * render)2171 void lv_draw_svg_render(lv_vector_dsc_t * dsc, const lv_svg_render_obj_t * render)
2172 {
2173     if(!render || !dsc) {
2174         return;
2175     }
2176 
2177     const lv_svg_render_obj_t * cur = render;
2178     while(cur) {
2179         if(cur->render && ((cur->flags & 3) == _RENDER_NORMAL)) {
2180             _prepare_render(cur, dsc);
2181             cur->render(cur, dsc, NULL);
2182         }
2183         cur = cur->next;
2184     }
2185 }
2186 
lv_draw_svg(lv_layer_t * layer,const lv_svg_node_t * svg_doc)2187 void lv_draw_svg(lv_layer_t * layer, const lv_svg_node_t * svg_doc)
2188 {
2189     if(!svg_doc) {
2190         return;
2191     }
2192 
2193     lv_vector_dsc_t * dsc = lv_vector_dsc_create(layer);
2194     lv_svg_render_obj_t * list = lv_svg_render_create(svg_doc);
2195     lv_draw_svg_render(dsc, list);
2196     lv_draw_vector(dsc);
2197     lv_svg_render_delete(list);
2198     lv_vector_dsc_delete(dsc);
2199 }
2200 
2201 /**********************
2202  *   STATIC FUNCTIONS
2203  **********************/
2204 #endif /*LV_USE_SVG*/
2205