1 /**
2  * @file lv_vg_lite_grad.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "../lv_draw_vector_private.h"
11 #include "lv_vg_lite_grad.h"
12 
13 #if LV_USE_DRAW_VG_LITE && LV_USE_VECTOR_GRAPHIC
14 
15 #include "lv_draw_vg_lite_type.h"
16 #include "lv_vg_lite_pending.h"
17 #include "lv_vg_lite_math.h"
18 #include "../../misc/lv_types.h"
19 #include "../../stdlib/lv_string.h"
20 
21 /*********************
22  *      DEFINES
23  *********************/
24 
25 #define SQUARE(x) ((x)*(x))
26 
27 #ifndef M_PI
28     #define M_PI 3.1415926f
29 #endif
30 
31 /**********************
32  *      TYPEDEFS
33  **********************/
34 
35 typedef enum {
36     GRAD_TYPE_UNKNOWN,
37     GRAD_TYPE_LINEAR,
38     GRAD_TYPE_LINEAR_EXT,
39     GRAD_TYPE_RADIAL,
40 } grad_type_t;
41 
42 typedef struct {
43     grad_type_t type;
44     lv_vector_gradient_t lv;
45     union {
46         vg_lite_linear_gradient_t linear;
47         vg_lite_ext_linear_gradient_t linear_ext;
48         vg_lite_radial_gradient_t radial;
49     } vg;
50 } grad_item_t;
51 
52 /**********************
53  *  STATIC PROTOTYPES
54  **********************/
55 
56 static grad_item_t * grad_get(struct _lv_draw_vg_lite_unit_t * u, const lv_vector_gradient_t * grad);
57 static void grad_cache_release_cb(void * entry, void * user_data);
58 static bool grad_create_cb(grad_item_t * item, void * user_data);
59 static void grad_free_cb(grad_item_t * item, void * user_data);
60 static lv_cache_compare_res_t grad_compare_cb(const grad_item_t * lhs, const grad_item_t * rhs);
61 
62 static grad_type_t lv_grad_style_to_type(lv_vector_gradient_style_t style);
63 static void grad_point_to_matrix(vg_lite_matrix_t * grad_matrix, float x1, float y1, float x2, float y2);
64 static vg_lite_gradient_spreadmode_t lv_spread_to_vg(lv_vector_gradient_spread_t spread);
65 
66 /**********************
67  *  STATIC VARIABLES
68  **********************/
69 
70 /**********************
71  *      MACROS
72  **********************/
73 
74 /**********************
75  *   GLOBAL FUNCTIONS
76  **********************/
77 
lv_vg_lite_grad_init(struct _lv_draw_vg_lite_unit_t * u,uint32_t cache_cnt)78 void lv_vg_lite_grad_init(struct _lv_draw_vg_lite_unit_t * u, uint32_t cache_cnt)
79 {
80     LV_ASSERT_NULL(u);
81 
82     lv_cache_ops_t ops = {
83         .compare_cb = (lv_cache_compare_cb_t)grad_compare_cb,
84         .create_cb = (lv_cache_create_cb_t)grad_create_cb,
85         .free_cb = (lv_cache_free_cb_t)grad_free_cb,
86     };
87 
88     u->grad_cache = lv_cache_create(&lv_cache_class_lru_rb_count, sizeof(grad_item_t), cache_cnt, ops);
89     lv_cache_set_name(u->grad_cache, "VG_GRAD");
90     u->grad_pending = lv_vg_lite_pending_create(sizeof(lv_cache_entry_t *), 4);
91     lv_vg_lite_pending_set_free_cb(u->grad_pending, grad_cache_release_cb, u->grad_cache);
92 }
93 
lv_vg_lite_grad_deinit(struct _lv_draw_vg_lite_unit_t * u)94 void lv_vg_lite_grad_deinit(struct _lv_draw_vg_lite_unit_t * u)
95 {
96     LV_ASSERT_NULL(u);
97     LV_ASSERT_NULL(u->grad_pending)
98     lv_vg_lite_pending_destroy(u->grad_pending);
99     u->grad_pending = NULL;
100     lv_cache_destroy(u->grad_cache, NULL);
101     u->grad_cache = NULL;
102 }
103 
lv_vg_lite_draw_grad(struct _lv_draw_vg_lite_unit_t * u,vg_lite_buffer_t * buffer,vg_lite_path_t * path,const lv_vector_gradient_t * grad,const vg_lite_matrix_t * grad_matrix,const vg_lite_matrix_t * matrix,vg_lite_fill_t fill,vg_lite_blend_t blend)104 bool lv_vg_lite_draw_grad(
105     struct _lv_draw_vg_lite_unit_t * u,
106     vg_lite_buffer_t * buffer,
107     vg_lite_path_t * path,
108     const lv_vector_gradient_t * grad,
109     const vg_lite_matrix_t * grad_matrix,
110     const vg_lite_matrix_t * matrix,
111     vg_lite_fill_t fill,
112     vg_lite_blend_t blend)
113 {
114     LV_ASSERT_NULL(u);
115     LV_VG_LITE_ASSERT_DEST_BUFFER(buffer);
116     LV_VG_LITE_ASSERT_PATH(path);
117     LV_ASSERT_NULL(grad);
118     LV_VG_LITE_ASSERT_MATRIX(grad_matrix);
119     LV_VG_LITE_ASSERT_MATRIX(matrix);
120 
121     /* check radial gradient is supported */
122     if(grad->style == LV_VECTOR_GRADIENT_STYLE_RADIAL) {
123         if(!vg_lite_query_feature(gcFEATURE_BIT_VG_RADIAL_GRADIENT)) {
124             LV_LOG_INFO("radial gradient is not supported");
125             return false;
126         }
127 
128         /* check if the radius is valid */
129         if(grad->cr <= 0) {
130             LV_LOG_INFO("radius: %f is not valid", grad->cr);
131             return false;
132         }
133     }
134 
135     /* check spread mode is supported */
136     if(grad->spread == LV_VECTOR_GRADIENT_SPREAD_REPEAT || grad->spread == LV_VECTOR_GRADIENT_SPREAD_REFLECT) {
137         if(!vg_lite_query_feature(gcFEATURE_BIT_VG_IM_REPEAT_REFLECT)) {
138             LV_LOG_INFO("repeat/reflect spread(%d) is not supported", grad->spread);
139             return false;
140         }
141     }
142 
143     LV_PROFILER_DRAW_BEGIN_TAG("grad_get");
144     grad_item_t * grad_item = grad_get(u, grad);
145     LV_PROFILER_DRAW_END_TAG("grad_get");
146     if(!grad_item) {
147         LV_LOG_WARN("Failed to get gradient, style: %d", grad->style);
148         return false;
149     }
150     LV_ASSERT(grad_item->lv.style == grad->style);
151 
152     switch(grad_item->type) {
153         case GRAD_TYPE_LINEAR: {
154                 vg_lite_linear_gradient_t * linear_grad = &grad_item->vg.linear;
155                 vg_lite_matrix_t * grad_mat_p = vg_lite_get_grad_matrix(linear_grad);
156                 LV_ASSERT_NULL(grad_mat_p);
157                 vg_lite_identity(grad_mat_p);
158                 lv_vg_lite_matrix_multiply(grad_mat_p, grad_matrix);
159                 grad_point_to_matrix(grad_mat_p, grad->x1, grad->y1, grad->x2, grad->y2);
160 
161                 LV_PROFILER_DRAW_BEGIN_TAG("vg_lite_draw_grad");
162                 LV_VG_LITE_CHECK_ERROR(vg_lite_draw_grad(
163                                            buffer,
164                                            path,
165                                            fill,
166                                            (vg_lite_matrix_t *)matrix,
167                                            linear_grad,
168                                            blend));
169                 LV_PROFILER_DRAW_END_TAG("vg_lite_draw_grad");
170             }
171             break;
172         case GRAD_TYPE_LINEAR_EXT: {
173                 vg_lite_ext_linear_gradient_t * linear_grad = &grad_item->vg.linear_ext;
174                 vg_lite_matrix_t * grad_mat_p = vg_lite_get_linear_grad_matrix(linear_grad);
175                 LV_ASSERT_NULL(grad_mat_p);
176                 *grad_mat_p = *grad_matrix;
177 
178                 LV_PROFILER_DRAW_BEGIN_TAG("vg_lite_draw_linear_grad");
179                 LV_VG_LITE_CHECK_ERROR(vg_lite_draw_linear_grad(
180                                            buffer,
181                                            path,
182                                            fill,
183                                            (vg_lite_matrix_t *)matrix,
184                                            linear_grad,
185                                            0,
186                                            blend,
187                                            VG_LITE_FILTER_LINEAR));
188                 LV_PROFILER_DRAW_END_TAG("vg_lite_draw_linear_grad");
189             }
190             break;
191 
192         case GRAD_TYPE_RADIAL: {
193                 vg_lite_radial_gradient_t * radial = &grad_item->vg.radial;
194                 vg_lite_matrix_t * grad_mat_p = vg_lite_get_radial_grad_matrix(radial);
195                 LV_ASSERT_NULL(grad_mat_p);
196                 *grad_mat_p = *grad_matrix;
197 
198                 LV_PROFILER_DRAW_BEGIN_TAG("vg_lite_draw_radial_grad");
199                 LV_VG_LITE_CHECK_ERROR(
200                     vg_lite_draw_radial_grad(
201                         buffer,
202                         path,
203                         fill,
204                         (vg_lite_matrix_t *)matrix,
205                         &grad_item->vg.radial,
206                         0,
207                         blend,
208                         VG_LITE_FILTER_LINEAR));
209                 LV_PROFILER_DRAW_END_TAG("vg_lite_draw_radial_grad");
210             }
211             break;
212 
213         default:
214             LV_LOG_ERROR("Unsupported gradient type: %d", grad_item->type);
215             return false;
216     }
217 
218     return true;
219 }
220 
lv_vg_lite_draw_grad_helper(struct _lv_draw_vg_lite_unit_t * u,vg_lite_buffer_t * buffer,vg_lite_path_t * path,const lv_area_t * area,const lv_grad_dsc_t * grad_dsc,const vg_lite_matrix_t * matrix,vg_lite_fill_t fill,vg_lite_blend_t blend)221 bool lv_vg_lite_draw_grad_helper(
222     struct _lv_draw_vg_lite_unit_t * u,
223     vg_lite_buffer_t * buffer,
224     vg_lite_path_t * path,
225     const lv_area_t * area,
226     const lv_grad_dsc_t * grad_dsc,
227     const vg_lite_matrix_t * matrix,
228     vg_lite_fill_t fill,
229     vg_lite_blend_t blend)
230 {
231     LV_ASSERT_NULL(u);
232     LV_VG_LITE_ASSERT_DEST_BUFFER(buffer);
233     LV_VG_LITE_ASSERT_PATH(path);
234     LV_ASSERT_NULL(area);
235     LV_ASSERT_NULL(grad_dsc);
236     LV_VG_LITE_ASSERT_MATRIX(matrix);
237 
238     lv_vector_gradient_t grad;
239     lv_memzero(&grad, sizeof(grad));
240 
241     grad.style = LV_VECTOR_GRADIENT_STYLE_LINEAR;
242     grad.stops_count = grad_dsc->stops_count;
243     lv_memcpy(grad.stops, grad_dsc->stops, sizeof(lv_gradient_stop_t) * grad_dsc->stops_count);
244 
245     /*convert to spread mode*/
246 #if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
247     switch(grad_dsc->extend) {
248         case LV_GRAD_EXTEND_PAD:
249             grad.spread = LV_VECTOR_GRADIENT_SPREAD_PAD;
250             break;
251         case LV_GRAD_EXTEND_REPEAT:
252             grad.spread = LV_VECTOR_GRADIENT_SPREAD_REPEAT;
253             break;
254         case LV_GRAD_EXTEND_REFLECT:
255             grad.spread = LV_VECTOR_GRADIENT_SPREAD_REFLECT;
256             break;
257         default:
258             LV_LOG_WARN("Unsupported gradient extend mode: %d", grad_dsc->extend);
259             grad.spread = LV_VECTOR_GRADIENT_SPREAD_PAD;
260             break;
261     }
262 #else
263     grad.spread = LV_VECTOR_GRADIENT_SPREAD_PAD;
264 #endif
265 
266     switch(grad_dsc->dir) {
267         case LV_GRAD_DIR_VER:
268             grad.x1 = area->x1;
269             grad.y1 = area->y1;
270             grad.x2 = area->x1;
271             grad.y2 = area->y2 + 1;
272             break;
273 
274         case LV_GRAD_DIR_HOR:
275             grad.x1 = area->x1;
276             grad.y1 = area->y1;
277             grad.x2 = area->x2 + 1;
278             grad.y2 = area->y1;
279             break;
280 
281 #if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
282         case LV_GRAD_DIR_LINEAR: {
283                 int32_t w = lv_area_get_width(area);
284                 int32_t h = lv_area_get_height(area);
285 
286                 grad.x1 = lv_pct_to_px(grad_dsc->params.linear.start.x, w) + area->x1;
287                 grad.y1 = lv_pct_to_px(grad_dsc->params.linear.start.y, h) + area->y1;
288                 grad.x2 = lv_pct_to_px(grad_dsc->params.linear.end.x, w) + area->x1;
289                 grad.y2 = lv_pct_to_px(grad_dsc->params.linear.end.y, h) + area->y1;
290             }
291             break;
292 
293         case LV_GRAD_DIR_RADIAL: {
294                 grad.style = LV_VECTOR_GRADIENT_STYLE_RADIAL;
295                 int32_t w = lv_area_get_width(area);
296                 int32_t h = lv_area_get_height(area);
297 
298                 grad.cx = lv_pct_to_px(grad_dsc->params.radial.focal.x, w) + area->x1;
299                 grad.cy = lv_pct_to_px(grad_dsc->params.radial.focal.y, h) + area->y1;
300                 int32_t end_extent_x = lv_pct_to_px(grad_dsc->params.radial.end_extent.x, w) + area->x1;
301                 int32_t end_extent_y = lv_pct_to_px(grad_dsc->params.radial.end_extent.y, h) + area->y1;
302                 grad.cr = LV_MAX(end_extent_x - grad.cx, end_extent_y - grad.cy);
303             }
304             break;
305 #endif
306 
307         default:
308             LV_LOG_WARN("Unsupported gradient direction: %d", grad_dsc->dir);
309             return false;
310     }
311 
312     return lv_vg_lite_draw_grad(u, buffer, path, &grad, matrix, matrix, fill, blend);
313 }
314 
315 /**********************
316  *   STATIC FUNCTIONS
317  **********************/
318 
grad_get(struct _lv_draw_vg_lite_unit_t * u,const lv_vector_gradient_t * grad)319 static grad_item_t * grad_get(struct _lv_draw_vg_lite_unit_t * u, const lv_vector_gradient_t * grad)
320 {
321     LV_ASSERT_NULL(u);
322     LV_ASSERT_NULL(grad);
323 
324     grad_item_t search_key;
325     lv_memzero(&search_key, sizeof(search_key));
326     search_key.type = lv_grad_style_to_type(grad->style);
327     search_key.lv = *grad;
328 
329     lv_cache_entry_t * cache_node_entry = lv_cache_acquire(u->grad_cache, &search_key, NULL);
330     if(cache_node_entry == NULL) {
331         /* check if the cache is full */
332         size_t free_size = lv_cache_get_free_size(u->grad_cache, NULL);
333         if(free_size == 0) {
334             LV_LOG_INFO("grad cache is full, release all pending cache entries");
335             lv_vg_lite_finish(u);
336         }
337 
338         cache_node_entry = lv_cache_acquire_or_create(u->grad_cache, &search_key, NULL);
339         if(cache_node_entry == NULL) {
340             LV_LOG_ERROR("grad cache creating failed");
341             return NULL;
342         }
343     }
344 
345     /* Add the new entry to the pending list */
346     lv_vg_lite_pending_add(u->grad_pending, &cache_node_entry);
347 
348     return lv_cache_entry_get_data(cache_node_entry);
349 }
350 
grad_cache_release_cb(void * entry,void * user_data)351 static void grad_cache_release_cb(void * entry, void * user_data)
352 {
353     lv_cache_entry_t ** entry_p = entry;
354     lv_cache_t * cache = user_data;
355     lv_cache_release(cache, * entry_p, NULL);
356 }
357 
grad_create_color_ramp(const lv_vector_gradient_t * grad)358 static vg_lite_color_ramp_t * grad_create_color_ramp(const lv_vector_gradient_t * grad)
359 {
360     LV_ASSERT_NULL(grad);
361 
362     vg_lite_color_ramp_t * color_ramp = lv_malloc(sizeof(vg_lite_color_ramp_t) * grad->stops_count);
363     LV_ASSERT_MALLOC(color_ramp);
364     if(!color_ramp) {
365         LV_LOG_ERROR("malloc failed for color_ramp");
366         return NULL;
367     }
368 
369     for(uint16_t i = 0; i < grad->stops_count; i++) {
370         color_ramp[i].stop = grad->stops[i].frac / 255.0f;
371         lv_color_t c = grad->stops[i].color;
372 
373         color_ramp[i].red = c.red / 255.0f;
374         color_ramp[i].green = c.green / 255.0f;
375         color_ramp[i].blue = c.blue / 255.0f;
376         color_ramp[i].alpha = grad->stops[i].opa / 255.0f;
377     }
378 
379     return color_ramp;
380 }
381 
linear_grad_create(grad_item_t * item)382 static bool linear_grad_create(grad_item_t * item)
383 {
384     LV_PROFILER_DRAW_BEGIN;
385 
386     vg_lite_error_t err = vg_lite_init_grad(&item->vg.linear);
387     if(err != VG_LITE_SUCCESS) {
388         LV_PROFILER_DRAW_END;
389         LV_LOG_ERROR("vg_lite_init_grad error: %d", (int)err);
390         lv_vg_lite_error_dump_info(err);
391         return false;
392     }
393 
394     vg_lite_uint32_t colors[VLC_MAX_GRADIENT_STOPS];
395     vg_lite_uint32_t stops[VLC_MAX_GRADIENT_STOPS];
396 
397     /* Gradient setup */
398     if(item->lv.stops_count > VLC_MAX_GRADIENT_STOPS) {
399         LV_LOG_WARN("Gradient stops limited: %d, max: %d", item->lv.stops_count, VLC_MAX_GRADIENT_STOPS);
400         item->lv.stops_count = VLC_MAX_GRADIENT_STOPS;
401     }
402 
403     for(uint16_t i = 0; i < item->lv.stops_count; i++) {
404         stops[i] = item->lv.stops[i].frac;
405         const lv_color_t * c = &item->lv.stops[i].color;
406         lv_opa_t opa = item->lv.stops[i].opa;
407 
408         /* lvgl color -> gradient color */
409         lv_color_t grad_color = lv_color_make(c->blue, c->green, c->red);
410         colors[i] = lv_vg_lite_color(grad_color, opa, true);
411     }
412 
413     LV_VG_LITE_CHECK_ERROR(vg_lite_set_grad(&item->vg.linear, item->lv.stops_count, colors, stops));
414 
415     LV_PROFILER_DRAW_BEGIN_TAG("vg_lite_update_grad");
416     LV_VG_LITE_CHECK_ERROR(vg_lite_update_grad(&item->vg.linear));
417     LV_PROFILER_DRAW_END_TAG("vg_lite_update_grad");
418 
419     LV_PROFILER_DRAW_END;
420     return true;
421 }
422 
linear_ext_grad_create(grad_item_t * item)423 static bool linear_ext_grad_create(grad_item_t * item)
424 {
425     LV_PROFILER_DRAW_BEGIN;
426 
427     if(item->lv.stops_count > VLC_MAX_COLOR_RAMP_STOPS) {
428         LV_LOG_WARN("Gradient stops limited: %d, max: %d", item->lv.stops_count, VLC_MAX_GRADIENT_STOPS);
429         item->lv.stops_count = VLC_MAX_COLOR_RAMP_STOPS;
430     }
431 
432     vg_lite_color_ramp_t * color_ramp = grad_create_color_ramp(&item->lv);
433     if(!color_ramp) {
434         LV_PROFILER_DRAW_END;
435         return false;
436     }
437 
438     const vg_lite_linear_gradient_parameter_t grad_param = {
439         .X0 = item->lv.x1,
440         .Y0 = item->lv.y1,
441         .X1 = item->lv.x2,
442         .Y1 = item->lv.y2,
443     };
444 
445     vg_lite_ext_linear_gradient_t linear_grad;
446     lv_memzero(&linear_grad, sizeof(linear_grad));
447 
448     LV_PROFILER_DRAW_BEGIN_TAG("vg_lite_set_linear_grad");
449     LV_VG_LITE_CHECK_ERROR(
450         vg_lite_set_linear_grad(
451             &linear_grad,
452             item->lv.stops_count,
453             color_ramp,
454             grad_param,
455             lv_spread_to_vg(item->lv.spread),
456             1));
457     LV_PROFILER_DRAW_END_TAG("vg_lite_set_linear_grad");
458 
459     LV_PROFILER_DRAW_BEGIN_TAG("vg_lite_update_linear_grad");
460     vg_lite_error_t err = vg_lite_update_linear_grad(&linear_grad);
461     LV_PROFILER_DRAW_END_TAG("vg_lite_update_linear_grad");
462     if(err == VG_LITE_SUCCESS) {
463         item->vg.linear_ext = linear_grad;
464     }
465     else {
466         LV_LOG_ERROR("vg_lite_update_linear_grad error: %d", (int)err);
467         lv_vg_lite_error_dump_info(err);
468     }
469 
470     lv_free(color_ramp);
471 
472     LV_PROFILER_DRAW_END;
473     return err == VG_LITE_SUCCESS;
474 }
475 
radial_grad_create(grad_item_t * item)476 static bool radial_grad_create(grad_item_t * item)
477 {
478     LV_PROFILER_DRAW_BEGIN;
479 
480     if(item->lv.stops_count > VLC_MAX_COLOR_RAMP_STOPS) {
481         LV_LOG_WARN("Gradient stops limited: %d, max: %d", item->lv.stops_count, VLC_MAX_GRADIENT_STOPS);
482         item->lv.stops_count = VLC_MAX_COLOR_RAMP_STOPS;
483     }
484 
485     vg_lite_color_ramp_t * color_ramp = grad_create_color_ramp(&item->lv);
486     if(!color_ramp) {
487         LV_PROFILER_DRAW_END;
488         return false;
489     }
490 
491     const vg_lite_radial_gradient_parameter_t grad_param = {
492         .cx = item->lv.cx,
493         .cy = item->lv.cy,
494         .r = item->lv.cr,
495         .fx = item->lv.cx,
496         .fy = item->lv.cy,
497     };
498 
499     vg_lite_radial_gradient_t radial_grad;
500     lv_memzero(&radial_grad, sizeof(radial_grad));
501 
502     LV_PROFILER_DRAW_BEGIN_TAG("vg_lite_set_radial_grad");
503     LV_VG_LITE_CHECK_ERROR(
504         vg_lite_set_radial_grad(
505             &radial_grad,
506             item->lv.stops_count,
507             color_ramp,
508             grad_param,
509             lv_spread_to_vg(item->lv.spread),
510             1));
511     LV_PROFILER_DRAW_END_TAG("vg_lite_set_radial_grad");
512 
513     LV_PROFILER_DRAW_BEGIN_TAG("vg_lite_update_radial_grad");
514     vg_lite_error_t err = vg_lite_update_radial_grad(&radial_grad);
515     LV_PROFILER_DRAW_END_TAG("vg_lite_update_radial_grad");
516     if(err == VG_LITE_SUCCESS) {
517         item->vg.radial = radial_grad;
518     }
519     else {
520         LV_LOG_ERROR("vg_lite_update_radial_grad error: %d", (int)err);
521         lv_vg_lite_error_dump_info(err);
522     }
523 
524     lv_free(color_ramp);
525 
526     LV_PROFILER_DRAW_END;
527     return err == VG_LITE_SUCCESS;
528 }
529 
lv_grad_style_to_type(lv_vector_gradient_style_t style)530 static grad_type_t lv_grad_style_to_type(lv_vector_gradient_style_t style)
531 {
532     if(style == LV_VECTOR_GRADIENT_STYLE_LINEAR) {
533         return vg_lite_query_feature(gcFEATURE_BIT_VG_LINEAR_GRADIENT_EXT) ? GRAD_TYPE_LINEAR_EXT : GRAD_TYPE_LINEAR;
534     }
535 
536     if(style == LV_VECTOR_GRADIENT_STYLE_RADIAL) {
537         return GRAD_TYPE_RADIAL;
538     }
539 
540     LV_LOG_WARN("unknown gradient style: %d", style);
541     return GRAD_TYPE_UNKNOWN;
542 }
543 
grad_point_to_matrix(vg_lite_matrix_t * grad_matrix,float x1,float y1,float x2,float y2)544 static void grad_point_to_matrix(vg_lite_matrix_t * grad_matrix, float x1, float y1, float x2, float y2)
545 {
546     vg_lite_translate(x1, y1, grad_matrix);
547 
548     float angle = atan2f(y2 - y1, x2 - x1) * 180.0f / (float)M_PI;
549     vg_lite_rotate(angle, grad_matrix);
550     float length = sqrtf(SQUARE(x2 - x1) + SQUARE(y2 - y1));
551     vg_lite_scale(length / 256.0f, 1, grad_matrix);
552 }
553 
lv_spread_to_vg(lv_vector_gradient_spread_t spread)554 static vg_lite_gradient_spreadmode_t lv_spread_to_vg(lv_vector_gradient_spread_t spread)
555 {
556     switch(spread) {
557         case LV_VECTOR_GRADIENT_SPREAD_PAD:
558             return VG_LITE_GRADIENT_SPREAD_PAD;
559         case LV_VECTOR_GRADIENT_SPREAD_REPEAT:
560             return VG_LITE_GRADIENT_SPREAD_REPEAT;
561         case LV_VECTOR_GRADIENT_SPREAD_REFLECT:
562             return VG_LITE_GRADIENT_SPREAD_REFLECT;
563         default:
564             LV_LOG_WARN("unknown spread mode: %d", spread);
565             break;
566     }
567 
568     return VG_LITE_GRADIENT_SPREAD_FILL;
569 }
570 
grad_create_cb(grad_item_t * item,void * user_data)571 static bool grad_create_cb(grad_item_t * item, void * user_data)
572 {
573     LV_UNUSED(user_data);
574     item->type = lv_grad_style_to_type(item->lv.style);
575     switch(item->type) {
576         case GRAD_TYPE_LINEAR:
577             return linear_grad_create(item);
578 
579         case GRAD_TYPE_LINEAR_EXT:
580             return linear_ext_grad_create(item);
581 
582         case GRAD_TYPE_RADIAL:
583             return radial_grad_create(item);
584 
585         default:
586             LV_LOG_ERROR("unknown gradient type: %d", item->type);
587             break;
588     }
589 
590     return false;
591 }
592 
grad_free_cb(grad_item_t * item,void * user_data)593 static void grad_free_cb(grad_item_t * item, void * user_data)
594 {
595     LV_UNUSED(user_data);
596     switch(item->type) {
597         case GRAD_TYPE_LINEAR:
598             LV_VG_LITE_CHECK_ERROR(vg_lite_clear_grad(&item->vg.linear));
599             break;
600 
601         case GRAD_TYPE_LINEAR_EXT:
602             LV_VG_LITE_CHECK_ERROR(vg_lite_clear_linear_grad(&item->vg.linear_ext));
603             break;
604 
605         case GRAD_TYPE_RADIAL:
606             LV_VG_LITE_CHECK_ERROR(vg_lite_clear_radial_grad(&item->vg.radial));
607             break;
608 
609         default:
610             LV_LOG_ERROR("unknown gradient type: %d", item->type);
611             break;
612     }
613 }
614 
grad_compare_cb(const grad_item_t * lhs,const grad_item_t * rhs)615 static lv_cache_compare_res_t grad_compare_cb(const grad_item_t * lhs, const grad_item_t * rhs)
616 {
617     /* compare type first */
618     if(lhs->type != rhs->type) {
619         return lhs->type > rhs->type ? 1 : -1;
620     }
621 
622     /* compare spread mode */
623     if(lhs->lv.spread != rhs->lv.spread) {
624         return lhs->lv.spread > rhs->lv.spread ? 1 : -1;
625     }
626 
627     /* compare gradient parameters */
628     switch(lhs->type) {
629         case GRAD_TYPE_LINEAR:
630             /* no extra compare needed */
631             break;
632 
633         case GRAD_TYPE_LINEAR_EXT:
634             if(!math_equal(lhs->lv.x1, rhs->lv.x1)) {
635                 return lhs->lv.x1 > rhs->lv.x1 ? 1 : -1;
636             }
637 
638             if(!math_equal(lhs->lv.y1, rhs->lv.y1)) {
639                 return lhs->lv.y1 > rhs->lv.y1 ? 1 : -1;
640             }
641 
642             if(!math_equal(lhs->lv.x2, rhs->lv.x2)) {
643                 return lhs->lv.x2 > rhs->lv.x2 ? 1 : -1;
644             }
645 
646             if(!math_equal(lhs->lv.y2, rhs->lv.y2)) {
647                 return lhs->lv.y2 > rhs->lv.y2 ? 1 : -1;
648             }
649             break;
650 
651         case GRAD_TYPE_RADIAL:
652             if(!math_equal(lhs->lv.cx, rhs->lv.cx)) {
653                 return lhs->lv.cx > rhs->lv.cx ? 1 : -1;
654             }
655 
656             if(!math_equal(lhs->lv.cy, rhs->lv.cy)) {
657                 return lhs->lv.cy > rhs->lv.cy ? 1 : -1;
658             }
659 
660             if(!math_equal(lhs->lv.cr, rhs->lv.cr)) {
661                 return lhs->lv.cr > rhs->lv.cr ? 1 : -1;
662             }
663             break;
664 
665         default:
666             LV_LOG_ERROR("unknown gradient type: %d", lhs->type);
667             break;
668     }
669 
670     /* compare stops count and stops */
671     if(lhs->lv.stops_count != rhs->lv.stops_count) {
672         return lhs->lv.stops_count > rhs->lv.stops_count ? 1 : -1;
673     }
674 
675     int cmp_res = lv_memcmp(lhs->lv.stops, rhs->lv.stops,
676                             sizeof(lv_gradient_stop_t) * lhs->lv.stops_count);
677     if(cmp_res != 0) {
678         return cmp_res > 0 ? 1 : -1;
679     }
680 
681     return 0;
682 }
683 
684 #endif /*LV_USE_DRAW_VG_LITE && LV_USE_VECTOR_GRAPHIC*/
685