perf(label): simplify handling of bytes overwritten with dots (#7001)

This commit is contained in:
Niklas Fiekas 2024-10-18 10:51:49 +02:00 committed by GitHub
parent e332a0db52
commit 59c72243cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 34 additions and 129 deletions

View File

@ -32,7 +32,7 @@
#define LV_LABEL_DEF_SCROLL_SPEED lv_anim_speed_clamped(40, 300, 10000)
#define LV_LABEL_SCROLL_DELAY 300
#define LV_LABEL_DOT_END_INV 0xFFFFFFFF
#define LV_LABEL_DOT_BEGIN_INV 0xFFFFFFFF
#define LV_LABEL_HINT_HEIGHT_LIMIT 1024 /*Enable "hint" to buffer info about labels larger than this. (Speed up drawing)*/
/**********************
@ -49,10 +49,8 @@ static void draw_main(lv_event_t * e);
static void lv_label_refr_text(lv_obj_t * obj);
static void lv_label_revert_dots(lv_obj_t * label);
static void lv_label_set_dots(lv_obj_t * label, uint32_t dot_begin);
static bool lv_label_set_dot_tmp(lv_obj_t * label, char * data, uint32_t len);
static char * lv_label_get_dot_tmp(lv_obj_t * label);
static void lv_label_dot_tmp_free(lv_obj_t * label);
static void set_ofs_x_anim(void * obj, int32_t v);
static void set_ofs_y_anim(void * obj, int32_t v);
static size_t get_text_length(const char * text);
@ -137,11 +135,10 @@ void lv_label_set_text(lv_obj_t * obj, const char * text)
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_label_t * label = (lv_label_t *)obj;
lv_obj_invalidate(obj);
/*If text is NULL then just refresh with the current text*/
if(text == NULL) text = label->text;
lv_label_revert_dots(obj); /*In case text == label->text*/
const size_t text_len = get_text_length(text);
/*If set its own text then reallocate it (maybe its size changed)*/
@ -237,11 +234,6 @@ void lv_label_set_long_mode(lv_obj_t * obj, lv_label_long_mode_t long_mode)
else
label->expand = 0;
/*Restore the character under the dots*/
if(label->long_mode == LV_LABEL_LONG_DOT && label->dot_end != LV_LABEL_DOT_END_INV) {
lv_label_revert_dots(obj);
}
label->long_mode = long_mode;
lv_label_refr_text(obj);
}
@ -722,7 +714,7 @@ static void lv_label_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
label->text = NULL;
label->recolor = 0;
label->static_txt = 0;
label->dot_end = LV_LABEL_DOT_END_INV;
label->dot_begin = LV_LABEL_DOT_BEGIN_INV;
label->long_mode = LV_LABEL_LONG_WRAP;
lv_point_set(&label->offset, 0, 0);
@ -736,8 +728,6 @@ static void lv_label_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
label->sel_start = LV_DRAW_LABEL_NO_TXT_SEL;
label->sel_end = LV_DRAW_LABEL_NO_TXT_SEL;
#endif
label->dot.tmp_ptr = NULL;
label->dot_tmp_alloc = 0;
lv_obj_remove_flag(obj, LV_OBJ_FLAG_CLICKABLE);
lv_label_set_long_mode(obj, LV_LABEL_LONG_WRAP);
@ -751,7 +741,6 @@ static void lv_label_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
LV_UNUSED(class_p);
lv_label_t * label = (lv_label_t *)obj;
lv_label_dot_tmp_free(obj);
if(!label->static_txt) lv_free(label->text);
label->text = NULL;
}
@ -768,8 +757,6 @@ static void lv_label_event(const lv_obj_class_t * class_p, lv_event_t * e)
lv_obj_t * obj = lv_event_get_current_target(e);
if((code == LV_EVENT_STYLE_CHANGED) || (code == LV_EVENT_SIZE_CHANGED)) {
/*Revert dots for proper refresh*/
lv_label_revert_dots(obj);
lv_label_refr_text(obj);
}
else if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
@ -791,13 +778,16 @@ static void lv_label_event(const lv_obj_class_t * class_p, lv_event_t * e)
if(label->recolor != 0) flag |= LV_TEXT_FLAG_RECOLOR;
if(label->expand != 0) flag |= LV_TEXT_FLAG_EXPAND;
int32_t w = lv_obj_get_content_width(obj);
int32_t w;
if(lv_obj_get_style_width(obj, LV_PART_MAIN) == LV_SIZE_CONTENT && !obj->w_layout) w = LV_COORD_MAX;
else w = lv_obj_get_content_width(obj);
w = LV_MIN(w, lv_obj_get_style_max_width(obj, 0));
uint32_t dot_begin = label->dot_begin;
lv_label_revert_dots(obj);
lv_text_get_size(&label->size_cache, label->text, font, letter_space, line_space, w, flag);
lv_label_set_dots(obj, dot_begin);
label->invalid_size_cache = false;
}
@ -955,6 +945,7 @@ static void lv_label_refr_text(lv_obj_t * obj)
lv_point_t size;
lv_text_flag_t flag = get_label_flags(label);
lv_label_revert_dots(obj);
lv_text_get_size(&size, label->text, font, letter_space, line_space, max_w, flag);
lv_obj_refresh_self_size(obj);
@ -1152,16 +1143,9 @@ static void lv_label_refr_text(lv_obj_t * obj)
}
}
else if(label->long_mode == LV_LABEL_LONG_DOT) {
if(size.y <= lv_area_get_height(&txt_coords)) { /*No dots are required, the text is short enough*/
label->dot_end = LV_LABEL_DOT_END_INV;
}
else if(size.y <= lv_font_get_line_height(font)) { /*No dots are required for one-line texts*/
label->dot_end = LV_LABEL_DOT_END_INV;
}
else if(lv_text_get_encoded_length(label->text) <= LV_LABEL_DOT_NUM) { /*Don't turn to dots all the characters*/
label->dot_end = LV_LABEL_DOT_END_INV;
}
else {
if(size.y > lv_area_get_height(&txt_coords) && /*Text overflows available area*/
size.y > lv_font_get_line_height(font) && /*No break requested, so no dots required*/
lv_text_get_encoded_length(label->text) > LV_LABEL_DOT_NUM) { /*Do not turn all characters into dots*/
lv_point_t p;
int32_t y_overed;
p.x = lv_area_get_width(&txt_coords) -
@ -1190,27 +1174,10 @@ static void lv_label_refr_text(lv_obj_t * obj)
}
/*Save letters under the dots and replace them with dots*/
uint32_t byte_id_ori = byte_id;
uint32_t i;
uint8_t len = 0;
for(i = 0; i <= LV_LABEL_DOT_NUM; i++) {
len += lv_text_encoded_size(&label->text[byte_id]);
lv_text_encoded_next(label->text, &byte_id);
if(len > LV_LABEL_DOT_NUM || byte_id > txt_len) {
break;
}
}
if(lv_label_set_dot_tmp(obj, &label->text[byte_id_ori], len)) {
for(i = 0; i < LV_LABEL_DOT_NUM; i++) {
label->text[byte_id_ori + i] = '.';
}
label->text[byte_id_ori + LV_LABEL_DOT_NUM] = '\0';
label->dot_end = letter_id + LV_LABEL_DOT_NUM;
}
lv_label_set_dots(obj, byte_id);
}
}
else if(label->long_mode == LV_LABEL_LONG_CLIP) {
else if(label->long_mode == LV_LABEL_LONG_CLIP || label->long_mode == LV_LABEL_LONG_WRAP) {
/*Do nothing*/
}
@ -1220,88 +1187,30 @@ static void lv_label_refr_text(lv_obj_t * obj)
static void lv_label_revert_dots(lv_obj_t * obj)
{
lv_label_t * label = (lv_label_t *)obj;
if(label->long_mode != LV_LABEL_LONG_DOT) return;
if(label->dot_end == LV_LABEL_DOT_END_INV) return;
const uint32_t letter_i = label->dot_end - LV_LABEL_DOT_NUM;
const uint32_t byte_i = lv_text_encoded_get_byte_id(label->text, letter_i);
/*Restore the characters*/
uint8_t i = 0;
char * dot_tmp = lv_label_get_dot_tmp(obj);
while(label->text[byte_i + i] != '\0') {
label->text[byte_i + i] = dot_tmp[i];
i++;
}
label->text[byte_i + i] = dot_tmp[i];
lv_label_dot_tmp_free(obj);
label->dot_end = LV_LABEL_DOT_END_INV;
}
/**
* Store `len` characters from `data`. Allocates space if necessary.
*
* @param label pointer to label object
* @param len Number of characters to store.
* @return true on success.
*/
static bool lv_label_set_dot_tmp(lv_obj_t * obj, char * data, uint32_t len)
{
lv_label_t * label = (lv_label_t *)obj;
lv_label_dot_tmp_free(obj); /*Deallocate any existing space*/
if(len > sizeof(char *)) {
/*Memory needs to be allocated. Allocates an additional byte
*for a NULL-terminator so it can be copied.*/
label->dot.tmp_ptr = lv_malloc(len + 1);
if(label->dot.tmp_ptr == NULL) {
LV_LOG_ERROR("Failed to allocate memory for dot_tmp_ptr");
return false;
if(label->dot_begin != LV_LABEL_DOT_BEGIN_INV) {
for(int i = 0; i < LV_LABEL_DOT_NUM + 1 && label->dot[i]; i++) {
label->text[label->dot_begin + i] = label->dot[i];
}
lv_memcpy(label->dot.tmp_ptr, data, len);
label->dot.tmp_ptr[len] = '\0';
label->dot_tmp_alloc = true;
}
else {
/*Characters can be directly stored in object*/
label->dot_tmp_alloc = false;
lv_memcpy(label->dot.tmp, data, len);
}
return true;
}
/**
* Get the stored dot_tmp characters
* @param label pointer to label object
* @return char pointer to a stored characters. Is *not* necessarily NULL-terminated.
*/
static char * lv_label_get_dot_tmp(lv_obj_t * obj)
{
lv_label_t * label = (lv_label_t *)obj;
if(label->dot_tmp_alloc) {
return label->dot.tmp_ptr;
}
else {
return label->dot.tmp;
label->dot_begin = LV_LABEL_DOT_BEGIN_INV;
}
}
/**
* Free the dot_tmp_ptr field if it was previously allocated.
* Always clears the field
* @param label pointer to label object.
*/
static void lv_label_dot_tmp_free(lv_obj_t * obj)
static void lv_label_set_dots(lv_obj_t * obj, uint32_t dot_begin)
{
lv_label_t * label = (lv_label_t *)obj;
if(label->dot_tmp_alloc && label->dot.tmp_ptr) {
lv_free(label->dot.tmp_ptr);
LV_ASSERT_MSG(label->dot_begin == LV_LABEL_DOT_BEGIN_INV, "Label dots already set");
if(dot_begin != LV_LABEL_DOT_BEGIN_INV) {
/*Save characters*/
lv_strncpy(label->dot, &label->text[dot_begin], LV_LABEL_DOT_NUM + 1);
label->dot_begin = dot_begin;
/*Overwrite up to LV_LABEL_DOT_NUM + 1 characters with dots and null terminator*/
int i = 0;
for(; i < LV_LABEL_DOT_NUM && label->text[dot_begin + i]; i++) {
label->text[dot_begin + i] = '.';
}
label->text[dot_begin + i] = '\0';
}
label->dot_tmp_alloc = false;
label->dot.tmp_ptr = NULL;
}
static void set_ofs_x_anim(void * obj, int32_t v)

View File

@ -31,11 +31,8 @@ extern "C" {
struct _lv_label_t {
lv_obj_t obj;
char * text;
union {
char * tmp_ptr; /**< Pointer to the allocated memory containing the character replaced by dots */
char tmp[LV_LABEL_DOT_NUM + 1]; /**< Directly store the characters if <=4 characters */
} dot;
uint32_t dot_end; /**< The real text length, used in dot mode */
char dot[LV_LABEL_DOT_NUM + 1]; /**< Bytes that have been replaced with dots */
uint32_t dot_begin; /**< Offset where bytes have been replaced with dots */
#if LV_LABEL_LONG_TXT_HINT
lv_draw_label_hint_t hint;
@ -52,7 +49,6 @@ struct _lv_label_t {
uint8_t static_txt : 1; /**< Flag to indicate the text is static */
uint8_t recolor : 1; /**< Enable in-line letter re-coloring*/
uint8_t expand : 1; /**< Ignore real width (used by the library with LV_LABEL_LONG_SCROLL) */
uint8_t dot_tmp_alloc : 1; /**< 1: dot is allocated, 0: dot directly holds up to 4 chars */
uint8_t invalid_size_cache : 1; /**< 1: Recalculate size and update cache */
};