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