diff --git a/lv_conf_template.h b/lv_conf_template.h index aab872fc4..baea0ca1f 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -344,14 +344,27 @@ typedef void * lv_font_user_data_t; /*Can break (wrap) texts on these chars*/ #define LV_TXT_BREAK_CHARS " ,.;:-_" -/* If a character is at least this long, will break wherever "prettiest" */ -#define LV_TXT_LINE_BREAK_LONG_LEN 12 + /* If a character is at least this long, will break wherever "prettiest" */ + #define LV_TXT_LINE_BREAK_LONG_LEN 12 -/* Minimum number of characters of a word to put on a line before a break */ -#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 + /* Minimum number of characters of a word to put on a line before a break */ + #define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 -/* Minimum number of characters of a word to put on a line after a break */ -#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 + /* Minimum number of characters of a word to put on a line after a break */ + #define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 + +/* Support bidirectional texts. + * Allows mixing Left-to-Right and Right-to-Left texts. + * The direction will be processed according to the Unicode Bidirectioanl Algorithm: + * https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/ +#define LV_USE_BIDI 0 +#if LV_USE_BIDI +/* Set the default direction. Supported values: + * `LV_BIDI_DIR_LTR` Left-to-Right + * `LV_BIDI_DIR_RTL` Right-to-Left + * `LV_BIDI_DIR_AUTO` detect texts base direction */ +#define LV_BIDI_BASE_DIR_DEF LV_BIDI_DIR_AUTO +#endif /*Change the built in (v)snprintf functions*/ #define LV_SPRINTF_CUSTOM 0 diff --git a/lvgl.h b/lvgl.h index 8fb52af49..567beb96b 100644 --- a/lvgl.h +++ b/lvgl.h @@ -34,6 +34,7 @@ extern "C" { #include "src/lv_font/lv_font.h" #include "src/lv_font/lv_font_fmt_txt.h" +#include "src/lv_misc/lv_bidi.h" #include "src/lv_objx/lv_btn.h" #include "src/lv_objx/lv_imgbtn.h" diff --git a/src/lv_conf_checker.h b/src/lv_conf_checker.h index a6ad94c81..fe67fbdfc 100644 --- a/src/lv_conf_checker.h +++ b/src/lv_conf_checker.h @@ -473,19 +473,36 @@ #define LV_TXT_BREAK_CHARS " ,.;:-_" #endif -/* If a character is at least this long, will break wherever "prettiest" */ + /* If a character is at least this long, will break wherever "prettiest" */ #ifndef LV_TXT_LINE_BREAK_LONG_LEN -#define LV_TXT_LINE_BREAK_LONG_LEN 120 +#define LV_TXT_LINE_BREAK_LONG_LEN 12 #endif -/* Minimum number of characters of a word to put on a line before a break */ + /* Minimum number of characters of a word to put on a line before a break */ #ifndef LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN -#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 + #define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 #endif -/* Minimum number of characters of a word to put on a line after a break */ + /* Minimum number of characters of a word to put on a line after a break */ #ifndef LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN -#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 + #define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 +#endif + +/* Support bidirectional texts. + * Allows mixing Left-to-Right and Right-to-Left texts. + * The direction will be processed according to the Unicode Bidirectioanl Algorithm: + * https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/ +#ifndef LV_USE_BIDI +#define LV_USE_BIDI 0 +#endif +#if LV_USE_BIDI +/* Set the default direction. Supported values: + * `LV_BIDI_DIR_LTR` Left-to-Right + * `LV_BIDI_DIR_RTL` Right-to-Left + * `LV_BIDI_DIR_AUTO` detect texts base direction */ +#ifndef LV_BIDI_BASE_DIR_DEF +#define LV_BIDI_BASE_DIR_DEF LV_BIDI_DIR_AUTO +#endif #endif /*Change the built in (v)snprintf functions*/ diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index 49aef0d4b..bf25baf4b 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -52,6 +52,7 @@ static void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coor static void report_style_mod_core(void * style_p, lv_obj_t * obj); static void refresh_children_style(lv_obj_t * obj); static void delete_children(lv_obj_t * obj); +static void base_dir_refr_children(lv_obj_t * obj); static void lv_event_mark_deleted(lv_obj_t * obj); static void lv_obj_del_async_cb(void * obj); static bool lv_obj_design(lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode); @@ -207,6 +208,16 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) new_obj->opa_scale_en = 0; new_obj->opa_scale = LV_OPA_COVER; new_obj->parent_event = 0; +#if LV_USE_BIDI +#if LV_BIDI_BASE_DIR_DEF == LV_BIDI_DIR_LTR || LV_BIDI_BASE_DIR_DEF == LV_BIDI_DIR_RTL || LV_BIDI_BASE_DIR_DEF == LV_BIDI_DIR_AUTO + new_obj->base_dir = LV_BIDI_BASE_DIR_DEF; +#else +#error "`LV_BIDI_BASE_DIR_DEF` should be `LV_BASE_DIR_LTR` or `LV_BASE_DIR_RTL` (See lv_conf.h)" +#endif +#else + new_obj->base_dir = LV_BIDI_DIR_LTR; +#endif + new_obj->reserved = 0; new_obj->ext_attr = NULL; @@ -225,11 +236,22 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) new_obj->par = parent; /*Set the parent*/ lv_ll_init(&(new_obj->child_ll), sizeof(lv_obj_t)); +#if LV_USE_BIDI + new_obj->base_dir = LV_BIDI_DIR_INHERIT; +#else + new_obj->base_dir = LV_BIDI_DIR_LTR; +#endif + /*Set coordinates left top corner of parent*/ - new_obj->coords.x1 = parent->coords.x1; new_obj->coords.y1 = parent->coords.y1; - new_obj->coords.x2 = parent->coords.x1 + LV_OBJ_DEF_WIDTH; new_obj->coords.y2 = parent->coords.y1 + LV_OBJ_DEF_HEIGHT; + if(lv_obj_get_base_dir(new_obj) == LV_BIDI_DIR_RTL) { + new_obj->coords.x2 = parent->coords.x2; + new_obj->coords.x1 = parent->coords.x2 - LV_OBJ_DEF_WIDTH; + } else { + new_obj->coords.x1 = parent->coords.x1; + new_obj->coords.x2 = parent->coords.x1 + LV_OBJ_DEF_WIDTH; + } new_obj->ext_draw_pad = 0; #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL @@ -292,6 +314,7 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) new_obj->opa_scale = LV_OPA_COVER; new_obj->opa_scale_en = 0; new_obj->parent_event = 0; + new_obj->reserved = 0; new_obj->ext_attr = NULL; } @@ -725,8 +748,12 @@ void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h) lv_obj_get_coords(obj, &ori); /*Set the length and height*/ - obj->coords.x2 = obj->coords.x1 + w - 1; obj->coords.y2 = obj->coords.y1 + h - 1; + if(lv_obj_get_base_dir(obj) == LV_BIDI_DIR_RTL) { + obj->coords.x1 = obj->coords.x2 - w + 1; + } else { + obj->coords.x2 = obj->coords.x1 + w - 1; + } /*Send a signal to the object with its new coordinates*/ obj->signal_cb(obj, LV_SIGNAL_CORD_CHG, &ori); @@ -1321,6 +1348,23 @@ void lv_obj_set_parent_event(lv_obj_t * obj, bool en) obj->parent_event = (en == true ? 1 : 0); } +void lv_obj_set_base_dir(lv_obj_t * obj, lv_bidi_dir_t dir) +{ + if(dir != LV_BIDI_DIR_LTR && dir != LV_BIDI_DIR_RTL && + dir != LV_BIDI_DIR_AUTO && dir != LV_BIDI_DIR_INHERIT) { + + LV_LOG_WARN("lv_obj_set_base_dir: invalid base dir"); + return; + } + + obj->base_dir = dir; + lv_signal_send(obj, LV_SIGNAL_BASE_DIR_CHG, NULL); + + /* Notify the children about the parent base dir has changed. + * (The children might have `LV_BIDI_DIR_INHERIT`)*/ + base_dir_refr_children(obj); +} + /** * Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`) * @param obj pointer to an object @@ -1742,8 +1786,11 @@ lv_coord_t lv_obj_get_x(const lv_obj_t * obj) lv_coord_t rel_x; lv_obj_t * parent = lv_obj_get_parent(obj); - rel_x = obj->coords.x1 - parent->coords.x1; - + if(parent) { + rel_x = obj->coords.x1 - parent->coords.x1; + } else { + rel_x = obj->coords.x1; + } return rel_x; } @@ -1758,8 +1805,11 @@ lv_coord_t lv_obj_get_y(const lv_obj_t * obj) lv_coord_t rel_y; lv_obj_t * parent = lv_obj_get_parent(obj); - rel_y = obj->coords.y1 - parent->coords.y1; - + if(parent) { + rel_y = obj->coords.y1 - parent->coords.y1; + } else { + rel_y = obj->coords.y1; + } return rel_y; } @@ -2068,6 +2118,25 @@ bool lv_obj_get_parent_event(const lv_obj_t * obj) return obj->parent_event == 0 ? false : true; } + +lv_bidi_dir_t lv_obj_get_base_dir(const lv_obj_t * obj) +{ +#if LV_USE_BIDI + const lv_obj_t * parent = obj; + + while(parent) { + if(parent->base_dir != LV_BIDI_DIR_INHERIT) return parent->base_dir; + + parent = lv_obj_get_parent(parent); + } + + return LV_BIDI_BASE_DIR_DEF; +#else + return LV_BIDI_DIR_LTR; +#endif +} + + /** * Get the opa scale enable parameter * @param obj pointer to an object @@ -2512,6 +2581,22 @@ static void delete_children(lv_obj_t * obj) lv_mem_free(obj); /*Free the object itself*/ } +static void base_dir_refr_children(lv_obj_t * obj) +{ + lv_obj_t * child; + child = lv_obj_get_child(obj, NULL); + + while(child) { + if(child->base_dir == LV_BIDI_DIR_INHERIT) { + lv_signal_send(child, LV_SIGNAL_BASE_DIR_CHG, NULL); + base_dir_refr_children(child); + } + + child = lv_obj_get_child(obj, child); + } +} + + static void lv_event_mark_deleted(lv_obj_t * obj) { lv_event_temp_data_t * t = event_temp_data_head; diff --git a/src/lv_core/lv_obj.h b/src/lv_core/lv_obj.h index ecd8f2d5b..201dbc635 100644 --- a/src/lv_core/lv_obj.h +++ b/src/lv_core/lv_obj.h @@ -28,6 +28,7 @@ extern "C" { #include "../lv_misc/lv_ll.h" #include "../lv_misc/lv_color.h" #include "../lv_misc/lv_log.h" +#include "../lv_misc/lv_bidi.h" #include "../lv_hal/lv_hal.h" /********************* @@ -111,7 +112,8 @@ enum { LV_SIGNAL_CHILD_CHG, /**< Child was removed/added */ LV_SIGNAL_CORD_CHG, /**< Object coordinates/size have changed */ LV_SIGNAL_PARENT_SIZE_CHG, /**< Parent's size has changed */ - LV_SIGNAL_STYLE_CHG, /**< Object's style has changed */ + LV_SIGNAL_STYLE_CHG, /**< Object's style has changed */ + LV_SIGNAL_BASE_DIR_CHG, /**dec_dsc.error_msg != NULL) { LV_LOG_WARN("Image draw error"); lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER); - lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, cdsc->dec_dsc.error_msg, LV_TXT_FLAG_NONE, NULL, NULL, NULL); + lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, cdsc->dec_dsc.error_msg, LV_TXT_FLAG_NONE, NULL, NULL, NULL, LV_BIDI_DIR_LTR); } /* The decoder open could open the image and gave the entire uncompressed image. * Just draw it!*/ diff --git a/src/lv_draw/lv_draw_label.c b/src/lv_draw/lv_draw_label.c index ba4ce341b..29865438f 100644 --- a/src/lv_draw/lv_draw_label.c +++ b/src/lv_draw/lv_draw_label.c @@ -8,6 +8,7 @@ *********************/ #include "lv_draw_label.h" #include "../lv_misc/lv_math.h" +#include "../lv_misc/lv_bidi.h" /********************* * DEFINES @@ -55,16 +56,13 @@ static uint8_t hex_char_to_num(char hex); */ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale, const char * txt, lv_txt_flag_t flag, lv_point_t * offset, lv_draw_label_txt_sel_t * sel, - lv_draw_label_hint_t * hint) + lv_draw_label_hint_t * hint, lv_bidi_dir_t bidi_dir) { const lv_font_t * font = style->text.font; lv_coord_t w; /*No need to waste processor time if string is empty*/ - if (txt[0] == '\0') - { - return; - } + if (txt[0] == '\0') return; if((flag & LV_TXT_FLAG_EXPAND) == 0) { /*Normally use the label's width as width*/ @@ -73,7 +71,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st /*If EXAPND is enabled then not limit the text's width to the object's width*/ lv_point_t p; lv_txt_get_size(&p, txt, style->text.font, style->text.letter_space, style->text.line_space, LV_COORD_MAX, - flag); + flag); w = p.x; } @@ -111,6 +109,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st pos.y += hint->y; } + uint32_t line_end = line_start + lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, w, flag); /*Go the first visible line*/ @@ -145,6 +144,18 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->text.opa : (uint16_t)((uint16_t)style->text.opa * opa_scale) >> 8; + uint16_t sel_start = 0xFFFF; + uint16_t sel_end = 0xFFFF; + if(sel) { + sel_start = sel->start; + sel_end = sel->end; + if(sel_start > sel_end) { + uint16_t tmp = sel_start; + sel_start = sel_end; + sel_end = tmp; + } + } + cmd_state_t cmd_state = CMD_STATE_WAIT; uint32_t i; uint16_t par_start = 0; @@ -161,12 +172,31 @@ 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); +#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, NULL, 0); +#else + const char *bidi_txt = txt + line_start; +#endif + + while(i < line_end - line_start) { + uint16_t logical_char_pos = 0; + if(sel_start != 0xFFFF && sel_end != 0xFFFF) { +#if LV_USE_BIDI + logical_char_pos = lv_txt_encoded_get_char_id(txt, line_start); + uint16_t t = lv_txt_encoded_get_char_id(bidi_txt, i); + logical_char_pos += lv_bidi_get_logical_pos(bidi_txt, NULL, line_end - line_start, bidi_dir, t, NULL); +#else + logical_char_pos = lv_txt_encoded_get_char_id(txt, line_start + i); +#endif + } + + 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) { @@ -189,7 +219,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]); @@ -211,18 +241,14 @@ 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) { - if(sel->start != 0xFFFF && sel->end != 0xFFFF) { - int char_ind = lv_encoded_get_char_id(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; - sel_coords.x1 = pos.x; - sel_coords.y1 = pos.y; - sel_coords.x2 = pos.x + letter_w + style->text.letter_space - 1; - sel_coords.y2 = pos.y + line_height - 1; - lv_draw_rect(&sel_coords, mask, &sel_style, opa); - } + if(sel_start != 0xFFFF && sel_end != 0xFFFF) { + if(logical_char_pos >= sel_start && logical_char_pos < sel_end) { + lv_area_t sel_coords; + sel_coords.x1 = pos.x; + sel_coords.y1 = pos.y; + sel_coords.x2 = pos.x + letter_w + style->text.letter_space - 1; + sel_coords.y2 = pos.y + line_height - 1; + lv_draw_rect(&sel_coords, mask, &sel_style, opa); } } @@ -240,7 +266,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st /*Align to middle*/ if(flag & LV_TXT_FLAG_CENTER) { line_width = - lv_txt_get_width(&txt[line_start], line_end - line_start, font, style->text.letter_space, flag); + lv_txt_get_width(&txt[line_start], line_end - line_start, font, style->text.letter_space, flag); pos.x += (lv_area_get_width(coords) - line_width) / 2; @@ -248,7 +274,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st /*Align to the right*/ else if(flag & LV_TXT_FLAG_RIGHT) { line_width = - lv_txt_get_width(&txt[line_start], line_end - line_start, font, style->text.letter_space, flag); + lv_txt_get_width(&txt[line_start], line_end - line_start, font, style->text.letter_space, flag); pos.x += lv_area_get_width(coords) - line_width; } @@ -278,13 +304,13 @@ static uint8_t hex_char_to_num(char hex) if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/ switch(hex) { - case 'A': result = 10; break; - case 'B': result = 11; break; - case 'C': result = 12; break; - case 'D': result = 13; break; - case 'E': result = 14; break; - case 'F': result = 15; break; - default: result = 0; break; + case 'A': result = 10; break; + case 'B': result = 11; break; + case 'C': result = 12; break; + case 'D': result = 13; break; + case 'E': result = 14; break; + case 'F': result = 15; break; + default: result = 0; break; } } diff --git a/src/lv_draw/lv_draw_label.h b/src/lv_draw/lv_draw_label.h index d1a77948e..6dc4d6464 100644 --- a/src/lv_draw/lv_draw_label.h +++ b/src/lv_draw/lv_draw_label.h @@ -14,6 +14,7 @@ extern "C" { * INCLUDES *********************/ #include "lv_draw.h" +#include "../lv_misc/lv_bidi.h" /********************* * DEFINES @@ -62,10 +63,11 @@ typedef struct { * @param flag settings for the text from 'txt_flag_t' enum * @param offset text offset in x and y direction (NULL if unused) * @param sel_start start index of selected area (`LV_LABEL_TXT_SEL_OFF` if none) + * @param bidi_dir base direction of the text */ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale, const char * txt, lv_txt_flag_t flag, lv_point_t * offset, lv_draw_label_txt_sel_t * sel, - lv_draw_label_hint_t * hint); + lv_draw_label_hint_t * hint, lv_bidi_dir_t bidi_dir); /********************** * MACROS diff --git a/src/lv_font/lv_font_heb_16.c b/src/lv_font/lv_font_heb_16.c new file mode 100644 index 000000000..5cff45178 --- /dev/null +++ b/src/lv_font/lv_font_heb_16.c @@ -0,0 +1,1133 @@ +#include "lvgl/lvgl.h" + +/******************************************************************************* + * Size: 16 px + * Bpp: 4 + * Opts: --font /usr/share/fonts/truetype/culmus/FrankRuehlCLM-Medium.ttf -r 0x20-0x7F -r 0x5d0-0x5ea --size 16 --format lvgl --bpp 4 --no-compress -o /home/amirgon/esp/projects/lv_mpy/lib/lv_bindings/lvgl/src/lv_font/lv_font_heb_16.c + ******************************************************************************/ + +#ifndef LV_FONT_HEB_16 +#define LV_FONT_HEB_16 1 +#endif + +#if LV_FONT_HEB_16 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = { + /* U+20 " " */ + + /* U+21 "!" */ + 0xab, 0xef, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x1, + 0x46, 0xde, 0x57, + + /* U+22 "\"" */ + 0xa, 0xc3, 0xe4, 0xf, 0x87, 0xf1, 0x1f, 0x18, + 0x90, 0x2a, 0x9, 0x20, 0x12, 0x3, 0x0, + + /* U+23 "#" */ + 0x0, 0x69, 0xc, 0x20, 0x0, 0x86, 0xe, 0x0, + 0x0, 0xa4, 0xe, 0x0, 0x3f, 0xff, 0xff, 0xf2, + 0x0, 0xe0, 0x4a, 0x0, 0x0, 0xe0, 0x68, 0x0, + 0x8f, 0xff, 0xff, 0xc0, 0x4, 0xa0, 0xa4, 0x0, + 0x6, 0x80, 0xd2, 0x0, 0x9, 0x60, 0xf0, 0x0, + + /* U+24 "$" */ + 0x0, 0xc, 0x10, 0x0, 0x1, 0xd4, 0x0, 0x6, + 0xce, 0xab, 0x1, 0xe0, 0xc4, 0xf5, 0x3e, 0xc, + 0x4f, 0x31, 0xfb, 0xd1, 0x0, 0x5, 0xff, 0xd5, + 0x0, 0x2, 0xde, 0xf6, 0x6, 0x1c, 0x1a, 0xb5, + 0xf6, 0xc1, 0x5b, 0x3f, 0x1c, 0x1a, 0x60, 0x6d, + 0xfc, 0x80, 0x0, 0xc, 0x10, 0x0, 0x0, 0x60, + 0x0, + + /* U+25 "%" */ + 0x0, 0x8e, 0x60, 0x3, 0x90, 0x0, 0x8f, 0x49, + 0x11, 0xc2, 0x0, 0x1f, 0x80, 0x7c, 0xa9, 0x0, + 0x5, 0xf1, 0xc, 0x15, 0x10, 0x0, 0x4f, 0x6, + 0x90, 0x80, 0x0, 0x0, 0xac, 0x80, 0x71, 0x2b, + 0xc3, 0x0, 0x0, 0x18, 0xe, 0x91, 0xa0, 0x0, + 0x9, 0x17, 0xf1, 0xa, 0x0, 0x2, 0x90, 0xc9, + 0x3, 0x60, 0x0, 0xa1, 0xc, 0x70, 0xa0, 0x0, + 0x39, 0x0, 0x4e, 0xc3, 0x0, + + /* U+26 "&" */ + 0x0, 0x9, 0xab, 0x20, 0x0, 0x0, 0x5, 0xc0, + 0x5b, 0x0, 0x0, 0x0, 0x8c, 0x5, 0xc0, 0x0, + 0x0, 0x7, 0xf2, 0xc6, 0x0, 0x0, 0x0, 0x3f, + 0xf7, 0x0, 0x0, 0x0, 0x8, 0xdc, 0x7, 0xcd, + 0xb0, 0xb, 0x54, 0xf5, 0x7, 0xa0, 0x3, 0xf2, + 0xb, 0xe0, 0xa1, 0x0, 0x4f, 0x60, 0x2f, 0xc6, + 0x2, 0x20, 0xee, 0x30, 0x9f, 0xa3, 0xb1, 0x3, + 0xcf, 0xc6, 0x6e, 0xe5, 0x0, + + /* U+27 "'" */ + 0xa, 0xc0, 0xf8, 0x1f, 0x12, 0xa0, 0x12, 0x0, + + /* U+28 "(" */ + 0x0, 0x6, 0x0, 0xa6, 0x6, 0xc0, 0xe, 0x60, + 0x4f, 0x30, 0x6f, 0x10, 0x7f, 0x0, 0x7f, 0x10, + 0x4f, 0x20, 0xe, 0x60, 0x7, 0xb0, 0x0, 0xb4, + 0x0, 0x7, + + /* U+29 ")" */ + 0x24, 0x0, 0x0, 0xb5, 0x0, 0x2, 0xf1, 0x0, + 0xc, 0x80, 0x0, 0x8e, 0x0, 0x7, 0xf1, 0x0, + 0x6f, 0x20, 0x7, 0xf1, 0x0, 0x8e, 0x0, 0xb, + 0x90, 0x1, 0xf2, 0x0, 0xa6, 0x0, 0x25, 0x0, + 0x0, + + /* U+2A "*" */ + 0x0, 0xb, 0x0, 0x0, 0x50, 0xb0, 0x50, 0x1c, + 0x77, 0x7b, 0x0, 0x6, 0xf4, 0x0, 0x1d, 0x57, + 0x7d, 0x0, 0x30, 0xc0, 0x40, 0x0, 0x9, 0x0, + 0x0, + + /* U+2B "+" */ + 0x0, 0x4, 0x40, 0x0, 0x0, 0x8, 0x90, 0x0, + 0x0, 0x8, 0x90, 0x0, 0x0, 0x8, 0x90, 0x0, + 0x4f, 0xff, 0xff, 0xf6, 0x2, 0x29, 0xa2, 0x21, + 0x0, 0x8, 0x90, 0x0, 0x0, 0x8, 0x90, 0x0, + + /* U+2C "," */ + 0x3b, 0xa, 0xf4, 0x4c, 0x6, 0x40, 0x10, 0x0, + + /* U+2D "-" */ + 0x19, 0x99, 0x90, 0x5f, 0xff, 0xd0, + + /* U+2E "." */ + 0x18, 0xa, 0xf3, 0x3b, 0x0, + + /* U+2F "/" */ + 0x0, 0x0, 0xe1, 0x0, 0x3, 0xb0, 0x0, 0x8, + 0x60, 0x0, 0xe, 0x10, 0x0, 0x3c, 0x0, 0x0, + 0x87, 0x0, 0x0, 0xd2, 0x0, 0x2, 0xc0, 0x0, + 0x8, 0x70, 0x0, 0xd, 0x20, 0x0, 0x2d, 0x0, + 0x0, + + /* U+30 "0" */ + 0x0, 0x8d, 0xd4, 0x0, 0x7, 0xd0, 0x4f, 0x20, + 0xe, 0x70, 0xe, 0x80, 0x3f, 0x50, 0xb, 0xd0, + 0x6f, 0x40, 0xb, 0xf0, 0x7f, 0x40, 0xb, 0xf0, + 0x6f, 0x40, 0xb, 0xf0, 0x4f, 0x50, 0xc, 0xd0, + 0xe, 0x70, 0xe, 0x80, 0x7, 0xd0, 0x4f, 0x20, + 0x0, 0x9d, 0xd4, 0x0, + + /* U+31 "1" */ + 0x0, 0xd, 0x0, 0x1, 0xbf, 0x0, 0x6d, 0xff, + 0x0, 0x0, 0xbf, 0x0, 0x0, 0xbf, 0x0, 0x0, + 0xbf, 0x0, 0x0, 0xbf, 0x0, 0x0, 0xbf, 0x0, + 0x0, 0xbf, 0x0, 0x0, 0xbf, 0x0, 0x6c, 0xff, + 0xd8, + + /* U+32 "2" */ + 0x1, 0xac, 0xd8, 0x0, 0xc2, 0x4, 0xf7, 0x2e, + 0x20, 0xe, 0xc2, 0xfc, 0x0, 0xfd, 0x7, 0x50, + 0x3f, 0x90, 0x0, 0xb, 0xe2, 0x0, 0x7, 0xf3, + 0x0, 0x3, 0xe3, 0x2, 0x1, 0xe3, 0x0, 0xb0, + 0xbd, 0xaa, 0xbd, 0x5f, 0xff, 0xff, 0xb0, + + /* U+33 "3" */ + 0x1, 0xac, 0xd8, 0x0, 0xb6, 0x4, 0xf6, 0xf, + 0xb0, 0xf, 0xa0, 0x96, 0x0, 0xf8, 0x0, 0x0, + 0x6c, 0x10, 0x7, 0xef, 0x90, 0x0, 0x0, 0x4f, + 0x91, 0x83, 0x0, 0xde, 0x6f, 0x70, 0xd, 0xd3, + 0xe0, 0x3, 0xf7, 0x5, 0xcc, 0xd7, 0x0, + + /* U+34 "4" */ + 0x0, 0x0, 0x4b, 0x0, 0x0, 0x0, 0xdb, 0x0, + 0x0, 0x6, 0xfb, 0x0, 0x0, 0xd, 0xfb, 0x0, + 0x0, 0x87, 0xfb, 0x0, 0x1, 0xd0, 0xfb, 0x0, + 0xa, 0x50, 0xfb, 0x0, 0x3c, 0x0, 0xfb, 0x0, + 0x7d, 0xdd, 0xff, 0xd1, 0x0, 0x0, 0xfb, 0x0, + 0x0, 0x1c, 0xff, 0x90, + + /* U+35 "5" */ + 0x6, 0x82, 0x5, 0x50, 0x8f, 0xff, 0xe1, 0x9, + 0xab, 0x92, 0x0, 0xa2, 0x0, 0x0, 0xc, 0xce, + 0xd7, 0x0, 0xc2, 0x6, 0xf6, 0x0, 0x0, 0xe, + 0xc1, 0xa4, 0x0, 0xde, 0x6f, 0x80, 0xe, 0xb2, + 0xf0, 0x5, 0xf4, 0x5, 0xcc, 0xc5, 0x0, + + /* U+36 "6" */ + 0x0, 0x3c, 0xcd, 0x30, 0x3, 0xf4, 0xf, 0xc0, + 0xb, 0xa0, 0xb, 0x80, 0x1f, 0x60, 0x0, 0x0, + 0x5f, 0x6b, 0xd9, 0x0, 0x7f, 0xe4, 0x5f, 0x90, + 0x6f, 0x80, 0xb, 0xf0, 0x5f, 0x60, 0xa, 0xf1, + 0x1f, 0x70, 0xb, 0xe0, 0x9, 0xd0, 0x1f, 0x60, + 0x0, 0x9d, 0xd8, 0x0, + + /* U+37 "7" */ + 0x0, 0x0, 0x0, 0x0, 0xef, 0xff, 0xfd, 0xf, + 0xaa, 0xad, 0x82, 0xa0, 0x0, 0xc2, 0x25, 0x0, + 0x3c, 0x0, 0x0, 0xa, 0x60, 0x0, 0x1, 0xf1, + 0x0, 0x0, 0x7d, 0x0, 0x0, 0xd, 0xb0, 0x0, + 0x1, 0xfa, 0x0, 0x0, 0x4f, 0xa0, 0x0, 0x2, + 0xe6, 0x0, + + /* U+38 "8" */ + 0x1, 0x9c, 0xd8, 0x0, 0xa, 0x80, 0xd, 0x60, + 0xf, 0x40, 0x9, 0xa0, 0xf, 0xb0, 0xc, 0x60, + 0x8, 0xfe, 0xb9, 0x0, 0x0, 0xdf, 0xfe, 0x30, + 0xd, 0x70, 0x6f, 0xc0, 0x5f, 0x0, 0x6, 0xf0, + 0x7e, 0x0, 0x5, 0xe0, 0x2f, 0x40, 0xb, 0x80, + 0x4, 0xcc, 0xc8, 0x0, + + /* U+39 "9" */ + 0x1, 0xbd, 0xd5, 0x0, 0xc, 0xa0, 0x4f, 0x30, + 0x4f, 0x50, 0xe, 0xa0, 0x7f, 0x30, 0xc, 0xe0, + 0x6f, 0x40, 0xd, 0xf0, 0x2f, 0xa0, 0x5f, 0xf0, + 0x5, 0xef, 0xbc, 0xf0, 0x0, 0x0, 0xd, 0xb0, + 0x9, 0x40, 0x1f, 0x60, 0x3f, 0x90, 0x9c, 0x0, + 0x8, 0xdc, 0x91, 0x0, + + /* U+3A ":" */ + 0x3b, 0xa, 0xf3, 0x18, 0x0, 0x0, 0x0, 0x1, + 0x80, 0xaf, 0x33, 0xb0, + + /* U+3B ";" */ + 0x18, 0xa, 0xf3, 0x3b, 0x0, 0x0, 0x0, 0x0, + 0x40, 0x8f, 0x26, 0xf1, 0x48, 0x5, 0x10, + + /* U+3C "<" */ + 0x0, 0x0, 0x0, 0x23, 0x0, 0x0, 0x2a, 0xf5, + 0x0, 0x2a, 0xf9, 0x10, 0x1a, 0xfa, 0x20, 0x0, + 0x5f, 0xa0, 0x0, 0x0, 0x4, 0xce, 0x70, 0x0, + 0x0, 0x4, 0xce, 0x70, 0x0, 0x0, 0x4, 0xc6, + 0x0, 0x0, 0x0, 0x0, + + /* U+3D "=" */ + 0x4f, 0xff, 0xff, 0xf6, 0x2, 0x22, 0x22, 0x21, + 0x0, 0x0, 0x0, 0x0, 0x5f, 0xff, 0xff, 0xf6, + 0x2, 0x22, 0x22, 0x21, + + /* U+3E ">" */ + 0x33, 0x0, 0x0, 0x0, 0x4f, 0xb3, 0x0, 0x0, + 0x1, 0x9f, 0xb3, 0x0, 0x0, 0x1, 0x9f, 0xb2, + 0x0, 0x0, 0x9, 0xf6, 0x0, 0x7, 0xed, 0x50, + 0x6, 0xed, 0x50, 0x0, 0x5d, 0x50, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + + /* U+3F "?" */ + 0x7, 0xce, 0xc2, 0x5, 0xf5, 0xe, 0xe0, 0x6f, + 0x60, 0xbf, 0x10, 0x20, 0xe, 0xe0, 0x0, 0x7, + 0xf3, 0x0, 0x1, 0xe3, 0x0, 0x0, 0x48, 0x0, + 0x0, 0x0, 0x10, 0x0, 0x0, 0x55, 0x0, 0x0, + 0xd, 0xd0, 0x0, 0x0, 0x66, 0x0, 0x0, + + /* U+40 "@" */ + 0x0, 0x19, 0xbb, 0xb3, 0x0, 0x1, 0xc3, 0x0, + 0x1a, 0x40, 0xa, 0x20, 0x0, 0x0, 0xd0, 0x1a, + 0x1, 0xa7, 0x84, 0x74, 0x56, 0xe, 0x54, 0xf2, + 0x56, 0x65, 0x7e, 0x4, 0xe0, 0x64, 0x56, 0x9a, + 0x8, 0xb0, 0xa0, 0x2a, 0x8a, 0xd, 0x74, 0x60, + 0xa, 0x39, 0x84, 0xa5, 0x91, 0x1, 0xc3, 0x0, + 0x9, 0x60, 0x0, 0x19, 0xcb, 0xb4, 0x0, + + /* U+41 "A" */ + 0x0, 0x0, 0xb, 0x30, 0x0, 0x0, 0x0, 0x1, + 0xf9, 0x0, 0x0, 0x0, 0x0, 0x6f, 0xe0, 0x0, + 0x0, 0x0, 0xc, 0xaf, 0x50, 0x0, 0x0, 0x1, + 0xd1, 0xfa, 0x0, 0x0, 0x0, 0x77, 0xb, 0xf1, + 0x0, 0x0, 0xc, 0x20, 0x5f, 0x60, 0x0, 0x2, + 0xfc, 0xcc, 0xfc, 0x0, 0x0, 0x86, 0x0, 0x9, + 0xf2, 0x0, 0xe, 0x20, 0x0, 0x2f, 0x80, 0x1d, + 0xfd, 0x40, 0x4c, 0xff, 0x80, + + /* U+42 "B" */ + 0x6d, 0xfe, 0xbc, 0xd5, 0x0, 0x2f, 0x50, 0x8, + 0xf1, 0x2, 0xf5, 0x0, 0x3f, 0x60, 0x2f, 0x50, + 0x3, 0xf4, 0x2, 0xf5, 0x0, 0xac, 0x0, 0x2f, + 0xcb, 0xed, 0x20, 0x2, 0xf5, 0x0, 0x5f, 0x50, + 0x2f, 0x50, 0x0, 0xdd, 0x2, 0xf5, 0x0, 0xb, + 0xd0, 0x2f, 0x50, 0x2, 0xf8, 0x6d, 0xfd, 0xbb, + 0xc7, 0x0, + + /* U+43 "C" */ + 0x0, 0x19, 0xba, 0xa5, 0x80, 0x1d, 0x60, 0x3, + 0xf9, 0x9, 0xd0, 0x0, 0x7, 0xa1, 0xf8, 0x0, + 0x0, 0x1a, 0x4f, 0x60, 0x0, 0x0, 0x26, 0xf5, + 0x0, 0x0, 0x0, 0x5f, 0x60, 0x0, 0x0, 0x2, + 0xf8, 0x0, 0x0, 0x9, 0xc, 0xc0, 0x0, 0x2, + 0x80, 0x2e, 0x50, 0x0, 0xb1, 0x0, 0x2a, 0xba, + 0xa2, 0x0, + + /* U+44 "D" */ + 0x6d, 0xfd, 0xab, 0xc6, 0x0, 0x2, 0xf5, 0x0, + 0x2e, 0x80, 0x2, 0xf5, 0x0, 0x7, 0xf2, 0x2, + 0xf5, 0x0, 0x2, 0xf8, 0x2, 0xf5, 0x0, 0x0, + 0xfa, 0x2, 0xf5, 0x0, 0x0, 0xfb, 0x2, 0xf5, + 0x0, 0x0, 0xfa, 0x2, 0xf5, 0x0, 0x2, 0xf7, + 0x2, 0xf5, 0x0, 0x6, 0xf2, 0x2, 0xf5, 0x0, + 0x1e, 0x80, 0x6d, 0xfd, 0xaa, 0xb5, 0x0, + + /* U+45 "E" */ + 0x6d, 0xfd, 0xbb, 0xef, 0x60, 0x2f, 0x50, 0x1, + 0xc7, 0x2, 0xf5, 0x0, 0x5, 0x80, 0x2f, 0x50, + 0x71, 0x19, 0x2, 0xf5, 0x1d, 0x20, 0x10, 0x2f, + 0xce, 0xf2, 0x0, 0x2, 0xf5, 0xd, 0x20, 0x0, + 0x2f, 0x50, 0x92, 0x9, 0x2, 0xf5, 0x0, 0x1, + 0xb0, 0x2f, 0x50, 0x0, 0xaa, 0x6d, 0xfd, 0xbb, + 0xef, 0x90, + + /* U+46 "F" */ + 0x6d, 0xfd, 0xbb, 0xff, 0x50, 0x2f, 0x50, 0x1, + 0xd6, 0x2, 0xf5, 0x0, 0x6, 0x60, 0x2f, 0x50, + 0x71, 0x37, 0x2, 0xf5, 0x1d, 0x20, 0x10, 0x2f, + 0xce, 0xf2, 0x0, 0x2, 0xf5, 0xd, 0x20, 0x0, + 0x2f, 0x50, 0x92, 0x0, 0x2, 0xf5, 0x0, 0x0, + 0x0, 0x2f, 0x50, 0x0, 0x0, 0x6d, 0xfd, 0xa0, + 0x0, 0x0, + + /* U+47 "G" */ + 0x0, 0x19, 0xbb, 0xb4, 0xa0, 0x0, 0x1d, 0x60, + 0x2, 0xeb, 0x0, 0xa, 0xc0, 0x0, 0x5, 0xc0, + 0x1, 0xf8, 0x0, 0x0, 0xb, 0x0, 0x5f, 0x50, + 0x0, 0x0, 0x0, 0x6, 0xf5, 0x0, 0x0, 0x0, + 0x0, 0x6f, 0x50, 0x0, 0xad, 0xdb, 0x33, 0xf7, + 0x0, 0x0, 0x8e, 0x0, 0xc, 0xc0, 0x0, 0x9, + 0xe0, 0x0, 0x2e, 0x60, 0x1, 0xde, 0x0, 0x0, + 0x2a, 0xba, 0xa2, 0xb0, 0x0, + + /* U+48 "H" */ + 0x6d, 0xfd, 0x80, 0x6d, 0xfd, 0x70, 0x2f, 0x50, + 0x0, 0x3f, 0x40, 0x2, 0xf5, 0x0, 0x3, 0xf4, + 0x0, 0x2f, 0x50, 0x0, 0x3f, 0x40, 0x2, 0xf5, + 0x0, 0x3, 0xf4, 0x0, 0x2f, 0xdc, 0xcc, 0xdf, + 0x40, 0x2, 0xf5, 0x0, 0x3, 0xf4, 0x0, 0x2f, + 0x50, 0x0, 0x3f, 0x40, 0x2, 0xf5, 0x0, 0x3, + 0xf4, 0x0, 0x2f, 0x50, 0x0, 0x3f, 0x40, 0x6d, + 0xfd, 0x80, 0x7d, 0xfd, 0x70, + + /* U+49 "I" */ + 0x5c, 0xfe, 0xa0, 0xf, 0x70, 0x0, 0xf7, 0x0, + 0xf, 0x70, 0x0, 0xf7, 0x0, 0xf, 0x70, 0x0, + 0xf7, 0x0, 0xf, 0x70, 0x0, 0xf7, 0x0, 0xf, + 0x70, 0x5c, 0xfe, 0xa0, + + /* U+4A "J" */ + 0x0, 0x2b, 0xff, 0xb1, 0x0, 0x0, 0xcb, 0x0, + 0x0, 0x0, 0xcb, 0x0, 0x0, 0x0, 0xcb, 0x0, + 0x0, 0x0, 0xcb, 0x0, 0x0, 0x0, 0xcb, 0x0, + 0x0, 0x0, 0xcb, 0x0, 0x9f, 0x40, 0xca, 0x0, + 0xef, 0x30, 0xd9, 0x0, 0xa1, 0x3, 0xf4, 0x0, + 0x2a, 0xad, 0x70, 0x0, + + /* U+4B "K" */ + 0x6d, 0xfd, 0x80, 0xbf, 0xfc, 0x10, 0x2f, 0x50, + 0x0, 0xd5, 0x0, 0x2, 0xf5, 0x0, 0x96, 0x0, + 0x0, 0x2f, 0x50, 0x78, 0x0, 0x0, 0x2, 0xf5, + 0x5f, 0x20, 0x0, 0x0, 0x2f, 0x9c, 0xfb, 0x0, + 0x0, 0x2, 0xfd, 0x17, 0xf4, 0x0, 0x0, 0x2f, + 0x50, 0xd, 0xd0, 0x0, 0x2, 0xf5, 0x0, 0x4f, + 0x80, 0x0, 0x2f, 0x50, 0x0, 0xbf, 0x20, 0x6d, + 0xfd, 0x80, 0x9e, 0xfe, 0x70, + + /* U+4C "L" */ + 0x5c, 0xfe, 0x90, 0x0, 0x0, 0x1f, 0x60, 0x0, + 0x0, 0x1, 0xf6, 0x0, 0x0, 0x0, 0x1f, 0x60, + 0x0, 0x0, 0x1, 0xf6, 0x0, 0x0, 0x0, 0x1f, + 0x60, 0x0, 0x0, 0x1, 0xf6, 0x0, 0x0, 0x10, + 0x1f, 0x60, 0x0, 0x19, 0x1, 0xf6, 0x0, 0x5, + 0x70, 0x1f, 0x60, 0x1, 0xd6, 0x5c, 0xfe, 0xbb, + 0xff, 0x50, + + /* U+4D "M" */ + 0x6d, 0xff, 0x0, 0x0, 0x5f, 0xfb, 0x10, 0x2d, + 0xf4, 0x0, 0x9, 0xdb, 0x0, 0x2, 0x9e, 0x90, + 0x0, 0xbc, 0xb0, 0x0, 0x29, 0xae, 0x0, 0x37, + 0xcb, 0x0, 0x2, 0x95, 0xf3, 0x8, 0x2c, 0xb0, + 0x0, 0x29, 0xf, 0x80, 0xb0, 0xcb, 0x0, 0x2, + 0x90, 0xbd, 0x19, 0xc, 0xb0, 0x0, 0x29, 0x5, + 0xf9, 0x40, 0xcb, 0x0, 0x2, 0x90, 0x1f, 0xf0, + 0xc, 0xb0, 0x0, 0x5c, 0x0, 0xbb, 0x0, 0xcb, + 0x0, 0x8f, 0xfc, 0x16, 0x62, 0xbf, 0xfb, 0x10, + + /* U+4E "N" */ + 0x8e, 0xf5, 0x0, 0x2d, 0xff, 0x70, 0x3f, 0xe1, + 0x0, 0xe, 0x30, 0x3, 0xbf, 0xa0, 0x0, 0xb1, + 0x0, 0x38, 0x7f, 0x40, 0xb, 0x0, 0x3, 0x80, + 0xce, 0x0, 0xb0, 0x0, 0x38, 0x2, 0xf9, 0xb, + 0x0, 0x3, 0x80, 0x8, 0xf4, 0xb0, 0x0, 0x38, + 0x0, 0xd, 0xdb, 0x0, 0x3, 0x80, 0x0, 0x3f, + 0xf0, 0x0, 0x6b, 0x0, 0x0, 0x8f, 0x0, 0x8f, + 0xfd, 0x0, 0x0, 0xd0, 0x0, + + /* U+4F "O" */ + 0x0, 0x1a, 0xbb, 0xb4, 0x0, 0x1, 0xe6, 0x0, + 0x2e, 0x50, 0xa, 0xd0, 0x0, 0x7, 0xf1, 0x1f, + 0x80, 0x0, 0x2, 0xf7, 0x4f, 0x60, 0x0, 0x0, + 0xfa, 0x6f, 0x50, 0x0, 0x0, 0xfb, 0x5f, 0x60, + 0x0, 0x0, 0xfa, 0x1f, 0x80, 0x0, 0x2, 0xf7, + 0xb, 0xd0, 0x0, 0x7, 0xf1, 0x1, 0xe6, 0x0, + 0x2e, 0x50, 0x0, 0x1a, 0xbb, 0xb4, 0x0, + + /* U+50 "P" */ + 0x6d, 0xfd, 0xbb, 0xc6, 0x0, 0x3f, 0x50, 0x5, + 0xf4, 0x3, 0xf5, 0x0, 0xf, 0x90, 0x3f, 0x50, + 0x1, 0xf9, 0x3, 0xf5, 0x0, 0x8f, 0x30, 0x3f, + 0xca, 0xba, 0x30, 0x3, 0xf5, 0x0, 0x0, 0x0, + 0x3f, 0x50, 0x0, 0x0, 0x3, 0xf5, 0x0, 0x0, + 0x0, 0x3f, 0x50, 0x0, 0x0, 0x6d, 0xfd, 0x90, + 0x0, 0x0, + + /* U+51 "Q" */ + 0x0, 0x19, 0xbb, 0xb4, 0x0, 0x1, 0xd6, 0x0, + 0x2e, 0x50, 0x9, 0xd0, 0x0, 0x6, 0xf1, 0x1f, + 0x90, 0x0, 0x2, 0xf7, 0x4f, 0x70, 0x0, 0x0, + 0xfb, 0x6f, 0x60, 0x0, 0x0, 0xfc, 0x5f, 0x60, + 0x0, 0x0, 0xfa, 0x1f, 0x82, 0xab, 0x31, 0xf6, + 0xa, 0xca, 0x1, 0xd7, 0xe0, 0x1, 0xdd, 0x0, + 0xaf, 0x40, 0x0, 0x19, 0xba, 0xec, 0x0, 0x0, + 0x0, 0x0, 0x7f, 0x18, 0x0, 0x0, 0x0, 0x4f, + 0x8a, 0x0, 0x0, 0x0, 0xa, 0xe4, + + /* U+52 "R" */ + 0x7d, 0xfd, 0xbb, 0xc4, 0x0, 0x3, 0xf4, 0x0, + 0x7f, 0x20, 0x3, 0xf4, 0x0, 0x3f, 0x60, 0x3, + 0xf4, 0x0, 0x3f, 0x50, 0x3, 0xf4, 0x0, 0xad, + 0x0, 0x3, 0xfc, 0xce, 0x70, 0x0, 0x3, 0xf4, + 0x7, 0xd0, 0x0, 0x3, 0xf4, 0x0, 0xf6, 0x0, + 0x3, 0xf4, 0x0, 0xea, 0x3, 0x3, 0xf4, 0x0, + 0xbe, 0x55, 0x7d, 0xfd, 0x70, 0x4e, 0xc1, + + /* U+53 "S" */ + 0x1, 0xab, 0xa8, 0x84, 0xb, 0x40, 0x5, 0xf5, + 0xf, 0x0, 0x0, 0xa6, 0xf, 0x70, 0x0, 0x35, + 0xb, 0xfd, 0x84, 0x0, 0x0, 0x9e, 0xff, 0xd1, + 0x11, 0x0, 0x38, 0xf9, 0x47, 0x0, 0x0, 0x6c, + 0x4d, 0x0, 0x0, 0x3b, 0x4f, 0x90, 0x0, 0x96, + 0x48, 0x6b, 0xab, 0x70, + + /* U+54 "T" */ + 0x9f, 0xdd, 0xfd, 0xdf, 0x79, 0xa0, 0x4f, 0x30, + 0xb8, 0xa2, 0x4, 0xf3, 0x4, 0x8a, 0x0, 0x4f, + 0x30, 0x9, 0x20, 0x4, 0xf3, 0x0, 0x20, 0x0, + 0x4f, 0x30, 0x0, 0x0, 0x4, 0xf3, 0x0, 0x0, + 0x0, 0x4f, 0x30, 0x0, 0x0, 0x4, 0xf3, 0x0, + 0x0, 0x0, 0x4f, 0x30, 0x0, 0x0, 0x9d, 0xfd, + 0x80, 0x0, + + /* U+55 "U" */ + 0x8d, 0xfc, 0x60, 0x1d, 0xff, 0x70, 0x5f, 0x20, + 0x0, 0xc, 0x40, 0x5, 0xf2, 0x0, 0x0, 0xa2, + 0x0, 0x5f, 0x20, 0x0, 0x9, 0x10, 0x5, 0xf2, + 0x0, 0x0, 0x91, 0x0, 0x5f, 0x20, 0x0, 0x9, + 0x10, 0x5, 0xf2, 0x0, 0x0, 0x91, 0x0, 0x5f, + 0x20, 0x0, 0xa, 0x0, 0x4, 0xf4, 0x0, 0x0, + 0xb0, 0x0, 0xd, 0xd1, 0x0, 0x86, 0x0, 0x0, + 0x1a, 0xec, 0xc6, 0x0, 0x0, + + /* U+56 "V" */ + 0x1c, 0xff, 0xb0, 0xa, 0xff, 0x80, 0xd, 0xd0, + 0x0, 0x9, 0x70, 0x0, 0x7f, 0x20, 0x0, 0xc0, + 0x0, 0x1, 0xf8, 0x0, 0x2a, 0x0, 0x0, 0xc, + 0xe0, 0x7, 0x50, 0x0, 0x0, 0x6f, 0x30, 0xc0, + 0x0, 0x0, 0x1, 0xf9, 0x2a, 0x0, 0x0, 0x0, + 0xa, 0xe8, 0x40, 0x0, 0x0, 0x0, 0x5f, 0xe0, + 0x0, 0x0, 0x0, 0x0, 0xf9, 0x0, 0x0, 0x0, + 0x0, 0x9, 0x40, 0x0, 0x0, + + /* U+57 "W" */ + 0xaf, 0xe9, 0x3d, 0xfd, 0x62, 0xdf, 0xd0, 0xc, + 0xc0, 0x1, 0xf7, 0x0, 0xd, 0x0, 0x7, 0xf1, + 0x0, 0xec, 0x0, 0x38, 0x0, 0x3, 0xf5, 0x2, + 0xff, 0x0, 0x74, 0x0, 0x0, 0xea, 0x6, 0x7f, + 0x50, 0xb0, 0x0, 0x0, 0x9e, 0xa, 0x1e, 0x90, + 0xb0, 0x0, 0x0, 0x5f, 0x4b, 0x9, 0xd4, 0x70, + 0x0, 0x0, 0xf, 0xc8, 0x4, 0xfb, 0x30, 0x0, + 0x0, 0xb, 0xf4, 0x0, 0xfe, 0x0, 0x0, 0x0, + 0x6, 0xf0, 0x0, 0xba, 0x0, 0x0, 0x0, 0x2, + 0xb0, 0x0, 0x66, 0x0, 0x0, + + /* U+58 "X" */ + 0xb, 0xff, 0xb0, 0x7f, 0xfb, 0x0, 0x9, 0xf3, + 0x0, 0xa6, 0x0, 0x0, 0x1e, 0xc0, 0x2b, 0x0, + 0x0, 0x0, 0x6f, 0x6b, 0x10, 0x0, 0x0, 0x0, + 0xcf, 0x70, 0x0, 0x0, 0x0, 0x4, 0xf8, 0x0, + 0x0, 0x0, 0x0, 0xab, 0xf2, 0x0, 0x0, 0x0, + 0x49, 0x1e, 0xc0, 0x0, 0x0, 0xc, 0x0, 0x6f, + 0x50, 0x0, 0x9, 0x90, 0x0, 0xce, 0x10, 0xd, + 0xff, 0x80, 0x9e, 0xfd, 0x60, + + /* U+59 "Y" */ + 0x1c, 0xff, 0xb1, 0x3c, 0xfe, 0x50, 0xb, 0xf1, + 0x0, 0xe, 0x10, 0x0, 0x3f, 0x90, 0x5, 0x70, + 0x0, 0x0, 0xaf, 0x20, 0xc0, 0x0, 0x0, 0x2, + 0xfb, 0x68, 0x0, 0x0, 0x0, 0x8, 0xfe, 0x10, + 0x0, 0x0, 0x0, 0x1f, 0xa0, 0x0, 0x0, 0x0, + 0x0, 0xe9, 0x0, 0x0, 0x0, 0x0, 0xe, 0x90, + 0x0, 0x0, 0x0, 0x0, 0xe9, 0x0, 0x0, 0x0, + 0x5, 0xbf, 0xeb, 0x10, 0x0, + + /* U+5A "Z" */ + 0x1f, 0xfc, 0xbc, 0xf8, 0x2f, 0x20, 0xb, 0xf1, + 0x39, 0x0, 0x3f, 0x70, 0x35, 0x0, 0xce, 0x0, + 0x0, 0x5, 0xf5, 0x0, 0x0, 0xe, 0xc0, 0x0, + 0x0, 0x7f, 0x30, 0x2, 0x1, 0xfa, 0x0, 0x1a, + 0x9, 0xf2, 0x0, 0x59, 0x2f, 0x90, 0x0, 0xc8, + 0xaf, 0xbb, 0xbe, 0xf7, + + /* U+5B "[" */ + 0x2f, 0x98, 0x2f, 0x10, 0x2f, 0x10, 0x2f, 0x10, + 0x2f, 0x10, 0x2f, 0x10, 0x2f, 0x10, 0x2f, 0x10, + 0x2f, 0x10, 0x2f, 0x10, 0x2f, 0x10, 0x1c, 0x88, + + /* U+5C "\\" */ + 0xb1, 0x0, 0x0, 0x4, 0x70, 0x0, 0x0, 0xb, + 0x0, 0x0, 0x0, 0x57, 0x0, 0x0, 0x0, 0xb0, + 0x0, 0x0, 0x5, 0x60, 0x0, 0x0, 0xb, 0x0, + 0x0, 0x0, 0x66, 0x0, 0x0, 0x0, 0xb0, 0x0, + 0x0, 0x6, 0x50, 0x0, 0x0, 0xb, 0x0, + + /* U+5D "]" */ + 0x48, 0xd8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, + 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, + 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x48, 0xa6, + + /* U+5E "^" */ + 0x0, 0xc, 0xd0, 0x0, 0x0, 0x3e, 0xe4, 0x0, + 0x0, 0xa8, 0x6c, 0x0, 0x2, 0xf1, 0xe, 0x30, + 0x9, 0x90, 0x7, 0xb0, 0x1f, 0x10, 0x0, 0xe2, + + /* U+5F "_" */ + 0xee, 0xee, 0xee, 0x90, + + /* U+60 "`" */ + 0x41, 0x0, 0x7c, 0x0, 0x3, 0x90, + + /* U+61 "a" */ + 0x4, 0xaa, 0xc5, 0x0, 0xf, 0x40, 0x5e, 0x0, + 0x8, 0x20, 0x5f, 0x0, 0x3, 0xa9, 0x9f, 0x0, + 0x2f, 0x30, 0x4f, 0x0, 0x5f, 0x0, 0xaf, 0x10, + 0xb, 0xdb, 0x4c, 0xd1, + + /* U+62 "b" */ + 0xaf, 0x60, 0x0, 0x0, 0xd6, 0x0, 0x0, 0xd, + 0x60, 0x0, 0x0, 0xd6, 0x0, 0x0, 0xd, 0x9a, + 0xd9, 0x0, 0xdc, 0x0, 0xe7, 0xd, 0x70, 0x9, + 0xc0, 0xd5, 0x0, 0x7e, 0xe, 0x60, 0x8, 0xc0, + 0xeb, 0x0, 0xd6, 0xb, 0x5b, 0xb7, 0x0, + + /* U+63 "c" */ + 0x3, 0xca, 0xb1, 0xe, 0x50, 0xe6, 0x6f, 0x0, + 0x82, 0x8e, 0x0, 0x0, 0x6f, 0x0, 0x2, 0x1f, + 0x70, 0x56, 0x4, 0xde, 0x90, + + /* U+64 "d" */ + 0x0, 0x3, 0xbf, 0x50, 0x0, 0x0, 0xf, 0x50, + 0x0, 0x0, 0xf, 0x50, 0x0, 0x0, 0xf, 0x50, + 0x3, 0xdc, 0x7f, 0x50, 0xe, 0x70, 0x7f, 0x50, + 0x4f, 0x10, 0xf, 0x50, 0x6f, 0x0, 0xf, 0x50, + 0x4f, 0x0, 0xf, 0x50, 0xe, 0x50, 0x6f, 0x50, + 0x3, 0xcb, 0x7f, 0xd4, + + /* U+65 "e" */ + 0x3, 0xba, 0xb1, 0x0, 0xe4, 0x7, 0xa0, 0x5f, + 0x0, 0x4f, 0x7, 0xfa, 0xab, 0xd2, 0x6f, 0x0, + 0x0, 0x1, 0xf6, 0x0, 0xa0, 0x3, 0xcc, 0xb3, + 0x0, + + /* U+66 "f" */ + 0x0, 0x7b, 0xc5, 0x3, 0xe0, 0xab, 0x8, 0xb0, + 0x11, 0x9, 0xb0, 0x0, 0x7d, 0xea, 0x10, 0x9, + 0xb0, 0x0, 0x9, 0xb0, 0x0, 0x9, 0xb0, 0x0, + 0x9, 0xb0, 0x0, 0x9, 0xb0, 0x0, 0x5e, 0xe8, + 0x0, + + /* U+67 "g" */ + 0x4, 0xb9, 0xb9, 0xe1, 0xf, 0x20, 0x7a, 0x60, + 0x2f, 0x0, 0x5e, 0x0, 0xe, 0x40, 0x9a, 0x0, + 0x9, 0xc9, 0x81, 0x0, 0x4b, 0x43, 0x31, 0x0, + 0x1d, 0xff, 0xff, 0x20, 0x5b, 0x0, 0xb, 0x60, + 0xa7, 0x0, 0xa, 0x30, 0x2b, 0xa9, 0xa6, 0x0, + + /* U+68 "h" */ + 0x8e, 0xa0, 0x0, 0x0, 0x9, 0xa0, 0x0, 0x0, + 0x9, 0xa0, 0x0, 0x0, 0x9, 0xa0, 0x0, 0x0, + 0x9, 0xa8, 0xed, 0x20, 0x9, 0xe4, 0xb, 0xb0, + 0x9, 0xc0, 0x6, 0xd0, 0x9, 0xa0, 0x6, 0xd0, + 0x9, 0xa0, 0x6, 0xd0, 0x9, 0xa0, 0x6, 0xd0, + 0x5e, 0xe6, 0x4c, 0xf8, + + /* U+69 "i" */ + 0x7, 0xa0, 0x4, 0x60, 0x0, 0x0, 0x0, 0x0, + 0x8e, 0xc0, 0x8, 0xc0, 0x8, 0xc0, 0x8, 0xc0, + 0x8, 0xc0, 0x8, 0xc0, 0x5d, 0xe7, + + /* U+6A "j" */ + 0x0, 0x7, 0xb0, 0x0, 0x46, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9e, 0xc0, 0x0, 0x8c, 0x0, + 0x8, 0xc0, 0x0, 0x8c, 0x0, 0x8, 0xc0, 0x0, + 0x8c, 0x0, 0x8, 0xb0, 0x0, 0x8a, 0xf, 0x3a, + 0x60, 0xbb, 0xa0, + + /* U+6B "k" */ + 0x9e, 0xa0, 0x0, 0x0, 0x9, 0xa0, 0x0, 0x0, + 0x9, 0xa0, 0x0, 0x0, 0x9, 0xa0, 0x0, 0x0, + 0x9, 0xa2, 0xbf, 0xc2, 0x9, 0xa0, 0xa5, 0x0, + 0x9, 0xa8, 0x90, 0x0, 0x9, 0xfb, 0xe1, 0x0, + 0x9, 0xb0, 0xda, 0x0, 0x9, 0xa0, 0x3f, 0x50, + 0x5e, 0xe6, 0x6f, 0xf8, + + /* U+6C "l" */ + 0x8e, 0xb0, 0x8, 0xb0, 0x8, 0xb0, 0x8, 0xb0, + 0x8, 0xb0, 0x8, 0xb0, 0x8, 0xb0, 0x8, 0xb0, + 0x8, 0xb0, 0x8, 0xb0, 0x5d, 0xe7, + + /* U+6D "m" */ + 0x7e, 0xba, 0xec, 0x3b, 0xea, 0x0, 0x9, 0xf3, + 0xd, 0xe2, 0x1e, 0x60, 0x9, 0xc0, 0xa, 0xa0, + 0xc, 0x80, 0x9, 0xb0, 0xa, 0x90, 0xb, 0x80, + 0x9, 0xb0, 0xa, 0x90, 0xb, 0x80, 0x9, 0xb0, + 0xa, 0x90, 0xb, 0x80, 0x5e, 0xe6, 0x6e, 0xd5, + 0x7e, 0xd5, + + /* U+6E "n" */ + 0x7e, 0xb9, 0xed, 0x10, 0x9, 0xf4, 0xb, 0xb0, + 0x9, 0xc0, 0x6, 0xd0, 0x9, 0xa0, 0x6, 0xd0, + 0x9, 0xa0, 0x6, 0xd0, 0x9, 0xa0, 0x6, 0xd0, + 0x5e, 0xe6, 0x4c, 0xf8, + + /* U+6F "o" */ + 0x3, 0xba, 0xa0, 0x0, 0xe3, 0x8, 0xa0, 0x6f, + 0x0, 0x4f, 0x8, 0xe0, 0x3, 0xf2, 0x6f, 0x0, + 0x4f, 0x0, 0xe3, 0x9, 0xa0, 0x3, 0xba, 0xa1, + 0x0, + + /* U+70 "p" */ + 0x7e, 0xba, 0xca, 0x0, 0x9, 0xf3, 0xb, 0xa0, + 0x9, 0xc0, 0x5, 0xf0, 0x9, 0xb0, 0x4, 0xf1, + 0x9, 0xc0, 0x6, 0xf0, 0x9, 0xf2, 0xb, 0x90, + 0x9, 0xba, 0xda, 0x0, 0x9, 0xb0, 0x0, 0x0, + 0x9, 0xb0, 0x0, 0x0, 0x5d, 0xe7, 0x0, 0x0, + + /* U+71 "q" */ + 0x3, 0xca, 0x94, 0x60, 0xe, 0x40, 0x6f, 0x40, + 0x5f, 0x0, 0x1f, 0x40, 0x7e, 0x0, 0xf, 0x40, + 0x6f, 0x0, 0x1f, 0x40, 0x1f, 0x50, 0x7f, 0x40, + 0x4, 0xdc, 0x7f, 0x40, 0x0, 0x0, 0xf, 0x40, + 0x0, 0x0, 0xf, 0x40, 0x0, 0x1, 0x9f, 0xb2, + + /* U+72 "r" */ + 0x8e, 0xa5, 0xb8, 0x9, 0xc4, 0xaa, 0x9, 0xf0, + 0x0, 0x9, 0xc0, 0x0, 0x9, 0xa0, 0x0, 0x9, + 0xa0, 0x0, 0x5e, 0xe7, 0x0, + + /* U+73 "s" */ + 0x8, 0xaa, 0xb3, 0x29, 0x0, 0xb3, 0x2e, 0x73, + 0x31, 0x7, 0xef, 0xe2, 0x34, 0x2, 0xa8, 0x5c, + 0x0, 0x47, 0x59, 0xa9, 0xa1, + + /* U+74 "t" */ + 0x0, 0x90, 0x0, 0x39, 0x0, 0xb, 0x90, 0x7, + 0xed, 0xa5, 0xa, 0x90, 0x0, 0xa9, 0x0, 0xa, + 0x90, 0x0, 0xa9, 0x8, 0x9, 0xb0, 0xa0, 0x3d, + 0xd4, + + /* U+75 "u" */ + 0x8f, 0x90, 0x8e, 0xc0, 0xa, 0x90, 0x8, 0xc0, + 0xa, 0x90, 0x8, 0xc0, 0xa, 0x90, 0x8, 0xc0, + 0xa, 0x90, 0x9, 0xc0, 0x8, 0xb0, 0x1e, 0xc0, + 0x1, 0xcc, 0x99, 0xfb, + + /* U+76 "v" */ + 0x9f, 0xb2, 0x5f, 0xc0, 0xc, 0x80, 0xb, 0x0, + 0x6, 0xe0, 0x28, 0x0, 0x0, 0xf5, 0x82, 0x0, + 0x0, 0x9b, 0xa0, 0x0, 0x0, 0x3f, 0x60, 0x0, + 0x0, 0xc, 0x10, 0x0, + + /* U+77 "w" */ + 0x7f, 0xb2, 0xcf, 0x72, 0xdd, 0x10, 0xc8, 0x3, + 0xf1, 0x9, 0x20, 0x6, 0xd0, 0x8e, 0x70, 0xa0, + 0x0, 0x1f, 0x3a, 0x6c, 0x37, 0x0, 0x0, 0xbc, + 0x71, 0xfb, 0x10, 0x0, 0x6, 0xf1, 0xb, 0xc0, + 0x0, 0x0, 0x1b, 0x0, 0x56, 0x0, 0x0, + + /* U+78 "x" */ + 0x8f, 0xd3, 0xaf, 0x70, 0x9, 0xe1, 0x76, 0x0, + 0x0, 0xdc, 0x90, 0x0, 0x0, 0x4f, 0x50, 0x0, + 0x0, 0xa9, 0xe1, 0x0, 0x7, 0x60, 0xda, 0x0, + 0x9f, 0x92, 0xdf, 0xb0, + + /* U+79 "y" */ + 0x8f, 0xc2, 0x5e, 0xc0, 0xb, 0xa0, 0xb, 0x0, + 0x4, 0xf1, 0x19, 0x0, 0x0, 0xe6, 0x73, 0x0, + 0x0, 0x8d, 0xb0, 0x0, 0x0, 0x2f, 0x80, 0x0, + 0x0, 0xb, 0x20, 0x0, 0x0, 0xa, 0x0, 0x0, + 0xc6, 0x74, 0x0, 0x0, 0xad, 0x70, 0x0, 0x0, + + /* U+7A "z" */ + 0x2f, 0xba, 0xfa, 0x29, 0x6, 0xf2, 0x13, 0x1e, + 0x70, 0x0, 0xad, 0x0, 0x4, 0xf3, 0x6, 0xd, + 0x90, 0x1b, 0x6f, 0xba, 0xeb, + + /* U+7B "{" */ + 0x0, 0x99, 0x0, 0xf0, 0x1, 0xe0, 0x1, 0xe0, + 0x2, 0xd0, 0xb, 0x60, 0x8, 0x90, 0x1, 0xd0, + 0x1, 0xe0, 0x1, 0xe0, 0x0, 0xf0, 0x0, 0x69, + + /* U+7C "|" */ + 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, + 0x79, 0x79, 0x79, + + /* U+7D "}" */ + 0x4c, 0x20, 0x8, 0x70, 0x7, 0x80, 0x7, 0x80, + 0x6, 0x90, 0x1, 0xc4, 0x3, 0xc2, 0x7, 0x80, + 0x7, 0x80, 0x7, 0x80, 0x9, 0x60, 0x49, 0x10, + + /* U+7E "~" */ + 0x8, 0xeb, 0x50, 0x72, 0x1a, 0x15, 0xdf, 0xb0, + 0x0, 0x0, 0x1, 0x0, + + /* U+5D0 "א" */ + 0x5, 0x0, 0x3, 0x0, 0xe, 0x80, 0x3f, 0xd3, + 0x9, 0xf5, 0x1d, 0xf7, 0x0, 0xcf, 0x37, 0x61, + 0x2, 0xde, 0xed, 0x0, 0xb, 0x82, 0xff, 0x0, + 0xd, 0xd0, 0x5f, 0xa0, 0xb, 0xf5, 0x7, 0xf5, + 0x2f, 0xf7, 0x0, 0xb5, 0x0, 0x0, 0x0, 0x0, + + /* U+5D1 "ב" */ + 0x13, 0x0, 0x0, 0x4, 0xff, 0xff, 0x70, 0x2d, + 0xee, 0xfd, 0x0, 0x0, 0x4, 0xf0, 0x0, 0x0, + 0xe, 0x0, 0x0, 0x0, 0xc0, 0x0, 0x0, 0x27, + 0x2, 0xee, 0xef, 0xe7, 0x6f, 0xff, 0xff, 0x40, + + /* U+5D2 "ג" */ + 0x3, 0x0, 0x0, 0xa, 0xff, 0x30, 0x6, 0xef, + 0x60, 0x0, 0x9, 0x50, 0x0, 0x7, 0x40, 0x0, + 0x8, 0x70, 0x0, 0xd, 0xc0, 0x1e, 0xf4, 0xe1, + 0x5f, 0xd0, 0x72, + + /* U+5D3 "ד" */ + 0x22, 0x0, 0x0, 0x8, 0xff, 0xff, 0xfa, 0x4d, + 0xee, 0xef, 0x90, 0x0, 0x0, 0xb0, 0x0, 0x0, + 0x49, 0x0, 0x0, 0x5, 0xa0, 0x0, 0x0, 0x5b, + 0x0, 0x0, 0x5, 0xd0, 0x0, 0x0, 0x68, 0x0, + + /* U+5D4 "ה" */ + 0x4, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xf0, + 0x1c, 0xee, 0xee, 0xf0, 0x0, 0x0, 0x3, 0x90, + 0x0, 0x0, 0x6, 0x80, 0xd, 0x20, 0x7, 0x90, + 0xf, 0x20, 0x6, 0xb0, 0xf, 0x20, 0x6, 0xc0, + 0x1f, 0x0, 0x7, 0x70, 0x1, 0x0, 0x0, 0x0, + + /* U+5D5 "ו" */ + 0x3, 0x0, 0x4f, 0xf7, 0x2d, 0xfd, 0x0, 0x2d, + 0x0, 0xd, 0x0, 0xd, 0x0, 0xd, 0x0, 0xd, + 0x0, 0x9, + + /* U+5D6 "ז" */ + 0x4, 0x0, 0x3, 0xff, 0xa0, 0x1d, 0xff, 0x0, + 0xa, 0x0, 0x3, 0xb0, 0x0, 0x4c, 0x0, 0x3, + 0xe0, 0x0, 0x3e, 0x0, 0x4, 0x90, 0x0, + + /* U+5D7 "ח" */ + 0x3, 0x0, 0x0, 0x0, 0x4f, 0xff, 0xff, 0xf3, + 0x1d, 0xfe, 0xee, 0xf4, 0x8, 0x60, 0x0, 0xc0, + 0xd, 0x20, 0x2, 0xc0, 0xd, 0x30, 0x2, 0xe0, + 0xe, 0x30, 0x1, 0xf0, 0xe, 0x40, 0x1, 0xf0, + 0xd, 0x0, 0x2, 0xb0, + + /* U+5D8 "ט" */ + 0x3, 0x0, 0x0, 0x0, 0x2f, 0xf3, 0x2e, 0xb0, + 0x1d, 0xf6, 0xdf, 0xf3, 0x5, 0x64, 0xb4, 0xe5, + 0xa, 0x31, 0x0, 0x75, 0xc, 0x40, 0x0, 0x74, + 0xa, 0x80, 0x0, 0xc1, 0x7, 0xfe, 0xee, 0xd0, + 0x5, 0xff, 0xff, 0x70, + + /* U+5D9 "י" */ + 0x3, 0x0, 0x4f, 0xf7, 0x2d, 0xfc, 0x0, 0x4a, + 0x0, 0x84, 0x0, 0x50, + + /* U+5DA "ך" */ + 0x22, 0x0, 0x0, 0x6, 0xff, 0xff, 0xe0, 0x3d, + 0xee, 0xed, 0x0, 0x0, 0x4, 0x60, 0x0, 0x0, + 0x56, 0x0, 0x0, 0x5, 0x60, 0x0, 0x0, 0x67, + 0x0, 0x0, 0x6, 0x80, 0x0, 0x0, 0x69, 0x0, + 0x0, 0x7, 0xa0, 0x0, 0x0, 0x7b, 0x0, 0x0, + 0x8, 0x90, 0x0, 0x0, 0x41, 0x0, + + /* U+5DB "כ" */ + 0x4, 0x0, 0x0, 0x1, 0xff, 0xff, 0x80, 0xc, + 0xee, 0xff, 0x30, 0x0, 0x0, 0xb7, 0x0, 0x0, + 0x3, 0x90, 0x0, 0x0, 0x39, 0x0, 0x0, 0x9, + 0x70, 0xde, 0xee, 0xf2, 0x3f, 0xff, 0xf7, 0x0, + + /* U+5DC "ל" */ + 0x31, 0x0, 0x0, 0x8, 0xf1, 0x0, 0x0, 0xc, + 0x0, 0x0, 0x0, 0x90, 0x0, 0x0, 0x2a, 0x0, + 0x0, 0x3, 0xff, 0xff, 0xf7, 0x2e, 0xee, 0xef, + 0xa0, 0x0, 0x0, 0x7b, 0x0, 0x0, 0x9, 0x80, + 0x0, 0x4, 0xd1, 0x0, 0x8, 0x90, 0x0, 0x5, + 0xb0, 0x0, 0x0, 0x69, 0x0, 0x0, + + /* U+5DD "ם" */ + 0x3, 0x0, 0x0, 0x0, 0xff, 0xff, 0xf8, 0xb, + 0xfe, 0xef, 0xe0, 0xa2, 0x0, 0x1e, 0xc, 0x0, + 0x0, 0xc1, 0xb0, 0x0, 0xc, 0x2c, 0x0, 0x0, + 0xd2, 0xfe, 0xee, 0xee, 0x1f, 0xff, 0xff, 0xc0, + + /* U+5DE "מ" */ + 0x3, 0x0, 0x0, 0x0, 0x2f, 0xd1, 0x8e, 0x40, + 0x1f, 0xf8, 0xff, 0xf0, 0x0, 0xa8, 0x14, 0xe5, + 0x2, 0xb0, 0x0, 0x76, 0x8, 0x60, 0x0, 0x56, + 0xc, 0x20, 0x0, 0x65, 0xe, 0x18, 0xee, 0xf3, + 0xe, 0xd, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, + + /* U+5DF "ן" */ + 0x13, 0x0, 0x5f, 0xf8, 0x2d, 0xfb, 0x0, 0x86, + 0x0, 0xb1, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xe1, + 0x0, 0xe2, 0x0, 0xe2, 0x0, 0xf3, 0x0, 0xf2, + 0x0, 0x50, + + /* U+5E0 "נ" */ + 0x3, 0x10, 0x0, 0x9f, 0xe2, 0x6, 0xef, 0x40, + 0x0, 0xa2, 0x0, 0xb, 0x10, 0x0, 0xb1, 0x0, + 0xb, 0x53, 0xee, 0xf7, 0x7f, 0xff, 0x50, + + /* U+5E1 "ס" */ + 0x3, 0x0, 0x0, 0x0, 0xff, 0xff, 0xa0, 0xc, + 0xfe, 0xef, 0x80, 0xa2, 0x0, 0x5c, 0xb, 0x0, + 0x0, 0xb2, 0xb0, 0x0, 0xc, 0xf, 0x40, 0x7, + 0xb0, 0xcf, 0xff, 0xf6, 0x2, 0xcf, 0xe8, 0x0, + + /* U+5E2 "ע" */ + 0x3, 0x0, 0x21, 0x0, 0x3f, 0xd3, 0x8f, 0xe2, + 0x1e, 0xf7, 0x5f, 0xf3, 0x0, 0xa0, 0x2, 0xb0, + 0x2, 0xd0, 0xa, 0x30, 0x0, 0xd9, 0x2e, 0x0, + 0x0, 0x2d, 0x8a, 0x0, 0x0, 0xb, 0xf6, 0x0, + 0x6, 0xdf, 0xd0, 0x0, 0x5f, 0xf9, 0x10, 0x0, + 0x59, 0x10, 0x0, 0x0, + + /* U+5E3 "ף" */ + 0x4, 0x0, 0x0, 0x1, 0xff, 0xff, 0xd1, 0xc, + 0xfe, 0xef, 0x60, 0x93, 0x0, 0x77, 0xf, 0xfa, + 0x3, 0x81, 0xb5, 0xa0, 0x49, 0x0, 0x0, 0x4, + 0x90, 0x0, 0x0, 0x5a, 0x0, 0x0, 0x5, 0xb0, + 0x0, 0x0, 0x6b, 0x0, 0x0, 0x6, 0xc0, 0x0, + 0x0, 0x7a, 0x0, 0x0, 0x4, 0x20, + + /* U+5E4 "פ" */ + 0x4, 0x0, 0x0, 0x0, 0xff, 0xff, 0xe2, 0xb, + 0xfe, 0xef, 0x90, 0x75, 0x0, 0x4c, 0xe, 0xfb, + 0x0, 0xb0, 0xc5, 0xc0, 0xc, 0x0, 0x0, 0x4, + 0xb0, 0xde, 0xee, 0xf9, 0x3f, 0xff, 0xff, 0x40, + + /* U+5E5 "ץ" */ + 0x13, 0x0, 0x40, 0x5, 0xff, 0x2e, 0xf6, 0x2d, + 0xf4, 0xaf, 0xa0, 0xd, 0x15, 0x91, 0x2, 0xa3, + 0xa0, 0x0, 0x3a, 0xc0, 0x0, 0x2, 0xf7, 0x0, + 0x0, 0x1f, 0x30, 0x0, 0x0, 0xf2, 0x0, 0x0, + 0xe, 0x30, 0x0, 0x0, 0xd4, 0x0, 0x0, 0xd, + 0x40, 0x0, 0x0, 0x60, 0x0, 0x0, + + /* U+5E6 "צ" */ + 0x3, 0x0, 0x30, 0x3, 0xff, 0x3b, 0xf9, 0x1c, + 0xe5, 0x8f, 0xc0, 0x6, 0x54, 0xa0, 0x0, 0x5c, + 0xc0, 0x0, 0x0, 0xcd, 0x50, 0x0, 0x0, 0x7f, + 0x80, 0xde, 0xee, 0xfc, 0x2f, 0xff, 0xff, 0x80, + + /* U+5E7 "ק" */ + 0x4, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0x90, + 0x1c, 0xee, 0xef, 0xf1, 0x1, 0x0, 0x2, 0xf2, + 0xe, 0x0, 0x0, 0xf1, 0xf, 0x0, 0x9, 0xb0, + 0xf, 0x2, 0xca, 0x10, 0xf, 0x1d, 0x30, 0x0, + 0xf, 0x57, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, + 0xf, 0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, + 0x5, 0x0, 0x0, 0x0, + + /* U+5E8 "ר" */ + 0x3, 0x0, 0x0, 0x4, 0xff, 0xff, 0xd1, 0x2d, + 0xee, 0xef, 0x50, 0x0, 0x0, 0xa6, 0x0, 0x0, + 0x8, 0x60, 0x0, 0x0, 0x86, 0x0, 0x0, 0x8, + 0x60, 0x0, 0x0, 0x86, 0x0, 0x0, 0x7, 0x40, + + /* U+5E9 "ש" */ + 0x2, 0x0, 0x20, 0x1, 0x0, 0x3f, 0xd7, 0xea, + 0x6e, 0x80, 0x2f, 0xf7, 0xef, 0x7f, 0xf0, 0x6, + 0x60, 0x86, 0x1, 0xd0, 0xb, 0x31, 0xe0, 0x9, + 0x50, 0xb, 0x46, 0x90, 0x4b, 0x0, 0x8, 0x9a, + 0x21, 0xe2, 0x0, 0x4, 0xff, 0xef, 0xa0, 0x0, + 0x0, 0xff, 0xff, 0x20, 0x0, + + /* U+5EA "ת" */ + 0x2, 0x10, 0x0, 0x0, 0x8, 0xff, 0xff, 0xd1, + 0x5, 0xef, 0xee, 0xf5, 0x0, 0xb3, 0x0, 0xa6, + 0x3, 0xc0, 0x0, 0x86, 0x4, 0xb0, 0x0, 0x86, + 0x3, 0xd0, 0x0, 0x86, 0x6e, 0xf0, 0x0, 0x86, + 0xaf, 0xb0, 0x0, 0x73 +}; + + +/*--------------------- + * GLYPH DESCRIPTION + *--------------------*/ + +static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { + {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, + {.bitmap_index = 0, .adv_w = 80, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 0, .adv_w = 64, .box_w = 2, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 11, .adv_w = 96, .box_w = 6, .box_h = 5, .ofs_x = 0, .ofs_y = 6}, + {.bitmap_index = 26, .adv_w = 128, .box_w = 8, .box_h = 10, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 66, .adv_w = 112, .box_w = 7, .box_h = 14, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 115, .adv_w = 176, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 176, .adv_w = 176, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 237, .adv_w = 48, .box_w = 3, .box_h = 5, .ofs_x = 0, .ofs_y = 6}, + {.bitmap_index = 245, .adv_w = 80, .box_w = 4, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 271, .adv_w = 80, .box_w = 5, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 304, .adv_w = 112, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 4}, + {.bitmap_index = 329, .adv_w = 128, .box_w = 8, .box_h = 8, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 361, .adv_w = 64, .box_w = 3, .box_h = 5, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 369, .adv_w = 96, .box_w = 6, .box_h = 2, .ofs_x = 0, .ofs_y = 4}, + {.bitmap_index = 375, .adv_w = 64, .box_w = 3, .box_h = 3, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 380, .adv_w = 64, .box_w = 6, .box_h = 11, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 413, .adv_w = 128, .box_w = 8, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 457, .adv_w = 128, .box_w = 6, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 490, .adv_w = 128, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 529, .adv_w = 128, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 568, .adv_w = 128, .box_w = 8, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 612, .adv_w = 128, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 651, .adv_w = 128, .box_w = 8, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 695, .adv_w = 128, .box_w = 7, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 737, .adv_w = 128, .box_w = 8, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 781, .adv_w = 128, .box_w = 8, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 825, .adv_w = 64, .box_w = 3, .box_h = 8, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 837, .adv_w = 64, .box_w = 3, .box_h = 10, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 852, .adv_w = 128, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 888, .adv_w = 128, .box_w = 8, .box_h = 5, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 908, .adv_w = 128, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 944, .adv_w = 112, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 983, .adv_w = 160, .box_w = 10, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1038, .adv_w = 160, .box_w = 11, .box_h = 11, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 1099, .adv_w = 160, .box_w = 9, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1149, .adv_w = 160, .box_w = 9, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1199, .adv_w = 160, .box_w = 10, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1254, .adv_w = 160, .box_w = 9, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1304, .adv_w = 144, .box_w = 9, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1354, .adv_w = 160, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1415, .adv_w = 176, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1476, .adv_w = 80, .box_w = 5, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1504, .adv_w = 112, .box_w = 8, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1548, .adv_w = 160, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1609, .adv_w = 144, .box_w = 9, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1659, .adv_w = 208, .box_w = 13, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1731, .adv_w = 176, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1792, .adv_w = 160, .box_w = 10, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1847, .adv_w = 144, .box_w = 9, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1897, .adv_w = 160, .box_w = 10, .box_h = 14, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 1967, .adv_w = 160, .box_w = 10, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2022, .adv_w = 128, .box_w = 8, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2066, .adv_w = 144, .box_w = 9, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2116, .adv_w = 176, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2177, .adv_w = 160, .box_w = 11, .box_h = 11, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 2238, .adv_w = 208, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2315, .adv_w = 144, .box_w = 11, .box_h = 11, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 2376, .adv_w = 144, .box_w = 11, .box_h = 11, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 2437, .adv_w = 128, .box_w = 8, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2481, .adv_w = 64, .box_w = 4, .box_h = 12, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 2505, .adv_w = 128, .box_w = 7, .box_h = 11, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2544, .adv_w = 64, .box_w = 4, .box_h = 12, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 2568, .adv_w = 128, .box_w = 8, .box_h = 6, .ofs_x = 0, .ofs_y = 5}, + {.bitmap_index = 2592, .adv_w = 112, .box_w = 7, .box_h = 1, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 2596, .adv_w = 64, .box_w = 4, .box_h = 3, .ofs_x = 0, .ofs_y = 8}, + {.bitmap_index = 2602, .adv_w = 112, .box_w = 8, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2630, .adv_w = 112, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2669, .adv_w = 96, .box_w = 6, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2690, .adv_w = 128, .box_w = 8, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2734, .adv_w = 112, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2759, .adv_w = 64, .box_w = 6, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2792, .adv_w = 112, .box_w = 8, .box_h = 10, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 2832, .adv_w = 128, .box_w = 8, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2876, .adv_w = 64, .box_w = 4, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2898, .adv_w = 64, .box_w = 5, .box_h = 14, .ofs_x = -2, .ofs_y = -3}, + {.bitmap_index = 2933, .adv_w = 128, .box_w = 8, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2977, .adv_w = 64, .box_w = 4, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2999, .adv_w = 192, .box_w = 12, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3041, .adv_w = 128, .box_w = 8, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3069, .adv_w = 112, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3094, .adv_w = 128, .box_w = 8, .box_h = 10, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3134, .adv_w = 112, .box_w = 8, .box_h = 10, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3174, .adv_w = 96, .box_w = 6, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3195, .adv_w = 96, .box_w = 6, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3216, .adv_w = 80, .box_w = 5, .box_h = 10, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3241, .adv_w = 128, .box_w = 8, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3269, .adv_w = 112, .box_w = 8, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3297, .adv_w = 160, .box_w = 11, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3336, .adv_w = 112, .box_w = 8, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3364, .adv_w = 112, .box_w = 8, .box_h = 10, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3404, .adv_w = 96, .box_w = 6, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3425, .adv_w = 64, .box_w = 4, .box_h = 12, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3449, .adv_w = 128, .box_w = 2, .box_h = 11, .ofs_x = 3, .ofs_y = 0}, + {.bitmap_index = 3460, .adv_w = 64, .box_w = 4, .box_h = 12, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3484, .adv_w = 128, .box_w = 8, .box_h = 3, .ofs_x = 0, .ofs_y = 2}, + {.bitmap_index = 3496, .adv_w = 128, .box_w = 8, .box_h = 10, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3536, .adv_w = 112, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3568, .adv_w = 96, .box_w = 6, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3595, .adv_w = 112, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3627, .adv_w = 128, .box_w = 8, .box_h = 10, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3667, .adv_w = 80, .box_w = 4, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3685, .adv_w = 80, .box_w = 5, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3708, .adv_w = 128, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3744, .adv_w = 128, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3780, .adv_w = 64, .box_w = 4, .box_h = 6, .ofs_x = 0, .ofs_y = 3}, + {.bitmap_index = 3792, .adv_w = 112, .box_w = 7, .box_h = 13, .ofs_x = 0, .ofs_y = -4}, + {.bitmap_index = 3838, .adv_w = 112, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3870, .adv_w = 112, .box_w = 7, .box_h = 13, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3916, .adv_w = 112, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3948, .adv_w = 128, .box_w = 8, .box_h = 10, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3988, .adv_w = 64, .box_w = 4, .box_h = 13, .ofs_x = 0, .ofs_y = -4}, + {.bitmap_index = 4014, .adv_w = 80, .box_w = 5, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 4037, .adv_w = 112, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 4069, .adv_w = 128, .box_w = 8, .box_h = 11, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 4113, .adv_w = 112, .box_w = 7, .box_h = 13, .ofs_x = 0, .ofs_y = -4}, + {.bitmap_index = 4159, .adv_w = 112, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 4191, .adv_w = 112, .box_w = 7, .box_h = 13, .ofs_x = 0, .ofs_y = -4}, + {.bitmap_index = 4237, .adv_w = 112, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 4269, .adv_w = 128, .box_w = 8, .box_h = 13, .ofs_x = 0, .ofs_y = -4}, + {.bitmap_index = 4321, .adv_w = 112, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 4353, .adv_w = 160, .box_w = 10, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 4398, .adv_w = 128, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = 0} +}; + +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + + + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = +{ + { + .range_start = 32, .range_length = 95, .glyph_id_start = 1, + .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY + }, + { + .range_start = 1488, .range_length = 27, .glyph_id_start = 96, + .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY + } +}; + +/*----------------- + * KERNING + *----------------*/ + + +/*Pair left and right glyphs for kerning*/ +static const uint8_t kern_pair_glyph_ids[] = +{ + 13, 18, + 14, 34, + 14, 53, + 14, 55, + 14, 56, + 14, 58, + 15, 18, + 17, 18, + 17, 21, + 17, 24, + 18, 13, + 18, 15, + 18, 17, + 18, 18, + 18, 19, + 18, 20, + 18, 21, + 18, 22, + 18, 23, + 18, 24, + 18, 25, + 18, 26, + 19, 18, + 19, 21, + 19, 24, + 20, 18, + 20, 21, + 20, 24, + 21, 18, + 21, 21, + 21, 24, + 22, 18, + 22, 21, + 22, 24, + 23, 18, + 23, 21, + 23, 24, + 24, 13, + 24, 15, + 24, 18, + 24, 19, + 24, 20, + 24, 21, + 24, 22, + 24, 23, + 24, 24, + 24, 25, + 24, 27, + 24, 28, + 25, 18, + 25, 21, + 25, 24, + 26, 18, + 26, 24 +}; + +/* Kerning between the respective left and right glyphs + * 4.4 format which needs to scaled with `kern_scale`*/ +static const int8_t kern_pair_values[] = +{ + -7, -1, -16, -12, -9, -19, -9, -11, + 1, -2, -5, -5, -11, -7, 0, -6, + -12, -6, -11, -18, -7, -5, -8, 1, + -3, -10, 0, -6, -7, 3, -10, -13, + 1, -8, -8, 2, -4, -15, -15, -8, + -7, -7, -16, -8, -8, -4, -8, -16, + -16, -9, 2, -5, -10, -2 +}; + +/*Collect the kern pair's data in one place*/ +static const lv_font_fmt_txt_kern_pair_t kern_pairs = +{ + .glyph_ids = kern_pair_glyph_ids, + .values = kern_pair_values, + .pair_cnt = 54, + .glyph_ids_size = 0 +}; + +/*-------------------- + * ALL CUSTOM DATA + *--------------------*/ + +/*Store all the custom data of the font*/ +static lv_font_fmt_txt_dsc_t font_dsc = { + .glyph_bitmap = gylph_bitmap, + .glyph_dsc = glyph_dsc, + .cmaps = cmaps, + .kern_dsc = &kern_pairs, + .kern_scale = 16, + .cmap_num = 2, + .bpp = 4, + .kern_classes = 0, + .bitmap_format = 0 +}; + + +/*----------------- + * PUBLIC FONT + *----------------*/ + +/*Initialize a public general font descriptor*/ +lv_font_t lv_font_heb_16 = { + .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ + .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ + .line_height = 17, /*The maximum line height required by the font*/ + .base_line = 4, /*Baseline measured from the bottom of the line*/ + .dsc = &font_dsc /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ +}; + +#endif /*#if LV_FONT_HEB_16*/ + diff --git a/src/lv_misc/lv_bidi.c b/src/lv_misc/lv_bidi.c new file mode 100644 index 000000000..bde752071 --- /dev/null +++ b/src/lv_misc/lv_bidi.c @@ -0,0 +1,540 @@ +/** + * @file lv_bidi.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_bidi.h" +#include "lv_txt.h" +#include "../lv_draw/lv_draw.h" + +#if LV_USE_BIDI + +/********************* + * DEFINES + *********************/ +#define LV_BIDI_BRACKLET_DEPTH 4 + +// Highest bit of the 16-bit pos_conv value specifies whether this pos is RTL or not +#define GET_POS(x) ((x) & 0x7FFF) +#define IS_RTL_POS(x) (((x) & 0x8000) != 0) +#define SET_RTL_POS(x, is_rtl) (GET_POS(x) | ((is_rtl)? 0x8000: 0)) + +/********************** + * TYPEDEFS + **********************/ +typedef struct +{ + uint32_t bracklet_pos; + lv_bidi_dir_t dir; +}bracket_stack_t; + +/********************** + * 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, 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 uint32_t get_txt_len(const char * txt, uint32_t max_len); + +/********************** + * 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 + **********************/ + +/********************** + * 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); + + uint32_t par_start = 0; + uint32_t par_len; + + while(str_in[par_start] == '\n' || str_in[par_start] == '\r') { + str_out[par_start] = str_in[par_start]; + par_start ++; + } + + 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, NULL, 0); + par_start += par_len; + + while(str_in[par_start] == '\n' || str_in[par_start] == '\r') { + str_out[par_start] = str_in[par_start]; + par_start ++; + } + } + + str_out[par_start] = '\0'; +} + +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; +} + +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 >= 0x5d0 && letter <= 0x5ea) return true; + if(letter == 0x202E) return true; /*Unicode of LV_BIDI_RLO*/ +// 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; +} + +uint16_t lv_bidi_get_logical_pos(const char * str_in, char **bidi_txt, uint32_t len, lv_bidi_dir_t base_dir, uint32_t visual_pos, bool *is_rtl) +{ + uint32_t pos_conv_len = get_txt_len(str_in, len); + void *buf = lv_draw_get_buf(len + pos_conv_len * sizeof(uint16_t)); + if (bidi_txt) *bidi_txt = buf; + uint16_t *pos_conv_buf = (uint16_t*) ((char*)buf + len); + lv_bidi_process_paragraph(str_in, bidi_txt? *bidi_txt: NULL, len, base_dir, pos_conv_buf, pos_conv_len); + if (is_rtl) *is_rtl = IS_RTL_POS(pos_conv_buf[visual_pos]); + return GET_POS(pos_conv_buf[visual_pos]); +} + +uint16_t lv_bidi_get_visual_pos(const char * str_in, char **bidi_txt, uint16_t len, lv_bidi_dir_t base_dir, uint32_t logical_pos, bool *is_rtl) +{ + uint32_t pos_conv_len = get_txt_len(str_in, len); + void *buf = lv_draw_get_buf(len + pos_conv_len * sizeof(uint16_t)); + if (bidi_txt) *bidi_txt = buf; + uint16_t *pos_conv_buf = (uint16_t*) ((char*)buf + len); + lv_bidi_process_paragraph(str_in, bidi_txt? *bidi_txt: NULL, len, base_dir, pos_conv_buf, pos_conv_len); + for (uint16_t i = 0; i < pos_conv_len; i++){ + if (GET_POS(pos_conv_buf[i]) == logical_pos){ + if (is_rtl) *is_rtl = IS_RTL_POS(pos_conv_buf[i]); + return i; + } + } + return (uint16_t) -1; +} + +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; + pos_conv_wr = pos_conv_len; + } + else { + wr = 0; + pos_conv_wr = 0; + } + + if (str_out) str_out[len] = '\0'; + + lv_bidi_dir_t dir = base_dir; + + /*Empty the bracket stack*/ + br_stack_p = 0; + + /*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); + pos_conv_rd--; + } + + if(rd) { + if(base_dir == LV_BIDI_DIR_LTR) { + 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; + 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 && str_in[rd]) { + 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) { + 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; + 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; + } +} + +uint32_t lv_bidi_get_next_paragraph(const char * txt) +{ + 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; +} + +/********************** + * 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; +} + +static void fill_pos_conv(uint16_t * out, uint16_t len, uint16_t index) +{ + for (uint16_t i = 0; i < len; i++) + { + out[i] = SET_RTL_POS(index, false); + 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; + } + } + + lv_bidi_dir_t run_dir = dir; + + 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; + *pos_conv_len = pos_conv_i_prev; + } + /*Exclude neutrals if `run_dir != base_dir` */ + 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; + 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; + *pos_conv_len = pos_conv_i_prev; + } + /*Exclude neutrals if `run_dir != base_dir` */ + 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, 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 != '%') { + 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; + pos_conv_first_weak = 0; + } + + 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); + if (dest) dest[wr] = (uint8_t)new_letter; + if (pos_conv_out) pos_conv_out[pos_conv_wr] = SET_RTL_POS(pos_conv_rd_base + pos_conv_letter, true); + wr++; + pos_conv_wr++; + } + /*Just store the letter*/ + else { + if (dest) memcpy(&dest[wr], &src[i], letter_size); + if (pos_conv_out) pos_conv_out[pos_conv_wr] = SET_RTL_POS(pos_conv_rd_base + pos_conv_i, true); + wr += letter_size; + pos_conv_wr++; + } + } + } +} + +static uint32_t char_change_to_pair(uint32_t letter) +{ + + uint8_t i; + for(i = 0; bracket_left[i] != '\0'; i++) { + if(letter == bracket_left[i]) return bracket_right[i]; + } + + for(i = 0; bracket_right[i] != '\0'; i++) { + if(letter == bracket_right[i]) return bracket_left[i]; + } + + return 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) +{ + 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_next); + 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 && bracket_dir != LV_BIDI_DIR_WEAK) 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); + 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_next); + 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 || br_stack_p == LV_BIDI_BRACKLET_DEPTH) return LV_BIDI_DIR_NEUTRAL; + + br_stack[br_stack_p].bracklet_pos = i; + br_stack[br_stack_p].dir = bracket_dir; + + br_stack_p++; + return bracket_dir; + } else if(br_stack_p > 0) { + /*Is the letter a closing bracket of the last opening?*/ + if(letter == bracket_right[br_stack[br_stack_p - 1].bracklet_pos]) { + bracket_dir = br_stack[br_stack_p - 1].dir; + br_stack_p--; + return bracket_dir; + } + } + + return LV_BIDI_DIR_NEUTRAL; +} + + +#endif /*LV_USE_BIDI*/ diff --git a/src/lv_misc/lv_bidi.h b/src/lv_misc/lv_bidi.h new file mode 100644 index 000000000..215727aa7 --- /dev/null +++ b/src/lv_misc/lv_bidi.h @@ -0,0 +1,76 @@ +/** + * @file lv_bifi.h + * + */ + +#ifndef LV_BIDI_H +#define LV_BIDI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "../../../lv_conf.h" +#endif + +#include +#include + +/********************* + * DEFINES + *********************/ +/* Special non printable strong characters. + * They can be inserted to texts to affect the run's direction*/ +#define LV_BIDI_LRO "\xE2\x80\xAD" /*U+202D*/ +#define LV_BIDI_RLO "\xE2\x80\xAE" /*U+202E*/ + +/********************** + * TYPEDEFS + **********************/ +enum +{ + /*The first 4 values are stored in `lv_obj_t` on 2 bits*/ + LV_BIDI_DIR_LTR = 0x00, + LV_BIDI_DIR_RTL = 0x01, + LV_BIDI_DIR_AUTO = 0x02, + LV_BIDI_DIR_INHERIT = 0x03, + + LV_BIDI_DIR_NEUTRAL = 0x20, + LV_BIDI_DIR_WEAK = 0x21, +}; + +typedef uint8_t lv_bidi_dir_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ +#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, 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); +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); +uint16_t lv_bidi_get_logical_pos(const char * str_in, char **bidi_txt, uint32_t len, lv_bidi_dir_t base_dir, uint32_t visual_pos, bool *is_rtl); +uint16_t lv_bidi_get_visual_pos(const char * str_in, char **bidi_txt, uint16_t len, lv_bidi_dir_t base_dir, uint32_t logical_pos, bool *is_rtl); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_BIDI*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BIDI_H*/ diff --git a/src/lv_misc/lv_txt.c b/src/lv_misc/lv_txt.c index b7570b1cb..ea2eaa81d 100644 --- a/src/lv_misc/lv_txt.c +++ b/src/lv_misc/lv_txt.c @@ -56,7 +56,7 @@ uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_utf8_con uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_utf8_next; uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_utf8_prev; uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_utf8_get_byte_id; -uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t) = lv_txt_utf8_get_char_id; +uint32_t (*lv_txt_encoded_get_char_id)(const char *, uint32_t) = lv_txt_utf8_get_char_id; uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_utf8_get_length; #elif LV_TXT_ENC == LV_TXT_ENC_ASCII uint8_t (*lv_txt_encoded_size)(const char *) = lv_txt_iso8859_1_size; @@ -65,7 +65,7 @@ uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_iso8859_ uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_iso8859_1_next; uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_iso8859_1_prev; uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_iso8859_1_get_byte_id; -uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t) = lv_txt_iso8859_1_get_char_id; +uint32_t (*lv_txt_encoded_get_char_id)(const char *, uint32_t) = lv_txt_iso8859_1_get_char_id; uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_iso8859_1_get_length; #endif @@ -468,7 +468,7 @@ static uint8_t lv_txt_utf8_size(const char * str) return 3; else if((str[0] & 0xF8) == 0xF0) return 4; - return 1; /*If the char was invalid step tell it's 1 byte long*/ + return 0; /*If the char was invalid tell it's 1 byte long*/ } /** @@ -645,7 +645,8 @@ static uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id) uint32_t i; uint32_t byte_cnt = 0; for(i = 0; i < utf8_id; i++) { - byte_cnt += lv_txt_encoded_size(&txt[byte_cnt]); + uint8_t c_size = lv_txt_encoded_size(&txt[byte_cnt]); + byte_cnt += c_size > 0 ? c_size : 1; } return byte_cnt; diff --git a/src/lv_misc/lv_txt.h b/src/lv_misc/lv_txt.h index 6fc6e4a63..865e2c97c 100644 --- a/src/lv_misc/lv_txt.h +++ b/src/lv_misc/lv_txt.h @@ -188,7 +188,7 @@ extern uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t); * @param byte_id byte index * @return character index of the letter at 'byte_id'th position */ -extern uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t); +extern uint32_t (*lv_txt_encoded_get_char_id)(const char *, uint32_t); /** * Get the number of characters (and NOT bytes) in a string. diff --git a/src/lv_objx/lv_btnm.c b/src/lv_objx/lv_btnm.c index eff4b0e68..32869007a 100644 --- a/src/lv_objx/lv_btnm.c +++ b/src/lv_objx/lv_btnm.c @@ -207,6 +207,8 @@ void lv_btnm_set_map(const lv_obj_t * btnm, const char * map[]) btn_h = lv_obj_get_height(btnm)- act_y - style_bg->body.padding.bottom - 1; } + lv_bidi_dir_t base_dir = lv_obj_get_base_dir(btnm); + /*Only deal with the non empty lines*/ if(btn_cnt != 0) { /*Calculate the width of all units*/ @@ -214,7 +216,8 @@ void lv_btnm_set_map(const lv_obj_t * btnm, const char * map[]) /*Set the button size and positions and set the texts*/ uint16_t i; - lv_coord_t act_x = style_bg->body.padding.left; + lv_coord_t act_x; + lv_coord_t act_unit_w; unit_act_cnt = 0; for(i = 0; i < btn_cnt; i++) { @@ -225,9 +228,13 @@ void lv_btnm_set_map(const lv_obj_t * btnm, const char * map[]) act_unit_w--; /*-1 because e.g. width = 100 means 101 pixels (0..100)*/ /*Always recalculate act_x because of rounding errors */ - act_x = (unit_act_cnt * all_unit_w) / unit_cnt + i * style_bg->body.padding.inner + - style_bg->body.padding.left; - + if(base_dir == LV_BIDI_DIR_RTL) { + act_x = (unit_act_cnt * all_unit_w) / unit_cnt + i * style_bg->body.padding.inner; + act_x = lv_obj_get_width(btnm) - style_bg->body.padding.right - act_x - act_unit_w - 1; + } else { + act_x = (unit_act_cnt * all_unit_w) / unit_cnt + i * style_bg->body.padding.inner + + style_bg->body.padding.left; + } /* Set the button's area. * If inner padding is zero then use the prev. button x2 as x1 to avoid rounding * errors*/ @@ -644,7 +651,6 @@ static bool lv_btnm_design(lv_obj_t * btnm, const lv_area_t * mask, lv_design_mo } /*Draw the object*/ else if(mode == LV_DESIGN_DRAW_MAIN) { - ancestor_design_f(btnm, mask, mode); lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); @@ -665,7 +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; - 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) { @@ -734,9 +739,10 @@ 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; - lv_draw_label(&area_tmp, mask, btn_style, opa_scale, ext->map_p[txt_i], txt_flag, NULL, NULL, NULL); + lv_draw_label(&area_tmp, mask, btn_style, opa_scale, ext->map_p[txt_i], txt_flag, NULL, NULL, NULL, lv_obj_get_base_dir(btnm)); } } + return true; } diff --git a/src/lv_objx/lv_calendar.c b/src/lv_objx/lv_calendar.c index 1e340a1e3..3f04e3371 100644 --- a/src/lv_objx/lv_calendar.c +++ b/src/lv_objx/lv_calendar.c @@ -670,6 +670,9 @@ static lv_coord_t get_day_names_height(lv_obj_t * calendar) static void draw_header(lv_obj_t * calendar, const lv_area_t * mask) { lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + + lv_bidi_dir_t bidi_dir = lv_obj_get_base_dir(calendar); + lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar); lv_area_t header_area; @@ -687,19 +690,19 @@ static void draw_header(lv_obj_t * calendar, const lv_area_t * mask) txt_buf[5] = '\0'; strcpy(&txt_buf[5], get_month_name(calendar, ext->showed_date.month)); header_area.y1 += ext->style_header->body.padding.top; - lv_draw_label(&header_area, mask, ext->style_header, opa_scale, txt_buf, LV_TXT_FLAG_CENTER, NULL, NULL, NULL); + lv_draw_label(&header_area, mask, ext->style_header, opa_scale, txt_buf, LV_TXT_FLAG_CENTER, NULL, NULL, NULL, bidi_dir); /*Add the left arrow*/ const lv_style_t * arrow_style = ext->btn_pressing < 0 ? ext->style_header_pr : ext->style_header; header_area.x1 += ext->style_header->body.padding.left; - lv_draw_label(&header_area, mask, arrow_style, opa_scale, LV_SYMBOL_LEFT, LV_TXT_FLAG_NONE, NULL, NULL, NULL); + lv_draw_label(&header_area, mask, arrow_style, opa_scale, LV_SYMBOL_LEFT, LV_TXT_FLAG_NONE, NULL, NULL, NULL, bidi_dir); /*Add the right arrow*/ arrow_style = ext->btn_pressing > 0 ? ext->style_header_pr : ext->style_header; header_area.x1 = header_area.x2 - ext->style_header->body.padding.right - lv_txt_get_width(LV_SYMBOL_RIGHT, strlen(LV_SYMBOL_RIGHT), arrow_style->text.font, arrow_style->text.line_space, LV_TXT_FLAG_NONE); - lv_draw_label(&header_area, mask, arrow_style, opa_scale, LV_SYMBOL_RIGHT, LV_TXT_FLAG_NONE, NULL, NULL, NULL); + lv_draw_label(&header_area, mask, arrow_style, opa_scale, LV_SYMBOL_RIGHT, LV_TXT_FLAG_NONE, NULL, NULL, NULL, bidi_dir); } /** @@ -710,6 +713,7 @@ static void draw_header(lv_obj_t * calendar, const lv_area_t * mask) static void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask) { lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + lv_bidi_dir_t bidi_dir = lv_obj_get_base_dir(calendar); lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar); lv_coord_t l_pad = ext->style_day_names->body.padding.left; @@ -724,7 +728,7 @@ static void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask) label_area.x1 = calendar->coords.x1 + (w * i) / 7 + l_pad; label_area.x2 = label_area.x1 + box_w - 1; lv_draw_label(&label_area, mask, ext->style_day_names, opa_scale, get_day_name(calendar, i), LV_TXT_FLAG_CENTER, - NULL, NULL, NULL); + NULL, NULL, NULL, bidi_dir); } } @@ -736,6 +740,7 @@ static void draw_day_names(lv_obj_t * calendar, const lv_area_t * mask) static void draw_days(lv_obj_t * calendar, const lv_area_t * mask) { lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar); + lv_bidi_dir_t bidi_dir = lv_obj_get_base_dir(calendar); const lv_style_t * style_bg = lv_calendar_get_style(calendar, LV_CALENDAR_STYLE_BG); lv_area_t label_area; lv_opa_t opa_scale = lv_obj_get_opa_scale(calendar); @@ -853,7 +858,7 @@ static void draw_days(lv_obj_t * calendar, const lv_area_t * mask) /*Write the day's number*/ lv_utils_num_to_str(day_cnt, buf); - lv_draw_label(&label_area, mask, final_style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL, NULL, NULL); + lv_draw_label(&label_area, mask, final_style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL, NULL, NULL, bidi_dir); /*Go to the next day*/ day_cnt++; diff --git a/src/lv_objx/lv_canvas.c b/src/lv_objx/lv_canvas.c index 453b06a86..58cd65cb2 100644 --- a/src/lv_objx/lv_canvas.c +++ b/src/lv_objx/lv_canvas.c @@ -585,7 +585,7 @@ void lv_canvas_draw_text(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord default: flag = LV_TXT_FLAG_NONE; break; } - lv_draw_label(&coords, &mask, style, LV_OPA_COVER, txt, flag, NULL, NULL, NULL); + lv_draw_label(&coords, &mask, style, LV_OPA_COVER, txt, flag, NULL, NULL, NULL, lv_obj_get_base_dir(canvas)); lv_refr_set_disp_refreshing(refr_ori); } diff --git a/src/lv_objx/lv_chart.c b/src/lv_objx/lv_chart.c index b99aa4241..5da3b848d 100644 --- a/src/lv_objx/lv_chart.c +++ b/src/lv_objx/lv_chart.c @@ -1379,7 +1379,7 @@ static void lv_chart_draw_y_ticks(lv_obj_t * chart, const lv_area_t * mask, uint a.x2 = p2.x + size.x + LV_CHART_AXIS_TO_LABEL_DISTANCE; } - lv_draw_label(&a, mask, style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL, NULL, NULL); + lv_draw_label(&a, mask, style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL, NULL, NULL, lv_obj_get_base_dir(chart)); } } @@ -1465,7 +1465,7 @@ static void lv_chart_draw_x_ticks(lv_obj_t * chart, const lv_area_t * mask) /* set the area at some distance of the major tick len under of the tick */ lv_area_t a = {(p2.x - size.x / 2), (p2.y + LV_CHART_AXIS_TO_LABEL_DISTANCE), (p2.x + size.x / 2), (p2.y + size.y + LV_CHART_AXIS_TO_LABEL_DISTANCE)}; - lv_draw_label(&a, mask, style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL, NULL, NULL); + lv_draw_label(&a, mask, style, opa_scale, buf, LV_TXT_FLAG_CENTER, NULL, NULL, NULL, lv_obj_get_base_dir(chart)); } } } diff --git a/src/lv_objx/lv_cont.c b/src/lv_objx/lv_cont.c index f819923a9..22e9f5145 100644 --- a/src/lv_objx/lv_cont.c +++ b/src/lv_objx/lv_cont.c @@ -21,6 +21,7 @@ #include "../lv_misc/lv_area.h" #include "../lv_misc/lv_color.h" #include "../lv_misc/lv_math.h" +#include "../lv_misc/lv_bidi.h" /********************* * DEFINES @@ -364,23 +365,23 @@ static void lv_cont_layout_row(lv_obj_t * cont) lv_align_t align; const lv_style_t * style = lv_obj_get_style(cont); lv_coord_t vpad_corr; - + lv_bidi_dir_t base_dir = lv_obj_get_base_dir(cont); switch(type) { case LV_LAYOUT_ROW_T: vpad_corr = style->body.padding.top; - align = LV_ALIGN_IN_TOP_LEFT; + align = base_dir == LV_BIDI_DIR_RTL ? LV_ALIGN_IN_TOP_RIGHT : LV_ALIGN_IN_TOP_LEFT; break; case LV_LAYOUT_ROW_M: vpad_corr = 0; - align = LV_ALIGN_IN_LEFT_MID; + align = base_dir == LV_BIDI_DIR_RTL ? LV_ALIGN_IN_RIGHT_MID: LV_ALIGN_IN_LEFT_MID; break; case LV_LAYOUT_ROW_B: vpad_corr = -style->body.padding.bottom; - align = LV_ALIGN_IN_BOTTOM_LEFT; + align = base_dir == LV_BIDI_DIR_RTL ? LV_ALIGN_IN_BOTTOM_RIGHT: LV_ALIGN_IN_BOTTOM_LEFT; break; default: vpad_corr = 0; - align = LV_ALIGN_IN_TOP_LEFT; + align = base_dir == LV_BIDI_DIR_RTL ? LV_ALIGN_IN_TOP_RIGHT : LV_ALIGN_IN_TOP_LEFT; break; } @@ -389,12 +390,19 @@ static void lv_cont_layout_row(lv_obj_t * cont) lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG); /* Align the children */ - lv_coord_t last_cord = style->body.padding.left; + lv_coord_t last_cord; + if(base_dir == LV_BIDI_DIR_RTL) last_cord = style->body.padding.right; + else last_cord = style->body.padding.left; + LV_LL_READ_BACK(cont->child_ll, child) { if(lv_obj_get_hidden(child) != false || lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue; - lv_obj_align(child, cont, align, last_cord, vpad_corr); +// last_cord -= lv_obj_get_width(child); + + if(base_dir == LV_BIDI_DIR_RTL) lv_obj_align(child, cont, align, -last_cord, vpad_corr); + else lv_obj_align(child, cont, align, last_cord, vpad_corr); + last_cord += lv_obj_get_width(child) + style->body.padding.inner; } diff --git a/src/lv_objx/lv_ddlist.c b/src/lv_objx/lv_ddlist.c index 870a3917d..a0100a74a 100644 --- a/src/lv_objx/lv_ddlist.c +++ b/src/lv_objx/lv_ddlist.c @@ -113,6 +113,11 @@ lv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy) lv_obj_set_drag(scrl, false); lv_page_set_scrl_fit2(new_ddlist, LV_FIT_FILL, LV_FIT_TIGHT); + /*Save (a later restore) the original X coordinate because it changes as the FITs applies*/ + lv_coord_t x; + if(lv_obj_get_base_dir(new_ddlist) == LV_BIDI_DIR_RTL) x = lv_obj_get_x(new_ddlist) + lv_obj_get_width(new_ddlist); + else x = lv_obj_get_x(new_ddlist); + ext->label = lv_label_create(new_ddlist, NULL); lv_cont_set_fit2(new_ddlist, LV_FIT_TIGHT, LV_FIT_NONE); lv_page_set_sb_mode(new_ddlist, LV_SB_MODE_HIDE); @@ -120,6 +125,10 @@ lv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy) lv_ddlist_set_options(new_ddlist, "Option 1\nOption 2\nOption 3"); + /*Restore the original X coordinate*/ + if(lv_obj_get_base_dir(new_ddlist) == LV_BIDI_DIR_RTL) lv_obj_set_x(new_ddlist, x - lv_obj_get_width(new_ddlist)); + else lv_obj_set_x(new_ddlist, x); + /*Set the default styles*/ lv_theme_t * th = lv_theme_get_current(); if(th) { @@ -131,6 +140,8 @@ lv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy) lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SEL, &lv_style_plain_color); lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SB, &lv_style_pretty_color); } + + } /*Copy an existing drop down list*/ else { @@ -186,7 +197,8 @@ void lv_ddlist_set_options(lv_obj_t * ddlist, const char * options) lv_ddlist_refr_width(ddlist); - switch(lv_label_get_align(ext->label)) { + lv_label_align_t align = lv_label_get_align(ext->label); + switch(align) { case LV_LABEL_ALIGN_LEFT: lv_obj_align(ext->label, NULL, LV_ALIGN_IN_LEFT_MID, 0, 0); break; case LV_LABEL_ALIGN_CENTER: lv_obj_align(ext->label, NULL, LV_ALIGN_CENTER, 0, 0); break; case LV_LABEL_ALIGN_RIGHT: lv_obj_align(ext->label, NULL, LV_ALIGN_IN_RIGHT_MID, 0, 0); break; @@ -597,7 +609,7 @@ static bool lv_ddlist_design(lv_obj_t * ddlist, const lv_area_t * mask, lv_desig new_style.text.opa = sel_style->text.opa; lv_txt_flag_t flag = lv_ddlist_get_txt_flag(ddlist); lv_draw_label(&ext->label->coords, &mask_sel, &new_style, opa_scale, lv_label_get_text(ext->label), - flag, NULL, NULL, NULL); + flag, NULL, NULL, NULL, lv_obj_get_base_dir(ddlist)); } } @@ -630,9 +642,9 @@ static bool lv_ddlist_design(lv_obj_t * ddlist, const lv_area_t * mask, lv_desig bool area_ok; area_ok = lv_area_intersect(&mask_arrow, mask, &area_arrow); if(area_ok) { + /*Use a down arrow in ddlist, you can replace it with yourcustom symbol*/ lv_draw_label(&area_arrow, &mask_arrow, &new_style, opa_scale, LV_SYMBOL_DOWN, LV_TXT_FLAG_NONE, - NULL, NULL, NULL); /*Use a down arrow in ddlist, you can replace it with your - custom symbol*/ + NULL, NULL, NULL, lv_obj_get_base_dir(ddlist)); } } } @@ -662,7 +674,15 @@ static lv_res_t lv_ddlist_signal(lv_obj_t * ddlist, lv_signal_t sign, void * par if(sign == LV_SIGNAL_STYLE_CHG) { lv_ddlist_refr_size(ddlist, 0); + } else if(sign == LV_SIGNAL_BASE_DIR_CHG) { + lv_label_align_t align = lv_label_get_align(ext->label); + switch(align) { + case LV_LABEL_ALIGN_LEFT: lv_obj_align(ext->label, NULL, LV_ALIGN_IN_LEFT_MID, 0, 0); break; + case LV_LABEL_ALIGN_CENTER: lv_obj_align(ext->label, NULL, LV_ALIGN_CENTER, 0, 0); break; + case LV_LABEL_ALIGN_RIGHT: lv_obj_align(ext->label, NULL, LV_ALIGN_IN_RIGHT_MID, 0, 0); break; + } + lv_ddlist_refr_size(ddlist, 0); } else if(sign == LV_SIGNAL_CLEANUP) { ext->label = NULL; } else if(sign == LV_SIGNAL_FOCUS) { @@ -981,7 +1001,12 @@ static void lv_ddlist_pos_current_option(lv_obj_t * ddlist) */ static void lv_ddlist_refr_width(lv_obj_t * ddlist) { - lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist); + + /*Save the current x coordinate because it should be kept after the refrsh*/ + lv_coord_t x; + if(lv_obj_get_base_dir(ddlist) == LV_BIDI_DIR_RTL) x = lv_obj_get_x(ddlist) + lv_obj_get_width(ddlist); + else x = lv_obj_get_x(ddlist); /*Set the TIGHT fit horizontally the set the width to the content*/ lv_page_set_scrl_fit2(ddlist, LV_FIT_TIGHT, lv_page_get_scrl_fit_bottom(ddlist)); @@ -989,6 +1014,9 @@ static void lv_ddlist_refr_width(lv_obj_t * ddlist) /*Revert FILL fit to fill the parent with the options area. It allows to RIGHT/CENTER align the text*/ lv_page_set_scrl_fit2(ddlist, LV_FIT_FILL, lv_page_get_scrl_fit_bottom(ddlist)); + if(lv_obj_get_base_dir(ddlist) == LV_BIDI_DIR_RTL) lv_obj_set_x(ddlist, x - lv_obj_get_width(ddlist)); + else lv_obj_set_x(ddlist, x); + switch(lv_label_get_align(ext->label)) { case LV_LABEL_ALIGN_LEFT: lv_obj_align(ext->label, NULL, LV_ALIGN_IN_LEFT_MID, 0, 0); break; case LV_LABEL_ALIGN_CENTER: lv_obj_align(ext->label, NULL, LV_ALIGN_CENTER, 0, 0); break; diff --git a/src/lv_objx/lv_gauge.c b/src/lv_objx/lv_gauge.c index f5ecc198f..7191d8320 100644 --- a/src/lv_objx/lv_gauge.c +++ b/src/lv_objx/lv_gauge.c @@ -389,7 +389,7 @@ static void lv_gauge_draw_scale(lv_obj_t * gauge, const lv_area_t * mask) label_cord.x2 = label_cord.x1 + label_size.x; label_cord.y2 = label_cord.y1 + label_size.y; - lv_draw_label(&label_cord, mask, style, opa_scale, scale_txt, LV_TXT_FLAG_NONE, NULL, NULL, NULL); + lv_draw_label(&label_cord, mask, style, opa_scale, scale_txt, LV_TXT_FLAG_NONE, NULL, NULL, NULL, lv_obj_get_base_dir(gauge)); } } /** diff --git a/src/lv_objx/lv_img.c b/src/lv_objx/lv_img.c index 8252b4bb8..c62ad0b44 100644 --- a/src/lv_objx/lv_img.c +++ b/src/lv_objx/lv_img.c @@ -384,7 +384,7 @@ static bool lv_img_design(lv_obj_t * img, const lv_area_t * mask, lv_design_mode lv_style_t style_mod; lv_style_copy(&style_mod, style); style_mod.text.color = style->image.color; - lv_draw_label(&coords, mask, &style_mod, opa_scale, ext->src, LV_TXT_FLAG_NONE, NULL, NULL, NULL); + lv_draw_label(&coords, mask, &style_mod, opa_scale, ext->src, LV_TXT_FLAG_NONE, NULL, NULL, NULL, lv_obj_get_base_dir(img)); } else { /*Trigger the error handler of image drawer*/ LV_LOG_WARN("lv_img_design: image source type is unknown"); diff --git a/src/lv_objx/lv_imgbtn.c b/src/lv_objx/lv_imgbtn.c index 9f90009a6..69f97f450 100644 --- a/src/lv_objx/lv_imgbtn.c +++ b/src/lv_objx/lv_imgbtn.c @@ -304,7 +304,7 @@ static bool lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * mask, lv_desig #if LV_IMGBTN_TILED == 0 const void * src = ext->img_src[state]; if(lv_img_src_get_type(src) == LV_IMG_SRC_SYMBOL) { - lv_draw_label(&imgbtn->coords, mask, style, opa_scale, src, LV_TXT_FLAG_NONE, NULL, NULL, NULL); + lv_draw_label(&imgbtn->coords, mask, style, opa_scale, src, LV_TXT_FLAG_NONE, NULL, NULL, NULL, lv_obj_get_base_dir(imgbtn)); } else { lv_draw_img(&imgbtn->coords, mask, src, style, opa_scale); } diff --git a/src/lv_objx/lv_kb.c b/src/lv_objx/lv_kb.c index 1c896ba6a..1913316a2 100644 --- a/src/lv_objx/lv_kb.c +++ b/src/lv_objx/lv_kb.c @@ -131,6 +131,7 @@ lv_obj_t * lv_kb_create(lv_obj_t * par, const lv_obj_t * copy) lv_obj_set_event_cb(new_kb, lv_kb_def_event_cb); lv_btnm_set_map(new_kb, kb_map_lc); lv_btnm_set_ctrl_map(new_kb, kb_ctrl_lc_map); + lv_obj_set_base_dir(new_kb, LV_BIDI_DIR_LTR); /*Set the default styles*/ lv_theme_t * th = lv_theme_get_current(); diff --git a/src/lv_objx/lv_label.c b/src/lv_objx/lv_label.c index c9f3b81a1..bd99c10c8 100644 --- a/src/lv_objx/lv_label.c +++ b/src/lv_objx/lv_label.c @@ -14,6 +14,7 @@ #include "../lv_core/lv_group.h" #include "../lv_misc/lv_color.h" #include "../lv_misc/lv_math.h" +#include "../lv_misc/lv_bidi.h" #include "../lv_misc/lv_printf.h" /********************* @@ -92,7 +93,7 @@ lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy) ext->static_txt = 0; ext->recolor = 0; ext->body_draw = 0; - ext->align = LV_LABEL_ALIGN_LEFT; + ext->align = LV_LABEL_ALIGN_AUTO; ext->dot_end = LV_LABEL_DOT_END_INV; ext->long_mode = LV_LABEL_LONG_EXPAND; #if LV_USE_ANIMATION @@ -205,7 +206,9 @@ void lv_label_set_text(lv_obj_t * label, const char * text) if(ext->text == NULL) return; strcpy(ext->text, text); - ext->static_txt = 0; /*Now the text is dynamically allocated*/ + + /*Now the text is dynamically allocated*/ + ext->static_txt = 0; } lv_label_refr_text(label); @@ -506,7 +509,22 @@ lv_label_align_t lv_label_get_align(const lv_obj_t * label) LV_ASSERT_OBJ(label, LV_OBJX_NAME); lv_label_ext_t * ext = lv_obj_get_ext_attr(label); - return ext->align; + + lv_label_align_t align = ext->align; + + if(align == LV_LABEL_ALIGN_AUTO) { +#if LV_USE_BIDI + lv_bidi_dir_t base_dir = lv_obj_get_base_dir(label); + if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(ext->text); + + if(base_dir == LV_BIDI_DIR_LTR) align = LV_LABEL_ALIGN_LEFT; + else if (base_dir == LV_BIDI_DIR_RTL) align = LV_LABEL_ALIGN_RIGHT; +#else + align = LV_LABEL_ALIGN_LEFT; +#endif + } + + return align; } /** @@ -560,7 +578,7 @@ uint16_t lv_label_get_anim_speed(const lv_obj_t * label) * index (different in UTF-8) * @param pos store the result here (E.g. index = 0 gives 0;0 coordinates) */ -void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t * pos) +void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t char_id, lv_point_t * pos) { LV_ASSERT_OBJ(label, LV_OBJX_NAME); LV_ASSERT_NULL(pos); @@ -578,19 +596,22 @@ void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; - if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + + lv_label_align_t align = lv_label_get_align(label); + if(align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + if(align == LV_LABEL_ALIGN_RIGHT) flag |= LV_TXT_FLAG_RIGHT; /*If the width will be expanded the set the max length to very big */ if(ext->long_mode == LV_LABEL_LONG_EXPAND) { max_w = LV_COORD_MAX; } - index = lv_txt_encoded_get_byte_id(txt, index); + uint16_t byte_id = lv_txt_encoded_get_byte_id(txt, char_id); /*Search the line of the index letter */; while(txt[new_line_start] != '\0') { new_line_start += lv_txt_get_next_line(&txt[line_start], font, style->text.letter_space, max_w, flag); - if(index < new_line_start || txt[new_line_start] == '\0') + if(byte_id < new_line_start || txt[new_line_start] == '\0') break; /*The line of 'index' letter begins at 'line_start'*/ y += letter_height + style->text.line_space; @@ -598,26 +619,50 @@ void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t } /*If the last character is line break then go to the next line*/ - if(index > 0) { - if((txt[index - 1] == '\n' || txt[index - 1] == '\r') && txt[index] == '\0') { + if(byte_id > 0) { + if((txt[byte_id - 1] == '\n' || txt[byte_id - 1] == '\r') && txt[byte_id] == '\0') { y += letter_height + style->text.line_space; - line_start = index; + line_start = byte_id; } } + const char *bidi_txt; + uint16_t visual_byte_pos; +#if LV_USE_BIDI + /*Handle Bidi*/ + if(new_line_start == byte_id) { + visual_byte_pos = byte_id - line_start; + bidi_txt = &txt[line_start]; + } + else { + uint16_t line_char_id = lv_txt_encoded_get_char_id(&txt[line_start], byte_id - line_start); + + bool is_rtl; + char *mutable_bidi_txt; + uint16_t visual_char_pos = lv_bidi_get_visual_pos(&txt[line_start], &mutable_bidi_txt, new_line_start - line_start, lv_obj_get_base_dir(label), line_char_id, &is_rtl); + bidi_txt = mutable_bidi_txt; + if (is_rtl) visual_char_pos++; + visual_byte_pos = lv_txt_encoded_get_byte_id(bidi_txt, visual_char_pos); + } +#else + bidi_txt = &txt[line_start]; + visual_byte_pos = byte_id - line_start; +#endif + + /*Calculate the x coordinate*/ - lv_coord_t x = lv_txt_get_width(&txt[line_start], index - line_start, font, style->text.letter_space, flag); + lv_coord_t x = lv_txt_get_width(bidi_txt, visual_byte_pos, font, style->text.letter_space, flag); - if(index != line_start) x += style->text.letter_space; + if(char_id != line_start) x += style->text.letter_space; - if(ext->align == LV_LABEL_ALIGN_CENTER) { + if(align == LV_LABEL_ALIGN_CENTER) { lv_coord_t line_w; - line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag); + line_w = lv_txt_get_width(bidi_txt, new_line_start - line_start, font, style->text.letter_space, flag); x += lv_obj_get_width(label) / 2 - line_w / 2; - } else if(ext->align == LV_LABEL_ALIGN_RIGHT) { + } else if(align == LV_LABEL_ALIGN_RIGHT) { lv_coord_t line_w; - line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag); + line_w = lv_txt_get_width(bidi_txt, new_line_start - line_start, font, style->text.letter_space, flag); x += lv_obj_get_width(label) - line_w; } @@ -647,10 +692,15 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos) uint8_t letter_height = lv_font_get_line_height(font); lv_coord_t y = 0; lv_txt_flag_t flag = LV_TXT_FLAG_NONE; + uint16_t logical_pos; + char *bidi_txt; if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; - if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + + lv_label_align_t align = lv_label_get_align(label); + if(align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + if(align == LV_LABEL_ALIGN_RIGHT) flag |= LV_TXT_FLAG_RIGHT; /*If the width will be expanded set the max length to very big */ if(ext->long_mode == LV_LABEL_LONG_EXPAND) { @@ -675,47 +725,72 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos) line_start = new_line_start; } +#if LV_USE_BIDI + bidi_txt = lv_draw_get_buf(new_line_start - line_start + 1); + uint16_t txt_len = new_line_start - line_start; + if(bidi_txt[new_line_start] == '\0') txt_len--; + lv_bidi_process_paragraph(txt + line_start, bidi_txt, txt_len, lv_obj_get_base_dir(label), NULL, 0); +#else + bidi_txt = txt + line_start; +#endif + /*Calculate the x coordinate*/ lv_coord_t x = 0; - if(ext->align == LV_LABEL_ALIGN_CENTER) { + if(align == LV_LABEL_ALIGN_CENTER) { lv_coord_t line_w; - line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag); + line_w = lv_txt_get_width(bidi_txt, new_line_start - line_start, font, style->text.letter_space, flag); x += lv_obj_get_width(label) / 2 - line_w / 2; } + else if(align == LV_LABEL_ALIGN_RIGHT) { + lv_coord_t line_w; + line_w = lv_txt_get_width(bidi_txt, new_line_start - line_start, font, style->text.letter_space, flag); + x += lv_obj_get_width(label) - line_w; + } lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; - uint32_t i = line_start; + uint32_t i = 0; uint32_t i_act = i; uint32_t letter; uint32_t letter_next; - while(i < new_line_start) { - /* Get the current letter.*/ - letter = lv_txt_encoded_next(txt, &i); + if(new_line_start > 0) { + while(i + line_start < new_line_start) { + /* Get the current letter.*/ + letter = lv_txt_encoded_next(bidi_txt, &i); - /*Get the next letter too for kerning*/ - letter_next = lv_txt_encoded_next(&txt[i], NULL); + /*Get the next letter too for kerning*/ + letter_next = lv_txt_encoded_next(&bidi_txt[i], NULL); - /*Handle the recolor command*/ - if((flag & LV_TXT_FLAG_RECOLOR) != 0) { - if(lv_txt_is_cmd(&cmd_state, txt[i]) != false) { - continue; /*Skip the letter is it is part of a command*/ + /*Handle the recolor command*/ + if((flag & LV_TXT_FLAG_RECOLOR) != 0) { + if(lv_txt_is_cmd(&cmd_state, bidi_txt[i]) != false) { + continue; /*Skip the letter is it is part of a command*/ + } } - } - x += lv_font_get_glyph_width(font, letter, letter_next); + x += lv_font_get_glyph_width(font, letter, letter_next); - /*Finish if the x position or the last char of the line is reached*/ - if(pos->x < x || i == new_line_start) { - i = i_act; - break; + /*Finish if the x position or the last char of the line is reached*/ + if(pos->x < x || i + line_start == new_line_start) { + i = i_act; + break; + } + x += style->text.letter_space; + i_act = i; } - x += style->text.letter_space; - i_act = i; } - return lv_encoded_get_char_id(txt, i); +#if LV_USE_BIDI + /*Handle Bidi*/ + bool is_rtl; + logical_pos = lv_bidi_get_logical_pos(&txt[line_start], NULL, txt_len, lv_obj_get_base_dir(label), lv_txt_encoded_get_char_id(bidi_txt, i), &is_rtl); + if (is_rtl) logical_pos++; +#else + logical_pos = lv_txt_encoded_get_char_id(bidi_txt, i); +#endif + + return logical_pos + lv_txt_encoded_get_char_id(txt, line_start); } /** @@ -776,10 +851,11 @@ bool lv_label_is_char_under_pos(const lv_obj_t * label, lv_point_t * pos) uint8_t letter_height = lv_font_get_line_height(font); lv_coord_t y = 0; lv_txt_flag_t flag = LV_TXT_FLAG_NONE; + lv_label_align_t align = lv_label_get_align(label); if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; - if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + if(align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; /*If the width will be expanded set the max length to very big */ if(ext->long_mode == LV_LABEL_LONG_EXPAND) { @@ -799,11 +875,16 @@ bool lv_label_is_char_under_pos(const lv_obj_t * label, lv_point_t * pos) /*Calculate the x coordinate*/ lv_coord_t x = 0; lv_coord_t last_x = 0; - if(ext->align == LV_LABEL_ALIGN_CENTER) { + if(align == LV_LABEL_ALIGN_CENTER) { lv_coord_t line_w; line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag); x += lv_obj_get_width(label) / 2 - line_w / 2; } + else if(align == LV_LABEL_ALIGN_RIGHT) { + lv_coord_t line_w; + line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag); + x += lv_obj_get_width(label) - line_w; + } lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; @@ -878,7 +959,6 @@ void lv_label_ins_text(lv_obj_t * label, uint32_t pos, const char * txt) } lv_txt_ins(ext->text, pos, txt); - lv_label_refr_text(label); } @@ -953,14 +1033,13 @@ static bool lv_label_design(lv_obj_t * label, const lv_area_t * mask, lv_design_ lv_draw_rect(&bg, mask, style, lv_obj_get_opa_scale(label)); } - /*TEST: draw a background for the label*/ - // lv_draw_rect(&label->coords, mask, &lv_style_plain_color, LV_OPA_COVER); + lv_label_align_t align = lv_label_get_align(label); lv_txt_flag_t flag = LV_TXT_FLAG_NONE; if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; - if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; - if(ext->align == LV_LABEL_ALIGN_RIGHT) flag |= LV_TXT_FLAG_RIGHT; + if(align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; + if(align == LV_LABEL_ALIGN_RIGHT) flag |= LV_TXT_FLAG_RIGHT; /* In ROLL mode the CENTER and RIGHT are pointless so remove them. * (In addition they will result mis-alignment is this case)*/ @@ -987,7 +1066,7 @@ static bool lv_label_design(lv_obj_t * label, const lv_area_t * mask, lv_design_ sel.start = lv_label_get_text_sel_start(label); sel.end = lv_label_get_text_sel_end(label); - lv_draw_label(&coords, mask, style, opa_scale, ext->text, flag, &ext->offset, &sel, hint); + lv_draw_label(&coords, mask, style, opa_scale, ext->text, flag, &ext->offset, &sel, hint, lv_obj_get_base_dir(label)); if(ext->long_mode == LV_LABEL_LONG_SROLL_CIRC) { @@ -1003,14 +1082,14 @@ static bool lv_label_design(lv_obj_t * label, const lv_area_t * mask, lv_design_ lv_font_get_glyph_width(style->text.font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT; ofs.y = ext->offset.y; - lv_draw_label(&coords, mask, style, opa_scale, ext->text, flag, &ofs, &sel, NULL); + lv_draw_label(&coords, mask, style, opa_scale, ext->text, flag, &ofs, &sel, NULL, lv_obj_get_base_dir(label)); } /*Draw the text again below the original to make an circular effect */ if(size.y > lv_obj_get_height(label)) { ofs.x = ext->offset.x; ofs.y = ext->offset.y + size.y + lv_font_get_line_height(style->text.font); - lv_draw_label(&coords, mask, style, opa_scale, ext->text, flag, &ofs, &sel, NULL); + lv_draw_label(&coords, mask, style, opa_scale, ext->text, flag, &ofs, &sel, NULL, lv_obj_get_base_dir(label)); } } } @@ -1061,6 +1140,18 @@ static lv_res_t lv_label_signal(lv_obj_t * label, lv_signal_t sign, void * param label->ext_draw_pad = LV_MATH_MAX(label->ext_draw_pad, style->body.padding.bottom); } } + else if(sign == LV_SIGNAL_BASE_DIR_CHG) { +#if LV_USE_BIDI + if(ext->static_txt == 0) lv_label_set_text(label, NULL); +#endif + } else if(sign == LV_SIGNAL_GET_TYPE) { + lv_obj_type_t * buf = param; + uint8_t i; + for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ + if(buf->type[i] == NULL) break; + } + buf->type[i] = "lv_label"; + } return res; } @@ -1144,11 +1235,12 @@ static void lv_label_refr_text(lv_obj_t * label) /*In roll inf. mode keep the size but start offset animations*/ else if(ext->long_mode == LV_LABEL_LONG_SROLL_CIRC) { #if LV_USE_ANIMATION + lv_label_align_t align = lv_label_get_align(label); + lv_anim_t anim; anim.var = label; anim.repeat = 1; anim.playback = 0; - anim.start = 0; anim.act_time = -(((lv_font_get_glyph_width(style->text.font, ' ', ' ') + style->text.letter_space) * 1000) / ext->anim_speed) * LV_LABEL_WAIT_CHAR_COUNT; @@ -1159,7 +1251,14 @@ static void lv_label_refr_text(lv_obj_t * label) bool hor_anim = false; if(size.x > lv_obj_get_width(label)) { - anim.end = -size.x - lv_font_get_glyph_width(font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT; + if(align == LV_LABEL_ALIGN_RIGHT) { + anim.end = 0; + anim.start = -size.x - lv_font_get_glyph_width(font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT; + } else { + anim.start = 0; + anim.end = -size.x - lv_font_get_glyph_width(font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT; + } + anim.exec_cb = (lv_anim_exec_xcb_t)lv_label_set_offset_x; anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); lv_anim_create(&anim); @@ -1171,7 +1270,14 @@ static void lv_label_refr_text(lv_obj_t * label) } if(size.y > lv_obj_get_height(label) && hor_anim == false) { - anim.end = -size.y - (lv_font_get_line_height(font)); + if(align == LV_LABEL_ALIGN_RIGHT) { + anim.end = 0; + anim.start = -size.y - (lv_font_get_line_height(font)); + } else { + anim.start = 0; + anim.end = -size.y - (lv_font_get_line_height(font)); + } + anim.exec_cb = (lv_anim_exec_xcb_t)lv_label_set_offset_y; anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); lv_anim_create(&anim); diff --git a/src/lv_objx/lv_label.h b/src/lv_objx/lv_label.h index a5eafd48f..faa21684f 100644 --- a/src/lv_objx/lv_label.h +++ b/src/lv_objx/lv_label.h @@ -60,6 +60,7 @@ enum { LV_LABEL_ALIGN_LEFT, /**< Align text to left */ LV_LABEL_ALIGN_CENTER, /**< Align text to center */ LV_LABEL_ALIGN_RIGHT, /**< Align text to right */ + LV_LABEL_ALIGN_AUTO, /**< Use LEFT or RIGHT depending on the direction of the text (LTR/RTL)*/ }; typedef uint8_t lv_label_align_t; @@ -68,12 +69,13 @@ typedef struct { /*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/ /*New data for this type */ - char * text; /*Text of the label*/ + char * text; /*Text of the label*/ + union { char * tmp_ptr; /* Pointer to the allocated memory containing the character which are replaced by dots (Handled by the library)*/ - char tmp[sizeof(char *)]; /* Directly store the characters if <=4 characters */ + char tmp[LV_LABEL_DOT_NUM + 1]; /* Directly store the characters if <=4 characters */ } dot; uint16_t dot_end; /*The text end position in dot mode (Handled by the library)*/ lv_point_t offset; /*Text draw position offset*/ diff --git a/src/lv_objx/lv_list.c b/src/lv_objx/lv_list.c index 10b31816e..2732428c9 100644 --- a/src/lv_objx/lv_list.c +++ b/src/lv_objx/lv_list.c @@ -218,7 +218,8 @@ lv_obj_t * lv_list_add_btn(lv_obj_t * list, const void * img_src, const char * t lv_label_set_text(label, txt); lv_obj_set_click(label, false); lv_label_set_long_mode(label, LV_LABEL_LONG_SROLL_CIRC); - lv_obj_set_width(label, liste->coords.x2 - label->coords.x1 - btn_hor_pad); + if(lv_obj_get_base_dir(liste) == LV_BIDI_DIR_RTL) lv_obj_set_width(label, label->coords.x2 - liste->coords.x1 - btn_hor_pad); + else lv_obj_set_width(label, liste->coords.x2 - label->coords.x1 - btn_hor_pad); if(label_signal == NULL) label_signal = lv_obj_get_signal_cb(label); } #if LV_USE_GROUP diff --git a/src/lv_objx/lv_page.c b/src/lv_objx/lv_page.c index 64f6ba923..b0d308d65 100644 --- a/src/lv_objx/lv_page.c +++ b/src/lv_objx/lv_page.c @@ -828,8 +828,10 @@ static lv_res_t lv_page_signal(lv_obj_t * page, lv_signal_t sign, void * param) lv_page_ext_t * ext = lv_obj_get_ext_attr(page); lv_obj_t * child; if(sign == LV_SIGNAL_CHILD_CHG) { /*Automatically move children to the scrollable object*/ - const lv_style_t * style = lv_page_get_style(page, LV_PAGE_STYLE_SCRL); + const lv_style_t * style_bg = lv_page_get_style(page, LV_PAGE_STYLE_BG); + const lv_style_t * style_scrl = lv_page_get_style(page, LV_PAGE_STYLE_SCRL); lv_fit_t fit_left = lv_page_get_scrl_fit_left(page); + lv_fit_t fit_right = lv_page_get_scrl_fit_right(page); lv_fit_t fit_top = lv_page_get_scrl_fit_top(page); child = lv_obj_get_child(page, NULL); while(child != NULL) { @@ -837,15 +839,19 @@ static lv_res_t lv_page_signal(lv_obj_t * page, lv_signal_t sign, void * param) lv_obj_t * tmp = child; child = lv_obj_get_child(page, child); /*Get the next child before move this*/ - /* Reposition the child to take padding into account (Only if it's on (0;0) now) + /* Reposition the child to take padding into account (Only if it's on (0;0) or (widht;height) coordinates now) * It's required to keep new the object on the same coordinate if FIT is enabled.*/ if((tmp->coords.x1 == page->coords.x1) && (fit_left == LV_FIT_TIGHT || fit_left == LV_FIT_FILL)) { - tmp->coords.x1 += style->body.padding.left; - tmp->coords.x2 += style->body.padding.left; + tmp->coords.x1 += style_scrl->body.padding.left; + tmp->coords.x2 += style_scrl->body.padding.left; + } + else if((tmp->coords.x2 == page->coords.x2) && (fit_right == LV_FIT_TIGHT || fit_right == LV_FIT_FILL)) { + tmp->coords.x1 -= style_scrl->body.padding.right + style_bg->body.padding.right; + tmp->coords.x2 -= style_scrl->body.padding.right + style_bg->body.padding.right; } if((tmp->coords.y1 == page->coords.y1) && (fit_top == LV_FIT_TIGHT || fit_top == LV_FIT_FILL)) { - tmp->coords.y1 += style->body.padding.top; - tmp->coords.y2 += style->body.padding.top; + tmp->coords.y1 += style_scrl->body.padding.top; + tmp->coords.y2 += style_scrl->body.padding.top; } lv_obj_set_parent(tmp, ext->scrl); } else { diff --git a/src/lv_objx/lv_roller.c b/src/lv_objx/lv_roller.c index 618192516..e098b18ba 100644 --- a/src/lv_objx/lv_roller.c +++ b/src/lv_objx/lv_roller.c @@ -397,7 +397,7 @@ static bool lv_roller_design(lv_obj_t * roller, const lv_area_t * mask, lv_desig new_style.text.color = sel_style->text.color; new_style.text.opa = sel_style->text.opa; lv_draw_label(&ext->ddlist.label->coords, &mask_sel, &new_style, opa_scale, - lv_label_get_text(ext->ddlist.label), txt_align, NULL, NULL, NULL); + lv_label_get_text(ext->ddlist.label), txt_align, NULL, NULL, NULL, lv_obj_get_base_dir(ext->ddlist.label)); } } diff --git a/src/lv_objx/lv_ta.c b/src/lv_objx/lv_ta.c index 2922fcae5..4e3560de0 100644 --- a/src/lv_objx/lv_ta.c +++ b/src/lv_objx/lv_ta.c @@ -1391,7 +1391,7 @@ static bool lv_ta_scrollable_design(lv_obj_t * scrl, const lv_area_t * mask, lv_ cur_area.x1 += cur_style.body.padding.left; cur_area.y1 += cur_style.body.padding.top; - lv_draw_label(&cur_area, mask, &cur_style, opa_scale, letter_buf, LV_TXT_FLAG_NONE, NULL, NULL, NULL); + lv_draw_label(&cur_area, mask, &cur_style, opa_scale, letter_buf, LV_TXT_FLAG_NONE, NULL, NULL, NULL, lv_obj_get_base_dir(ta)); } else if(ext->cursor.type == LV_CURSOR_OUTLINE) { cur_style.body.opa = LV_OPA_TRANSP; @@ -1855,53 +1855,53 @@ static void update_cursor_position_on_click(lv_obj_t * ta, lv_signal_t sign, lv_ lv_indev_get_vect(click_source, &vect_act); if(point_act.x < 0 || point_act.y < 0) return; /*Ignore event from keypad*/ - lv_point_t relative_position; - relative_position.x = point_act.x - label_coords.x1; - relative_position.y = point_act.y - label_coords.y1; + lv_point_t rel_pos; + rel_pos.x = point_act.x - label_coords.x1; + rel_pos.y = point_act.y - label_coords.y1; lv_coord_t label_width = lv_obj_get_width(ext->label); - uint16_t index_of_char_at_position; + uint16_t char_id_at_click; #if LV_LABEL_TEXT_SEL lv_label_ext_t * ext_label = lv_obj_get_ext_attr(ext->label); bool click_outside_label; /*Check if the click happened on the left side of the area outside the label*/ - if(relative_position.x < 0) { - index_of_char_at_position = 0; + if(rel_pos.x < 0) { + char_id_at_click = 0; click_outside_label = true; } /*Check if the click happened on the right side of the area outside the label*/ - else if(relative_position.x >= label_width) { - index_of_char_at_position = LV_TA_CURSOR_LAST; + else if(rel_pos.x >= label_width) { + char_id_at_click = LV_TA_CURSOR_LAST; click_outside_label = true; } else { - index_of_char_at_position = lv_label_get_letter_on(ext->label, &relative_position); - click_outside_label = !lv_label_is_char_under_pos(ext->label, &relative_position); + char_id_at_click = lv_label_get_letter_on(ext->label, &rel_pos); + click_outside_label = !lv_label_is_char_under_pos(ext->label, &rel_pos); } if(ext->text_sel_en) { if(!ext->text_sel_in_prog && !click_outside_label && sign == LV_SIGNAL_PRESSED) { /*Input device just went down. Store the selection start position*/ - ext->sel.start = index_of_char_at_position; - ext->sel.end = LV_DRAW_LABEL_NO_TXT_SEL; + ext->sel.start = char_id_at_click; + ext->sel.end = LV_LABEL_TEXT_SEL_OFF; ext->text_sel_in_prog = 1; lv_obj_set_drag(lv_page_get_scrl(ta), false); } else if(ext->text_sel_in_prog && sign == LV_SIGNAL_PRESSING) { /*Input device may be moving. Store the end position */ - ext->sel.end = index_of_char_at_position; + ext->sel.end = char_id_at_click; } else if(ext->text_sel_in_prog && (sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_RELEASED)) { /*Input device is released. Check if anything was selected.*/ lv_obj_set_drag(lv_page_get_scrl(ta), true); } } - if(ext->text_sel_in_prog || sign == LV_SIGNAL_PRESSED) lv_ta_set_cursor_pos(ta, index_of_char_at_position); + if(ext->text_sel_in_prog || sign == LV_SIGNAL_PRESSED) lv_ta_set_cursor_pos(ta, char_id_at_click); if(ext->text_sel_in_prog) { /*If the selected area has changed then update the real values and*/ - /*invalidate the text area.*/ + /*Invalidate the text area.*/ if(ext->sel.start > ext->sel.end) { if(ext_label->txt_sel_start != ext->sel.end || ext_label->txt_sel_end != ext->sel.start) { ext_label->txt_sel_start = ext->sel.end; @@ -1928,17 +1928,17 @@ static void update_cursor_position_on_click(lv_obj_t * ta, lv_signal_t sign, lv_ } #else /*Check if the click happened on the left side of the area outside the label*/ - if(relative_position.x < 0) { - index_of_char_at_position = 0; + if(rel_pos.x < 0) { + char_id_at_click = 0; } /*Check if the click happened on the right side of the area outside the label*/ - else if(relative_position.x >= label_width) { - index_of_char_at_position = LV_TA_CURSOR_LAST; + else if(rel_pos.x >= label_width) { + char_id_at_click = LV_TA_CURSOR_LAST; } else { - index_of_char_at_position = lv_label_get_letter_on(ext->label, &relative_position); + char_id_at_click = lv_label_get_letter_on(ext->label, &rel_pos); } - if(sign == LV_SIGNAL_PRESSED) lv_ta_set_cursor_pos(ta, index_of_char_at_position); + if(sign == LV_SIGNAL_PRESSED) lv_ta_set_cursor_pos(ta, char_id_at_click); #endif } diff --git a/src/lv_objx/lv_table.c b/src/lv_objx/lv_table.c index cedd7d65d..79cdc777e 100644 --- a/src/lv_objx/lv_table.c +++ b/src/lv_objx/lv_table.c @@ -151,14 +151,23 @@ void lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const } /*Initialize the format byte*/ else { - format.s.align = LV_LABEL_ALIGN_LEFT; +#if LV_USE_BIDI + lv_bidi_dir_t base_dir = lv_obj_get_base_dir(table); + if(base_dir == LV_BIDI_DIR_LTR) format.s.align = LV_LABEL_ALIGN_LEFT; + else if(base_dir == LV_BIDI_DIR_RTL) format.s.align = LV_LABEL_ALIGN_RIGHT; + else if(base_dir == LV_BIDI_DIR_AUTO) format.s.align = lv_bidi_detect_base_dir(txt); +#else + format.s.align = LV_LABEL_ALIGN_LEFT; +#endif + format.s.right_merge = 0; format.s.type = 0; format.s.crop = 0; } ext->cell_data[cell] = lv_mem_realloc(ext->cell_data[cell], strlen(txt) + 2); /*+1: trailing '\0; +1: format byte*/ - strcpy(ext->cell_data[cell] + 1, txt); /*Leave the format byte*/ + strcpy(ext->cell_data[cell] + 1, txt); /*+1 to skip the format byte*/ + ext->cell_data[cell][0] = format.format_byte; refr_size(table); } @@ -729,7 +738,7 @@ static bool lv_table_design(lv_obj_t * table, const lv_area_t * mask, lv_design_ label_mask_ok = lv_area_intersect(&label_mask, mask, &cell_area); if(label_mask_ok) { lv_draw_label(&txt_area, &label_mask, cell_style, opa_scale, ext->cell_data[cell] + 1, - txt_flags, NULL, NULL, NULL); + txt_flags, NULL, NULL, NULL, lv_obj_get_base_dir(table)); } /*Draw lines after '\n's*/ lv_point_t p1; diff --git a/src/lv_objx/lv_tabview.c b/src/lv_objx/lv_tabview.c index 19924b19b..8f323facb 100644 --- a/src/lv_objx/lv_tabview.c +++ b/src/lv_objx/lv_tabview.c @@ -147,7 +147,7 @@ lv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy) lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_TGL_PR, th->style.tabview.btn.tgl_pr); } else { lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BG, &lv_style_plain); - lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_BG, &lv_style_transp); + lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_BG, &lv_style_pretty);//transp); lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_INDIC, &lv_style_plain_color); } } @@ -222,8 +222,8 @@ lv_obj_t * lv_tabview_add_tab(lv_obj_t * tabview, const char * name) lv_obj_t * h = lv_page_create(ext->content, NULL); lv_obj_set_size(h, lv_obj_get_width(tabview), lv_obj_get_height(ext->content)); lv_page_set_sb_mode(h, LV_SB_MODE_AUTO); - lv_page_set_style(h, LV_PAGE_STYLE_BG, &lv_style_transp); - lv_page_set_style(h, LV_PAGE_STYLE_SCRL, &lv_style_transp); + lv_page_set_style(h, LV_PAGE_STYLE_BG, &lv_style_transp_tight); + lv_page_set_style(h, LV_PAGE_STYLE_SCRL, &lv_style_transp);//plain_color); if(page_signal == NULL) page_signal = lv_obj_get_signal_cb(h); if(page_scrl_signal == NULL) page_scrl_signal = lv_obj_get_signal_cb(lv_page_get_scrl(h)); @@ -351,6 +351,10 @@ void lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, lv_anim_enable_t an ext->tab_cur = id; + if(lv_obj_get_base_dir(tabview) == LV_BIDI_DIR_RTL) { + id = (ext->tab_cnt - (id + 1)); + } + lv_coord_t cont_x; switch(ext->btns_pos) { @@ -910,7 +914,11 @@ static void tabpage_pressing_handler(lv_obj_t * tabview, lv_obj_t * tabpage) p = ((tabpage->coords.x1 - tabview->coords.x1) * (indic_size + tabs_style->body.padding.inner)) / lv_obj_get_width(tabview); - lv_obj_set_x(ext->indic, indic_size * ext->tab_cur + tabs_style->body.padding.inner * ext->tab_cur + + uint16_t id = ext->tab_cur; + if(lv_obj_get_base_dir(tabview) == LV_BIDI_DIR_RTL) { + id = (ext->tab_cnt - (id + 1)); + } + lv_obj_set_x(ext->indic, indic_size * id + tabs_style->body.padding.inner * id + indic_style->body.padding.left - p); break; case LV_TABVIEW_BTNS_POS_LEFT: @@ -953,13 +961,18 @@ static void tabpage_press_lost_handler(lv_obj_t * tabview, lv_obj_t * tabpage) lv_coord_t page_x2 = page_x1 + lv_obj_get_width(tabpage); lv_coord_t treshold = lv_obj_get_width(tabview) / 2; - uint16_t tab_cur = ext->tab_cur; + int16_t tab_cur = ext->tab_cur; if(page_x1 > treshold) { - if(tab_cur != 0) tab_cur--; + if(lv_obj_get_base_dir(tabview) == LV_BIDI_DIR_RTL) tab_cur++; + else tab_cur--; } else if(page_x2 < treshold) { - if(tab_cur < ext->tab_cnt - 1) tab_cur++; + if(lv_obj_get_base_dir(tabview) == LV_BIDI_DIR_RTL) tab_cur--; + else tab_cur++; } + if(tab_cur > ext->tab_cnt - 1) tab_cur = ext->tab_cnt - 1; + else if(tab_cur < 0) tab_cur = 0; + uint32_t id_prev = lv_tabview_get_tab_act(tabview); lv_tabview_set_tab_act(tabview, tab_cur, LV_ANIM_ON); uint32_t id_new = lv_tabview_get_tab_act(tabview);