bidi: add bracket algorithm
This commit is contained in:
@@ -15,10 +15,16 @@
|
|||||||
/*********************
|
/*********************
|
||||||
* DEFINES
|
* DEFINES
|
||||||
*********************/
|
*********************/
|
||||||
|
#define LV_BIDI_BRACKLET_DEPTH 4
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* TYPEDEFS
|
* TYPEDEFS
|
||||||
**********************/
|
**********************/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t bracklet_pos;
|
||||||
|
lv_bidi_dir_t dir;
|
||||||
|
}bracket_stack_t;
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* STATIC PROTOTYPES
|
* STATIC PROTOTYPES
|
||||||
@@ -28,10 +34,15 @@ 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 * len);
|
||||||
static void rtl_reverse(char * dest, const char * src, 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);
|
static uint32_t char_change_to_pair(uint32_t letter);
|
||||||
|
static lv_bidi_dir_t bracket_process(const uint8_t * txt, uint32_t next_pos, uint32_t len, uint32_t letter, lv_bidi_dir_t base_dir);
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* STATIC VARIABLES
|
* STATIC VARIABLES
|
||||||
**********************/
|
**********************/
|
||||||
|
static const uint8_t bracket_left[] = {"<({["};
|
||||||
|
static const uint8_t bracket_right[] = {">)}]"};
|
||||||
|
static bracket_stack_t br_stack[LV_BIDI_BRACKLET_DEPTH];
|
||||||
|
static uint8_t br_stack_p;
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* MACROS
|
* MACROS
|
||||||
@@ -43,6 +54,7 @@ static uint32_t char_change_to_pair(uint32_t letter);
|
|||||||
|
|
||||||
void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir)
|
void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir)
|
||||||
{
|
{
|
||||||
|
br_stack_p = 0;
|
||||||
|
|
||||||
if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(str_in);
|
if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(str_in);
|
||||||
|
|
||||||
@@ -151,6 +163,8 @@ static void process_paragraph(const char * str_in, char * str_out, uint32_t len,
|
|||||||
while(rd < len) {
|
while(rd < len) {
|
||||||
uint32_t letter = lv_txt_encoded_next(str_in, &rd);
|
uint32_t letter = lv_txt_encoded_next(str_in, &rd);
|
||||||
dir = lv_bidi_get_letter_dir(letter);
|
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(dir != LV_BIDI_DIR_NEUTRAL && dir != LV_BIDI_DIR_WEAK) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,11 +218,15 @@ static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint
|
|||||||
|
|
||||||
letter = lv_txt_encoded_next(txt, NULL);
|
letter = lv_txt_encoded_next(txt, NULL);
|
||||||
lv_bidi_dir_t dir = lv_bidi_get_letter_dir(letter);
|
lv_bidi_dir_t dir = lv_bidi_get_letter_dir(letter);
|
||||||
|
if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(txt, 0, len, letter, base_dir);
|
||||||
|
|
||||||
|
|
||||||
/*Find the first strong char. Skip the neutrals*/
|
/*Find the first strong char. Skip the neutrals*/
|
||||||
while(dir == LV_BIDI_DIR_NEUTRAL || dir == LV_BIDI_DIR_WEAK) {
|
while(dir == LV_BIDI_DIR_NEUTRAL || dir == LV_BIDI_DIR_WEAK) {
|
||||||
letter = lv_txt_encoded_next(txt, &i);
|
letter = lv_txt_encoded_next(txt, &i);
|
||||||
dir = lv_bidi_get_letter_dir(letter);
|
dir = lv_bidi_get_letter_dir(letter);
|
||||||
|
if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(txt, i, len, letter, base_dir);
|
||||||
|
|
||||||
if(txt[i] == '\0' || txt[i] == '\n' || txt[i] == '\r') {
|
if(txt[i] == '\0' || txt[i] == '\n' || txt[i] == '\r') {
|
||||||
*len = i;
|
*len = i;
|
||||||
return base_dir;
|
return base_dir;
|
||||||
@@ -225,6 +243,7 @@ static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint
|
|||||||
while(txt[i] != '\0'&& txt[i] != '\n' && txt[i] != '\r') {
|
while(txt[i] != '\0'&& txt[i] != '\n' && txt[i] != '\r') {
|
||||||
letter = lv_txt_encoded_next(txt, &i);
|
letter = lv_txt_encoded_next(txt, &i);
|
||||||
next_dir = lv_bidi_get_letter_dir(letter);
|
next_dir = lv_bidi_get_letter_dir(letter);
|
||||||
|
if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(txt, i, len, letter, base_dir);
|
||||||
|
|
||||||
/*New dir found?*/
|
/*New dir found?*/
|
||||||
if((next_dir == LV_BIDI_DIR_RTL || next_dir == LV_BIDI_DIR_LTR) && next_dir != run_dir) {
|
if((next_dir == LV_BIDI_DIR_RTL || next_dir == LV_BIDI_DIR_LTR) && next_dir != run_dir) {
|
||||||
@@ -303,19 +322,98 @@ static void rtl_reverse(char * dest, const char * src, uint32_t len)
|
|||||||
|
|
||||||
static uint32_t char_change_to_pair(uint32_t letter)
|
static uint32_t char_change_to_pair(uint32_t letter)
|
||||||
{
|
{
|
||||||
static uint8_t left[] = {"<({["};
|
|
||||||
static uint8_t right[] = {">)}]"};
|
|
||||||
|
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
for(i = 0; left[i] != '\0'; i++) {
|
for(i = 0; bracket_left[i] != '\0'; i++) {
|
||||||
if(letter == left[i]) return right[i];
|
if(letter == bracket_left[i]) return bracket_right[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; right[i] != '\0'; i++) {
|
for(i = 0; bracket_right[i] != '\0'; i++) {
|
||||||
if(letter == right[i]) return left[i];
|
if(letter == bracket_right[i]) return bracket_left[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return letter;
|
return letter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static lv_bidi_dir_t bracket_process(const uint8_t * txt, uint32_t next_pos, uint32_t len, uint32_t letter, lv_bidi_dir_t base_dir)
|
||||||
|
{
|
||||||
|
if(br_stack_p >= LV_BIDI_BRACKLET_DEPTH) return LV_BIDI_DIR_NEUTRAL;
|
||||||
|
|
||||||
|
lv_bidi_dir_t bracket_dir = LV_BIDI_DIR_NEUTRAL;
|
||||||
|
|
||||||
|
uint8_t i;
|
||||||
|
/*Is the letter an opening bracket?*/
|
||||||
|
for(i = 0; bracket_left[i] != '\0'; i++) {
|
||||||
|
if(bracket_left[i] == letter) {
|
||||||
|
/* If so find it's matching closing bracket.
|
||||||
|
* If a char with base dir. direction is found then the brackets will have `base_dir` direction*/
|
||||||
|
uint32_t txt_i = next_pos;
|
||||||
|
while(txt_i < len) {
|
||||||
|
uint32_t letter_next = lv_txt_encoded_next(txt, &txt_i);
|
||||||
|
if(letter_next == bracket_right[i]) {
|
||||||
|
/*Closing bracket found*/
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
/*Save the dir*/
|
||||||
|
lv_bidi_dir_t letter_dir = lv_bidi_get_letter_dir(letter);
|
||||||
|
if(letter_dir == base_dir) {
|
||||||
|
bracket_dir = base_dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*There were no matching closing bracket*/
|
||||||
|
if(txt_i >= len) return LV_BIDI_DIR_NEUTRAL;
|
||||||
|
|
||||||
|
/*There where a strong char with base dir in the bracket so the dir is found.*/
|
||||||
|
if(bracket_dir != LV_BIDI_DIR_NEUTRAL) break;
|
||||||
|
|
||||||
|
/*If there were no matching strong chars in the brackets then check the previous chars*/
|
||||||
|
txt_i = next_pos;
|
||||||
|
if(txt_i) lv_txt_encoded_prev(txt, &txt_i);
|
||||||
|
if(txt_i) lv_txt_encoded_prev(txt, &txt_i);
|
||||||
|
while(txt_i > 0) {
|
||||||
|
uint32_t letter_next = lv_txt_encoded_prev(txt, &txt_i);
|
||||||
|
lv_bidi_dir_t letter_dir = lv_bidi_get_letter_dir(letter);
|
||||||
|
if(letter_dir == LV_BIDI_DIR_LTR || letter_dir == LV_BIDI_DIR_RTL) {
|
||||||
|
bracket_dir = letter_dir;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*There where a previous strong char which can be used*/
|
||||||
|
if(bracket_dir != LV_BIDI_DIR_NEUTRAL) break;
|
||||||
|
|
||||||
|
/*There were no strong chars before the bracket, so use the base dir.*/
|
||||||
|
if(txt_i == 0) bracket_dir = base_dir;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*The letter was an opening bracket*/
|
||||||
|
if(bracket_left[i] != '\0') {
|
||||||
|
|
||||||
|
if(bracket_dir == LV_BIDI_DIR_NEUTRAL) break;
|
||||||
|
|
||||||
|
br_stack[br_stack_p].bracklet_pos = i;
|
||||||
|
br_stack[br_stack_p].dir = bracket_dir;
|
||||||
|
|
||||||
|
br_stack_p++;
|
||||||
|
return bracket_dir;
|
||||||
|
} else {
|
||||||
|
/*Is the letter a closing bracket of the last opening?*/
|
||||||
|
if(letter == bracket_right[br_stack[br_stack_p].bracklet_pos]) {
|
||||||
|
bracket_dir = br_stack[br_stack_p].dir;
|
||||||
|
br_stack_p--;
|
||||||
|
return bracket_dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return LV_BIDI_DIR_NEUTRAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /*LV_USE_BIDI*/
|
#endif /*LV_USE_BIDI*/
|
||||||
|
|||||||
Reference in New Issue
Block a user