Support text wrap for bidi text

TODO: conditional LV_USE_BIDI, allocate global buffer once, pass dir as parameter to lv_draw_label
This commit is contained in:
Amir Gonnen
2019-10-18 02:13:41 +03:00
parent 770645ecd0
commit c6b7cf130b
6 changed files with 23 additions and 58 deletions

View File

@@ -8,6 +8,7 @@
*********************/
#include "lv_draw_label.h"
#include "../lv_misc/lv_math.h"
#include "../lv_misc/lv_bidi.h"
/*********************
* DEFINES
@@ -162,12 +163,16 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
}
/*Write all letter of a line*/
cmd_state = CMD_STATE_WAIT;
i = line_start;
i = 0;
uint32_t letter;
uint32_t letter_next;
while(i < line_end) {
letter = lv_txt_encoded_next(txt, &i);
letter_next = lv_txt_encoded_next(&txt[i], NULL);
while(i < line_end - line_start) {
// TODO handle bidi conditionally on ifdef
static char bidi_txt[1000]; // TODO: allocate dynamically once (gloablly?), according to max label size
lv_bidi_process_paragraph(txt + line_start, bidi_txt, line_end - line_start, LV_BIDI_DIR_RTL /* lv_obj_get_base_dir(label) */ ); // TODO: pass base dir as paramter
letter = lv_txt_encoded_next(bidi_txt, &i);
letter_next = lv_txt_encoded_next(&bidi_txt[i], NULL);
/*Handle the re-color command*/
if((flag & LV_TXT_FLAG_RECOLOR) != 0) {
@@ -190,7 +195,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
/*Get the parameter*/
if(i - par_start == LABEL_RECOLOR_PAR_LENGTH + 1) {
char buf[LABEL_RECOLOR_PAR_LENGTH + 1];
memcpy(buf, &txt[par_start], LABEL_RECOLOR_PAR_LENGTH);
memcpy(buf, &bidi_txt[par_start], LABEL_RECOLOR_PAR_LENGTH);
buf[LABEL_RECOLOR_PAR_LENGTH] = '\0';
int r, g, b;
r = (hex_char_to_num(buf[0]) << 4) + hex_char_to_num(buf[1]);
@@ -213,7 +218,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
letter_w = lv_font_get_glyph_width(font, letter, letter_next);
if(sel_start != 0xFFFF && sel_end != 0xFFFF) {
int char_ind = lv_encoded_get_char_id(txt, i);
int char_ind = lv_encoded_get_char_id(bidi_txt, i);
/*Do not draw the rectangle on the character at `sel_start`.*/
if(char_ind > sel_start && char_ind <= sel_end) {
lv_area_t sel_coords;

View File

@@ -23,9 +23,7 @@
/**********************
* STATIC PROTOTYPES
**********************/
static void process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_bidi_dir_t base_dir);
static uint32_t get_next_paragraph(const char * txt);
static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t * len);
static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t max_len, uint32_t * len);
static void rtl_reverse(char * dest, const char * src, uint32_t len);
static uint32_t char_change_to_pair(uint32_t letter);
@@ -55,8 +53,8 @@ void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir
}
while(str_in[par_start] != '\0') {
par_len = get_next_paragraph(&str_in[par_start]);
process_paragraph(&str_in[par_start], &str_out[par_start], par_len, base_dir);
par_len = lv_bidi_get_next_paragraph(&str_in[par_start]);
lv_bidi_process_paragraph(&str_in[par_start], &str_out[par_start], par_len, base_dir);
par_start += par_len;
while(str_in[par_start] == '\n' || str_in[par_start] == '\r') {
@@ -134,7 +132,7 @@ bool lv_bidi_letter_is_neutral(uint32_t letter)
* STATIC FUNCTIONS
**********************/
static void process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_bidi_dir_t base_dir)
void lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_bidi_dir_t base_dir)
{
uint32_t run_len = 0;
lv_bidi_dir_t run_dir;
@@ -168,7 +166,7 @@ static void process_paragraph(const char * str_in, char * str_out, uint32_t len,
/*Get and process the runs*/
while(rd < len) {
run_dir = get_next_run(&str_in[rd], base_dir, &run_len);
run_dir = get_next_run(&str_in[rd], base_dir, len - rd, &run_len);
if(base_dir == LV_BIDI_DIR_LTR) {
if(run_dir == LV_BIDI_DIR_LTR) memcpy(&str_out[wr], &str_in[rd], run_len);
@@ -184,7 +182,7 @@ static void process_paragraph(const char * str_in, char * str_out, uint32_t len,
}
}
static uint32_t get_next_paragraph(const char * txt)
uint32_t lv_bidi_get_next_paragraph(const char * txt)
{
uint32_t i = 0;
@@ -197,7 +195,7 @@ static uint32_t get_next_paragraph(const char * txt)
return i;
}
static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t * len)
static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t max_len, uint32_t * len)
{
uint32_t i = 0;
uint32_t letter;
@@ -209,7 +207,7 @@ static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint
while(dir == LV_BIDI_DIR_NEUTRAL || dir == LV_BIDI_DIR_WEAK) {
letter = lv_txt_encoded_next(txt, &i);
dir = lv_bidi_get_letter_dir(letter);
if(txt[i] == '\0' || txt[i] == '\n' || txt[i] == '\r') {
if(i >= max_len || txt[i] == '\0' || txt[i] == '\n' || txt[i] == '\r') {
*len = i;
return base_dir;
}
@@ -222,7 +220,7 @@ static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint
/*Find the next char which has different direction*/
lv_bidi_dir_t next_dir = base_dir;
while(txt[i] != '\0'&& txt[i] != '\n' && txt[i] != '\r') {
while(i_prev < max_len && txt[i] != '\0' && txt[i] != '\n' && txt[i] != '\r') {
letter = lv_txt_encoded_next(txt, &i);
next_dir = lv_bidi_get_letter_dir(letter);

View File

@@ -53,6 +53,8 @@ typedef uint8_t lv_bidi_dir_t;
#if LV_USE_BIDI
void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir);
void lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_bidi_dir_t base_dir);
uint32_t lv_bidi_get_next_paragraph(const char * txt);
lv_bidi_dir_t lv_bidi_detect_base_dir(const char * txt);
lv_bidi_dir_t lv_bidi_get_letter_dir(uint32_t letter);
bool lv_bidi_letter_is_weak(uint32_t letter);

View File

@@ -671,11 +671,6 @@ static bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mo
lv_txt_flag_t txt_flag = LV_TXT_FLAG_NONE;
if(ext->recolor) txt_flag = LV_TXT_FLAG_RECOLOR;
#if LV_USE_BIDI
char * bidi_buf = lv_mem_alloc(64);
lv_bidi_dir_t base_dir = lv_obj_get_base_dir(btnm);
#endif
for(btn_i = 0; btn_i < ext->btn_cnt; btn_i++, txt_i++) {
/*Search the next valid text in the map*/
while(strcmp(ext->map_p[txt_i], "\n") == 0) {
@@ -744,22 +739,8 @@ static bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mo
area_tmp.x2 = area_tmp.x1 + txt_size.x;
area_tmp.y2 = area_tmp.y1 + txt_size.y;
#if LV_USE_BIDI == 0
lv_draw_label(&area_tmp, mask, btn_style, opa_scale, ext->map_p[txt_i], txt_flag, NULL, -1, -1, NULL);
#else
uint32_t txt_len = strlen(ext->map_p[txt_i]) + 1;
if(txt_len > lv_mem_get_size(bidi_buf)) {
bidi_buf = lv_mem_realloc(bidi_buf, txt_len);
}
lv_bidi_process(ext->map_p[txt_i], bidi_buf, base_dir);
lv_draw_label(&area_tmp, mask, btn_style, opa_scale, bidi_buf, txt_flag, NULL, -1, -1, NULL);
#endif
}
#if LV_USE_BIDI
lv_mem_free(bidi_buf);
#endif
}
return true;

View File

@@ -205,12 +205,8 @@ void lv_label_set_text(lv_obj_t * label, const char * text)
LV_ASSERT_MEM(ext->text);
if(ext->text == NULL) return;
#if LV_USE_BIDI == 0
strcpy(ext->text, text);
#else
lv_bidi_dir_t base_dir = lv_obj_get_base_dir(label);
lv_bidi_process(text, ext->text, base_dir);
#endif
/*Now the text is dynamically allocated*/
ext->static_txt = 0;
}
@@ -904,19 +900,7 @@ void lv_label_ins_text(lv_obj_t * label, uint32_t pos, const char * txt)
pos = lv_txt_get_encoded_length(ext->text);
}
#if LV_USE_BIDI
char * bidi_buf = lv_mem_alloc(ins_len) + 1;
LV_ASSERT_MEM(bidi_buf);
if(bidi_buf == NULL) return;
lv_bidi_process(txt, bidi_buf, lv_obj_get_base_dir(label));
lv_txt_ins(ext->text, pos, bidi_buf);
lv_mem_free(bidi_buf);
#else
lv_txt_ins(ext->text, pos, txt);
#endif
lv_label_refr_text(label);
}

View File

@@ -163,12 +163,7 @@ void lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const
}
ext->cell_data[cell] = lv_mem_realloc(ext->cell_data[cell], strlen(txt) + 2); /*+1: trailing '\0; +1: format byte*/
#if LV_USE_BIDI == 0
strcpy(ext->cell_data[cell] + 1, txt); /*+1 to skip the format byte*/
#else
lv_bidi_process(txt, ext->cell_data[cell] + 1, base_dir);
#endif
ext->cell_data[cell][0] = format.format_byte;
refr_size(table);