1 /**
2 * @file lv_draw_img.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "../lv_image_decoder_private.h"
10 #include "../lv_draw_vector_private.h"
11 #include "../lv_draw_private.h"
12 #include "lv_draw_sw.h"
13
14 #if LV_USE_VECTOR_GRAPHIC && LV_USE_THORVG
15 #if LV_USE_THORVG_EXTERNAL
16 #include <thorvg_capi.h>
17 #else
18 #include "../../libs/thorvg/thorvg_capi.h"
19 #endif
20 #include "../../stdlib/lv_string.h"
21
22 /*********************
23 * DEFINES
24 *********************/
25
26 /**********************
27 * TYPEDEFS
28 **********************/
29 typedef struct {
30 float x;
31 float y;
32 float w;
33 float h;
34 } _tvg_rect;
35
36 typedef struct {
37 uint8_t r;
38 uint8_t g;
39 uint8_t b;
40 uint8_t a;
41 } _tvg_color;
42
43 /**********************
44 * STATIC PROTOTYPES
45 **********************/
46
47 /**********************
48 * STATIC VARIABLES
49 **********************/
50
51 /**********************
52 * MACROS
53 **********************/
54
lv_area_to_tvg(_tvg_rect * rect,const lv_area_t * area)55 static void lv_area_to_tvg(_tvg_rect * rect, const lv_area_t * area)
56 {
57 rect->x = area->x1;
58 rect->y = area->y1;
59 rect->w = lv_area_get_width(area) - 1;
60 rect->h = lv_area_get_height(area) - 1;
61 }
62
lv_color_to_tvg(_tvg_color * color,const lv_color32_t * c,lv_opa_t opa)63 static void lv_color_to_tvg(_tvg_color * color, const lv_color32_t * c, lv_opa_t opa)
64 {
65 color->r = c->red;
66 color->g = c->green;
67 color->b = c->blue;
68 color->a = LV_OPA_MIX2(c->alpha, opa);
69 }
70
lv_matrix_to_tvg(Tvg_Matrix * tm,const lv_matrix_t * m)71 static void lv_matrix_to_tvg(Tvg_Matrix * tm, const lv_matrix_t * m)
72 {
73 tm->e11 = m->m[0][0];
74 tm->e12 = m->m[0][1];
75 tm->e13 = m->m[0][2];
76 tm->e21 = m->m[1][0];
77 tm->e22 = m->m[1][1];
78 tm->e23 = m->m[1][2];
79 tm->e31 = m->m[2][0];
80 tm->e32 = m->m[2][1];
81 tm->e33 = m->m[2][2];
82 }
83
_set_paint_matrix(Tvg_Paint * obj,const Tvg_Matrix * m)84 static void _set_paint_matrix(Tvg_Paint * obj, const Tvg_Matrix * m)
85 {
86 tvg_paint_set_transform(obj, m);
87 }
88
_set_paint_shape(Tvg_Paint * obj,const lv_vector_path_t * p)89 static void _set_paint_shape(Tvg_Paint * obj, const lv_vector_path_t * p)
90 {
91 uint32_t pidx = 0;
92 lv_vector_path_op_t * op = lv_array_front(&p->ops);
93 uint32_t size = lv_array_size(&p->ops);
94 for(uint32_t i = 0; i < size; i++) {
95 switch(op[i]) {
96 case LV_VECTOR_PATH_OP_MOVE_TO: {
97 lv_fpoint_t * pt = lv_array_at(&p->points, pidx);
98 tvg_shape_move_to(obj, pt->x, pt->y);
99 pidx += 1;
100 }
101 break;
102 case LV_VECTOR_PATH_OP_LINE_TO: {
103 lv_fpoint_t * pt = lv_array_at(&p->points, pidx);
104 tvg_shape_line_to(obj, pt->x, pt->y);
105 pidx += 1;
106 }
107 break;
108 case LV_VECTOR_PATH_OP_QUAD_TO: {
109 lv_fpoint_t * pt1 = lv_array_at(&p->points, pidx);
110 lv_fpoint_t * pt2 = lv_array_at(&p->points, pidx + 1);
111
112 lv_fpoint_t * last_pt = lv_array_at(&p->points, pidx - 1);
113
114 lv_fpoint_t cp[2];
115 cp[0].x = (last_pt->x + 2 * pt1->x) * (1.0f / 3.0f);
116 cp[0].y = (last_pt->y + 2 * pt1->y) * (1.0f / 3.0f);
117 cp[1].x = (pt2->x + 2 * pt1->x) * (1.0f / 3.0f);
118 cp[1].y = (pt2->y + 2 * pt1->y) * (1.0f / 3.0f);
119
120 tvg_shape_cubic_to(obj, cp[0].x, cp[0].y, cp[1].x, cp[1].y, pt2->x, pt2->y);
121 pidx += 2;
122 }
123 break;
124 case LV_VECTOR_PATH_OP_CUBIC_TO: {
125 lv_fpoint_t * pt1 = lv_array_at(&p->points, pidx);
126 lv_fpoint_t * pt2 = lv_array_at(&p->points, pidx + 1);
127 lv_fpoint_t * pt3 = lv_array_at(&p->points, pidx + 2);
128
129 tvg_shape_cubic_to(obj, pt1->x, pt1->y, pt2->x, pt2->y, pt3->x, pt3->y);
130 pidx += 3;
131 }
132 break;
133 case LV_VECTOR_PATH_OP_CLOSE: {
134 tvg_shape_close(obj);
135 }
136 break;
137 }
138 }
139 }
140
lv_stroke_cap_to_tvg(lv_vector_stroke_cap_t cap)141 static Tvg_Stroke_Cap lv_stroke_cap_to_tvg(lv_vector_stroke_cap_t cap)
142 {
143 switch(cap) {
144 case LV_VECTOR_STROKE_CAP_SQUARE:
145 return TVG_STROKE_CAP_SQUARE;
146 case LV_VECTOR_STROKE_CAP_ROUND:
147 return TVG_STROKE_CAP_ROUND;
148 case LV_VECTOR_STROKE_CAP_BUTT:
149 return TVG_STROKE_CAP_BUTT;
150 default:
151 return TVG_STROKE_CAP_SQUARE;
152 }
153 }
154
lv_stroke_join_to_tvg(lv_vector_stroke_join_t join)155 static Tvg_Stroke_Join lv_stroke_join_to_tvg(lv_vector_stroke_join_t join)
156 {
157 switch(join) {
158 case LV_VECTOR_STROKE_JOIN_BEVEL:
159 return TVG_STROKE_JOIN_BEVEL;
160 case LV_VECTOR_STROKE_JOIN_ROUND:
161 return TVG_STROKE_JOIN_ROUND;
162 case LV_VECTOR_STROKE_JOIN_MITER:
163 return TVG_STROKE_JOIN_MITER;
164 default:
165 return TVG_STROKE_JOIN_BEVEL;
166 }
167 }
168
lv_spread_to_tvg(lv_vector_gradient_spread_t sp)169 static Tvg_Stroke_Fill lv_spread_to_tvg(lv_vector_gradient_spread_t sp)
170 {
171 switch(sp) {
172 case LV_VECTOR_GRADIENT_SPREAD_PAD:
173 return TVG_STROKE_FILL_PAD;
174 case LV_VECTOR_GRADIENT_SPREAD_REPEAT:
175 return TVG_STROKE_FILL_REPEAT;
176 case LV_VECTOR_GRADIENT_SPREAD_REFLECT:
177 return TVG_STROKE_FILL_REFLECT;
178 default:
179 return TVG_STROKE_FILL_PAD;
180 }
181 }
182
_setup_gradient(Tvg_Gradient * gradient,const lv_vector_gradient_t * grad,const lv_matrix_t * matrix)183 static void _setup_gradient(Tvg_Gradient * gradient, const lv_vector_gradient_t * grad,
184 const lv_matrix_t * matrix)
185 {
186 Tvg_Color_Stop * stops = (Tvg_Color_Stop *)lv_malloc(sizeof(Tvg_Color_Stop) * grad->stops_count);
187 LV_ASSERT_MALLOC(stops);
188 for(uint16_t i = 0; i < grad->stops_count; i++) {
189 const lv_gradient_stop_t * s = &(grad->stops[i]);
190
191 stops[i].offset = s->frac / 255.0f;
192 stops[i].r = s->color.red;
193 stops[i].g = s->color.green;
194 stops[i].b = s->color.blue;
195 stops[i].a = s->opa;
196 }
197
198 tvg_gradient_set_color_stops(gradient, stops, grad->stops_count);
199 tvg_gradient_set_spread(gradient, lv_spread_to_tvg(grad->spread));
200 Tvg_Matrix mtx;
201 lv_matrix_to_tvg(&mtx, matrix);
202 tvg_gradient_set_transform(gradient, &mtx);
203 lv_free(stops);
204 }
205
_set_paint_stroke_gradient(Tvg_Paint * obj,const lv_vector_gradient_t * g,const lv_matrix_t * m)206 static void _set_paint_stroke_gradient(Tvg_Paint * obj, const lv_vector_gradient_t * g, const lv_matrix_t * m)
207 {
208 Tvg_Gradient * grad = NULL;
209 if(g->style == LV_VECTOR_GRADIENT_STYLE_RADIAL) {
210 grad = tvg_radial_gradient_new();
211 tvg_radial_gradient_set(grad, g->cx, g->cy, g->cr);
212 _setup_gradient(grad, g, m);
213 tvg_shape_set_stroke_radial_gradient(obj, grad);
214 }
215 else {
216 grad = tvg_linear_gradient_new();
217 tvg_linear_gradient_set(grad, g->x1, g->y1, g->x2, g->y2);
218 _setup_gradient(grad, g, m);
219 tvg_shape_set_stroke_linear_gradient(obj, grad);
220 }
221 }
222
_set_paint_stroke(Tvg_Paint * obj,const lv_vector_stroke_dsc_t * dsc)223 static void _set_paint_stroke(Tvg_Paint * obj, const lv_vector_stroke_dsc_t * dsc)
224 {
225 if(dsc->style == LV_VECTOR_DRAW_STYLE_SOLID) {
226 _tvg_color c;
227 lv_color_to_tvg(&c, &dsc->color, dsc->opa);
228 tvg_shape_set_stroke_color(obj, c.r, c.g, c.b, c.a);
229 }
230 else { /*gradient*/
231 _set_paint_stroke_gradient(obj, &dsc->gradient, &dsc->matrix);
232 }
233
234 tvg_shape_set_stroke_width(obj, dsc->width);
235 tvg_shape_set_stroke_miterlimit(obj, dsc->miter_limit);
236 tvg_shape_set_stroke_cap(obj, lv_stroke_cap_to_tvg(dsc->cap));
237 tvg_shape_set_stroke_join(obj, lv_stroke_join_to_tvg(dsc->join));
238
239 if(!lv_array_is_empty(&dsc->dash_pattern)) {
240 float * dash_array = lv_array_front(&dsc->dash_pattern);
241 tvg_shape_set_stroke_dash(obj, dash_array, dsc->dash_pattern.size);
242 }
243 }
244
lv_fill_rule_to_tvg(lv_vector_fill_t rule)245 static Tvg_Fill_Rule lv_fill_rule_to_tvg(lv_vector_fill_t rule)
246 {
247 switch(rule) {
248 case LV_VECTOR_FILL_NONZERO:
249 return TVG_FILL_RULE_WINDING;
250 case LV_VECTOR_FILL_EVENODD:
251 return TVG_FILL_RULE_EVEN_ODD;
252 default:
253 return TVG_FILL_RULE_WINDING;
254 }
255 }
256
_set_paint_fill_gradient(Tvg_Paint * obj,const lv_vector_gradient_t * g,const lv_matrix_t * m)257 static void _set_paint_fill_gradient(Tvg_Paint * obj, const lv_vector_gradient_t * g, const lv_matrix_t * m)
258 {
259 Tvg_Gradient * grad = NULL;
260 if(g->style == LV_VECTOR_GRADIENT_STYLE_RADIAL) {
261 grad = tvg_radial_gradient_new();
262 tvg_radial_gradient_set(grad, g->cx, g->cy, g->cr);
263 _setup_gradient(grad, g, m);
264 tvg_shape_set_radial_gradient(obj, grad);
265 }
266 else {
267 grad = tvg_linear_gradient_new();
268 tvg_linear_gradient_set(grad, g->x1, g->y1, g->x2, g->y2);
269 _setup_gradient(grad, g, m);
270 tvg_shape_set_linear_gradient(obj, grad);
271 }
272 }
273
_set_paint_fill_pattern(Tvg_Paint * obj,Tvg_Canvas * canvas,const lv_draw_image_dsc_t * p,const lv_matrix_t * m)274 static void _set_paint_fill_pattern(Tvg_Paint * obj, Tvg_Canvas * canvas, const lv_draw_image_dsc_t * p,
275 const lv_matrix_t * m)
276 {
277 lv_image_decoder_dsc_t decoder_dsc;
278 lv_image_decoder_args_t args = { 0 };
279 args.premultiply = 1;
280 lv_result_t res = lv_image_decoder_open(&decoder_dsc, p->src, &args);
281 if(res != LV_RESULT_OK) {
282 LV_LOG_ERROR("Failed to open image");
283 return;
284 }
285
286 if(!decoder_dsc.decoded) {
287 lv_image_decoder_close(&decoder_dsc);
288 LV_LOG_ERROR("Image not ready");
289 return;
290 }
291
292 const uint8_t * src_buf = decoder_dsc.decoded->data;
293 const lv_image_header_t * header = &decoder_dsc.decoded->header;
294 lv_color_format_t cf = header->cf;
295
296 if(cf != LV_COLOR_FORMAT_ARGB8888) {
297 lv_image_decoder_close(&decoder_dsc);
298 LV_LOG_ERROR("Not support image format");
299 return;
300 }
301
302 Tvg_Paint * img = tvg_picture_new();
303 tvg_picture_load_raw(img, (uint32_t *)src_buf, header->w, header->h, true);
304 Tvg_Paint * clip_path = tvg_paint_duplicate(obj);
305 tvg_paint_set_composite_method(img, clip_path, TVG_COMPOSITE_METHOD_CLIP_PATH);
306 tvg_paint_set_opacity(img, p->opa);
307
308 Tvg_Matrix mtx;
309 lv_matrix_to_tvg(&mtx, m);
310 tvg_paint_set_transform(img, &mtx);
311 tvg_canvas_push(canvas, img);
312 lv_image_decoder_close(&decoder_dsc);
313 }
314
_set_paint_fill(Tvg_Paint * obj,Tvg_Canvas * canvas,const lv_vector_fill_dsc_t * dsc,const lv_matrix_t * matrix)315 static void _set_paint_fill(Tvg_Paint * obj, Tvg_Canvas * canvas, const lv_vector_fill_dsc_t * dsc,
316 const lv_matrix_t * matrix)
317 {
318 tvg_shape_set_fill_rule(obj, lv_fill_rule_to_tvg(dsc->fill_rule));
319
320 if(dsc->style == LV_VECTOR_DRAW_STYLE_SOLID) {
321 _tvg_color c;
322 lv_color_to_tvg(&c, &dsc->color, dsc->opa);
323 tvg_shape_set_fill_color(obj, c.r, c.g, c.b, c.a);
324 }
325 else if(dsc->style == LV_VECTOR_DRAW_STYLE_PATTERN) {
326 float x, y, w, h;
327 tvg_paint_get_bounds(obj, &x, &y, &w, &h, false);
328
329 lv_matrix_t imx;
330 lv_memcpy(&imx, matrix, sizeof(lv_matrix_t));
331 lv_matrix_translate(&imx, x, y);
332 lv_matrix_multiply(&imx, &dsc->matrix);
333 _set_paint_fill_pattern(obj, canvas, &dsc->img_dsc, &imx);
334 }
335 else if(dsc->style == LV_VECTOR_DRAW_STYLE_GRADIENT) {
336 _set_paint_fill_gradient(obj, &dsc->gradient, &dsc->matrix);
337 }
338 }
339
lv_blend_to_tvg(lv_vector_blend_t blend)340 static Tvg_Blend_Method lv_blend_to_tvg(lv_vector_blend_t blend)
341 {
342 switch(blend) {
343 case LV_VECTOR_BLEND_SRC_OVER:
344 return TVG_BLEND_METHOD_NORMAL;
345 case LV_VECTOR_BLEND_SCREEN:
346 return TVG_BLEND_METHOD_SCREEN;
347 case LV_VECTOR_BLEND_MULTIPLY:
348 return TVG_BLEND_METHOD_MULTIPLY;
349 case LV_VECTOR_BLEND_NONE:
350 return TVG_BLEND_METHOD_SRCOVER;
351 case LV_VECTOR_BLEND_ADDITIVE:
352 return TVG_BLEND_METHOD_ADD;
353 case LV_VECTOR_BLEND_SRC_IN:
354 case LV_VECTOR_BLEND_DST_OVER:
355 case LV_VECTOR_BLEND_DST_IN:
356 case LV_VECTOR_BLEND_SUBTRACTIVE:
357 /*not support yet.*/
358 default:
359 return TVG_BLEND_METHOD_NORMAL;
360 }
361 }
362
_set_paint_blend_mode(Tvg_Paint * obj,lv_vector_blend_t blend)363 static void _set_paint_blend_mode(Tvg_Paint * obj, lv_vector_blend_t blend)
364 {
365 tvg_paint_set_blend_method(obj, lv_blend_to_tvg(blend));
366 }
367
_task_draw_cb(void * ctx,const lv_vector_path_t * path,const lv_vector_draw_dsc_t * dsc)368 static void _task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vector_draw_dsc_t * dsc)
369 {
370 Tvg_Canvas * canvas = (Tvg_Canvas *)ctx;
371
372 Tvg_Paint * obj = tvg_shape_new();
373
374 if(!path) { /*clear*/
375 _tvg_rect rc;
376 lv_area_to_tvg(&rc, &dsc->scissor_area);
377
378 _tvg_color c;
379 lv_color_to_tvg(&c, &dsc->fill_dsc.color, dsc->fill_dsc.opa);
380
381 Tvg_Matrix mtx = {
382 1.0f, 0.0f, 0.0f,
383 0.0f, 1.0f, 0.0f,
384 0.0f, 0.0f, 1.0f,
385 };
386 _set_paint_matrix(obj, &mtx);
387 tvg_shape_append_rect(obj, rc.x, rc.y, rc.w, rc.h, 0, 0);
388 tvg_shape_set_fill_color(obj, c.r, c.g, c.b, c.a);
389 }
390 else {
391 Tvg_Matrix mtx;
392 lv_matrix_to_tvg(&mtx, &dsc->matrix);
393 _set_paint_matrix(obj, &mtx);
394
395 _set_paint_shape(obj, path);
396
397 _set_paint_fill(obj, canvas, &dsc->fill_dsc, &dsc->matrix);
398 _set_paint_stroke(obj, &dsc->stroke_dsc);
399 _set_paint_blend_mode(obj, dsc->blend_mode);
400 }
401
402 tvg_canvas_push(canvas, obj);
403 }
404
405 /**********************
406 * GLOBAL FUNCTIONS
407 **********************/
lv_draw_sw_vector(lv_draw_unit_t * draw_unit,const lv_draw_vector_task_dsc_t * dsc)408 void lv_draw_sw_vector(lv_draw_unit_t * draw_unit, const lv_draw_vector_task_dsc_t * dsc)
409 {
410 LV_UNUSED(draw_unit);
411
412 if(dsc->task_list == NULL)
413 return;
414
415 lv_layer_t * layer = dsc->base.layer;
416 lv_draw_buf_t * draw_buf = layer->draw_buf;
417 if(draw_buf == NULL)
418 return;
419
420 lv_color_format_t cf = draw_buf->header.cf;
421
422 if(cf != LV_COLOR_FORMAT_ARGB8888 && \
423 cf != LV_COLOR_FORMAT_XRGB8888) {
424 LV_LOG_ERROR("unsupported layer color: %d", cf);
425 return;
426 }
427
428 void * buf = draw_buf->data;
429 int32_t width = lv_area_get_width(&layer->buf_area) - 1;
430 int32_t height = lv_area_get_height(&layer->buf_area) - 1;
431 uint32_t stride = draw_buf->header.stride;
432 Tvg_Canvas * canvas = tvg_swcanvas_create();
433 tvg_swcanvas_set_target(canvas, buf, stride / 4, width, height, TVG_COLORSPACE_ARGB8888);
434
435 _tvg_rect rc;
436 lv_area_to_tvg(&rc, draw_unit->clip_area);
437 tvg_canvas_set_viewport(canvas, (int32_t)rc.x, (int32_t)rc.y, (int32_t)rc.w, (int32_t)rc.h);
438
439 lv_ll_t * task_list = dsc->task_list;
440 lv_vector_for_each_destroy_tasks(task_list, _task_draw_cb, canvas);
441
442 if(tvg_canvas_draw(canvas) == TVG_RESULT_SUCCESS) {
443 tvg_canvas_sync(canvas);
444 }
445
446 tvg_canvas_destroy(canvas);
447 }
448
449 /**********************
450 * STATIC FUNCTIONS
451 **********************/
452
453 #endif /*LV_USE_DRAW_SW*/
454