1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-21 06:53:01 +08:00
lvgl/src/lv_misc/lv_bidi.c

522 lines
16 KiB
C
Raw Normal View History

2019-09-24 21:00:58 +02:00
/**
* @file lv_bidi.c
*
*/
/*********************
* INCLUDES
*********************/
#include <stddef.h>
#include "lv_bidi.h"
2019-09-24 21:00:58 +02:00
#include "lv_txt.h"
#include "../lv_draw/lv_draw.h"
2019-09-24 21:00:58 +02:00
#if LV_USE_BIDI
2019-09-24 21:00:58 +02:00
/*********************
* DEFINES
*********************/
2019-10-25 06:15:11 +02:00
#define LV_BIDI_BRACKLET_DEPTH 4
2019-09-24 21:00:58 +02:00
/**********************
* TYPEDEFS
**********************/
2019-10-25 06:15:11 +02:00
typedef struct
{
uint32_t bracklet_pos;
lv_bidi_dir_t dir;
}bracket_stack_t;
2019-09-24 21:00:58 +02:00
/**********************
* STATIC PROTOTYPES
**********************/
2019-11-04 01:31:54 +02:00
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);
2019-10-27 10:21:37 +01:00
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);
2019-11-04 01:31:54 +02:00
static void fill_pos_conv(uint16_t * out, uint16_t len, uint16_t index);
static uint32_t get_txt_len(const char * txt, uint32_t max_len);
2019-09-24 21:00:58 +02:00
/**********************
* STATIC VARIABLES
**********************/
2019-10-25 06:15:11 +02:00
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;
2019-09-24 21:00:58 +02:00
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir)
{
if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(str_in);
2019-10-09 14:00:28 +02:00
uint32_t par_start = 0;
uint32_t par_len;
2019-09-24 21:00:58 +02:00
2019-10-09 14:00:28 +02:00
while(str_in[par_start] == '\n' || str_in[par_start] == '\r') {
str_out[par_start] = str_in[par_start];
par_start ++;
2019-09-24 21:00:58 +02:00
}
2019-10-09 14:00:28 +02:00
while(str_in[par_start] != '\0') {
par_len = lv_bidi_get_next_paragraph(&str_in[par_start]);
2019-11-04 01:31:54 +02:00
lv_bidi_process_paragraph(&str_in[par_start], &str_out[par_start], par_len, base_dir, NULL, 0);
2019-10-09 14:00:28 +02:00
par_start += par_len;
2019-09-24 21:00:58 +02:00
2019-10-09 14:00:28 +02:00
while(str_in[par_start] == '\n' || str_in[par_start] == '\r') {
str_out[par_start] = str_in[par_start];
par_start ++;
}
2019-09-24 21:00:58 +02:00
}
2019-10-09 14:00:28 +02:00
str_out[par_start] = '\0';
2019-09-24 21:00:58 +02:00
}
lv_bidi_dir_t lv_bidi_detect_base_dir(const char * txt)
{
uint32_t i = 0;
uint32_t letter;
while(txt[i] != '\0') {
letter = lv_txt_encoded_next(txt, &i);
lv_bidi_dir_t dir;
dir = lv_bidi_get_letter_dir(letter);
if(dir == LV_BIDI_DIR_RTL || dir == LV_BIDI_DIR_LTR) return dir;
}
/*If there were no strong char earlier return with the default base dir */
if(LV_BIDI_BASE_DIR_DEF == LV_BIDI_DIR_AUTO) return LV_BIDI_DIR_LTR;
else return LV_BIDI_BASE_DIR_DEF;
}
2019-09-24 21:00:58 +02:00
lv_bidi_dir_t lv_bidi_get_letter_dir(uint32_t letter)
{
if(lv_bidi_letter_is_rtl(letter)) return LV_BIDI_DIR_RTL;
if(lv_bidi_letter_is_neutral(letter)) return LV_BIDI_DIR_NEUTRAL;
if(lv_bidi_letter_is_weak(letter)) return LV_BIDI_DIR_WEAK;
return LV_BIDI_DIR_LTR;
}
bool lv_bidi_letter_is_weak(uint32_t letter)
{
uint32_t i = 0;
static const char weaks[] = "0123456789";
do {
uint32_t x = lv_txt_encoded_next(weaks, &i);
if(letter == x) {
return true;
}
} while(weaks[i] != '\0');
return false;
}
bool lv_bidi_letter_is_rtl(uint32_t letter)
{
2019-09-27 06:03:54 +02:00
if(letter >= 0x5d0 && letter <= 0x5ea) return true;
2019-10-09 15:36:38 +02:00
if(letter == 0x202E) return true; /*Unicode of LV_BIDI_RLO*/
2019-09-27 06:03:54 +02:00
// if(letter >= 'a' && letter <= 'z') return true;
2019-09-24 21:00:58 +02:00
return false;
}
bool lv_bidi_letter_is_neutral(uint32_t letter)
{
uint16_t i;
2019-10-22 01:36:37 +03:00
static const char neutrals[] = " \t\n\r.,:;'\"`!?%/\\-=()[]{}<>@#&$|";
2019-09-24 21:00:58 +02:00
for(i = 0; neutrals[i] != '\0'; i++) {
if(letter == (uint32_t)neutrals[i]) return true;
}
return false;
}
uint16_t lv_bidi_get_logical_pos(const char * str_in, uint16_t len, lv_bidi_dir_t base_dir, uint32_t visual_pos)
{
return 0; // TODO
}
uint16_t lv_bidi_get_visual_pos(const char * str_in, uint16_t len, lv_bidi_dir_t base_dir, uint32_t logical_pos)
{
uint32_t pos_conv_len = get_txt_len(str_in, len) * sizeof(uint16_t);
uint16_t *pos_conv_buf = lv_draw_get_buf(pos_conv_len);
lv_bidi_process_paragraph(str_in, NULL, len, base_dir, pos_conv_buf, pos_conv_len);
return pos_conv_buf[logical_pos];
}
2019-11-04 01:31:54 +02:00
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)
2019-10-09 14:00:28 +02:00
{
uint32_t run_len = 0;
lv_bidi_dir_t run_dir;
uint32_t rd = 0;
uint32_t wr;
2019-11-04 01:31:54 +02:00
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);
2019-11-04 01:31:54 +02:00
if(base_dir == LV_BIDI_DIR_RTL) {
wr = len;
pos_conv_wr = pos_conv_len;
}
else {
wr = 0;
pos_conv_wr = 0;
}
2019-10-09 14:00:28 +02:00
2019-11-04 01:31:54 +02:00
if (str_out) str_out[len] = '\0';
2019-10-09 14:00:28 +02:00
lv_bidi_dir_t dir = base_dir;
2019-10-27 10:21:37 +01:00
/*Empty the bracket stack*/
br_stack_p = 0;
2019-10-09 14:00:28 +02:00
/*Process neutral chars in the beginning*/
while(rd < len) {
uint32_t letter = lv_txt_encoded_next(str_in, &rd);
2019-11-04 01:31:54 +02:00
pos_conv_rd++;
2019-10-09 14:00:28 +02:00
dir = lv_bidi_get_letter_dir(letter);
2019-10-25 06:15:11 +02:00
if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(str_in, rd, len, letter, base_dir);
2019-10-09 15:36:38 +02:00
if(dir != LV_BIDI_DIR_NEUTRAL && dir != LV_BIDI_DIR_WEAK) break;
2019-10-09 14:00:28 +02:00
}
2019-11-04 01:31:54 +02:00
if(rd && str_in[rd] != '\0') {
lv_txt_encoded_prev(str_in, &rd);
pos_conv_rd--;
}
2019-10-09 14:00:28 +02:00
if(rd) {
if(base_dir == LV_BIDI_DIR_LTR) {
2019-11-04 01:31:54 +02:00
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;
}
2019-10-09 14:00:28 +02:00
} else {
wr -= rd;
2019-11-04 01:31:54 +02:00
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_rd]: NULL, 0, pos_conv_rd);
2019-10-09 14:00:28 +02:00
}
}
/*Get and process the runs*/
2019-11-04 01:31:54 +02:00
2019-10-09 14:00:28 +02:00
while(rd < len) {
2019-11-04 01:31:54 +02:00
run_dir = get_next_run(&str_in[rd], base_dir, len - rd, &run_len, &pos_conv_run_len);
2019-10-09 14:00:28 +02:00
if(base_dir == LV_BIDI_DIR_LTR) {
2019-11-04 01:31:54 +02:00
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_rd] : NULL, pos_conv_rd, pos_conv_run_len);
2019-10-09 14:00:28 +02:00
wr += run_len;
2019-11-04 01:31:54 +02:00
pos_conv_wr += pos_conv_run_len;
2019-10-09 14:00:28 +02:00
} else {
wr -= run_len;
2019-11-04 01:31:54 +02:00
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_rd] : NULL, pos_conv_rd, pos_conv_run_len);
2019-10-09 14:00:28 +02:00
}
rd += run_len;
2019-11-04 01:31:54 +02:00
pos_conv_rd += pos_conv_run_len;
2019-10-09 14:00:28 +02:00
}
}
uint32_t lv_bidi_get_next_paragraph(const char * txt)
2019-10-09 14:00:28 +02:00
{
uint32_t i = 0;
lv_txt_encoded_next(txt, &i);
while(txt[i] != '\0' && txt[i] != '\n' && txt[i] != '\r') {
lv_txt_encoded_next(txt, &i);
}
return i;
}
2019-11-04 01:31:54 +02:00
/**********************
* STATIC FUNCTIONS
**********************/
static uint32_t get_txt_len(const char * txt, uint32_t max_len)
{
uint32_t len = 0;
uint32_t i = 0;
while(i < max_len && txt[i] != '\0') {
lv_txt_encoded_next(txt, &i);
len++;
}
return len;
}
2019-11-04 01:31:54 +02:00
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)
2019-09-24 21:00:58 +02:00
{
uint32_t i = 0;
uint32_t letter;
2019-11-04 01:31:54 +02:00
uint16_t pos_conv_i = 0;
2019-09-24 21:00:58 +02:00
letter = lv_txt_encoded_next(txt, NULL);
lv_bidi_dir_t dir = lv_bidi_get_letter_dir(letter);
2019-10-27 10:44:00 +01:00
if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(txt, 0, max_len, letter, base_dir);
2019-10-25 06:15:11 +02:00
2019-10-09 15:36:38 +02:00
/*Find the first strong char. Skip the neutrals*/
2019-09-24 21:00:58 +02:00
while(dir == LV_BIDI_DIR_NEUTRAL || dir == LV_BIDI_DIR_WEAK) {
letter = lv_txt_encoded_next(txt, &i);
2019-11-04 01:31:54 +02:00
pos_conv_i++;
2019-09-24 21:00:58 +02:00
dir = lv_bidi_get_letter_dir(letter);
2019-10-27 10:44:00 +01:00
if(dir == LV_BIDI_DIR_NEUTRAL) dir = bracket_process(txt, i, max_len, letter, base_dir);
2019-10-25 06:15:11 +02:00
if(i >= max_len || txt[i] == '\0' || txt[i] == '\n' || txt[i] == '\r') {
2019-09-24 21:00:58 +02:00
*len = i;
2019-11-04 01:31:54 +02:00
*pos_conv_len = pos_conv_i;
2019-09-24 21:00:58 +02:00
return base_dir;
}
}
lv_bidi_dir_t run_dir = dir;
uint32_t i_prev = i;
uint32_t i_last_strong = i;
2019-11-04 01:31:54 +02:00
uint16_t pos_conv_i_prev = pos_conv_i;
uint16_t pos_conv_i_last_strong = pos_conv_i;
2019-09-24 21:00:58 +02:00
/*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') {
2019-09-24 21:00:58 +02:00
letter = lv_txt_encoded_next(txt, &i);
2019-11-04 01:31:54 +02:00
pos_conv_i++;
2019-09-24 21:00:58 +02:00
next_dir = lv_bidi_get_letter_dir(letter);
2019-10-27 10:44:00 +01:00
if(next_dir == LV_BIDI_DIR_NEUTRAL) next_dir = bracket_process(txt, i, max_len, letter, base_dir);
2019-09-24 21:00:58 +02:00
/*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` */
2019-11-04 01:31:54 +02:00
if(run_dir == base_dir) {
*len = i_prev;
*pos_conv_len = pos_conv_i_prev;
}
2019-09-24 21:00:58 +02:00
/*Exclude neutrals if `run_dir != base_dir` */
2019-11-04 01:31:54 +02:00
else {
*len = i_last_strong;
*pos_conv_len = pos_conv_i_last_strong;
}
2019-09-24 21:00:58 +02:00
return run_dir;
}
2019-11-04 01:31:54 +02:00
if(next_dir != LV_BIDI_DIR_NEUTRAL) {
i_last_strong = i;
pos_conv_i_last_strong = pos_conv_i;
}
2019-09-24 21:00:58 +02:00
i_prev = i;
2019-11-04 01:31:54 +02:00
pos_conv_i_prev = pos_conv_i;
2019-09-24 21:00:58 +02:00
}
/*Handle end of of string. Apply `base_dir` on trailing neutrals*/
/*Include neutrals if `run_dir == base_dir` */
2019-11-04 01:31:54 +02:00
if(run_dir == base_dir) {
*len = i_prev;
*pos_conv_len = pos_conv_i_prev;
}
2019-09-24 21:00:58 +02:00
/*Exclude neutrals if `run_dir != base_dir` */
2019-11-04 01:31:54 +02:00
else {
*len = i_last_strong;
*pos_conv_len = pos_conv_i_last_strong;
}
2019-09-24 21:00:58 +02:00
return run_dir;
}
2019-11-04 01:31:54 +02:00
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)
2019-09-24 21:00:58 +02:00
{
uint32_t i = len;
uint32_t wr = 0;
2019-11-04 01:31:54 +02:00
uint16_t pos_conv_i = pos_conv_len;
uint16_t pos_conv_wr = 0;
2019-09-24 21:00:58 +02:00
while(i) {
uint32_t letter = lv_txt_encoded_prev(src, &i);
2019-11-04 01:31:54 +02:00
uint16_t pos_conv_letter = --pos_conv_i;
2019-09-24 21:00:58 +02:00
/*Keep weak letters (numbers) as LTR*/
2019-09-24 21:00:58 +02:00
if(lv_bidi_letter_is_weak(letter)) {
uint32_t last_weak = i;
uint32_t first_weak = i;
2019-11-04 01:31:54 +02:00
uint16_t pos_conv_last_weak = pos_conv_i;
uint16_t pos_conv_first_weak = pos_conv_i;
2019-09-24 21:00:58 +02:00
while(i) {
letter = lv_txt_encoded_prev(src, &i);
2019-11-04 01:31:54 +02:00
pos_conv_letter = --pos_conv_i;
/*No need to call `char_change_to_pair` because there not such chars here*/
2019-09-28 08:40:02 +02:00
/*Finish on non-weak char */
/*but treat number and currency related chars as weak*/
2019-11-04 01:31:54 +02:00
if (lv_bidi_letter_is_weak(letter) == false && letter != '.' && letter != ',' && letter != '$' && letter != '%') {
2019-09-24 21:00:58 +02:00
lv_txt_encoded_next(src, &i); /*Rewind one letter*/
2019-11-04 01:31:54 +02:00
pos_conv_i++;
2019-09-24 21:00:58 +02:00
first_weak = i;
2019-11-04 01:31:54 +02:00
pos_conv_first_weak = pos_conv_i;
2019-09-24 21:00:58 +02:00
break;
}
}
2019-11-04 01:31:54 +02:00
if(i == 0) {
first_weak = 0;
pos_conv_first_weak = 0;
}
2019-09-24 21:00:58 +02:00
2019-11-04 01:31:54 +02:00
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);
2019-09-24 21:00:58 +02:00
wr += last_weak - first_weak + 1;
2019-11-04 01:31:54 +02:00
pos_conv_wr += pos_conv_last_weak - pos_conv_first_weak + 1;
2019-09-24 21:00:58 +02:00
}
2019-11-04 01:31:54 +02:00
2019-09-24 21:00:58 +02:00
/*Simply store in reversed order*/
else {
2019-09-27 06:03:54 +02:00
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);
2019-11-04 01:31:54 +02:00
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;
2019-11-04 01:31:54 +02:00
pos_conv_wr += 1;
}
/*Just store the letter*/
else {
2019-11-04 01:31:54 +02:00
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;
2019-11-04 01:31:54 +02:00
pos_conv_wr++;
}
2019-09-24 21:00:58 +02:00
}
}
}
static uint32_t char_change_to_pair(uint32_t letter)
{
uint8_t i;
2019-10-25 06:15:11 +02:00
for(i = 0; bracket_left[i] != '\0'; i++) {
if(letter == bracket_left[i]) return bracket_right[i];
}
2019-10-25 06:15:11 +02:00
for(i = 0; bracket_right[i] != '\0'; i++) {
if(letter == bracket_right[i]) return bracket_left[i];
}
return letter;
}
2019-10-27 10:21:37 +01:00
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)
2019-10-25 06:15:11 +02:00
{
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*/
2019-10-27 10:44:00 +01:00
lv_bidi_dir_t letter_dir = lv_bidi_get_letter_dir(letter_next);
2019-10-25 06:15:11 +02:00
if(letter_dir == base_dir) {
bracket_dir = base_dir;
}
}
}
/*There were no matching closing bracket*/
2019-10-27 10:44:00 +01:00
if(txt_i > len) return LV_BIDI_DIR_NEUTRAL;
2019-10-25 06:15:11 +02:00
/*There where a strong char with base dir in the bracket so the dir is found.*/
2019-10-27 10:44:00 +01:00
if(bracket_dir != LV_BIDI_DIR_NEUTRAL && bracket_dir != LV_BIDI_DIR_WEAK) break;
2019-10-25 06:15:11 +02:00
/*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);
while(txt_i > 0) {
uint32_t letter_next = lv_txt_encoded_prev(txt, &txt_i);
2019-10-27 10:44:00 +01:00
lv_bidi_dir_t letter_dir = lv_bidi_get_letter_dir(letter_next);
2019-10-25 06:15:11 +02:00
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') {
2019-10-28 05:47:31 +01:00
if(bracket_dir == LV_BIDI_DIR_NEUTRAL || br_stack_p == LV_BIDI_BRACKLET_DEPTH) return LV_BIDI_DIR_NEUTRAL;
2019-10-25 06:15:11 +02:00
br_stack[br_stack_p].bracklet_pos = i;
br_stack[br_stack_p].dir = bracket_dir;
br_stack_p++;
return bracket_dir;
2019-10-27 10:44:00 +01:00
} else if(br_stack_p > 0) {
2019-10-25 06:15:11 +02:00
/*Is the letter a closing bracket of the last opening?*/
2019-10-27 10:44:00 +01:00
if(letter == bracket_right[br_stack[br_stack_p - 1].bracklet_pos]) {
bracket_dir = br_stack[br_stack_p - 1].dir;
2019-10-25 06:15:11 +02:00
br_stack_p--;
return bracket_dir;
}
}
return LV_BIDI_DIR_NEUTRAL;
}
#endif /*LV_USE_BIDI*/