mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-28 07:03:00 +08:00
create lv_bidi.c/h
This commit is contained in:
parent
7ef624054a
commit
3dfbc5c85d
221
src/lv_misc/lv_bidi.c
Normal file
221
src/lv_misc/lv_bidi.c
Normal file
@ -0,0 +1,221 @@
|
||||
/**
|
||||
* @file lv_bidi.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_bidi.h"
|
||||
#include <stddef.h>
|
||||
#include "lv_txt.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
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 VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir)
|
||||
{
|
||||
uint32_t run_len = 0;
|
||||
lv_bidi_dir_t run_dir;
|
||||
uint32_t rd = 0;
|
||||
|
||||
lv_bidi_dir_t dir = base_dir;
|
||||
|
||||
/*Process neutral chars in the beginning*/
|
||||
while(str_in[rd] != '\0') {
|
||||
uint32_t letter = lv_txt_encoded_next(str_in, &rd);
|
||||
dir = lv_bidi_get_letter_dir(letter);
|
||||
if(dir != LV_BIDI_DIR_NEUTRAL) break;
|
||||
}
|
||||
|
||||
/*if there were neutrals in the beginning apply `base_dir` on them */
|
||||
if(rd && str_in[rd] != '\0') lv_txt_encoded_prev(str_in, &rd);
|
||||
|
||||
if(rd) {
|
||||
memcpy(str_out, str_in, rd);
|
||||
str_out[rd] = '\0';
|
||||
printf("%s: \"%s\"\n", base_dir == LV_BIDI_DIR_LTR ? "LTR" : "RTL", str_out);
|
||||
}
|
||||
|
||||
/*Get and process the runs*/
|
||||
while(str_in[rd] != '\0') {
|
||||
run_dir = get_next_run(&str_in[rd], base_dir, &run_len);
|
||||
|
||||
memcpy(str_out, &str_in[rd], run_len);
|
||||
str_out[run_len] = '\0';
|
||||
if(run_dir == LV_BIDI_DIR_LTR) {
|
||||
printf("%s: \"%s\"\n", "LTR" , str_out);
|
||||
} else {
|
||||
printf("%s: \"%s\" -> ", "RTL" , str_out);
|
||||
|
||||
rtl_reverse(str_out, &str_in[rd], run_len);
|
||||
printf("\"%s\"\n", str_out);
|
||||
|
||||
}
|
||||
|
||||
rd += run_len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if(letter >= 'a' && letter <= 'z') return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lv_bidi_letter_is_neutral(uint32_t letter)
|
||||
{
|
||||
uint16_t i;
|
||||
static const char neutrals[] = " \t\n\r.,:;'\"`!?%/\\=()[]{}<>@#&|";
|
||||
for(i = 0; neutrals[i] != '\0'; i++) {
|
||||
if(letter == (uint32_t)neutrals[i]) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t * len)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t letter;
|
||||
|
||||
letter = lv_txt_encoded_next(txt, NULL);
|
||||
lv_bidi_dir_t dir = lv_bidi_get_letter_dir(letter);
|
||||
|
||||
/*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);
|
||||
dir = lv_bidi_get_letter_dir(letter);
|
||||
if(txt[i] == '\0') {
|
||||
*len = i;
|
||||
return base_dir;
|
||||
}
|
||||
}
|
||||
|
||||
lv_bidi_dir_t run_dir = dir;
|
||||
|
||||
uint32_t i_prev = i;
|
||||
uint32_t i_last_strong = i;
|
||||
|
||||
/*Find the next char which has different direction*/
|
||||
lv_bidi_dir_t next_dir = base_dir;
|
||||
while(txt[i] != '\0') {
|
||||
letter = lv_txt_encoded_next(txt, &i);
|
||||
next_dir = lv_bidi_get_letter_dir(letter);
|
||||
|
||||
/*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;
|
||||
/*Exclude neutrals if `run_dir != base_dir` */
|
||||
else *len = i_last_strong;
|
||||
|
||||
return run_dir;
|
||||
}
|
||||
|
||||
if(next_dir != LV_BIDI_DIR_NEUTRAL) i_last_strong = i;
|
||||
|
||||
i_prev = 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;
|
||||
/*Exclude neutrals if `run_dir != base_dir` */
|
||||
else *len = i_last_strong;
|
||||
|
||||
return run_dir;
|
||||
|
||||
}
|
||||
|
||||
static void rtl_reverse(char * dest, const char * src, uint32_t len)
|
||||
{
|
||||
uint32_t i = len;
|
||||
uint32_t wr = 0;
|
||||
|
||||
while(i) {
|
||||
uint32_t letter = lv_txt_encoded_prev(src, &i);
|
||||
|
||||
/*Keep weak letters as LTR*/
|
||||
if(lv_bidi_letter_is_weak(letter)) {
|
||||
uint32_t last_weak = i;
|
||||
uint32_t first_weak = i;
|
||||
while(i) {
|
||||
letter = lv_txt_encoded_prev(src, &i);
|
||||
if(lv_bidi_letter_is_weak(letter) == false) {
|
||||
lv_txt_encoded_next(src, &i); /*Rewind one letter*/
|
||||
first_weak = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i == 0) first_weak = 0;
|
||||
|
||||
memcpy(&dest[wr], &src[first_weak], last_weak - first_weak + 1);
|
||||
wr += last_weak - first_weak + 1;
|
||||
|
||||
}
|
||||
/*Simply store in reversed order*/
|
||||
else {
|
||||
uint32_t letter_size = lv_txt_encoded_size((const char *)&letter);
|
||||
memcpy(&dest[wr], &src[i], letter_size);
|
||||
wr += letter_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
52
src/lv_misc/lv_bidi.h
Normal file
52
src/lv_misc/lv_bidi.h
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @file lv_bifi.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_BIDI_H
|
||||
#define LV_BIDI_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
typedef enum
|
||||
{
|
||||
LV_BIDI_DIR_LTR,
|
||||
LV_BIDI_DIR_RTL,
|
||||
LV_BIDI_DIR_NEUTRAL,
|
||||
LV_BIDI_DIR_WEAK,
|
||||
}lv_bidi_dir_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir);
|
||||
|
||||
lv_bidi_dir_t lv_bidi_get_letter_dir(uint32_t letter);
|
||||
bool lv_bidi_letter_is_weak(uint32_t letter);
|
||||
bool lv_bidi_letter_is_rtl(uint32_t letter);
|
||||
bool lv_bidi_letter_is_neutral(uint32_t letter);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /*LV_BIDI_H*/
|
@ -346,123 +346,6 @@ void lv_txt_cut(char * txt, uint32_t pos, uint32_t len)
|
||||
}
|
||||
}
|
||||
|
||||
lv_txt_dir_t lv_txt_get_letter_dir(uint32_t letter)
|
||||
{
|
||||
|
||||
if(letter >= 'a' && letter <= 'z') return LV_TXT_DIR_RTL;
|
||||
|
||||
uint16_t i;
|
||||
|
||||
static const char neutrals[] = " \t\n\r.,:;'\"`!?%/\\=()[]{}<>@#&|";
|
||||
for(i = 0; neutrals[i] != '\0'; i++) {
|
||||
if(letter == neutrals[i]) return LV_TXT_DIR_NEUTRAL;
|
||||
}
|
||||
|
||||
static const char weaks[] = "0123456789";
|
||||
for(i = 0; weaks[i] != '\0'; i++) {
|
||||
if(letter == weaks[i]) return LV_TXT_DIR_WEAK;
|
||||
}
|
||||
|
||||
return LV_TXT_DIR_LTR;
|
||||
}
|
||||
|
||||
|
||||
lv_txt_dir_t lv_txt_rtl_next_run(const char * txt, lv_txt_dir_t base_dir, uint32_t * len)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t letter;
|
||||
|
||||
letter = lv_txt_encoded_next(txt, NULL);
|
||||
lv_txt_dir_t dir = lv_txt_get_letter_dir(letter);
|
||||
|
||||
/*Find the first strong char. Skip the neutrals.*/
|
||||
while(dir == LV_TXT_DIR_NEUTRAL || dir == LV_TXT_DIR_WEAK) {
|
||||
letter = lv_txt_encoded_next(txt, &i);
|
||||
dir = lv_txt_get_letter_dir(letter);
|
||||
if(txt[i] == '\0') {
|
||||
*len = i;
|
||||
return base_dir;
|
||||
}
|
||||
}
|
||||
|
||||
lv_txt_dir_t run_dir = dir;
|
||||
|
||||
uint32_t i_prev = i;
|
||||
uint32_t i_last_strong = i;
|
||||
|
||||
/*Find the next char which has different direction*/
|
||||
lv_txt_dir_t next_dir = base_dir;
|
||||
while(txt[i] != '\0') {
|
||||
letter = lv_txt_encoded_next(txt, &i);
|
||||
next_dir = lv_txt_get_letter_dir(letter);
|
||||
|
||||
/*New dir found?*/
|
||||
if((next_dir == LV_TXT_DIR_RTL || next_dir == LV_TXT_DIR_LTR) && next_dir != run_dir) {
|
||||
/*Include neutrals if `run_dir == base_dir` */
|
||||
if(run_dir == base_dir) *len = i_prev;
|
||||
/*Exclude neutrals if `run_dir != base_dir` */
|
||||
else *len = i_last_strong;
|
||||
|
||||
return run_dir;
|
||||
}
|
||||
|
||||
if(next_dir != LV_TXT_DIR_NEUTRAL) i_last_strong = i;
|
||||
|
||||
i_prev = 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;
|
||||
/*Exclude neutrals if `run_dir != base_dir` */
|
||||
else *len = i_last_strong;
|
||||
|
||||
return run_dir;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool lv_txt_rtl_proc(const char * str_in, char * str_out, lv_txt_dir_t base_dir)
|
||||
{
|
||||
|
||||
uint32_t run_len = 0;
|
||||
lv_txt_dir_t run_dir;
|
||||
uint32_t rd = 0;
|
||||
|
||||
lv_txt_dir_t dir = base_dir;
|
||||
|
||||
/*Process neutral chars in the beginning*/
|
||||
while(str_in[rd] != '\0') {
|
||||
uint32_t letter = lv_txt_encoded_next(str_in, &rd);
|
||||
dir = lv_txt_get_letter_dir(letter);
|
||||
if(dir != LV_TXT_DIR_NEUTRAL) break;
|
||||
}
|
||||
|
||||
/*if there were neutrals in the beginning apply `base_dir` on them */
|
||||
if(rd && str_in[rd] != '\0') lv_txt_encoded_prev(str_in, &rd);
|
||||
|
||||
if(rd) {
|
||||
memcpy(str_out, str_in, rd);
|
||||
str_out[rd] = '\0';
|
||||
printf("%s: \"%s\"\n", base_dir == LV_TXT_DIR_LTR ? "LTR" : "RTL", str_out);
|
||||
}
|
||||
|
||||
/*Get and process the runs*/
|
||||
while(str_in[rd] != '\0') {
|
||||
run_dir = lv_txt_rtl_next_run(&str_in[rd], base_dir, &run_len);
|
||||
|
||||
memcpy(str_out, &str_in[rd], run_len);
|
||||
str_out[run_len] = '\0';
|
||||
printf("%s: \"%s\"\n", run_dir == LV_TXT_DIR_LTR ? "LTR" : "RTL", str_out);
|
||||
rd += run_len;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if LV_TXT_ENC == LV_TXT_ENC_UTF8
|
||||
/*******************************
|
||||
* UTF-8 ENCODER/DECOER
|
||||
|
@ -56,15 +56,6 @@ enum {
|
||||
};
|
||||
typedef uint8_t lv_txt_cmd_state_t;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LV_TXT_DIR_LTR,
|
||||
LV_TXT_DIR_RTL,
|
||||
LV_TXT_DIR_NEUTRAL,
|
||||
LV_TXT_DIR_WEAK,
|
||||
}lv_txt_dir_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
@ -137,9 +128,6 @@ void lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt);
|
||||
*/
|
||||
void lv_txt_cut(char * txt, uint32_t pos, uint32_t len);
|
||||
|
||||
|
||||
bool lv_txt_rtl_proc(const char * str_in, char * str_out, lv_txt_dir_t base_dir);
|
||||
|
||||
/***************************************************************
|
||||
* GLOBAL FUNCTION POINTERS FOR CAHRACTER ENCODING INTERFACE
|
||||
***************************************************************/
|
||||
|
Loading…
x
Reference in New Issue
Block a user