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