acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
lv_bidi.c (22834B)
1 /** 2 * @file lv_bidi.c 3 * 4 */ 5 6 /********************* 7 * INCLUDES 8 *********************/ 9 #include <stddef.h> 10 #include "lv_bidi.h" 11 #include "lv_txt.h" 12 #include "../misc/lv_mem.h" 13 14 #if LV_USE_BIDI 15 16 /********************* 17 * DEFINES 18 *********************/ 19 #define LV_BIDI_BRACKLET_DEPTH 4 20 21 // Highest bit of the 16-bit pos_conv value specifies whether this pos is RTL or not 22 #define GET_POS(x) ((x) & 0x7FFF) 23 #define IS_RTL_POS(x) (((x) & 0x8000) != 0) 24 #define SET_RTL_POS(x, is_rtl) (GET_POS(x) | ((is_rtl)? 0x8000: 0)) 25 26 /********************** 27 * TYPEDEFS 28 **********************/ 29 typedef struct { 30 uint32_t bracklet_pos; 31 lv_base_dir_t dir; 32 } bracket_stack_t; 33 34 /********************** 35 * STATIC PROTOTYPES 36 **********************/ 37 38 static uint32_t lv_bidi_get_next_paragraph(const char * txt); 39 static lv_base_dir_t lv_bidi_get_letter_dir(uint32_t letter); 40 static bool lv_bidi_letter_is_weak(uint32_t letter); 41 static bool lv_bidi_letter_is_rtl(uint32_t letter); 42 static bool lv_bidi_letter_is_neutral(uint32_t letter); 43 44 static lv_base_dir_t get_next_run(const char * txt, lv_base_dir_t base_dir, uint32_t max_len, uint32_t * len, 45 uint16_t * pos_conv_len); 46 static void rtl_reverse(char * dest, const char * src, uint32_t len, uint16_t * pos_conv_out, uint16_t pos_conv_rd_base, 47 uint16_t pos_conv_len); 48 static uint32_t char_change_to_pair(uint32_t letter); 49 static lv_base_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32_t len, uint32_t letter, 50 lv_base_dir_t base_dir); 51 static void fill_pos_conv(uint16_t * out, uint16_t len, uint16_t index); 52 static uint32_t get_txt_len(const char * txt, uint32_t max_len); 53 54 /********************** 55 * STATIC VARIABLES 56 **********************/ 57 static const uint8_t bracket_left[] = {"<({["}; 58 static const uint8_t bracket_right[] = {">)}]"}; 59 static bracket_stack_t br_stack[LV_BIDI_BRACKLET_DEPTH]; 60 static uint8_t br_stack_p; 61 62 /********************** 63 * MACROS 64 **********************/ 65 66 /********************** 67 * GLOBAL FUNCTIONS 68 **********************/ 69 70 /** 71 * Convert a text to get the characters in the correct visual order according to 72 * Unicode Bidirectional Algorithm 73 * @param str_in the text to process 74 * @param str_out store the result here. Has the be `strlen(str_in)` length 75 * @param base_dir `LV_BASE_DIR_LTR` or `LV_BASE_DIR_RTL` 76 */ 77 void _lv_bidi_process(const char * str_in, char * str_out, lv_base_dir_t base_dir) 78 { 79 if(base_dir == LV_BASE_DIR_AUTO) base_dir = _lv_bidi_detect_base_dir(str_in); 80 81 uint32_t par_start = 0; 82 uint32_t par_len; 83 84 while(str_in[par_start] == '\n' || str_in[par_start] == '\r') { 85 str_out[par_start] = str_in[par_start]; 86 par_start ++; 87 } 88 89 while(str_in[par_start] != '\0') { 90 par_len = lv_bidi_get_next_paragraph(&str_in[par_start]); 91 _lv_bidi_process_paragraph(&str_in[par_start], &str_out[par_start], par_len, base_dir, NULL, 0); 92 par_start += par_len; 93 94 while(str_in[par_start] == '\n' || str_in[par_start] == '\r') { 95 str_out[par_start] = str_in[par_start]; 96 par_start ++; 97 } 98 } 99 100 str_out[par_start] = '\0'; 101 } 102 103 /** 104 * Auto-detect the direction of a text based on the first strong character 105 * @param txt the text to process 106 * @return `LV_BASE_DIR_LTR` or `LV_BASE_DIR_RTL` 107 */ 108 lv_base_dir_t _lv_bidi_detect_base_dir(const char * txt) 109 { 110 uint32_t i = 0; 111 uint32_t letter; 112 while(txt[i] != '\0') { 113 letter = _lv_txt_encoded_next(txt, &i); 114 115 lv_base_dir_t dir; 116 dir = lv_bidi_get_letter_dir(letter); 117 if(dir == LV_BASE_DIR_RTL || dir == LV_BASE_DIR_LTR) return dir; 118 } 119 120 /*If there were no strong char earlier return with the default base dir*/ 121 if(LV_BIDI_BASE_DIR_DEF == LV_BASE_DIR_AUTO) return LV_BASE_DIR_LTR; 122 else return LV_BIDI_BASE_DIR_DEF; 123 } 124 125 /** 126 * Get the logical position of a character in a line 127 * @param str_in the input string. Can be only one line. 128 * @param bidi_txt internally the text is bidi processed which buffer can be get here. 129 * If not required anymore has to freed with `lv_mem_free()` 130 * Can be `NULL` is unused 131 * @param len length of the line in character count 132 * @param base_dir base direction of the text: `LV_BASE_DIR_LTR` or `LV_BASE_DIR_RTL` 133 * @param visual_pos the visual character position which logical position should be get 134 * @param is_rtl tell the char at `visual_pos` is RTL or LTR context 135 * @return the logical character position 136 */ 137 uint16_t _lv_bidi_get_logical_pos(const char * str_in, char ** bidi_txt, uint32_t len, lv_base_dir_t base_dir, 138 uint32_t visual_pos, bool * is_rtl) 139 { 140 uint32_t pos_conv_len = get_txt_len(str_in, len); 141 char * buf = lv_mem_buf_get(len + 1); 142 if(buf == NULL) return (uint16_t) -1; 143 144 uint16_t * pos_conv_buf = lv_mem_buf_get(pos_conv_len * sizeof(uint16_t)); 145 if(pos_conv_buf == NULL) { 146 lv_mem_buf_release(buf); 147 return (uint16_t) -1; 148 } 149 150 if(bidi_txt) *bidi_txt = buf; 151 152 _lv_bidi_process_paragraph(str_in, bidi_txt ? *bidi_txt : NULL, len, base_dir, pos_conv_buf, pos_conv_len); 153 154 if(is_rtl) *is_rtl = IS_RTL_POS(pos_conv_buf[visual_pos]); 155 156 if(bidi_txt == NULL) lv_mem_buf_release(buf); 157 uint16_t res = GET_POS(pos_conv_buf[visual_pos]); 158 lv_mem_buf_release(pos_conv_buf); 159 return res; 160 } 161 162 /** 163 * Get the visual position of a character in a line 164 * @param str_in the input string. Can be only one line. 165 * @param bidi_txt internally the text is bidi processed which buffer can be get here. 166 * If not required anymore has to freed with `lv_mem_free()` 167 * Can be `NULL` is unused 168 * @param len length of the line in character count 169 * @param base_dir base direction of the text: `LV_BASE_DIR_LTR` or `LV_BASE_DIR_RTL` 170 * @param logical_pos the logical character position which visual position should be get 171 * @param is_rtl tell the char at `logical_pos` is RTL or LTR context 172 * @return the visual character position 173 */ 174 uint16_t _lv_bidi_get_visual_pos(const char * str_in, char ** bidi_txt, uint16_t len, lv_base_dir_t base_dir, 175 uint32_t logical_pos, bool * is_rtl) 176 { 177 uint32_t pos_conv_len = get_txt_len(str_in, len); 178 char * buf = lv_mem_buf_get(len + 1); 179 if(buf == NULL) return (uint16_t) -1; 180 181 uint16_t * pos_conv_buf = lv_mem_buf_get(pos_conv_len * sizeof(uint16_t)); 182 if(pos_conv_buf == NULL) { 183 lv_mem_buf_release(buf); 184 return (uint16_t) -1; 185 } 186 187 if(bidi_txt) *bidi_txt = buf; 188 189 _lv_bidi_process_paragraph(str_in, bidi_txt ? *bidi_txt : NULL, len, base_dir, pos_conv_buf, pos_conv_len); 190 191 for(uint16_t i = 0; i < pos_conv_len; i++) { 192 if(GET_POS(pos_conv_buf[i]) == logical_pos) { 193 194 if(is_rtl) *is_rtl = IS_RTL_POS(pos_conv_buf[i]); 195 lv_mem_buf_release(pos_conv_buf); 196 197 if(bidi_txt == NULL) lv_mem_buf_release(buf); 198 return i; 199 } 200 } 201 lv_mem_buf_release(pos_conv_buf); 202 if(bidi_txt == NULL) lv_mem_buf_release(buf); 203 return (uint16_t) -1; 204 } 205 206 /** 207 * Bidi process a paragraph of text 208 * @param str_in the string to process 209 * @param str_out store the result here 210 * @param len length of the text 211 * @param base_dir base dir of the text 212 * @param pos_conv_out an `uint16_t` array to store the related logical position of the character. 213 * Can be `NULL` is unused 214 * @param pos_conv_len length of `pos_conv_out` in element count 215 */ 216 void _lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_base_dir_t base_dir, 217 uint16_t * pos_conv_out, uint16_t pos_conv_len) 218 { 219 uint32_t run_len = 0; 220 lv_base_dir_t run_dir; 221 uint32_t rd = 0; 222 uint32_t wr; 223 uint16_t pos_conv_run_len = 0; 224 uint16_t pos_conv_rd = 0; 225 uint16_t pos_conv_wr; 226 227 if(base_dir == LV_BASE_DIR_AUTO) base_dir = _lv_bidi_detect_base_dir(str_in); 228 if(base_dir == LV_BASE_DIR_RTL) { 229 wr = len; 230 pos_conv_wr = pos_conv_len; 231 } 232 else { 233 wr = 0; 234 pos_conv_wr = 0; 235 } 236 237 if(str_out) str_out[len] = '\0'; 238 239 lv_base_dir_t dir = base_dir; 240 241 /*Empty the bracket stack*/ 242 br_stack_p = 0; 243 244 /*Process neutral chars in the beginning*/ 245 while(rd < len) { 246 uint32_t letter = _lv_txt_encoded_next(str_in, &rd); 247 pos_conv_rd++; 248 dir = lv_bidi_get_letter_dir(letter); 249 if(dir == LV_BASE_DIR_NEUTRAL) dir = bracket_process(str_in, rd, len, letter, base_dir); 250 if(dir != LV_BASE_DIR_NEUTRAL && dir != LV_BASE_DIR_WEAK) break; 251 } 252 253 if(rd && str_in[rd] != '\0') { 254 _lv_txt_encoded_prev(str_in, &rd); 255 pos_conv_rd--; 256 } 257 258 if(rd) { 259 if(base_dir == LV_BASE_DIR_LTR) { 260 if(str_out) { 261 lv_memcpy(&str_out[wr], str_in, rd); 262 wr += rd; 263 } 264 if(pos_conv_out) { 265 fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_rd, 0); 266 pos_conv_wr += pos_conv_rd; 267 } 268 } 269 else { 270 wr -= rd; 271 pos_conv_wr -= pos_conv_rd; 272 rtl_reverse(str_out ? &str_out[wr] : NULL, str_in, rd, pos_conv_out ? &pos_conv_out[pos_conv_wr] : NULL, 0, 273 pos_conv_rd); 274 } 275 } 276 277 /*Get and process the runs*/ 278 279 while(rd < len && str_in[rd]) { 280 run_dir = get_next_run(&str_in[rd], base_dir, len - rd, &run_len, &pos_conv_run_len); 281 282 if(base_dir == LV_BASE_DIR_LTR) { 283 if(run_dir == LV_BASE_DIR_LTR) { 284 if(str_out) lv_memcpy(&str_out[wr], &str_in[rd], run_len); 285 if(pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_run_len, pos_conv_rd); 286 } 287 else rtl_reverse(str_out ? &str_out[wr] : NULL, &str_in[rd], run_len, pos_conv_out ? &pos_conv_out[pos_conv_wr] : NULL, 288 pos_conv_rd, pos_conv_run_len); 289 wr += run_len; 290 pos_conv_wr += pos_conv_run_len; 291 } 292 else { 293 wr -= run_len; 294 pos_conv_wr -= pos_conv_run_len; 295 if(run_dir == LV_BASE_DIR_LTR) { 296 if(str_out) lv_memcpy(&str_out[wr], &str_in[rd], run_len); 297 if(pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_run_len, pos_conv_rd); 298 } 299 else rtl_reverse(str_out ? &str_out[wr] : NULL, &str_in[rd], run_len, pos_conv_out ? &pos_conv_out[pos_conv_wr] : NULL, 300 pos_conv_rd, pos_conv_run_len); 301 } 302 303 rd += run_len; 304 pos_conv_rd += pos_conv_run_len; 305 } 306 } 307 308 void lv_bidi_calculate_align(lv_text_align_t * align, lv_base_dir_t * base_dir, const char * txt) 309 { 310 if(*base_dir == LV_BASE_DIR_AUTO) *base_dir = _lv_bidi_detect_base_dir(txt); 311 312 if(*align == LV_TEXT_ALIGN_AUTO) { 313 if(*base_dir == LV_BASE_DIR_RTL) *align = LV_TEXT_ALIGN_RIGHT; 314 else *align = LV_TEXT_ALIGN_LEFT; 315 } 316 } 317 318 /********************** 319 * STATIC FUNCTIONS 320 **********************/ 321 322 /** 323 * Get the next paragraph from a text 324 * @param txt the text to process 325 * @return the length of the current paragraph in byte count 326 */ 327 static uint32_t lv_bidi_get_next_paragraph(const char * txt) 328 { 329 uint32_t i = 0; 330 331 _lv_txt_encoded_next(txt, &i); 332 333 while(txt[i] != '\0' && txt[i] != '\n' && txt[i] != '\r') { 334 _lv_txt_encoded_next(txt, &i); 335 } 336 337 return i; 338 } 339 340 /** 341 * Get the direction of a character 342 * @param letter a Unicode character 343 * @return `LV_BASE_DIR_RTL/LTR/WEAK/NEUTRAL` 344 */ 345 static lv_base_dir_t lv_bidi_get_letter_dir(uint32_t letter) 346 { 347 if(lv_bidi_letter_is_rtl(letter)) return LV_BASE_DIR_RTL; 348 if(lv_bidi_letter_is_neutral(letter)) return LV_BASE_DIR_NEUTRAL; 349 if(lv_bidi_letter_is_weak(letter)) return LV_BASE_DIR_WEAK; 350 351 return LV_BASE_DIR_LTR; 352 } 353 /** 354 * Tell whether a character is weak or not 355 * @param letter a Unicode character 356 * @return true/false 357 */ 358 static bool lv_bidi_letter_is_weak(uint32_t letter) 359 { 360 uint32_t i = 0; 361 static const char weaks[] = "0123456789"; 362 363 do { 364 uint32_t x = _lv_txt_encoded_next(weaks, &i); 365 if(letter == x) { 366 return true; 367 } 368 } while(weaks[i] != '\0'); 369 370 return false; 371 } 372 /** 373 * Tell whether a character is RTL or not 374 * @param letter a Unicode character 375 * @return true/false 376 */ 377 static bool lv_bidi_letter_is_rtl(uint32_t letter) 378 { 379 if(letter >= 0x5d0 && letter <= 0x5ea) return true; 380 if(letter == 0x202E) return true; /*Unicode of LV_BIDI_RLO*/ 381 382 /*Check for Persian and Arabic characters [https://en.wikipedia.org/wiki/Arabic_script_in_Unicode]*/ 383 if(letter >= 0x600 && letter <= 0x6FF) return true; 384 if(letter >= 0xFB50 && letter <= 0xFDFF) return true; 385 if(letter >= 0xFE70 && letter <= 0xFEFF) return true; 386 387 return false; 388 } 389 390 /** 391 * Tell whether a character is neutral or not 392 * @param letter a Unicode character 393 * @return true/false 394 */ 395 static bool lv_bidi_letter_is_neutral(uint32_t letter) 396 { 397 uint16_t i; 398 static const char neutrals[] = " \t\n\r.,:;'\"`!?%/\\-=()[]{}<>@#&$|"; 399 for(i = 0; neutrals[i] != '\0'; i++) { 400 if(letter == (uint32_t)neutrals[i]) return true; 401 } 402 403 return false; 404 } 405 406 static uint32_t get_txt_len(const char * txt, uint32_t max_len) 407 { 408 uint32_t len = 0; 409 uint32_t i = 0; 410 411 while(i < max_len && txt[i] != '\0') { 412 _lv_txt_encoded_next(txt, &i); 413 len++; 414 } 415 416 return len; 417 } 418 419 static void fill_pos_conv(uint16_t * out, uint16_t len, uint16_t index) 420 { 421 uint16_t i; 422 for(i = 0; i < len; i++) { 423 out[i] = SET_RTL_POS(index, false); 424 index++; 425 } 426 } 427 428 static lv_base_dir_t get_next_run(const char * txt, lv_base_dir_t base_dir, uint32_t max_len, uint32_t * len, 429 uint16_t * pos_conv_len) 430 { 431 uint32_t i = 0; 432 uint32_t letter; 433 434 uint16_t pos_conv_i = 0; 435 436 letter = _lv_txt_encoded_next(txt, NULL); 437 lv_base_dir_t dir = lv_bidi_get_letter_dir(letter); 438 if(dir == LV_BASE_DIR_NEUTRAL) dir = bracket_process(txt, 0, max_len, letter, base_dir); 439 440 /*Find the first strong char. Skip the neutrals*/ 441 while(dir == LV_BASE_DIR_NEUTRAL || dir == LV_BASE_DIR_WEAK) { 442 letter = _lv_txt_encoded_next(txt, &i); 443 444 pos_conv_i++; 445 dir = lv_bidi_get_letter_dir(letter); 446 if(dir == LV_BASE_DIR_NEUTRAL) dir = bracket_process(txt, i, max_len, letter, base_dir); 447 448 if(dir == LV_BASE_DIR_LTR || dir == LV_BASE_DIR_RTL) break; 449 450 if(i >= max_len || txt[i] == '\0' || txt[i] == '\n' || txt[i] == '\r') { 451 *len = i; 452 *pos_conv_len = pos_conv_i; 453 return base_dir; 454 } 455 } 456 457 lv_base_dir_t run_dir = dir; 458 459 uint32_t i_prev = i; 460 uint32_t i_last_strong = i; 461 uint16_t pos_conv_i_prev = pos_conv_i; 462 uint16_t pos_conv_i_last_strong = pos_conv_i; 463 464 /*Find the next char which has different direction*/ 465 lv_base_dir_t next_dir = base_dir; 466 while(i_prev < max_len && txt[i] != '\0' && txt[i] != '\n' && txt[i] != '\r') { 467 letter = _lv_txt_encoded_next(txt, &i); 468 pos_conv_i++; 469 next_dir = lv_bidi_get_letter_dir(letter); 470 if(next_dir == LV_BASE_DIR_NEUTRAL) next_dir = bracket_process(txt, i, max_len, letter, base_dir); 471 472 if(next_dir == LV_BASE_DIR_WEAK) { 473 if(run_dir == LV_BASE_DIR_RTL) { 474 if(base_dir == LV_BASE_DIR_RTL) { 475 next_dir = LV_BASE_DIR_LTR; 476 } 477 } 478 } 479 480 /*New dir found?*/ 481 if((next_dir == LV_BASE_DIR_RTL || next_dir == LV_BASE_DIR_LTR) && next_dir != run_dir) { 482 /*Include neutrals if `run_dir == base_dir`*/ 483 if(run_dir == base_dir) { 484 *len = i_prev; 485 *pos_conv_len = pos_conv_i_prev; 486 } 487 /*Exclude neutrals if `run_dir != base_dir`*/ 488 else { 489 *len = i_last_strong; 490 *pos_conv_len = pos_conv_i_last_strong; 491 } 492 493 return run_dir; 494 } 495 496 if(next_dir != LV_BASE_DIR_NEUTRAL) { 497 i_last_strong = i; 498 pos_conv_i_last_strong = pos_conv_i; 499 } 500 501 i_prev = i; 502 pos_conv_i_prev = pos_conv_i; 503 } 504 505 /*Handle end of of string. Apply `base_dir` on trailing neutrals*/ 506 507 /*Include neutrals if `run_dir == base_dir`*/ 508 if(run_dir == base_dir) { 509 *len = i_prev; 510 *pos_conv_len = pos_conv_i_prev; 511 } 512 /*Exclude neutrals if `run_dir != base_dir`*/ 513 else { 514 *len = i_last_strong; 515 *pos_conv_len = pos_conv_i_last_strong; 516 } 517 518 return run_dir; 519 } 520 521 static void rtl_reverse(char * dest, const char * src, uint32_t len, uint16_t * pos_conv_out, uint16_t pos_conv_rd_base, 522 uint16_t pos_conv_len) 523 { 524 uint32_t i = len; 525 uint32_t wr = 0; 526 uint16_t pos_conv_i = pos_conv_len; 527 uint16_t pos_conv_wr = 0; 528 529 while(i) { 530 uint32_t letter = _lv_txt_encoded_prev(src, &i); 531 uint16_t pos_conv_letter = --pos_conv_i; 532 533 /*Keep weak letters (numbers) as LTR*/ 534 if(lv_bidi_letter_is_weak(letter)) { 535 uint32_t last_weak = i; 536 uint32_t first_weak = i; 537 uint16_t pos_conv_last_weak = pos_conv_i; 538 uint16_t pos_conv_first_weak = pos_conv_i; 539 while(i) { 540 letter = _lv_txt_encoded_prev(src, &i); 541 pos_conv_letter = --pos_conv_i; 542 543 /*No need to call `char_change_to_pair` because there not such chars here*/ 544 545 /*Finish on non-weak char*/ 546 /*but treat number and currency related chars as weak*/ 547 if(lv_bidi_letter_is_weak(letter) == false && letter != '.' && letter != ',' && letter != '$' && letter != '%') { 548 _lv_txt_encoded_next(src, &i); /*Rewind one letter*/ 549 pos_conv_i++; 550 first_weak = i; 551 pos_conv_first_weak = pos_conv_i; 552 break; 553 } 554 } 555 if(i == 0) { 556 first_weak = 0; 557 pos_conv_first_weak = 0; 558 } 559 560 if(dest) lv_memcpy(&dest[wr], &src[first_weak], last_weak - first_weak + 1); 561 if(pos_conv_out) fill_pos_conv(&pos_conv_out[pos_conv_wr], pos_conv_last_weak - pos_conv_first_weak + 1, 562 pos_conv_rd_base + pos_conv_first_weak); 563 wr += last_weak - first_weak + 1; 564 pos_conv_wr += pos_conv_last_weak - pos_conv_first_weak + 1; 565 } 566 567 /*Simply store in reversed order*/ 568 else { 569 uint32_t letter_size = _lv_txt_encoded_size((const char *)&src[i]); 570 /*Swap arithmetical symbols*/ 571 if(letter_size == 1) { 572 uint32_t new_letter = letter = char_change_to_pair(letter); 573 if(dest) dest[wr] = (uint8_t)new_letter; 574 if(pos_conv_out) pos_conv_out[pos_conv_wr] = SET_RTL_POS(pos_conv_rd_base + pos_conv_letter, true); 575 wr++; 576 pos_conv_wr++; 577 } 578 /*Just store the letter*/ 579 else { 580 if(dest) lv_memcpy(&dest[wr], &src[i], letter_size); 581 if(pos_conv_out) pos_conv_out[pos_conv_wr] = SET_RTL_POS(pos_conv_rd_base + pos_conv_i, true); 582 wr += letter_size; 583 pos_conv_wr++; 584 } 585 } 586 } 587 } 588 589 static uint32_t char_change_to_pair(uint32_t letter) 590 { 591 592 uint8_t i; 593 for(i = 0; bracket_left[i] != '\0'; i++) { 594 if(letter == bracket_left[i]) return bracket_right[i]; 595 } 596 597 for(i = 0; bracket_right[i] != '\0'; i++) { 598 if(letter == bracket_right[i]) return bracket_left[i]; 599 } 600 601 return letter; 602 } 603 604 static lv_base_dir_t bracket_process(const char * txt, uint32_t next_pos, uint32_t len, uint32_t letter, 605 lv_base_dir_t base_dir) 606 { 607 lv_base_dir_t bracket_dir = LV_BASE_DIR_NEUTRAL; 608 609 uint8_t i; 610 /*Is the letter an opening bracket?*/ 611 for(i = 0; bracket_left[i] != '\0'; i++) { 612 if(bracket_left[i] == letter) { 613 /*If so find its matching closing bracket. 614 *If a char with base dir. direction is found then the brackets will have `base_dir` direction*/ 615 uint32_t txt_i = next_pos; 616 while(txt_i < len) { 617 uint32_t letter_next = _lv_txt_encoded_next(txt, &txt_i); 618 if(letter_next == bracket_right[i]) { 619 /*Closing bracket found*/ 620 break; 621 } 622 else { 623 /*Save the dir*/ 624 lv_base_dir_t letter_dir = lv_bidi_get_letter_dir(letter_next); 625 if(letter_dir == base_dir) { 626 bracket_dir = base_dir; 627 } 628 } 629 } 630 631 /*There were no matching closing bracket*/ 632 if(txt_i > len) return LV_BASE_DIR_NEUTRAL; 633 634 /*There where a strong char with base dir in the bracket so the dir is found.*/ 635 if(bracket_dir != LV_BASE_DIR_NEUTRAL && bracket_dir != LV_BASE_DIR_WEAK) break; 636 637 /*If there were no matching strong chars in the brackets then check the previous chars*/ 638 txt_i = next_pos; 639 if(txt_i) _lv_txt_encoded_prev(txt, &txt_i); 640 while(txt_i > 0) { 641 uint32_t letter_next = _lv_txt_encoded_prev(txt, &txt_i); 642 lv_base_dir_t letter_dir = lv_bidi_get_letter_dir(letter_next); 643 if(letter_dir == LV_BASE_DIR_LTR || letter_dir == LV_BASE_DIR_RTL) { 644 bracket_dir = letter_dir; 645 break; 646 } 647 } 648 649 /*There where a previous strong char which can be used*/ 650 if(bracket_dir != LV_BASE_DIR_NEUTRAL) break; 651 652 /*There were no strong chars before the bracket, so use the base dir.*/ 653 if(txt_i == 0) bracket_dir = base_dir; 654 655 break; 656 } 657 } 658 659 /*The letter was an opening bracket*/ 660 if(bracket_left[i] != '\0') { 661 662 if(bracket_dir == LV_BASE_DIR_NEUTRAL || br_stack_p == LV_BIDI_BRACKLET_DEPTH) return LV_BASE_DIR_NEUTRAL; 663 664 br_stack[br_stack_p].bracklet_pos = i; 665 br_stack[br_stack_p].dir = bracket_dir; 666 667 br_stack_p++; 668 return bracket_dir; 669 } 670 else if(br_stack_p > 0) { 671 /*Is the letter a closing bracket of the last opening?*/ 672 if(letter == bracket_right[br_stack[br_stack_p - 1].bracklet_pos]) { 673 bracket_dir = br_stack[br_stack_p - 1].dir; 674 br_stack_p--; 675 return bracket_dir; 676 } 677 } 678 679 return LV_BASE_DIR_NEUTRAL; 680 } 681 682 #endif /*LV_USE_BIDI*/