perf(span): optimize span render performance up by 50% (#7290)

This commit is contained in:
Benign X 2024-11-21 22:42:16 +08:00 committed by GitHub
parent 65d2d42124
commit 7cfe085f46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 64 additions and 87 deletions

View File

@ -67,6 +67,7 @@ void lv_draw_label_dsc_init(lv_draw_label_dsc_t * dsc)
lv_memzero(dsc, sizeof(lv_draw_label_dsc_t));
dsc->opa = LV_OPA_COVER;
dsc->color = lv_color_black();
dsc->text_length = LV_TEXT_LEN_MAX;
dsc->font = LV_FONT_DEFAULT;
dsc->sel_start = LV_DRAW_LABEL_NO_TXT_SEL;
dsc->sel_end = LV_DRAW_LABEL_NO_TXT_SEL;
@ -214,14 +215,16 @@ void lv_draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_draw_
pos.y += dsc->hint->y;
}
uint32_t line_end = line_start + lv_text_get_next_line(&dsc->text[line_start], font, dsc->letter_space, w, NULL,
dsc->flag);
uint32_t remaining_len = dsc->text_length;
uint32_t line_end = line_start + lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space,
w, NULL, dsc->flag);
/*Go the first visible line*/
while(pos.y + line_height_font < draw_unit->clip_area->y1) {
/*Go to next line*/
line_start = line_end;
line_end += lv_text_get_next_line(&dsc->text[line_start], font, dsc->letter_space, w, NULL, dsc->flag);
line_end += lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space, w, NULL, dsc->flag);
pos.y += line_height;
/*Save at the threshold coordinate*/
@ -277,7 +280,7 @@ void lv_draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_draw_
uint8_t is_first_space_after_cmd = 0;
/*Write out all lines*/
while(dsc->text[line_start] != '\0') {
while(remaining_len && dsc->text[line_start] != '\0') {
pos.x += x_ofs;
line_start_x = pos.x;
@ -292,7 +295,7 @@ void lv_draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_draw_
const char * bidi_txt = dsc->text + line_start;
#endif
while(next_char_offset < line_end - line_start) {
while(next_char_offset < remaining_len && next_char_offset < line_end - line_start) {
uint32_t logical_char_pos = 0;
/* Check if the text selection is enabled */
@ -440,8 +443,11 @@ void lv_draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_draw_
bidi_txt = NULL;
#endif
/*Go to next line*/
remaining_len -= line_end - line_start;
line_start = line_end;
line_end += lv_text_get_next_line(&dsc->text[line_start], font, dsc->letter_space, w, NULL, dsc->flag);
if(remaining_len) {
line_end += lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space, w, NULL, dsc->flag);
}
pos.x = coords->x1;
/*Align to middle*/

View File

@ -33,6 +33,7 @@ typedef struct {
lv_draw_dsc_base_t base;
const char * text;
uint32_t text_length;
const lv_font_t * font;
uint32_t sel_start;
uint32_t sel_end;

View File

@ -106,7 +106,7 @@ void lv_text_get_size(lv_point_t * size_res, const char * text, const lv_font_t
/*Calc. the height and longest line*/
while(text[line_start] != '\0') {
new_line_start += lv_text_get_next_line(&text[line_start], font, letter_space, max_width, NULL, flag);
new_line_start += lv_text_get_next_line(&text[line_start], LV_TEXT_LEN_MAX, font, letter_space, max_width, NULL, flag);
if((unsigned long)size_res->y + (unsigned long)letter_height + (unsigned long)line_space > LV_MAX_OF(int32_t)) {
LV_LOG_WARN("integer overflow while calculating text height");
@ -246,6 +246,9 @@ static uint32_t lv_text_get_next_word(const char * txt, const lv_font_t * font,
if(break_index == NO_BREAK_FOUND && (cur_w - letter_space) > max_width) {
break_index = i;
break_letter_count = word_len - 1;
if(flag & LV_TEXT_FLAG_BREAK_ALL) {
break;
}
/*break_index is now pointing at the character that doesn't fit*/
}
@ -315,9 +318,9 @@ static uint32_t lv_text_get_next_word(const char * txt, const lv_font_t * font,
#endif
}
uint32_t lv_text_get_next_line(const char * txt, const lv_font_t * font,
int32_t letter_space, int32_t max_width,
int32_t * used_width, lv_text_flag_t flag)
uint32_t lv_text_get_next_line(const char * txt, uint32_t len,
const lv_font_t * font, int32_t letter_space,
int32_t max_width, int32_t * used_width, lv_text_flag_t flag)
{
if(used_width) *used_width = 0;
@ -331,10 +334,10 @@ uint32_t lv_text_get_next_line(const char * txt, const lv_font_t * font,
*without thinking about word wrapping*/
if((flag & LV_TEXT_FLAG_EXPAND) || (flag & LV_TEXT_FLAG_FIT)) {
uint32_t i;
for(i = 0; txt[i] != '\n' && txt[i] != '\r' && txt[i] != '\0'; i++) {
for(i = 0; i < len && txt[i] != '\n' && txt[i] != '\r' && txt[i] != '\0'; i++) {
/*Just find the new line chars or string ends by incrementing `i`*/
}
if(txt[i] != '\0') i++; /*To go beyond `\n`*/
if(i < len && txt[i] != '\0') i++; /*To go beyond `\n`*/
if(used_width) *used_width = -1;
return i;
}
@ -344,7 +347,7 @@ uint32_t lv_text_get_next_line(const char * txt, const lv_font_t * font,
uint32_t i = 0; /*Iterating index into txt*/
while(txt[i] != '\0' && max_width > 0) {
while(i < len && txt[i] != '\0' && max_width > 0) {
lv_text_flag_t word_flag = flag;
if(i == 0) word_flag |= LV_TEXT_FLAG_BREAK_ALL;

View File

@ -30,6 +30,8 @@ extern "C" {
#define LV_TXT_ENC_UTF8 1
#define LV_TXT_ENC_ASCII 2
#define LV_TEXT_LEN_MAX UINT32_MAX
/**********************
* TYPEDEFS
**********************/

View File

@ -31,6 +31,7 @@ extern "C" {
/**
* Get the next line of text. Check line length and break chars too.
* @param txt a '\0' terminated string
* @param len length of 'txt' in bytes
* @param font pointer to a font
* @param letter_space letter space
* @param max_width max width of the text (break the lines to fit this size). Set COORD_MAX to avoid
@ -41,7 +42,7 @@ extern "C" {
* @return the index of the first char of the new line (in byte index not letter index. With UTF-8
* they are different)
*/
uint32_t lv_text_get_next_line(const char * txt, const lv_font_t * font, int32_t letter_space,
uint32_t lv_text_get_next_line(const char * txt, uint32_t len, const lv_font_t * font, int32_t letter_space,
int32_t max_width, int32_t * used_width, lv_text_flag_t flag);
/**

View File

@ -346,7 +346,7 @@ void lv_label_get_letter_pos(const lv_obj_t * obj, uint32_t char_id, lv_point_t
bool last_line = y + letter_height + line_space + letter_height > max_h;
if(last_line && label->long_mode == LV_LABEL_LONG_DOT) flag |= LV_TEXT_FLAG_BREAK_ALL;
new_line_start += lv_text_get_next_line(&txt[line_start], font, letter_space, max_w, NULL, flag);
new_line_start += lv_text_get_next_line(&txt[line_start], LV_TEXT_LEN_MAX, font, letter_space, max_w, NULL, flag);
if(byte_id < new_line_start || txt[new_line_start] == '\0')
break; /*The line of 'index' letter begins at 'line_start'*/
@ -437,7 +437,7 @@ uint32_t lv_label_get_letter_on(const lv_obj_t * obj, lv_point_t * pos_in, bool
bool last_line = y + letter_height + line_space + letter_height > max_h;
if(last_line && label->long_mode == LV_LABEL_LONG_DOT) flag |= LV_TEXT_FLAG_BREAK_ALL;
new_line_start += lv_text_get_next_line(&txt[line_start], font, letter_space, max_w, NULL, flag);
new_line_start += lv_text_get_next_line(&txt[line_start], LV_TEXT_LEN_MAX, font, letter_space, max_w, NULL, flag);
if(pos.y <= y + letter_height) {
/*The line is found (stored in 'line_start')*/
@ -558,7 +558,7 @@ bool lv_label_is_char_under_pos(const lv_obj_t * obj, lv_point_t * pos)
bool last_line = y + letter_height + line_space + letter_height > max_h;
if(last_line && label->long_mode == LV_LABEL_LONG_DOT) flag |= LV_TEXT_FLAG_BREAK_ALL;
new_line_start += lv_text_get_next_line(&txt[line_start], font, letter_space, max_w, NULL, flag);
new_line_start += lv_text_get_next_line(&txt[line_start], LV_TEXT_LEN_MAX, font, letter_space, max_w, NULL, flag);
if(pos->y <= y + letter_height) break; /*The line is found (stored in 'line_start')*/
y += letter_height + line_space;

View File

@ -738,7 +738,7 @@ static bool lv_text_get_snippet(const char * txt, const lv_font_t * font,
real_max_width++;
#endif
uint32_t ofs = lv_text_get_next_line(txt, font, letter_space, real_max_width, use_width, flag);
uint32_t ofs = lv_text_get_next_line(txt, LV_TEXT_LEN_MAX, font, letter_space, real_max_width, use_width, flag);
*end_ofs = ofs;
if(txt[ofs] == '\0' && *use_width < max_width && !(ofs && (txt[ofs - 1] == '\n' || txt[ofs - 1] == '\r'))) {
@ -1018,16 +1018,11 @@ static void lv_draw_span(lv_obj_t * obj, lv_layer_t * layer)
if(last_snippet->txt[last_snippet->bytes] == '\0') {
next_line_h = 0;
lv_span_t * next_span = lv_ll_get_next(&spans->child_ll, last_snippet->span);
if(next_span) { /* have the next line */
if(next_span && next_span->txt && next_span->txt[0]) { /* have the next line */
next_line_h = lv_font_get_line_height(lv_span_get_style_text_font(obj, next_span)) + line_space;
}
}
if(txt_pos.y + max_line_h + next_line_h - line_space > coords.y2 + 1) { /* for overflow if is end line. */
if(last_snippet->txt[last_snippet->bytes] != '\0') {
last_snippet->bytes = lv_strlen(last_snippet->txt);
last_snippet->txt_w = lv_text_get_width_with_flags(last_snippet->txt, last_snippet->bytes, last_snippet->font,
last_snippet->letter_space, label_draw_dsc.flag);
}
ellipsis_valid = spans->overflow == LV_SPAN_OVERFLOW_ELLIPSIS;
is_end_line = true;
}
@ -1076,76 +1071,45 @@ static void lv_draw_span(lv_obj_t * obj, lv_layer_t * layer)
}
uint32_t txt_bytes = pinfo->bytes;
/* overflow */
uint32_t dot_letter_w = 0;
uint32_t dot_width = 0;
if(ellipsis_valid) {
dot_letter_w = lv_font_get_glyph_width(pinfo->font, '.', '.');
dot_width = dot_letter_w * 3;
}
int32_t ellipsis_width = coords.x1 + max_width - dot_width;
uint32_t j = 0;
while(j < txt_bytes) {
/* skip invalid fields */
if(pos.x > clip_area.x2) {
break;
}
uint32_t letter = lv_text_encoded_next(bidi_txt, &j);
uint32_t letter_next = lv_text_encoded_next(&bidi_txt[j], NULL);
int32_t letter_w = lv_font_get_glyph_width(pinfo->font, letter, letter_next);
/* skip invalid fields */
if(pos.x + letter_w + pinfo->letter_space < clip_area.x1) {
if(letter_w > 0) {
pos.x = pos.x + letter_w + pinfo->letter_space;
}
continue;
}
if(ellipsis_valid && pos.x + letter_w + pinfo->letter_space > ellipsis_width) {
for(int ell = 0; ell < 3; ell++) {
lv_draw_character(layer, &label_draw_dsc, &pos, '.');
pos.x = pos.x + dot_letter_w + pinfo->letter_space;
}
if(pos.x <= ellipsis_width) {
pos.x = ellipsis_width + 1;
}
break;
}
else {
lv_draw_character(layer, &label_draw_dsc, &pos, letter);
if(letter_w > 0) {
pos.x = pos.x + letter_w + pinfo->letter_space;
}
}
label_draw_dsc.text = bidi_txt;
label_draw_dsc.text_length = txt_bytes;
label_draw_dsc.letter_space = pinfo->letter_space;
label_draw_dsc.decor = lv_span_get_style_text_decor(obj, pinfo->span);
lv_area_t a;
a.x1 = pos.x;
a.y1 = pos.y;
a.x2 = a.x1 + pinfo->txt_w;
a.y2 = a.y1 + pinfo->line_h;
bool need_draw_ellipsis = false;
uint32_t dot_width = 0;
/* deal overflow */
if(ellipsis_valid) {
uint32_t dot_letter_w = lv_font_get_glyph_width(pinfo->font, '.', '.');
dot_width = dot_letter_w * 3;
label_draw_dsc.flag = LV_TEXT_FLAG_BREAK_ALL;
uint32_t next_ofs;
need_draw_ellipsis = lv_text_get_snippet(pinfo->txt, pinfo->font, pinfo->letter_space, coords.x2 - a.x1 - dot_width,
label_draw_dsc.flag, &pinfo->txt_w, &next_ofs);
a.x2 = a.x1 + pinfo->txt_w;
label_draw_dsc.text_length = next_ofs + 1;
}
/* draw decor */
lv_text_decor_t decor = lv_span_get_style_text_decor(obj, pinfo->span);
if(decor != LV_TEXT_DECOR_NONE) {
lv_draw_line_dsc_t line_dsc;
lv_draw_line_dsc_init(&line_dsc);
line_dsc.color = label_draw_dsc.color;
line_dsc.width = label_draw_dsc.font->underline_thickness ? pinfo->font->underline_thickness : 1;
line_dsc.opa = label_draw_dsc.opa;
line_dsc.blend_mode = label_draw_dsc.blend_mode;
lv_draw_label(layer, &label_draw_dsc, &a);
if(decor & LV_TEXT_DECOR_STRIKETHROUGH) {
int32_t y = pos.y + ((pinfo->line_h - line_space) >> 1) + (line_dsc.width >> 1);
lv_point_precise_set(&line_dsc.p1, txt_pos.x, y);
lv_point_precise_set(&line_dsc.p2, pos.x, y);
lv_draw_line(layer, &line_dsc);
if(need_draw_ellipsis) {
label_draw_dsc.text = "...";
a.x1 = a.x2;
a.x2 = a.x1 + dot_width;
lv_draw_label(layer, &label_draw_dsc, &a);
}
if(decor & LV_TEXT_DECOR_UNDERLINE) {
int32_t y = pos.y + pinfo->line_h - line_space - pinfo->font->base_line - pinfo->font->underline_position;
lv_point_precise_set(&line_dsc.p1, txt_pos.x, y);
lv_point_precise_set(&line_dsc.p2, pos.x, y);
lv_draw_line(layer, &line_dsc);
}
}
txt_pos.x = pos.x;
txt_pos.x = a.x2;
}
Next_line_init:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -134,7 +134,7 @@ void test_txt_next_line_should_handle_empty_string(void)
int32_t max_width = 0;
lv_text_flag_t flag = LV_TEXT_FLAG_NONE;
uint32_t next_line = lv_text_get_next_line("", font_ptr, letter_space, max_width, NULL, flag);
uint32_t next_line = lv_text_get_next_line("", 0, font_ptr, letter_space, max_width, NULL, flag);
TEST_ASSERT_EQUAL_UINT32(0, next_line);
}