Skip to content

Commit

Permalink
fix(vg_lite): fix stroke crash when update failed (lvgl#7399)
Browse files Browse the repository at this point in the history
Signed-off-by: pengyiqiang <[email protected]>
Co-authored-by: pengyiqiang <[email protected]>
  • Loading branch information
FASTSHIFT and pengyiqiang authored Dec 6, 2024
1 parent 65a52f2 commit 4f2fd4b
Showing 1 changed file with 149 additions and 76 deletions.
225 changes: 149 additions & 76 deletions src/draw/vg_lite/lv_vg_lite_stroke.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,41 @@
* TYPEDEFS
**********************/


/**
* Since the key-value data structure of lv_cache is integrated, the kv data structure
* will be saved at the same time when the cache is successfully created.
* In order to pursue efficiency during the matching process, the primary key (lv) used for matching
* will not dup the dash_pattern secondary pointer, so when the creation is successful, dash_pattern needs
* to be dup to the child key (vg), so type is added here to distinguish where the real data of dash_pattern exists.
*/
typedef enum {
DASH_PATTERN_TYPE_LV,
DASH_PATTERN_TYPE_VG
} dash_pattern_type_t;

typedef struct {
/* stroke path */
lv_vg_lite_path_t * path;

/* stroke parameters */
float width;
lv_vector_stroke_cap_t cap;
lv_vector_stroke_join_t join;
uint16_t miter_limit;
lv_array_t dash_pattern;
dash_pattern_type_t dash_pattern_type;

struct {
/* path data */
lv_vg_lite_path_t * path;

/* stroke parameters */
float width;
lv_vector_stroke_cap_t cap;
lv_vector_stroke_join_t join;
uint16_t miter_limit;
lv_array_t dash_pattern;
} lv;

struct {
/* stroke path */
lv_vg_lite_path_t * path;

/* dash pattern, for comparison only */
lv_array_t dash_pattern;
} vg;
} stroke_item_t;

/**********************
Expand Down Expand Up @@ -124,21 +149,21 @@ lv_cache_entry_t * lv_vg_lite_stroke_get(struct _lv_draw_vg_lite_unit_t * unit,
/* prepare search key */
stroke_item_t search_key;
lv_memzero(&search_key, sizeof(search_key));
search_key.cap = dsc->cap;
search_key.join = dsc->join;
search_key.width = dsc->width;
search_key.miter_limit = dsc->miter_limit;
search_key.lv.cap = dsc->cap;
search_key.lv.join = dsc->join;
search_key.lv.width = dsc->width;
search_key.lv.miter_limit = dsc->miter_limit;

/* A one-time read-only array that only copies the pointer but not the content */
search_key.dash_pattern = dsc->dash_pattern;
search_key.path = path;
search_key.lv.dash_pattern = dsc->dash_pattern;
search_key.lv.path = path;

lv_cache_entry_t * cache_node_entry = lv_cache_acquire(unit->stroke_cache, &search_key, &search_key);
lv_cache_entry_t * cache_node_entry = lv_cache_acquire(unit->stroke_cache, &search_key, NULL);
if(cache_node_entry) {
return cache_node_entry;
}

cache_node_entry = lv_cache_acquire_or_create(unit->stroke_cache, &search_key, &search_key);
cache_node_entry = lv_cache_acquire_or_create(unit->stroke_cache, &search_key, NULL);
if(cache_node_entry == NULL) {
LV_LOG_ERROR("stroke cache creating failed");
return NULL;
Expand All @@ -153,7 +178,13 @@ struct _lv_vg_lite_path_t * lv_vg_lite_stroke_get_path(lv_cache_entry_t * cache_

stroke_item_t * stroke_item = lv_cache_entry_get_data(cache_entry);
LV_ASSERT_NULL(stroke_item);
return stroke_item->path;

if(lv_array_size(&stroke_item->vg.dash_pattern)) {
/* check if dash pattern must be duped */
LV_ASSERT(stroke_item->dash_pattern_type == DASH_PATTERN_TYPE_VG);
}

return stroke_item->vg.path;
}

void lv_vg_lite_stroke_drop(struct _lv_draw_vg_lite_unit_t * unit,
Expand All @@ -170,43 +201,49 @@ void lv_vg_lite_stroke_drop(struct _lv_draw_vg_lite_unit_t * unit,

static bool stroke_create_cb(stroke_item_t * item, void * user_data)
{
LV_UNUSED(user_data);
LV_ASSERT_NULL(item);

stroke_item_t * src = user_data;
LV_ASSERT_NULL(src);

lv_memzero(item, sizeof(stroke_item_t));
/* Check if stroke width is valid */
if(item->lv.width <= 0) {
LV_LOG_WARN("stroke width error: %f", item->lv.width);
return false;
}

/* copy path */
item->path = lv_vg_lite_path_create(VG_LITE_FP32);
lv_vg_lite_path_append_path(item->path, src->path);
/* Reset the dash pattern type */
item->dash_pattern_type = DASH_PATTERN_TYPE_LV;

/* copy parameters */
item->cap = src->cap;
item->join = src->join;
item->width = src->width;
item->miter_limit = src->miter_limit;
/* dup the path */
item->vg.path = lv_vg_lite_path_create(VG_LITE_FP32);
lv_vg_lite_path_append_path(item->vg.path, item->lv.path);

/* copy dash pattern */
uint32_t size = lv_array_size(&src->dash_pattern);
/* dup the dash pattern */
vg_lite_float_t * vg_dash_pattern = NULL;
const uint32_t size = lv_array_size(&item->lv.dash_pattern);
if(size) {
lv_array_init(&item->dash_pattern, size, sizeof(float));
lv_array_copy(&item->dash_pattern, &src->dash_pattern);
/* Only support float dash pattern */
LV_ASSERT(item->lv.dash_pattern.element_size == sizeof(float));
lv_array_init(&item->vg.dash_pattern, size, sizeof(float));
lv_array_copy(&item->vg.dash_pattern, &item->lv.dash_pattern);

/* mark dash pattern has been duped */
item->dash_pattern_type = DASH_PATTERN_TYPE_VG;
vg_dash_pattern = lv_array_front(&item->vg.dash_pattern);
}

/* update parameters */
vg_lite_path_t * vg_path = lv_vg_lite_path_get_path(item->path);
vg_lite_path_t * vg_path = lv_vg_lite_path_get_path(item->vg.path);
LV_VG_LITE_CHECK_ERROR(vg_lite_set_path_type(vg_path, VG_LITE_DRAW_STROKE_PATH));

vg_lite_error_t error = vg_lite_set_stroke(
vg_path,
lv_stroke_cap_to_vg(item->cap),
lv_stroke_join_to_vg(item->join),
item->width,
item->miter_limit,
lv_array_front(&item->dash_pattern),
lv_stroke_cap_to_vg(item->lv.cap),
lv_stroke_join_to_vg(item->lv.join),
item->lv.width,
item->lv.miter_limit,
vg_dash_pattern,
size,
item->width / 2,
item->lv.width / 2,
0);

if(error != VG_LITE_SUCCESS) {
Expand Down Expand Up @@ -242,68 +279,104 @@ static void stroke_free_cb(stroke_item_t * item, void * user_data)
LV_UNUSED(user_data);
LV_ASSERT_NULL(item);

lv_array_deinit(&item->dash_pattern);
lv_vg_lite_path_destroy(item->path);
lv_memzero(item, sizeof(stroke_item_t));
if(item->vg.path) {
lv_vg_lite_path_destroy(item->vg.path);
item->vg.path = NULL;
}

if(item->dash_pattern_type == DASH_PATTERN_TYPE_VG) {
lv_array_deinit(&item->vg.dash_pattern);
item->dash_pattern_type = DASH_PATTERN_TYPE_LV;
}
}

static lv_cache_compare_res_t path_compare(const vg_lite_path_t * lhs, const vg_lite_path_t * rhs)
static lv_cache_compare_res_t dash_pattern_compare(const stroke_item_t * lhs, const stroke_item_t * rhs)
{
LV_ASSERT(lhs->format == VG_LITE_FP32);
LV_ASSERT(rhs->format == VG_LITE_FP32);
/* Select the dash pattern to compare */
const lv_array_t * lhs_dash_pattern = lhs->dash_pattern_type == DASH_PATTERN_TYPE_LV ?
&lhs->lv.dash_pattern :
&lhs->vg.dash_pattern;
const lv_array_t * rhs_dash_pattern = rhs->dash_pattern_type == DASH_PATTERN_TYPE_LV ?
&rhs->lv.dash_pattern :
&rhs->vg.dash_pattern;

const uint32_t lhs_dash_pattern_size = lv_array_size(lhs_dash_pattern);
const uint32_t rhs_dash_pattern_size = lv_array_size(rhs_dash_pattern);

if(lhs_dash_pattern_size != rhs_dash_pattern_size) {
return lhs_dash_pattern_size > rhs_dash_pattern_size ? 1 : -1;
}

if(lhs->path_length != rhs->path_length) {
return lhs->path_length > rhs->path_length ? 1 : -1;
if(lhs_dash_pattern_size == 0 && rhs_dash_pattern_size == 0) {
return 0;
}

int cmp_res = lv_memcmp(lhs->path, rhs->path, lhs->path_length);
/* Both dash pattern has the same size, compare them */
LV_ASSERT(lhs_dash_pattern->element_size == sizeof(float));
LV_ASSERT(rhs_dash_pattern->element_size == sizeof(float));

/* compare dash pattern data */
int cmp_res = lv_memcmp(
lv_array_front(lhs_dash_pattern),
lv_array_front(rhs_dash_pattern),
lhs_dash_pattern_size * sizeof(float));

if(cmp_res != 0) {
return cmp_res > 0 ? 1 : -1;
}

return 0;
}

static lv_cache_compare_res_t stroke_compare_cb(const stroke_item_t * lhs, const stroke_item_t * rhs)
static lv_cache_compare_res_t path_compare(const stroke_item_t * lhs, const stroke_item_t * rhs)
{
if(lhs->width != lhs->width) {
return lhs->width > lhs->width ? 1 : -1;
/* Give priority to using dup vg.path */
const vg_lite_path_t * lhs_path = lhs->vg.path ?
lv_vg_lite_path_get_path(lhs->vg.path) :
lv_vg_lite_path_get_path(lhs->lv.path);
const vg_lite_path_t * rhs_path = rhs->vg.path ?
lv_vg_lite_path_get_path(rhs->vg.path) :
lv_vg_lite_path_get_path(rhs->lv.path);

LV_ASSERT(lhs_path->format == VG_LITE_FP32);
LV_ASSERT(rhs_path->format == VG_LITE_FP32);

if(lhs_path->path_length != rhs_path->path_length) {
return lhs_path->path_length > rhs_path->path_length ? 1 : -1;
}

if(lhs->cap != rhs->cap) {
return lhs->cap > rhs->cap ? 1 : -1;
int cmp_res = lv_memcmp(lhs_path->path, rhs_path->path, lhs_path->path_length);
if(cmp_res != 0) {
return cmp_res > 0 ? 1 : -1;
}

if(lhs->join != rhs->join) {
return lhs->join > rhs->join ? 1 : -1;
}
return 0;
}

if(lhs->miter_limit != rhs->miter_limit) {
return lhs->miter_limit > rhs->miter_limit ? 1 : -1;
static lv_cache_compare_res_t stroke_compare_cb(const stroke_item_t * lhs, const stroke_item_t * rhs)
{
if(lhs->lv.width != rhs->lv.width) {
return lhs->lv.width > rhs->lv.width ? 1 : -1;
}

uint32_t lhs_dash_pattern_size = lv_array_size(&lhs->dash_pattern);
uint32_t rhs_dash_pattern_size = lv_array_size(&rhs->dash_pattern);

if(lhs_dash_pattern_size != rhs_dash_pattern_size) {
return lhs_dash_pattern_size > rhs_dash_pattern_size ? 1 : -1;
if(lhs->lv.cap != rhs->lv.cap) {
return lhs->lv.cap > rhs->lv.cap ? 1 : -1;
}

if(lhs_dash_pattern_size > 0 && rhs_dash_pattern_size > 0) {
LV_ASSERT(lhs->dash_pattern.element_size == sizeof(float));
LV_ASSERT(rhs->dash_pattern.element_size == sizeof(float));
if(lhs->lv.join != rhs->lv.join) {
return lhs->lv.join > rhs->lv.join ? 1 : -1;
}

const float * lhs_dash_pattern = lv_array_front(&lhs->dash_pattern);
const float * rhs_dash_pattern = lv_array_front(&rhs->dash_pattern);
if(lhs->lv.miter_limit != rhs->lv.miter_limit) {
return lhs->lv.miter_limit > rhs->lv.miter_limit ? 1 : -1;
}

/* compare dash pattern */
int cmp_res = lv_memcmp(lhs_dash_pattern, rhs_dash_pattern, lhs_dash_pattern_size * sizeof(float));
if(cmp_res != 0) {
return cmp_res > 0 ? 1 : -1;
}
lv_cache_compare_res_t dash_pattern_res = dash_pattern_compare(lhs, rhs);
if(dash_pattern_res != 0) {
return dash_pattern_res;
}

return path_compare(lv_vg_lite_path_get_path(lhs->path), lv_vg_lite_path_get_path(rhs->path));
return path_compare(lhs, rhs);
}

#endif /*LV_USE_DRAW_VG_LITE && LV_USE_VECTOR_GRAPHIC*/

0 comments on commit 4f2fd4b

Please sign in to comment.