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