mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-28 07:03:00 +08:00
WIP: Bidi pos_conv
This commit is contained in:
parent
dd68877aae
commit
f6829a17b2
@ -169,7 +169,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
|
||||
while(i < line_end - line_start) {
|
||||
#if LV_USE_BIDI
|
||||
char *bidi_txt = lv_draw_get_buf(line_end - line_start + 1);
|
||||
lv_bidi_process_paragraph(txt + line_start, bidi_txt, line_end - line_start, bidi_dir);
|
||||
lv_bidi_process_paragraph(txt + line_start, bidi_txt, line_end - line_start, bidi_dir, NULL, 0);
|
||||
#else
|
||||
const char *bidi_txt = txt + line_start;
|
||||
#endif
|
||||
|
@ -29,10 +29,11 @@ typedef struct
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
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 lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t max_len, uint32_t * len, uint16_t * pos_conv_len);
|
||||
static void rtl_reverse(char * dest, const char * src, uint32_t len, uint16_t *pos_conv_out, uint16_t pos_conv_rd_base, uint16_t pos_conv_len);
|
||||
static uint32_t char_change_to_pair(uint32_t letter);
|
||||
static lv_bidi_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32_t len, uint32_t letter, lv_bidi_dir_t base_dir);
|
||||
static void fill_pos_conv(uint16_t * out, uint16_t len, uint16_t index);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@ -64,7 +65,7 @@ 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 = 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);
|
||||
lv_bidi_process_paragraph(&str_in[par_start], &str_out[par_start], par_len, base_dir, NULL, 0);
|
||||
par_start += par_len;
|
||||
|
||||
while(str_in[par_start] == '\n' || str_in[par_start] == '\r') {
|
||||
@ -137,23 +138,27 @@ bool lv_bidi_letter_is_neutral(uint32_t letter)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_bidi_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, uint16_t *pos_conv_out, uint16_t pos_conv_len)
|
||||
{
|
||||
uint32_t run_len = 0;
|
||||
lv_bidi_dir_t run_dir;
|
||||
uint32_t rd = 0;
|
||||
uint32_t wr;
|
||||
uint16_t pos_conv_run_len = 0;
|
||||
uint16_t pos_conv_rd = 0;
|
||||
uint16_t pos_conv_wr;
|
||||
|
||||
if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(str_in);
|
||||
if(base_dir == LV_BIDI_DIR_RTL) wr = len;
|
||||
else wr = 0;
|
||||
if(base_dir == LV_BIDI_DIR_RTL) {
|
||||
wr = len;
|
||||
pos_conv_wr = pos_conv_len;
|
||||
}
|
||||
else {
|
||||
wr = 0;
|
||||
pos_conv_wr = 0;
|
||||
}
|
||||
|
||||
str_out[len] = '\0';
|
||||
if (str_out) str_out[len] = '\0';
|
||||
|
||||
lv_bidi_dir_t dir = base_dir;
|
||||
|
||||
@ -163,39 +168,59 @@ void lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len
|
||||
/*Process neutral chars in the beginning*/
|
||||
while(rd < len) {
|
||||
uint32_t letter = lv_txt_encoded_next(str_in, &rd);
|
||||
pos_conv_rd++;
|
||||
dir = lv_bidi_get_letter_dir(letter);
|
||||
if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(str_in, rd, len, letter, base_dir);
|
||||
|
||||
if(dir != LV_BIDI_DIR_NEUTRAL && dir != LV_BIDI_DIR_WEAK) break;
|
||||
}
|
||||
|
||||
if(rd && str_in[rd] != '\0') lv_txt_encoded_prev(str_in, &rd);
|
||||
if(rd && str_in[rd] != '\0') {
|
||||
lv_txt_encoded_prev(str_in, &rd);
|
||||
pos_conv_rd--;
|
||||
}
|
||||
|
||||
if(rd) {
|
||||
if(base_dir == LV_BIDI_DIR_LTR) {
|
||||
memcpy(&str_out[wr], str_in, rd);
|
||||
wr += rd;
|
||||
if (str_out) {
|
||||
memcpy(&str_out[wr], str_in, rd);
|
||||
wr += rd;
|
||||
}
|
||||
if (pos_conv_out) {
|
||||
fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_rd, 0);
|
||||
pos_conv_wr += pos_conv_rd;
|
||||
}
|
||||
} else {
|
||||
wr -= rd;
|
||||
rtl_reverse(&str_out[wr], str_in, rd);
|
||||
pos_conv_wr -= pos_conv_rd;
|
||||
rtl_reverse(str_out? &str_out[wr]: NULL, str_in, rd, pos_conv_out? &pos_conv_out[pos_conv_wr]: NULL, 0, pos_conv_rd);
|
||||
}
|
||||
}
|
||||
|
||||
/*Get and process the runs*/
|
||||
|
||||
while(rd < len) {
|
||||
run_dir = get_next_run(&str_in[rd], base_dir, len - rd, &run_len);
|
||||
run_dir = get_next_run(&str_in[rd], base_dir, len - rd, &run_len, &pos_conv_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);
|
||||
else rtl_reverse(&str_out[wr], &str_in[rd], run_len);
|
||||
if(run_dir == LV_BIDI_DIR_LTR) {
|
||||
if (str_out) memcpy(&str_out[wr], &str_in[rd], run_len);
|
||||
if (pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_run_len, pos_conv_rd);
|
||||
}
|
||||
else rtl_reverse(str_out? &str_out[wr]: NULL, &str_in[rd], run_len, pos_conv_out? &pos_conv_out[pos_conv_wr] : NULL, pos_conv_rd, pos_conv_run_len);
|
||||
wr += run_len;
|
||||
pos_conv_wr += pos_conv_run_len;
|
||||
} else {
|
||||
wr -= run_len;
|
||||
if(run_dir == LV_BIDI_DIR_LTR) memcpy(&str_out[wr], &str_in[rd], run_len);
|
||||
else rtl_reverse(&str_out[wr], &str_in[rd], run_len);
|
||||
pos_conv_wr -= pos_conv_run_len;
|
||||
if(run_dir == LV_BIDI_DIR_LTR) {
|
||||
if (str_out) memcpy(&str_out[wr], &str_in[rd], run_len);
|
||||
if (pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_run_len, pos_conv_rd);
|
||||
}
|
||||
else rtl_reverse(str_out? &str_out[wr]: NULL, &str_in[rd], run_len, pos_conv_out? &pos_conv_out[pos_conv_wr] : NULL, pos_conv_rd, pos_conv_run_len);
|
||||
}
|
||||
|
||||
rd += run_len;
|
||||
pos_conv_rd += pos_conv_run_len;
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,24 +237,40 @@ uint32_t lv_bidi_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 max_len, uint32_t * len)
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void fill_pos_conv(uint16_t * out, uint16_t len, uint16_t index)
|
||||
{
|
||||
for (uint16_t i = 0; i < len; i++)
|
||||
{
|
||||
out[i] = index;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t max_len, uint32_t * len, uint16_t * pos_conv_len)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t letter;
|
||||
|
||||
uint16_t pos_conv_i = 0;
|
||||
|
||||
letter = lv_txt_encoded_next(txt, NULL);
|
||||
lv_bidi_dir_t dir = lv_bidi_get_letter_dir(letter);
|
||||
if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(txt, 0, max_len, letter, base_dir);
|
||||
|
||||
|
||||
/*Find the first strong char. Skip the neutrals*/
|
||||
while(dir == LV_BIDI_DIR_NEUTRAL || dir == LV_BIDI_DIR_WEAK) {
|
||||
letter = lv_txt_encoded_next(txt, &i);
|
||||
pos_conv_i++;
|
||||
dir = lv_bidi_get_letter_dir(letter);
|
||||
if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(txt, i, max_len, letter, base_dir);
|
||||
|
||||
if(i >= max_len || txt[i] == '\0' || txt[i] == '\n' || txt[i] == '\r') {
|
||||
*len = i;
|
||||
*pos_conv_len = pos_conv_i;
|
||||
return base_dir;
|
||||
}
|
||||
}
|
||||
@ -238,84 +279,119 @@ static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint
|
||||
|
||||
uint32_t i_prev = i;
|
||||
uint32_t i_last_strong = i;
|
||||
uint16_t pos_conv_i_prev = pos_conv_i;
|
||||
uint16_t pos_conv_i_last_strong = pos_conv_i;
|
||||
|
||||
/*Find the next char which has different direction*/
|
||||
lv_bidi_dir_t next_dir = base_dir;
|
||||
while(i_prev < max_len && txt[i] != '\0' && txt[i] != '\n' && txt[i] != '\r') {
|
||||
letter = lv_txt_encoded_next(txt, &i);
|
||||
pos_conv_i++;
|
||||
next_dir = lv_bidi_get_letter_dir(letter);
|
||||
if(next_dir == LV_BIDI_DIR_NEUTRAL) next_dir = bracket_process(txt, i, max_len, letter, base_dir);
|
||||
|
||||
/*New dir found?*/
|
||||
if((next_dir == LV_BIDI_DIR_RTL || next_dir == LV_BIDI_DIR_LTR) && next_dir != run_dir) {
|
||||
/*Include neutrals if `run_dir == base_dir` */
|
||||
if(run_dir == base_dir) *len = i_prev;
|
||||
if(run_dir == base_dir) {
|
||||
*len = i_prev;
|
||||
*pos_conv_len = pos_conv_i_prev;
|
||||
}
|
||||
/*Exclude neutrals if `run_dir != base_dir` */
|
||||
else *len = i_last_strong;
|
||||
else {
|
||||
*len = i_last_strong;
|
||||
*pos_conv_len = pos_conv_i_last_strong;
|
||||
}
|
||||
|
||||
return run_dir;
|
||||
}
|
||||
|
||||
if(next_dir != LV_BIDI_DIR_NEUTRAL) i_last_strong = i;
|
||||
if(next_dir != LV_BIDI_DIR_NEUTRAL) {
|
||||
i_last_strong = i;
|
||||
pos_conv_i_last_strong = pos_conv_i;
|
||||
}
|
||||
|
||||
i_prev = i;
|
||||
pos_conv_i_prev = pos_conv_i;
|
||||
}
|
||||
|
||||
|
||||
/*Handle end of of string. Apply `base_dir` on trailing neutrals*/
|
||||
|
||||
/*Include neutrals if `run_dir == base_dir` */
|
||||
if(run_dir == base_dir) *len = i_prev;
|
||||
if(run_dir == base_dir) {
|
||||
*len = i_prev;
|
||||
*pos_conv_len = pos_conv_i_prev;
|
||||
}
|
||||
/*Exclude neutrals if `run_dir != base_dir` */
|
||||
else *len = i_last_strong;
|
||||
else {
|
||||
*len = i_last_strong;
|
||||
*pos_conv_len = pos_conv_i_last_strong;
|
||||
}
|
||||
|
||||
return run_dir;
|
||||
|
||||
}
|
||||
|
||||
static void rtl_reverse(char * dest, const char * src, uint32_t len)
|
||||
static void rtl_reverse(char * dest, const char * src, uint32_t len, uint16_t *pos_conv_out, uint16_t pos_conv_rd_base, uint16_t pos_conv_len)
|
||||
{
|
||||
uint32_t i = len;
|
||||
uint32_t wr = 0;
|
||||
uint16_t pos_conv_i = pos_conv_len;
|
||||
uint16_t pos_conv_wr = 0;
|
||||
|
||||
while(i) {
|
||||
uint32_t letter = lv_txt_encoded_prev(src, &i);
|
||||
uint16_t pos_conv_letter = --pos_conv_i;
|
||||
|
||||
/*Keep weak letters (numbers) as LTR*/
|
||||
if(lv_bidi_letter_is_weak(letter)) {
|
||||
uint32_t last_weak = i;
|
||||
uint32_t first_weak = i;
|
||||
uint16_t pos_conv_last_weak = pos_conv_i;
|
||||
uint16_t pos_conv_first_weak = pos_conv_i;
|
||||
while(i) {
|
||||
letter = lv_txt_encoded_prev(src, &i);
|
||||
pos_conv_letter = --pos_conv_i;
|
||||
|
||||
/*No need to call `char_change_to_pair` because there not such chars here*/
|
||||
|
||||
/*Finish on non-weak char */
|
||||
/*but treat number and currency related chars as weak*/
|
||||
if(lv_bidi_letter_is_weak(letter) == false && letter != '.' && letter != ',' && letter != '$' && letter != '%') {
|
||||
if (lv_bidi_letter_is_weak(letter) == false && letter != '.' && letter != ',' && letter != '$' && letter != '%') {
|
||||
lv_txt_encoded_next(src, &i); /*Rewind one letter*/
|
||||
pos_conv_i++;
|
||||
first_weak = i;
|
||||
pos_conv_first_weak = pos_conv_i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i == 0) first_weak = 0;
|
||||
if(i == 0) {
|
||||
first_weak = 0;
|
||||
pos_conv_first_weak = 0;
|
||||
}
|
||||
|
||||
memcpy(&dest[wr], &src[first_weak], last_weak - first_weak + 1);
|
||||
if (dest) memcpy(&dest[wr], &src[first_weak], last_weak - first_weak + 1);
|
||||
if (pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_last_weak - pos_conv_first_weak + 1, pos_conv_rd_base + pos_conv_first_weak);
|
||||
wr += last_weak - first_weak + 1;
|
||||
|
||||
pos_conv_wr += pos_conv_last_weak - pos_conv_first_weak + 1;
|
||||
}
|
||||
|
||||
/*Simply store in reversed order*/
|
||||
else {
|
||||
uint32_t letter_size = lv_txt_encoded_size((const char *)&src[i]);
|
||||
/*Swap arithmetical symbols*/
|
||||
if(letter_size == 1) {
|
||||
uint32_t new_letter = letter = char_change_to_pair(letter);
|
||||
dest[wr] = (uint8_t)new_letter;
|
||||
if (dest) dest[wr] = (uint8_t)new_letter;
|
||||
if (pos_conv_out) pos_conv_out[pos_conv_wr] = pos_conv_rd_base + pos_conv_letter;
|
||||
wr += 1;
|
||||
pos_conv_wr += 1;
|
||||
}
|
||||
/*Just store the letter*/
|
||||
else {
|
||||
memcpy(&dest[wr], &src[i], letter_size);
|
||||
if (dest) memcpy(&dest[wr], &src[i], letter_size);
|
||||
if (pos_conv_out) pos_conv_out[pos_conv_wr] = pos_conv_rd_base + pos_conv_i;
|
||||
wr += letter_size;
|
||||
pos_conv_wr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ 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);
|
||||
void lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_bidi_dir_t base_dir, uint16_t *pos_conv_out, uint16_t pos_conv_len);
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user