1 /**
2 * @file lv_draw_vector.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_draw_vector_private.h"
10 #include "../misc/lv_area_private.h"
11 #include "lv_draw_private.h"
12 
13 #if LV_USE_VECTOR_GRAPHIC
14 
15 #include "../misc/lv_ll.h"
16 #include "../misc/lv_types.h"
17 #include "../stdlib/lv_string.h"
18 #include <math.h>
19 #include <float.h>
20 
21 #define MATH_PI  3.14159265358979323846f
22 #define MATH_HALF_PI 1.57079632679489661923f
23 
24 #define DEG_TO_RAD 0.017453292519943295769236907684886f
25 #define RAD_TO_DEG 57.295779513082320876798154814105f
26 
27 #define MATH_RADIANS(deg) ((deg) * DEG_TO_RAD)
28 #define MATH_DEGREES(rad) ((rad) * RAD_TO_DEG)
29 
30 /*********************
31  *      DEFINES
32  *********************/
33 
34 #ifndef M_PI
35     #define M_PI 3.1415926f
36 #endif
37 
38 #define CHECK_AND_RESIZE_PATH_CONTAINER(P, N) \
39     do { \
40         if ((lv_array_size(&(P)->ops) + (N)) > lv_array_capacity(&(P)->ops)) { \
41             lv_array_resize(&(P)->ops, ((P)->ops.capacity << 1)); \
42         } \
43         if ((lv_array_size(&(P)->points) + (N)) > lv_array_capacity(&(P)->points)) { \
44             lv_array_resize(&(P)->points, ((P)->points.capacity << 1)); \
45         } \
46     } while(0)
47 
48 /**********************
49  *      TYPEDEFS
50  **********************/
51 
52 typedef struct {
53     lv_vector_path_t * path;
54     lv_vector_draw_dsc_t dsc;
55 } lv_vector_draw_task;
56 
57 /**********************
58  *  STATIC PROTOTYPES
59  **********************/
60 
_copy_draw_dsc(lv_vector_draw_dsc_t * dst,const lv_vector_draw_dsc_t * src)61 static void _copy_draw_dsc(lv_vector_draw_dsc_t * dst, const lv_vector_draw_dsc_t * src)
62 {
63     lv_memcpy(&(dst->fill_dsc), &(src->fill_dsc), sizeof(lv_vector_fill_dsc_t));
64 
65     dst->stroke_dsc.style = src->stroke_dsc.style;
66     dst->stroke_dsc.color = src->stroke_dsc.color;
67     dst->stroke_dsc.opa = src->stroke_dsc.opa;
68     dst->stroke_dsc.width = src->stroke_dsc.width;
69     dst->stroke_dsc.cap = src->stroke_dsc.cap;
70     dst->stroke_dsc.join = src->stroke_dsc.join;
71     dst->stroke_dsc.miter_limit = src->stroke_dsc.miter_limit;
72     lv_array_copy(&(dst->stroke_dsc.dash_pattern), &(src->stroke_dsc.dash_pattern));
73     dst->stroke_dsc.gradient.style = src->stroke_dsc.gradient.style;
74     dst->stroke_dsc.gradient.cx = src->stroke_dsc.gradient.cx;
75     dst->stroke_dsc.gradient.cy = src->stroke_dsc.gradient.cy;
76     dst->stroke_dsc.gradient.cr = src->stroke_dsc.gradient.cr;
77     dst->stroke_dsc.gradient.spread = src->fill_dsc.gradient.spread;
78     lv_memcpy(&(dst->stroke_dsc.gradient), &(src->stroke_dsc.gradient), sizeof(lv_vector_gradient_t));
79     lv_memcpy(&(dst->stroke_dsc.matrix), &(src->stroke_dsc.matrix), sizeof(lv_matrix_t));
80 
81     dst->blend_mode = src->blend_mode;
82     lv_memcpy(&(dst->matrix), &(src->matrix), sizeof(lv_matrix_t));
83     lv_area_copy(&(dst->scissor_area), &(src->scissor_area));
84 }
85 /**********************
86  *   GLOBAL FUNCTIONS
87  **********************/
88 
lv_matrix_transform_point(const lv_matrix_t * matrix,lv_fpoint_t * point)89 void lv_matrix_transform_point(const lv_matrix_t * matrix, lv_fpoint_t * point)
90 {
91     float x = point->x;
92     float y = point->y;
93 
94     point->x = x * matrix->m[0][0] + y * matrix->m[1][0] + matrix->m[0][2];
95     point->y = x * matrix->m[0][1] + y * matrix->m[1][1] + matrix->m[1][2];
96 }
97 
lv_matrix_transform_path(const lv_matrix_t * matrix,lv_vector_path_t * path)98 void lv_matrix_transform_path(const lv_matrix_t * matrix, lv_vector_path_t * path)
99 {
100     lv_fpoint_t * pt = lv_array_front(&path->points);
101     uint32_t size = lv_array_size(&path->points);
102     for(uint32_t i = 0; i < size; i++) {
103         lv_matrix_transform_point(matrix, &pt[i]);
104     }
105 }
106 
107 /* path functions */
lv_vector_path_create(lv_vector_path_quality_t quality)108 lv_vector_path_t * lv_vector_path_create(lv_vector_path_quality_t quality)
109 {
110     lv_vector_path_t * path = lv_malloc(sizeof(lv_vector_path_t));
111     LV_ASSERT_MALLOC(path);
112     lv_memzero(path, sizeof(lv_vector_path_t));
113     path->quality = quality;
114     lv_array_init(&path->ops, 8, sizeof(lv_vector_path_op_t));
115     lv_array_init(&path->points, 8, sizeof(lv_fpoint_t));
116     return path;
117 }
118 
lv_vector_path_copy(lv_vector_path_t * target_path,const lv_vector_path_t * path)119 void lv_vector_path_copy(lv_vector_path_t * target_path, const lv_vector_path_t * path)
120 {
121     target_path->quality = path->quality;
122     lv_array_copy(&target_path->ops, &path->ops);
123     lv_array_copy(&target_path->points, &path->points);
124 }
125 
lv_vector_path_clear(lv_vector_path_t * path)126 void lv_vector_path_clear(lv_vector_path_t * path)
127 {
128     lv_array_clear(&path->ops);
129     lv_array_clear(&path->points);
130 }
131 
lv_vector_path_delete(lv_vector_path_t * path)132 void lv_vector_path_delete(lv_vector_path_t * path)
133 {
134     lv_array_deinit(&path->ops);
135     lv_array_deinit(&path->points);
136     lv_free(path);
137 }
138 
lv_vector_path_move_to(lv_vector_path_t * path,const lv_fpoint_t * p)139 void lv_vector_path_move_to(lv_vector_path_t * path, const lv_fpoint_t * p)
140 {
141     CHECK_AND_RESIZE_PATH_CONTAINER(path, 1);
142 
143     lv_vector_path_op_t op = LV_VECTOR_PATH_OP_MOVE_TO;
144     lv_array_push_back(&path->ops, &op);
145     lv_array_push_back(&path->points, p);
146 }
147 
lv_vector_path_line_to(lv_vector_path_t * path,const lv_fpoint_t * p)148 void lv_vector_path_line_to(lv_vector_path_t * path, const lv_fpoint_t * p)
149 {
150     if(lv_array_is_empty(&path->ops)) {
151         /*first op must be move_to*/
152         return;
153     }
154 
155     CHECK_AND_RESIZE_PATH_CONTAINER(path, 1);
156 
157     lv_vector_path_op_t op = LV_VECTOR_PATH_OP_LINE_TO;
158     lv_array_push_back(&path->ops, &op);
159     lv_array_push_back(&path->points, p);
160 }
161 
lv_vector_path_quad_to(lv_vector_path_t * path,const lv_fpoint_t * p1,const lv_fpoint_t * p2)162 void lv_vector_path_quad_to(lv_vector_path_t * path, const lv_fpoint_t * p1, const lv_fpoint_t * p2)
163 {
164     if(lv_array_is_empty(&path->ops)) {
165         /*first op must be move_to*/
166         return;
167     }
168 
169     CHECK_AND_RESIZE_PATH_CONTAINER(path, 2);
170 
171     lv_vector_path_op_t op = LV_VECTOR_PATH_OP_QUAD_TO;
172     lv_array_push_back(&path->ops, &op);
173     lv_array_push_back(&path->points, p1);
174     lv_array_push_back(&path->points, p2);
175 }
176 
lv_vector_path_cubic_to(lv_vector_path_t * path,const lv_fpoint_t * p1,const lv_fpoint_t * p2,const lv_fpoint_t * p3)177 void lv_vector_path_cubic_to(lv_vector_path_t * path, const lv_fpoint_t * p1, const lv_fpoint_t * p2,
178                              const lv_fpoint_t * p3)
179 {
180     if(lv_array_is_empty(&path->ops)) {
181         /*first op must be move_to*/
182         return;
183     }
184 
185     CHECK_AND_RESIZE_PATH_CONTAINER(path, 3);
186 
187     lv_vector_path_op_t op = LV_VECTOR_PATH_OP_CUBIC_TO;
188     lv_array_push_back(&path->ops, &op);
189     lv_array_push_back(&path->points, p1);
190     lv_array_push_back(&path->points, p2);
191     lv_array_push_back(&path->points, p3);
192 }
193 
lv_vector_path_close(lv_vector_path_t * path)194 void lv_vector_path_close(lv_vector_path_t * path)
195 {
196     if(lv_array_is_empty(&path->ops)) {
197         /*first op must be move_to*/
198         return;
199     }
200 
201     CHECK_AND_RESIZE_PATH_CONTAINER(path, 1);
202 
203     lv_vector_path_op_t op = LV_VECTOR_PATH_OP_CLOSE;
204     lv_array_push_back(&path->ops, &op);
205 }
206 
lv_vector_path_get_bounding(const lv_vector_path_t * path,lv_area_t * area)207 void lv_vector_path_get_bounding(const lv_vector_path_t * path, lv_area_t * area)
208 {
209     LV_ASSERT_NULL(path);
210     LV_ASSERT_NULL(area);
211 
212     uint32_t len = lv_array_size(&path->points);
213     if(len == 0) {
214         lv_memzero(area, sizeof(lv_area_t));
215         return;
216     }
217 
218     lv_fpoint_t * p = lv_array_front(&path->points);
219     float x1 = p[0].x;
220     float x2 = p[0].x;
221     float y1 = p[0].y;
222     float y2 = p[0].y;
223 
224     for(uint32_t i = 1; i < len; i++) {
225         if(p[i].x < x1) x1 = p[i].x;
226         if(p[i].y < y1) y1 = p[i].y;
227         if(p[i].x > x2) x2 = p[i].x;
228         if(p[i].y > y2) y2 = p[i].y;
229     }
230 
231     area->x1 = lroundf(x1);
232     area->y1 = lroundf(y1);
233     area->x2 = lroundf(x2);
234     area->y2 = lroundf(y2);
235 }
236 
lv_vector_path_append_rect(lv_vector_path_t * path,const lv_area_t * rect,float rx,float ry)237 void lv_vector_path_append_rect(lv_vector_path_t * path, const lv_area_t * rect, float rx, float ry)
238 {
239     float x = rect->x1;
240     float y = rect->y1;
241     float w = (float)lv_area_get_width(rect);
242     float h = (float)lv_area_get_height(rect);
243 
244     float hw = w * 0.5f;
245     float hh = h * 0.5f;
246 
247     if(rx > hw) rx = hw;
248     if(ry > hh) ry = hh;
249 
250     if(rx == 0 && ry == 0) {
251         lv_fpoint_t pt = {x, y};
252         lv_vector_path_move_to(path, &pt);
253         pt.x += w;
254         lv_vector_path_line_to(path, &pt);
255         pt.y += h;
256         lv_vector_path_line_to(path, &pt);
257         pt.x -= w;
258         lv_vector_path_line_to(path, &pt);
259         lv_vector_path_close(path);
260     }
261     else if(rx == hw && ry == hh) {
262         lv_fpoint_t pt = {x + w * 0.5f, y + h * 0.5f};
263         lv_vector_path_append_circle(path, &pt, rx, ry);
264     }
265     else {
266         float hrx = rx * 0.5f;
267         float hry = ry * 0.5f;
268         lv_fpoint_t pt, pt2, pt3;
269 
270         pt.x = x + rx;
271         pt.y = y;
272         lv_vector_path_move_to(path, &pt);
273 
274         pt.x = x + w - rx;
275         pt.y = y;
276         lv_vector_path_line_to(path, &pt);
277 
278         pt.x = x + w - rx + hrx;
279         pt.y = y;
280         pt2.x = x + w;
281         pt2.y = y + ry - hry;
282         pt3.x = x + w;
283         pt3.y = y + ry;
284         lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
285 
286         pt.x = x + w;
287         pt.y = y + h - ry;
288         lv_vector_path_line_to(path, &pt);
289 
290         pt.x = x + w;
291         pt.y = y + h - ry + hry;
292         pt2.x = x + w - rx + hrx;
293         pt2.y = y + h;
294         pt3.x = x + w - rx;
295         pt3.y = y + h;
296         lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
297 
298         pt.x = x + rx;
299         pt.y = y + h;
300         lv_vector_path_line_to(path, &pt);
301 
302         pt.x = x + rx - hrx;
303         pt.y = y + h;
304         pt2.x = x;
305         pt2.y = y + h - ry + hry;
306         pt3.x = x;
307         pt3.y = y + h - ry;
308         lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
309 
310         pt.x = x;
311         pt.y = y + ry;
312         lv_vector_path_line_to(path, &pt);
313 
314         pt.x = x;
315         pt.y = y + ry - hry;
316         pt2.x = x + rx - hrx;
317         pt2.y = y;
318         pt3.x = x + rx;
319         pt3.y = y;
320         lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
321         lv_vector_path_close(path);
322     }
323 }
324 
lv_vector_path_append_circle(lv_vector_path_t * path,const lv_fpoint_t * c,float rx,float ry)325 void lv_vector_path_append_circle(lv_vector_path_t * path, const lv_fpoint_t * c, float rx, float ry)
326 {
327     float krx = rx * 0.552284f;
328     float kry = ry * 0.552284f;
329     float cx = c->x;
330     float cy = c->y;
331 
332     lv_fpoint_t pt, pt2, pt3;
333     pt.x = cx;
334     pt.y = cy - ry;
335     lv_vector_path_move_to(path, &pt);
336 
337     pt.x = cx + krx;
338     pt.y = cy - ry;
339     pt2.x = cx + rx;
340     pt2.y = cy - kry;
341     pt3.x = cx + rx;
342     pt3.y = cy;
343     lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
344 
345     pt.x = cx + rx;
346     pt.y = cy + kry;
347     pt2.x = cx + krx;
348     pt2.y = cy + ry;
349     pt3.x = cx;
350     pt3.y = cy + ry;
351     lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
352 
353     pt.x = cx - krx;
354     pt.y = cy + ry;
355     pt2.x = cx - rx;
356     pt2.y = cy + kry;
357     pt3.x = cx - rx;
358     pt3.y = cy;
359     lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
360 
361     pt.x = cx - rx;
362     pt.y = cy - kry;
363     pt2.x = cx - krx;
364     pt2.y = cy - ry;
365     pt3.x = cx;
366     pt3.y = cy - ry;
367     lv_vector_path_cubic_to(path, &pt, &pt2, &pt3);
368 
369     lv_vector_path_close(path);
370 }
371 
372 /**
373  * Add a arc to the path
374  * @param path              pointer to a path
375  * @param c                 pointer to a `lv_fpoint_t` variable for center of the circle
376  * @param radius            the radius for arc
377  * @param start_angle       the start angle for arc
378  * @param sweep             the sweep angle for arc, could be negative
379  * @param pie               true: draw a pie, false: draw a arc
380  */
lv_vector_path_append_arc(lv_vector_path_t * path,const lv_fpoint_t * c,float radius,float start_angle,float sweep,bool pie)381 void lv_vector_path_append_arc(lv_vector_path_t * path, const lv_fpoint_t * c, float radius, float start_angle,
382                                float sweep, bool pie)
383 {
384     float cx = c->x;
385     float cy = c->y;
386 
387     /* just circle */
388     if(sweep >= 360.0f || sweep <= -360.0f) {
389         lv_vector_path_append_circle(path, c, radius, radius);
390         return;
391     }
392 
393     start_angle = MATH_RADIANS(start_angle);
394     sweep = MATH_RADIANS(sweep);
395 
396     int n_curves = (int)ceil(fabsf(sweep / MATH_HALF_PI));
397     float sweep_sign = sweep < 0 ? -1.f : 1.f;
398     float fract = fmodf(sweep, MATH_HALF_PI);
399     fract = (fabsf(fract) < FLT_EPSILON) ? MATH_HALF_PI * sweep_sign : fract;
400 
401     /* Start from here */
402     lv_fpoint_t start = {
403         .x = radius * cosf(start_angle),
404         .y = radius * sinf(start_angle),
405     };
406 
407     if(pie) {
408         lv_vector_path_move_to(path, &(lv_fpoint_t) {
409             cx, cy
410         });
411         lv_vector_path_line_to(path, &(lv_fpoint_t) {
412             start.x + cx, start.y + cy
413         });
414     }
415 
416     for(int i = 0; i < n_curves; ++i) {
417         float end_angle = start_angle + ((i != n_curves - 1) ? MATH_HALF_PI * sweep_sign : fract);
418         float end_x = radius * cosf(end_angle);
419         float end_y = radius * sinf(end_angle);
420 
421         /* variables needed to calculate bezier control points */
422 
423         /** get bezier control points using article:
424          * (http://itc.ktu.lt/index.php/ITC/article/view/11812/6479)
425          */
426         float ax = start.x;
427         float ay = start.y;
428         float bx = end_x;
429         float by = end_y;
430         float q1 = ax * ax + ay * ay;
431         float q2 = ax * bx + ay * by + q1;
432         float k2 = (4.0f / 3.0f) * ((sqrtf(2 * q1 * q2) - q2) / (ax * by - ay * bx));
433 
434         /* Next start point is the current end point */
435         start.x = end_x;
436         start.y = end_y;
437 
438         end_x += cx;
439         end_y += cy;
440 
441         lv_fpoint_t ctrl1 = {ax - k2 * ay + cx, ay + k2 * ax + cy};
442         lv_fpoint_t ctrl2 = {bx + k2 * by + cx, by - k2 * bx + cy};
443         lv_fpoint_t end = {end_x, end_y};
444         lv_vector_path_cubic_to(path, &ctrl1, &ctrl2, &end);
445         start_angle = end_angle;
446     }
447 
448     if(pie) {
449         lv_vector_path_close(path);
450     }
451 }
452 
lv_vector_path_append_path(lv_vector_path_t * path,const lv_vector_path_t * subpath)453 void lv_vector_path_append_path(lv_vector_path_t * path, const lv_vector_path_t * subpath)
454 {
455     uint32_t ops_size = lv_array_size(&path->ops);
456     uint32_t nops_size = lv_array_size(&subpath->ops);
457     uint32_t point_size = lv_array_size(&path->points);
458     uint32_t npoint_size = lv_array_size(&subpath->points);
459 
460     lv_array_concat(&path->ops, &subpath->ops);
461     path->ops.size = ops_size + nops_size;
462 
463     lv_array_concat(&path->points, &subpath->points);
464     path->points.size = point_size + npoint_size;
465 }
466 
467 /* draw dsc functions */
468 
lv_vector_dsc_create(lv_layer_t * layer)469 lv_vector_dsc_t * lv_vector_dsc_create(lv_layer_t * layer)
470 {
471     lv_vector_dsc_t * dsc = lv_malloc(sizeof(lv_vector_dsc_t));
472     LV_ASSERT_MALLOC(dsc);
473     lv_memzero(dsc, sizeof(lv_vector_dsc_t));
474 
475     dsc->layer = layer;
476 
477     lv_vector_fill_dsc_t * fill_dsc = &(dsc->current_dsc.fill_dsc);
478     fill_dsc->style = LV_VECTOR_DRAW_STYLE_SOLID;
479     fill_dsc->color = lv_color_to_32(lv_color_black(), 0xFF);
480     fill_dsc->opa = LV_OPA_COVER;
481     fill_dsc->fill_rule = LV_VECTOR_FILL_NONZERO;
482     lv_matrix_identity(&(fill_dsc->matrix)); /*identity matrix*/
483 
484     lv_vector_stroke_dsc_t * stroke_dsc = &(dsc->current_dsc.stroke_dsc);
485     stroke_dsc->style = LV_VECTOR_DRAW_STYLE_SOLID;
486     stroke_dsc->color = lv_color_to_32(lv_color_black(), 0xFF);
487     stroke_dsc->opa = LV_OPA_0; /*default no stroke*/
488     stroke_dsc->width = 1.0f;
489     stroke_dsc->cap = LV_VECTOR_STROKE_CAP_BUTT;
490     stroke_dsc->join = LV_VECTOR_STROKE_JOIN_MITER;
491     stroke_dsc->miter_limit = 4.0f;
492     lv_matrix_identity(&(stroke_dsc->matrix)); /*identity matrix*/
493 
494     dsc->current_dsc.blend_mode = LV_VECTOR_BLEND_SRC_OVER;
495     dsc->current_dsc.scissor_area = layer->_clip_area;
496     lv_matrix_identity(&(dsc->current_dsc.matrix)); /*identity matrix*/
497     dsc->tasks.task_list = NULL;
498     return dsc;
499 }
500 
lv_vector_dsc_delete(lv_vector_dsc_t * dsc)501 void lv_vector_dsc_delete(lv_vector_dsc_t * dsc)
502 {
503     if(dsc->tasks.task_list) {
504         lv_ll_t * task_list = dsc->tasks.task_list;
505         lv_vector_for_each_destroy_tasks(task_list, NULL, NULL);
506         dsc->tasks.task_list = NULL;
507     }
508     lv_array_deinit(&(dsc->current_dsc.stroke_dsc.dash_pattern));
509     lv_free(dsc);
510 }
511 
lv_vector_dsc_set_blend_mode(lv_vector_dsc_t * dsc,lv_vector_blend_t blend)512 void lv_vector_dsc_set_blend_mode(lv_vector_dsc_t * dsc, lv_vector_blend_t blend)
513 {
514     dsc->current_dsc.blend_mode = blend;
515 }
516 
lv_vector_dsc_set_transform(lv_vector_dsc_t * dsc,const lv_matrix_t * matrix)517 void lv_vector_dsc_set_transform(lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
518 {
519     lv_memcpy(&(dsc->current_dsc.matrix), matrix, sizeof(lv_matrix_t));
520 }
521 
lv_vector_dsc_set_fill_color(lv_vector_dsc_t * dsc,lv_color_t color)522 void lv_vector_dsc_set_fill_color(lv_vector_dsc_t * dsc, lv_color_t color)
523 {
524     dsc->current_dsc.fill_dsc.style = LV_VECTOR_DRAW_STYLE_SOLID;
525     dsc->current_dsc.fill_dsc.color = lv_color_to_32(color, 0xFF);
526 }
527 
lv_vector_dsc_set_fill_color32(lv_vector_dsc_t * dsc,lv_color32_t color)528 void lv_vector_dsc_set_fill_color32(lv_vector_dsc_t * dsc, lv_color32_t color)
529 {
530     dsc->current_dsc.fill_dsc.style = LV_VECTOR_DRAW_STYLE_SOLID;
531     dsc->current_dsc.fill_dsc.color = color;
532 }
533 
lv_vector_dsc_set_fill_opa(lv_vector_dsc_t * dsc,lv_opa_t opa)534 void lv_vector_dsc_set_fill_opa(lv_vector_dsc_t * dsc, lv_opa_t opa)
535 {
536     dsc->current_dsc.fill_dsc.opa = opa;
537 }
538 
lv_vector_dsc_set_fill_rule(lv_vector_dsc_t * dsc,lv_vector_fill_t rule)539 void lv_vector_dsc_set_fill_rule(lv_vector_dsc_t * dsc, lv_vector_fill_t rule)
540 {
541     dsc->current_dsc.fill_dsc.fill_rule = rule;
542 }
543 
lv_vector_dsc_set_fill_image(lv_vector_dsc_t * dsc,const lv_draw_image_dsc_t * img_dsc)544 void lv_vector_dsc_set_fill_image(lv_vector_dsc_t * dsc, const lv_draw_image_dsc_t * img_dsc)
545 {
546     dsc->current_dsc.fill_dsc.style = LV_VECTOR_DRAW_STYLE_PATTERN;
547     lv_memcpy(&(dsc->current_dsc.fill_dsc.img_dsc), img_dsc, sizeof(lv_draw_image_dsc_t));
548 }
549 
lv_vector_dsc_set_fill_linear_gradient(lv_vector_dsc_t * dsc,float x1,float y1,float x2,float y2)550 void lv_vector_dsc_set_fill_linear_gradient(lv_vector_dsc_t * dsc, float x1, float y1, float x2, float y2)
551 {
552     dsc->current_dsc.fill_dsc.style = LV_VECTOR_DRAW_STYLE_GRADIENT;
553     dsc->current_dsc.fill_dsc.gradient.style = LV_VECTOR_GRADIENT_STYLE_LINEAR;
554     dsc->current_dsc.fill_dsc.gradient.x1 = x1;
555     dsc->current_dsc.fill_dsc.gradient.y1 = y1;
556     dsc->current_dsc.fill_dsc.gradient.x2 = x2;
557     dsc->current_dsc.fill_dsc.gradient.y2 = y2;
558 }
559 
lv_vector_dsc_set_fill_radial_gradient(lv_vector_dsc_t * dsc,float cx,float cy,float radius)560 void lv_vector_dsc_set_fill_radial_gradient(lv_vector_dsc_t * dsc, float cx, float cy, float radius)
561 {
562     dsc->current_dsc.fill_dsc.style = LV_VECTOR_DRAW_STYLE_GRADIENT;
563     dsc->current_dsc.fill_dsc.gradient.style = LV_VECTOR_GRADIENT_STYLE_RADIAL;
564     dsc->current_dsc.fill_dsc.gradient.cx = cx;
565     dsc->current_dsc.fill_dsc.gradient.cy = cy;
566     dsc->current_dsc.fill_dsc.gradient.cr = radius;
567 }
568 
lv_vector_dsc_set_fill_gradient_spread(lv_vector_dsc_t * dsc,lv_vector_gradient_spread_t spread)569 void lv_vector_dsc_set_fill_gradient_spread(lv_vector_dsc_t * dsc, lv_vector_gradient_spread_t spread)
570 {
571     dsc->current_dsc.fill_dsc.gradient.spread = spread;
572 }
573 
lv_vector_dsc_set_fill_gradient_color_stops(lv_vector_dsc_t * dsc,const lv_gradient_stop_t * stops,uint16_t count)574 void lv_vector_dsc_set_fill_gradient_color_stops(lv_vector_dsc_t * dsc, const lv_gradient_stop_t * stops,
575                                                  uint16_t count)
576 {
577     if(count > LV_GRADIENT_MAX_STOPS) {
578         LV_LOG_WARN("Gradient stops limited: %d, max: %d", count, LV_GRADIENT_MAX_STOPS);
579         count = LV_GRADIENT_MAX_STOPS;
580     }
581 
582     lv_memcpy(&(dsc->current_dsc.fill_dsc.gradient.stops), stops, sizeof(lv_gradient_stop_t) * count);
583     dsc->current_dsc.fill_dsc.gradient.stops_count = count;
584 }
585 
lv_vector_dsc_set_fill_transform(lv_vector_dsc_t * dsc,const lv_matrix_t * matrix)586 void lv_vector_dsc_set_fill_transform(lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
587 {
588     lv_memcpy(&(dsc->current_dsc.fill_dsc.matrix), matrix, sizeof(lv_matrix_t));
589 }
590 
lv_vector_dsc_set_stroke_transform(lv_vector_dsc_t * dsc,const lv_matrix_t * matrix)591 void lv_vector_dsc_set_stroke_transform(lv_vector_dsc_t * dsc, const lv_matrix_t * matrix)
592 {
593     lv_memcpy(&(dsc->current_dsc.stroke_dsc.matrix), matrix, sizeof(lv_matrix_t));
594 }
595 
lv_vector_dsc_set_stroke_color32(lv_vector_dsc_t * dsc,lv_color32_t color)596 void lv_vector_dsc_set_stroke_color32(lv_vector_dsc_t * dsc, lv_color32_t color)
597 {
598     dsc->current_dsc.stroke_dsc.style = LV_VECTOR_DRAW_STYLE_SOLID;
599     dsc->current_dsc.stroke_dsc.color = color;
600 }
601 
lv_vector_dsc_set_stroke_color(lv_vector_dsc_t * dsc,lv_color_t color)602 void lv_vector_dsc_set_stroke_color(lv_vector_dsc_t * dsc, lv_color_t color)
603 {
604     dsc->current_dsc.stroke_dsc.style = LV_VECTOR_DRAW_STYLE_SOLID;
605     dsc->current_dsc.stroke_dsc.color = lv_color_to_32(color, 0xFF);
606 }
607 
lv_vector_dsc_set_stroke_opa(lv_vector_dsc_t * dsc,lv_opa_t opa)608 void lv_vector_dsc_set_stroke_opa(lv_vector_dsc_t * dsc, lv_opa_t opa)
609 {
610     dsc->current_dsc.stroke_dsc.opa = opa;
611 }
612 
lv_vector_dsc_set_stroke_width(lv_vector_dsc_t * dsc,float width)613 void lv_vector_dsc_set_stroke_width(lv_vector_dsc_t * dsc, float width)
614 {
615     dsc->current_dsc.stroke_dsc.width = width;
616 }
617 
lv_vector_dsc_set_stroke_dash(lv_vector_dsc_t * dsc,float * dash_pattern,uint16_t dash_count)618 void lv_vector_dsc_set_stroke_dash(lv_vector_dsc_t * dsc, float * dash_pattern, uint16_t dash_count)
619 {
620     lv_array_t * dash_array = &(dsc->current_dsc.stroke_dsc.dash_pattern);
621     if(dash_pattern) {
622         lv_array_clear(dash_array);
623         if(lv_array_capacity(dash_array) == 0) {
624             lv_array_init(dash_array, dash_count, sizeof(float));
625         }
626         else {
627             lv_array_resize(dash_array, dash_count);
628         }
629         for(uint16_t i = 0; i < dash_count; i++) {
630             lv_array_push_back(dash_array, &dash_pattern[i]);
631         }
632     }
633     else {   /*clear dash*/
634         lv_array_clear(dash_array);
635     }
636 }
637 
lv_vector_dsc_set_stroke_cap(lv_vector_dsc_t * dsc,lv_vector_stroke_cap_t cap)638 void lv_vector_dsc_set_stroke_cap(lv_vector_dsc_t * dsc, lv_vector_stroke_cap_t cap)
639 {
640     dsc->current_dsc.stroke_dsc.cap = cap;
641 }
642 
lv_vector_dsc_set_stroke_join(lv_vector_dsc_t * dsc,lv_vector_stroke_join_t join)643 void lv_vector_dsc_set_stroke_join(lv_vector_dsc_t * dsc, lv_vector_stroke_join_t join)
644 {
645     dsc->current_dsc.stroke_dsc.join = join;
646 }
647 
lv_vector_dsc_set_stroke_miter_limit(lv_vector_dsc_t * dsc,uint16_t miter_limit)648 void lv_vector_dsc_set_stroke_miter_limit(lv_vector_dsc_t * dsc, uint16_t miter_limit)
649 {
650     dsc->current_dsc.stroke_dsc.miter_limit = miter_limit;
651 }
652 
lv_vector_dsc_set_stroke_linear_gradient(lv_vector_dsc_t * dsc,float x1,float y1,float x2,float y2)653 void lv_vector_dsc_set_stroke_linear_gradient(lv_vector_dsc_t * dsc, float x1, float y1, float x2, float y2)
654 {
655     dsc->current_dsc.stroke_dsc.style = LV_VECTOR_DRAW_STYLE_GRADIENT;
656     dsc->current_dsc.stroke_dsc.gradient.style = LV_VECTOR_GRADIENT_STYLE_LINEAR;
657     dsc->current_dsc.stroke_dsc.gradient.x1 = x1;
658     dsc->current_dsc.stroke_dsc.gradient.y1 = y1;
659     dsc->current_dsc.stroke_dsc.gradient.x2 = x2;
660     dsc->current_dsc.stroke_dsc.gradient.y2 = y2;
661 }
662 
lv_vector_dsc_set_stroke_radial_gradient(lv_vector_dsc_t * dsc,float cx,float cy,float radius)663 void lv_vector_dsc_set_stroke_radial_gradient(lv_vector_dsc_t * dsc, float cx, float cy, float radius)
664 {
665     dsc->current_dsc.stroke_dsc.style = LV_VECTOR_DRAW_STYLE_GRADIENT;
666     dsc->current_dsc.stroke_dsc.gradient.style = LV_VECTOR_GRADIENT_STYLE_RADIAL;
667     dsc->current_dsc.stroke_dsc.gradient.cx = cx;
668     dsc->current_dsc.stroke_dsc.gradient.cy = cy;
669     dsc->current_dsc.stroke_dsc.gradient.cr = radius;
670 }
671 
lv_vector_dsc_set_stroke_gradient_spread(lv_vector_dsc_t * dsc,lv_vector_gradient_spread_t spread)672 void lv_vector_dsc_set_stroke_gradient_spread(lv_vector_dsc_t * dsc, lv_vector_gradient_spread_t spread)
673 {
674     dsc->current_dsc.stroke_dsc.gradient.spread = spread;
675 }
676 
lv_vector_dsc_set_stroke_gradient_color_stops(lv_vector_dsc_t * dsc,const lv_gradient_stop_t * stops,uint16_t count)677 void lv_vector_dsc_set_stroke_gradient_color_stops(lv_vector_dsc_t * dsc, const lv_gradient_stop_t * stops,
678                                                    uint16_t count)
679 {
680     if(count > LV_GRADIENT_MAX_STOPS) {
681         LV_LOG_WARN("Gradient stops limited: %d, max: %d", count, LV_GRADIENT_MAX_STOPS);
682         count = LV_GRADIENT_MAX_STOPS;
683     }
684 
685     lv_memcpy(&(dsc->current_dsc.stroke_dsc.gradient.stops), stops, sizeof(lv_gradient_stop_t) * count);
686     dsc->current_dsc.stroke_dsc.gradient.stops_count = count;
687 }
688 
689 /* draw functions */
lv_vector_dsc_add_path(lv_vector_dsc_t * dsc,const lv_vector_path_t * path)690 void lv_vector_dsc_add_path(lv_vector_dsc_t * dsc, const lv_vector_path_t * path)
691 {
692     lv_area_t rect;
693     if(!lv_area_intersect(&rect, &(dsc->layer->_clip_area), &(dsc->current_dsc.scissor_area))) {
694         return;
695     }
696 
697     if(dsc->current_dsc.fill_dsc.opa == 0
698        && dsc->current_dsc.stroke_dsc.opa == 0) {
699         return;
700     }
701 
702     if(!dsc->tasks.task_list) {
703         dsc->tasks.task_list = lv_malloc(sizeof(lv_ll_t));
704         LV_ASSERT_MALLOC(dsc->tasks.task_list);
705         lv_ll_init(dsc->tasks.task_list, sizeof(lv_vector_draw_task));
706     }
707 
708     lv_vector_draw_task * new_task = (lv_vector_draw_task *)lv_ll_ins_tail(dsc->tasks.task_list);
709     lv_memset(new_task, 0, sizeof(lv_vector_draw_task));
710 
711     new_task->path = lv_vector_path_create(0);
712 
713     _copy_draw_dsc(&(new_task->dsc), &(dsc->current_dsc));
714     lv_vector_path_copy(new_task->path, path);
715     new_task->dsc.scissor_area = rect;
716 }
717 
lv_vector_clear_area(lv_vector_dsc_t * dsc,const lv_area_t * rect)718 void lv_vector_clear_area(lv_vector_dsc_t * dsc, const lv_area_t * rect)
719 {
720     lv_area_t r;
721     if(!lv_area_intersect(&r, &(dsc->layer->_clip_area), &(dsc->current_dsc.scissor_area))) {
722         return;
723     }
724 
725     if(!dsc->tasks.task_list) {
726         dsc->tasks.task_list = lv_malloc(sizeof(lv_ll_t));
727         LV_ASSERT_MALLOC(dsc->tasks.task_list);
728         lv_ll_init(dsc->tasks.task_list, sizeof(lv_vector_draw_task));
729     }
730 
731     lv_vector_draw_task * new_task = (lv_vector_draw_task *)lv_ll_ins_tail(dsc->tasks.task_list);
732     lv_memset(new_task, 0, sizeof(lv_vector_draw_task));
733 
734     new_task->dsc.fill_dsc.color = dsc->current_dsc.fill_dsc.color;
735     new_task->dsc.fill_dsc.opa = dsc->current_dsc.fill_dsc.opa;
736     lv_area_copy(&(new_task->dsc.scissor_area), rect);
737 }
738 
lv_draw_vector(lv_vector_dsc_t * dsc)739 void lv_draw_vector(lv_vector_dsc_t * dsc)
740 {
741     if(!dsc->tasks.task_list) {
742         return;
743     }
744 
745     lv_layer_t * layer = dsc->layer;
746 
747     lv_draw_task_t * t = lv_draw_add_task(layer, &(layer->_clip_area));
748     t->type = LV_DRAW_TASK_TYPE_VECTOR;
749     t->draw_dsc = lv_malloc(sizeof(lv_draw_vector_task_dsc_t));
750     lv_memcpy(t->draw_dsc, &(dsc->tasks), sizeof(lv_draw_vector_task_dsc_t));
751     lv_draw_finalize_task_creation(layer, t);
752     dsc->tasks.task_list = NULL;
753 }
754 
755 /* draw dsc transform */
lv_vector_dsc_identity(lv_vector_dsc_t * dsc)756 void lv_vector_dsc_identity(lv_vector_dsc_t * dsc)
757 {
758     lv_matrix_identity(&(dsc->current_dsc.matrix)); /*identity matrix*/
759 }
760 
lv_vector_dsc_scale(lv_vector_dsc_t * dsc,float scale_x,float scale_y)761 void lv_vector_dsc_scale(lv_vector_dsc_t * dsc, float scale_x, float scale_y)
762 {
763     lv_matrix_scale(&(dsc->current_dsc.matrix), scale_x, scale_y);
764 }
765 
lv_vector_dsc_rotate(lv_vector_dsc_t * dsc,float degree)766 void lv_vector_dsc_rotate(lv_vector_dsc_t * dsc, float degree)
767 {
768     lv_matrix_rotate(&(dsc->current_dsc.matrix), degree);
769 }
770 
lv_vector_dsc_translate(lv_vector_dsc_t * dsc,float tx,float ty)771 void lv_vector_dsc_translate(lv_vector_dsc_t * dsc, float tx, float ty)
772 {
773     lv_matrix_translate(&(dsc->current_dsc.matrix), tx, ty);
774 }
775 
lv_vector_dsc_skew(lv_vector_dsc_t * dsc,float skew_x,float skew_y)776 void lv_vector_dsc_skew(lv_vector_dsc_t * dsc, float skew_x, float skew_y)
777 {
778     lv_matrix_skew(&(dsc->current_dsc.matrix), skew_x, skew_y);
779 }
780 
lv_vector_for_each_destroy_tasks(lv_ll_t * task_list,vector_draw_task_cb cb,void * data)781 void lv_vector_for_each_destroy_tasks(lv_ll_t * task_list, vector_draw_task_cb cb, void * data)
782 {
783     lv_vector_draw_task * task = lv_ll_get_head(task_list);
784     lv_vector_draw_task * next_task = NULL;
785 
786     while(task != NULL) {
787         next_task = lv_ll_get_next(task_list, task);
788         lv_ll_remove(task_list, task);
789 
790         if(cb) {
791             cb(data, task->path, &(task->dsc));
792         }
793 
794         if(task->path) {
795             lv_vector_path_delete(task->path);
796         }
797         lv_array_deinit(&(task->dsc.stroke_dsc.dash_pattern));
798 
799         lv_free(task);
800         task = next_task;
801     }
802     lv_free(task_list);
803 }
804 #endif /* LV_USE_VECTOR_GRAPHIC */
805