charset.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /*
  19. Current problems with Unicode rendering:
  20. - B and BN bidi type characters (ignored)
  21. - Mc type characters with combining class 0 (poorly combined)
  22. - Mn type characters with combining class 0 (poorly combined)
  23. - Me type characters with combining class 0 (poorly combined)
  24. - Cf type characters (ignored)
  25. - Cc type characters (ignored)
  26. - Line-breaking rules (e.g. Zs type characters)
  27. - Indic languages
  28. - non-Semitic shaping (rarely used)
  29. - Zl and Zp characters
  30. - Combining characters of types 7, 8, 9, 21, 35, 36, 84, 91, 103, 107,
  31. 118, 122, 129, 130, 132, 218, 224, 226, 233, 234
  32. - Private use characters (not really a problem)
  33. - Variations (no font support)
  34. - Vertical text
  35. - Ligatures
  36. Font information ignored:
  37. - Kerning
  38. - Justification data
  39. - Glyph posititioning
  40. - Baseline data
  41. Most underline diacritics aren't displayed in gfxterm
  42. */
  43. #include <grub/charset.h>
  44. #include <grub/mm.h>
  45. #include <grub/misc.h>
  46. #include <grub/unicode.h>
  47. #include <grub/term.h>
  48. #include <grub/normal.h>
  49. #include <grub/safemath.h>
  50. #if HAVE_FONT_SOURCE
  51. #include "widthspec.h"
  52. #endif
  53. /* Returns -2 if not enough space, -1 on invalid character. */
  54. grub_ssize_t
  55. grub_encode_utf8_character (grub_uint8_t *dest, grub_uint8_t *destend,
  56. grub_uint32_t code)
  57. {
  58. if (dest >= destend)
  59. return -2;
  60. if (code <= 0x007F)
  61. {
  62. *dest++ = code;
  63. return 1;
  64. }
  65. if (code <= 0x07FF)
  66. {
  67. if (dest + 1 >= destend)
  68. return -2;
  69. *dest++ = (code >> 6) | 0xC0;
  70. *dest++ = (code & 0x3F) | 0x80;
  71. return 2;
  72. }
  73. if ((code >= 0xDC00 && code <= 0xDFFF)
  74. || (code >= 0xD800 && code <= 0xDBFF))
  75. {
  76. /* No surrogates in UCS-4... */
  77. return -1;
  78. }
  79. if (code < 0x10000)
  80. {
  81. if (dest + 2 >= destend)
  82. return -2;
  83. *dest++ = (code >> 12) | 0xE0;
  84. *dest++ = ((code >> 6) & 0x3F) | 0x80;
  85. *dest++ = (code & 0x3F) | 0x80;
  86. return 3;
  87. }
  88. {
  89. if (dest + 3 >= destend)
  90. return -2;
  91. *dest++ = (code >> 18) | 0xF0;
  92. *dest++ = ((code >> 12) & 0x3F) | 0x80;
  93. *dest++ = ((code >> 6) & 0x3F) | 0x80;
  94. *dest++ = (code & 0x3F) | 0x80;
  95. return 4;
  96. }
  97. }
  98. /* Convert UCS-4 to UTF-8. */
  99. grub_size_t
  100. grub_ucs4_to_utf8 (const grub_uint32_t *src, grub_size_t size,
  101. grub_uint8_t *dest, grub_size_t destsize)
  102. {
  103. /* Keep last char for \0. */
  104. grub_uint8_t *destend = dest + destsize - 1;
  105. grub_uint8_t *dest0 = dest;
  106. while (size-- && dest < destend)
  107. {
  108. grub_uint32_t code = *src++;
  109. grub_ssize_t s;
  110. s = grub_encode_utf8_character (dest, destend, code);
  111. if (s == -2)
  112. break;
  113. if (s == -1)
  114. {
  115. *dest++ = '?';
  116. continue;
  117. }
  118. dest += s;
  119. }
  120. *dest = 0;
  121. return dest - dest0;
  122. }
  123. /* Returns the number of bytes the string src would occupy is converted
  124. to UTF-8, excluding trailing \0. */
  125. grub_size_t
  126. grub_get_num_of_utf8_bytes (const grub_uint32_t *src, grub_size_t size)
  127. {
  128. grub_size_t remaining;
  129. const grub_uint32_t *ptr;
  130. grub_size_t cnt = 0;
  131. remaining = size;
  132. ptr = src;
  133. while (remaining--)
  134. {
  135. grub_uint32_t code = *ptr++;
  136. if (code <= 0x007F)
  137. cnt++;
  138. else if (code <= 0x07FF)
  139. cnt += 2;
  140. else if ((code >= 0xDC00 && code <= 0xDFFF)
  141. || (code >= 0xD800 && code <= 0xDBFF))
  142. /* No surrogates in UCS-4... */
  143. cnt++;
  144. else if (code < 0x10000)
  145. cnt += 3;
  146. else
  147. cnt += 4;
  148. }
  149. return cnt;
  150. }
  151. /* Convert UCS-4 to UTF-8. */
  152. char *
  153. grub_ucs4_to_utf8_alloc (const grub_uint32_t *src, grub_size_t size)
  154. {
  155. grub_uint8_t *ret;
  156. grub_size_t cnt = grub_get_num_of_utf8_bytes (src, size) + 1;
  157. ret = grub_malloc (cnt);
  158. if (!ret)
  159. return 0;
  160. grub_ucs4_to_utf8 (src, size, ret, cnt);
  161. return (char *) ret;
  162. }
  163. int
  164. grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize)
  165. {
  166. int count = 0;
  167. grub_uint32_t code = 0;
  168. while (srcsize)
  169. {
  170. if (srcsize != (grub_size_t)-1)
  171. srcsize--;
  172. if (!grub_utf8_process (*src++, &code, &count))
  173. return 0;
  174. if (count != 0)
  175. continue;
  176. if (code == 0)
  177. return 1;
  178. if (code > GRUB_UNICODE_LAST_VALID)
  179. return 0;
  180. }
  181. return 1;
  182. }
  183. grub_ssize_t
  184. grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg,
  185. grub_uint32_t **last_position)
  186. {
  187. grub_size_t msg_len = grub_strlen (msg);
  188. *unicode_msg = grub_calloc (msg_len, sizeof (grub_uint32_t));
  189. if (!*unicode_msg)
  190. return -1;
  191. msg_len = grub_utf8_to_ucs4 (*unicode_msg, msg_len,
  192. (grub_uint8_t *) msg, -1, 0);
  193. if (last_position)
  194. *last_position = *unicode_msg + msg_len;
  195. return msg_len;
  196. }
  197. /* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE
  198. bytes (if SRCSIZE is -1, it is ignored) in length to a UCS-4 string.
  199. Return the number of characters converted. DEST must be able to hold
  200. at least DESTSIZE characters.
  201. If SRCEND is not NULL, then *SRCEND is set to the next byte after the
  202. last byte used in SRC. */
  203. grub_size_t
  204. grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
  205. const grub_uint8_t *src, grub_size_t srcsize,
  206. const grub_uint8_t **srcend)
  207. {
  208. grub_uint32_t *p = dest;
  209. int count = 0;
  210. grub_uint32_t code = 0;
  211. if (srcend)
  212. *srcend = src;
  213. while (srcsize && destsize)
  214. {
  215. int was_count = count;
  216. if (srcsize != (grub_size_t)-1)
  217. srcsize--;
  218. if (!grub_utf8_process (*src++, &code, &count))
  219. {
  220. code = '?';
  221. count = 0;
  222. /* Character c may be valid, don't eat it. */
  223. if (was_count)
  224. src--;
  225. }
  226. if (count != 0)
  227. continue;
  228. if (code == 0)
  229. break;
  230. *p++ = code;
  231. destsize--;
  232. }
  233. if (srcend)
  234. *srcend = src;
  235. return p - dest;
  236. }
  237. static grub_uint8_t *join_types = NULL;
  238. static void
  239. unpack_join (void)
  240. {
  241. unsigned i;
  242. struct grub_unicode_compact_range *cur;
  243. join_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
  244. if (!join_types)
  245. {
  246. grub_errno = GRUB_ERR_NONE;
  247. return;
  248. }
  249. for (cur = grub_unicode_compact; cur->len; cur++)
  250. for (i = cur->start; i < cur->start + (unsigned) cur->len
  251. && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
  252. join_types[i] = cur->join_type;
  253. }
  254. static grub_uint8_t *bidi_types = NULL;
  255. static void
  256. unpack_bidi (void)
  257. {
  258. unsigned i;
  259. struct grub_unicode_compact_range *cur;
  260. bidi_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
  261. if (!bidi_types)
  262. {
  263. grub_errno = GRUB_ERR_NONE;
  264. return;
  265. }
  266. for (cur = grub_unicode_compact; cur->len; cur++)
  267. for (i = cur->start; i < cur->start + (unsigned) cur->len
  268. && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
  269. if (cur->bidi_mirror)
  270. bidi_types[i] = cur->bidi_type | 0x80;
  271. else
  272. bidi_types[i] = cur->bidi_type | 0x00;
  273. }
  274. static inline enum grub_bidi_type
  275. get_bidi_type (grub_uint32_t c)
  276. {
  277. struct grub_unicode_compact_range *cur;
  278. if (!bidi_types)
  279. unpack_bidi ();
  280. if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
  281. return bidi_types[c] & 0x7f;
  282. for (cur = grub_unicode_compact; cur->len; cur++)
  283. if (cur->start <= c && c < cur->start + (unsigned) cur->len)
  284. return cur->bidi_type;
  285. return GRUB_BIDI_TYPE_L;
  286. }
  287. static inline enum grub_join_type
  288. get_join_type (grub_uint32_t c)
  289. {
  290. struct grub_unicode_compact_range *cur;
  291. if (!join_types)
  292. unpack_join ();
  293. if (join_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
  294. return join_types[c];
  295. for (cur = grub_unicode_compact; cur->len; cur++)
  296. if (cur->start <= c && c < cur->start + (unsigned) cur->len)
  297. return cur->join_type;
  298. return GRUB_JOIN_TYPE_NONJOINING;
  299. }
  300. static inline int
  301. is_mirrored (grub_uint32_t c)
  302. {
  303. struct grub_unicode_compact_range *cur;
  304. if (!bidi_types)
  305. unpack_bidi ();
  306. if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
  307. return !!(bidi_types[c] & 0x80);
  308. for (cur = grub_unicode_compact; cur->len; cur++)
  309. if (cur->start <= c && c < cur->start + (unsigned) cur->len)
  310. return cur->bidi_mirror;
  311. return 0;
  312. }
  313. enum grub_comb_type
  314. grub_unicode_get_comb_type (grub_uint32_t c)
  315. {
  316. static grub_uint8_t *comb_types = NULL;
  317. struct grub_unicode_compact_range *cur;
  318. if (!comb_types)
  319. {
  320. unsigned i;
  321. comb_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
  322. if (comb_types)
  323. for (cur = grub_unicode_compact; cur->len; cur++)
  324. for (i = cur->start; i < cur->start + (unsigned) cur->len
  325. && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
  326. comb_types[i] = cur->comb_type;
  327. else
  328. grub_errno = GRUB_ERR_NONE;
  329. }
  330. if (comb_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
  331. return comb_types[c];
  332. for (cur = grub_unicode_compact; cur->len; cur++)
  333. if (cur->start <= c && c < cur->start + (unsigned) cur->len)
  334. return cur->comb_type;
  335. return GRUB_UNICODE_COMB_NONE;
  336. }
  337. #if HAVE_FONT_SOURCE
  338. grub_size_t
  339. grub_unicode_estimate_width (const struct grub_unicode_glyph *c)
  340. {
  341. if (grub_unicode_get_comb_type (c->base))
  342. return 0;
  343. if (((unsigned long) (c->base >> 3)) >= ARRAY_SIZE (widthspec))
  344. return 1;
  345. if (widthspec[c->base >> 3] & (1 << (c->base & 7)))
  346. return 2;
  347. else
  348. return 1;
  349. }
  350. #endif
  351. static inline int
  352. is_type_after (enum grub_comb_type a, enum grub_comb_type b)
  353. {
  354. /* Shadda is numerically higher than most of Arabic diacritics but has
  355. to be rendered before them. */
  356. if (a == GRUB_UNICODE_COMB_ARABIC_SHADDA
  357. && b <= GRUB_UNICODE_COMB_ARABIC_KASRA
  358. && b >= GRUB_UNICODE_COMB_ARABIC_FATHATAN)
  359. return 0;
  360. if (b == GRUB_UNICODE_COMB_ARABIC_SHADDA
  361. && a <= GRUB_UNICODE_COMB_ARABIC_KASRA
  362. && a >= GRUB_UNICODE_COMB_ARABIC_FATHATAN)
  363. return 1;
  364. return a > b;
  365. }
  366. grub_size_t
  367. grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
  368. struct grub_unicode_glyph *out)
  369. {
  370. int haveout = 0;
  371. const grub_uint32_t *ptr;
  372. unsigned last_comb_pointer = 0;
  373. grub_memset (out, 0, sizeof (*out));
  374. if (inlen && grub_iscntrl (*in))
  375. {
  376. out->base = *in;
  377. out->variant = 0;
  378. out->attributes = 0;
  379. out->ncomb = 0;
  380. out->estimated_width = 1;
  381. return 1;
  382. }
  383. for (ptr = in; ptr < in + inlen; ptr++)
  384. {
  385. /* Variation selectors >= 17 are outside of BMP and SMP.
  386. Handle variation selectors first to avoid potentially costly lookups.
  387. */
  388. if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1
  389. && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16)
  390. {
  391. if (haveout)
  392. out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_1 + 1;
  393. continue;
  394. }
  395. if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17
  396. && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256)
  397. {
  398. if (haveout)
  399. out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_17 + 17;
  400. continue;
  401. }
  402. enum grub_comb_type comb_type;
  403. comb_type = grub_unicode_get_comb_type (*ptr);
  404. if (comb_type)
  405. {
  406. struct grub_unicode_combining *n;
  407. unsigned j;
  408. grub_size_t sz;
  409. if (!haveout)
  410. continue;
  411. if (out->ncomb == GRUB_UNICODE_NCOMB_MAX)
  412. continue;
  413. if (comb_type == GRUB_UNICODE_COMB_MC
  414. || comb_type == GRUB_UNICODE_COMB_ME
  415. || comb_type == GRUB_UNICODE_COMB_MN)
  416. last_comb_pointer = out->ncomb;
  417. if (out->ncomb + 1 <= (int) ARRAY_SIZE (out->combining_inline))
  418. n = out->combining_inline;
  419. else if (out->ncomb > (int) ARRAY_SIZE (out->combining_inline))
  420. {
  421. if (grub_add (out->ncomb, 1, &sz) ||
  422. grub_mul (sz, sizeof (n[0]), &sz))
  423. goto fail;
  424. n = grub_realloc (out->combining_ptr, sz);
  425. if (!n)
  426. {
  427. fail:
  428. grub_errno = GRUB_ERR_NONE;
  429. continue;
  430. }
  431. out->combining_ptr = n;
  432. }
  433. else
  434. {
  435. n = grub_calloc (out->ncomb + 1, sizeof (n[0]));
  436. if (!n)
  437. {
  438. grub_errno = GRUB_ERR_NONE;
  439. continue;
  440. }
  441. grub_memcpy (n, out->combining_inline,
  442. sizeof (out->combining_inline));
  443. out->combining_ptr = n;
  444. }
  445. for (j = last_comb_pointer; j < out->ncomb; j++)
  446. if (is_type_after (n[j].type, comb_type))
  447. break;
  448. grub_memmove (n + j + 1,
  449. n + j,
  450. (out->ncomb - j)
  451. * sizeof (n[0]));
  452. n[j].code = *ptr;
  453. n[j].type = comb_type;
  454. out->ncomb++;
  455. continue;
  456. }
  457. if (haveout)
  458. return ptr - in;
  459. haveout = 1;
  460. out->base = *ptr;
  461. out->variant = 0;
  462. out->attributes = 0;
  463. out->ncomb = 0;
  464. out->estimated_width = 1;
  465. }
  466. return ptr - in;
  467. }
  468. static void
  469. revert (struct grub_unicode_glyph *visual,
  470. struct grub_term_pos *pos,
  471. unsigned start, unsigned end)
  472. {
  473. struct grub_unicode_glyph t;
  474. unsigned i;
  475. int a = 0, b = 0;
  476. if (pos)
  477. {
  478. a = pos[visual[start].orig_pos].x;
  479. b = pos[visual[end].orig_pos].x;
  480. }
  481. for (i = 0; i < (end - start) / 2 + 1; i++)
  482. {
  483. t = visual[start + i];
  484. visual[start + i] = visual[end - i];
  485. visual[end - i] = t;
  486. if (pos)
  487. {
  488. pos[visual[start + i].orig_pos].x = a + b - pos[visual[start + i].orig_pos].x;
  489. pos[visual[end - i].orig_pos].x = a + b - pos[visual[end - i].orig_pos].x;
  490. }
  491. }
  492. }
  493. static grub_ssize_t
  494. bidi_line_wrap (struct grub_unicode_glyph *visual_out,
  495. struct grub_unicode_glyph *visual,
  496. grub_size_t visual_len,
  497. grub_size_t (*getcharwidth) (const struct grub_unicode_glyph *visual, void *getcharwidth_arg),
  498. void *getcharwidth_arg,
  499. grub_size_t maxwidth, grub_size_t startwidth,
  500. grub_uint32_t contchar,
  501. struct grub_term_pos *pos, int primitive_wrap,
  502. grub_size_t log_end)
  503. {
  504. struct grub_unicode_glyph *outptr = visual_out;
  505. unsigned line_start = 0;
  506. grub_ssize_t line_width;
  507. unsigned k;
  508. grub_ssize_t last_space = -1;
  509. grub_ssize_t last_space_width = 0;
  510. int lines = 0;
  511. if (!visual_len)
  512. return 0;
  513. if (startwidth >= maxwidth && (grub_ssize_t) maxwidth > 0)
  514. {
  515. if (contchar)
  516. {
  517. grub_memset (outptr, 0, sizeof (visual[0]));
  518. outptr->base = contchar;
  519. outptr++;
  520. }
  521. grub_memset (outptr, 0, sizeof (visual[0]));
  522. outptr->base = '\n';
  523. outptr++;
  524. startwidth = 0;
  525. }
  526. line_width = startwidth;
  527. for (k = 0; k <= visual_len; k++)
  528. {
  529. grub_ssize_t last_width = 0;
  530. if (pos && k != visual_len)
  531. {
  532. pos[visual[k].orig_pos].x = line_width;
  533. pos[visual[k].orig_pos].y = lines;
  534. pos[visual[k].orig_pos].valid = 1;
  535. }
  536. if (k == visual_len && pos)
  537. {
  538. pos[log_end].x = line_width;
  539. pos[log_end].y = lines;
  540. pos[log_end].valid = 1;
  541. }
  542. if (getcharwidth && k != visual_len)
  543. line_width += last_width = getcharwidth (&visual[k], getcharwidth_arg);
  544. if (k != visual_len && (visual[k].base == ' '
  545. || visual[k].base == '\t')
  546. && !primitive_wrap)
  547. {
  548. last_space = k;
  549. last_space_width = line_width;
  550. }
  551. if (((grub_ssize_t) maxwidth > 0
  552. && line_width > (grub_ssize_t) maxwidth) || k == visual_len)
  553. {
  554. unsigned min_odd_level = 0xffffffff;
  555. unsigned max_level = 0;
  556. unsigned kk = k;
  557. lines++;
  558. if (k != visual_len && last_space > (signed) line_start)
  559. {
  560. kk = last_space;
  561. line_width -= last_space_width;
  562. }
  563. else if (k != visual_len && line_start == 0 && startwidth != 0
  564. && !primitive_wrap && lines == 1
  565. && line_width - startwidth < maxwidth)
  566. {
  567. kk = 0;
  568. line_width -= startwidth;
  569. }
  570. else
  571. line_width = last_width;
  572. {
  573. unsigned i;
  574. for (i = line_start; i < kk; i++)
  575. {
  576. if (visual[i].bidi_level > max_level)
  577. max_level = visual[i].bidi_level;
  578. if (visual[i].bidi_level < min_odd_level && (visual[i].bidi_level & 1))
  579. min_odd_level = visual[i].bidi_level;
  580. }
  581. }
  582. {
  583. unsigned j;
  584. /* FIXME: can be optimized. */
  585. for (j = max_level; j > min_odd_level - 1; j--)
  586. {
  587. unsigned in = line_start;
  588. unsigned i;
  589. for (i = line_start; i < kk; i++)
  590. {
  591. if (i != line_start && visual[i].bidi_level >= j
  592. && visual[i-1].bidi_level < j)
  593. in = i;
  594. if (visual[i].bidi_level >= j && (i + 1 == kk
  595. || visual[i+1].bidi_level < j))
  596. revert (visual, pos, in, i);
  597. }
  598. }
  599. }
  600. {
  601. unsigned i;
  602. for (i = line_start; i < kk; i++)
  603. {
  604. if (is_mirrored (visual[i].base) && visual[i].bidi_level)
  605. visual[i].attributes |= GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR;
  606. if ((visual[i].attributes & GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN)
  607. && visual[i].bidi_level)
  608. {
  609. int left, right;
  610. left = visual[i].attributes
  611. & (GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED
  612. | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT);
  613. right = visual[i].attributes
  614. & (GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
  615. | GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT);
  616. visual[i].attributes &= ~GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN;
  617. left <<= GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN_LEFT_TO_RIGHT_SHIFT;
  618. right >>= GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN_LEFT_TO_RIGHT_SHIFT;
  619. visual[i].attributes |= (left | right);
  620. }
  621. }
  622. }
  623. {
  624. int left_join = 0;
  625. unsigned i;
  626. for (i = line_start; i < kk; i++)
  627. {
  628. enum grub_join_type join_type = get_join_type (visual[i].base);
  629. if (!(visual[i].attributes
  630. & GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT)
  631. && (join_type == GRUB_JOIN_TYPE_LEFT
  632. || join_type == GRUB_JOIN_TYPE_DUAL))
  633. {
  634. if (left_join)
  635. visual[i].attributes
  636. |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED;
  637. else
  638. visual[i].attributes
  639. &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED;
  640. }
  641. if (join_type == GRUB_JOIN_TYPE_NONJOINING
  642. || join_type == GRUB_JOIN_TYPE_LEFT)
  643. left_join = 0;
  644. if (join_type == GRUB_JOIN_TYPE_RIGHT
  645. || join_type == GRUB_JOIN_TYPE_DUAL
  646. || join_type == GRUB_JOIN_TYPE_CAUSING)
  647. left_join = 1;
  648. }
  649. }
  650. {
  651. int right_join = 0;
  652. signed i;
  653. for (i = kk - 1; i >= 0 && (unsigned) i + 1 > line_start;
  654. i--)
  655. {
  656. enum grub_join_type join_type = get_join_type (visual[i].base);
  657. if (!(visual[i].attributes
  658. & GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT)
  659. && (join_type == GRUB_JOIN_TYPE_RIGHT
  660. || join_type == GRUB_JOIN_TYPE_DUAL))
  661. {
  662. if (right_join)
  663. visual[i].attributes
  664. |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED;
  665. else
  666. visual[i].attributes
  667. &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED;
  668. }
  669. if (join_type == GRUB_JOIN_TYPE_NONJOINING
  670. || join_type == GRUB_JOIN_TYPE_RIGHT)
  671. right_join = 0;
  672. if (join_type == GRUB_JOIN_TYPE_LEFT
  673. || join_type == GRUB_JOIN_TYPE_DUAL
  674. || join_type == GRUB_JOIN_TYPE_CAUSING)
  675. right_join = 1;
  676. }
  677. }
  678. grub_memcpy (outptr, &visual[line_start],
  679. (kk - line_start) * sizeof (visual[0]));
  680. outptr += kk - line_start;
  681. if (kk != visual_len)
  682. {
  683. if (contchar)
  684. {
  685. grub_memset (outptr, 0, sizeof (visual[0]));
  686. outptr->base = contchar;
  687. outptr++;
  688. }
  689. grub_memset (outptr, 0, sizeof (visual[0]));
  690. outptr->base = '\n';
  691. outptr++;
  692. }
  693. if ((signed) kk == last_space)
  694. kk++;
  695. line_start = kk;
  696. if (pos && kk != visual_len)
  697. {
  698. pos[visual[kk].orig_pos].x = 0;
  699. pos[visual[kk].orig_pos].y = lines;
  700. }
  701. }
  702. }
  703. return outptr - visual_out;
  704. }
  705. static grub_ssize_t
  706. grub_bidi_line_logical_to_visual (const grub_uint32_t *logical,
  707. grub_size_t logical_len,
  708. struct grub_unicode_glyph *visual_out,
  709. grub_size_t (*getcharwidth) (const struct grub_unicode_glyph *visual, void *getcharwidth_arg),
  710. void *getcharwidth_arg,
  711. grub_size_t maxwidth, grub_size_t startwidth,
  712. grub_uint32_t contchar,
  713. struct grub_term_pos *pos,
  714. int primitive_wrap,
  715. grub_size_t log_end)
  716. {
  717. enum grub_bidi_type type = GRUB_BIDI_TYPE_L;
  718. enum override_status {OVERRIDE_NEUTRAL = 0, OVERRIDE_R, OVERRIDE_L};
  719. unsigned base_level;
  720. enum override_status cur_override;
  721. unsigned i;
  722. unsigned stack_level[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3];
  723. enum override_status stack_override[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3];
  724. unsigned stack_depth = 0;
  725. unsigned invalid_pushes = 0;
  726. unsigned visual_len = 0;
  727. unsigned run_start, run_end;
  728. struct grub_unicode_glyph *visual;
  729. unsigned cur_level;
  730. int bidi_needed = 0;
  731. #define push_stack(new_override, new_level) \
  732. { \
  733. if (new_level > GRUB_BIDI_MAX_EXPLICIT_LEVEL) \
  734. { \
  735. invalid_pushes++; \
  736. } \
  737. else \
  738. { \
  739. stack_level[stack_depth] = cur_level; \
  740. stack_override[stack_depth] = cur_override; \
  741. stack_depth++; \
  742. cur_level = new_level; \
  743. cur_override = new_override; \
  744. } \
  745. }
  746. #define pop_stack() \
  747. { \
  748. if (invalid_pushes) \
  749. { \
  750. invalid_pushes--; \
  751. } \
  752. else if (stack_depth) \
  753. { \
  754. stack_depth--; \
  755. cur_level = stack_level[stack_depth]; \
  756. cur_override = stack_override[stack_depth]; \
  757. } \
  758. }
  759. visual = grub_calloc (logical_len, sizeof (visual[0]));
  760. if (!visual)
  761. return -1;
  762. for (i = 0; i < logical_len; i++)
  763. {
  764. type = get_bidi_type (logical[i]);
  765. if (type == GRUB_BIDI_TYPE_L || type == GRUB_BIDI_TYPE_AL
  766. || type == GRUB_BIDI_TYPE_R)
  767. break;
  768. }
  769. if (type == GRUB_BIDI_TYPE_R || type == GRUB_BIDI_TYPE_AL)
  770. base_level = 1;
  771. else
  772. base_level = 0;
  773. cur_level = base_level;
  774. cur_override = OVERRIDE_NEUTRAL;
  775. {
  776. const grub_uint32_t *lptr;
  777. enum {JOIN_DEFAULT, NOJOIN, JOIN_FORCE} join_state = JOIN_DEFAULT;
  778. int zwj_propagate_to_previous = 0;
  779. for (lptr = logical; lptr < logical + logical_len;)
  780. {
  781. grub_size_t p;
  782. if (*lptr == GRUB_UNICODE_ZWJ)
  783. {
  784. if (zwj_propagate_to_previous)
  785. {
  786. visual[visual_len - 1].attributes
  787. |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT
  788. | GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED;
  789. }
  790. zwj_propagate_to_previous = 0;
  791. join_state = JOIN_FORCE;
  792. lptr++;
  793. continue;
  794. }
  795. if (*lptr == GRUB_UNICODE_ZWNJ)
  796. {
  797. if (zwj_propagate_to_previous)
  798. {
  799. visual[visual_len - 1].attributes
  800. |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT;
  801. visual[visual_len - 1].attributes
  802. &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED;
  803. }
  804. zwj_propagate_to_previous = 0;
  805. join_state = NOJOIN;
  806. lptr++;
  807. continue;
  808. }
  809. /* The tags: deprecated, never used. */
  810. if (*lptr >= GRUB_UNICODE_TAG_START && *lptr <= GRUB_UNICODE_TAG_END)
  811. continue;
  812. p = grub_unicode_aglomerate_comb (lptr, logical + logical_len - lptr,
  813. &visual[visual_len]);
  814. visual[visual_len].orig_pos = lptr - logical;
  815. type = get_bidi_type (visual[visual_len].base);
  816. switch (type)
  817. {
  818. case GRUB_BIDI_TYPE_RLE:
  819. bidi_needed = 1;
  820. push_stack (cur_override, (cur_level | 1) + 1);
  821. break;
  822. case GRUB_BIDI_TYPE_RLO:
  823. bidi_needed = 1;
  824. push_stack (OVERRIDE_R, (cur_level | 1) + 1);
  825. break;
  826. case GRUB_BIDI_TYPE_LRE:
  827. push_stack (cur_override, (cur_level & ~1) + 2);
  828. break;
  829. case GRUB_BIDI_TYPE_LRO:
  830. push_stack (OVERRIDE_L, (cur_level & ~1) + 2);
  831. break;
  832. case GRUB_BIDI_TYPE_PDF:
  833. pop_stack ();
  834. break;
  835. case GRUB_BIDI_TYPE_BN:
  836. break;
  837. case GRUB_BIDI_TYPE_R:
  838. case GRUB_BIDI_TYPE_AL:
  839. bidi_needed = 1;
  840. /* Fallthrough. */
  841. default:
  842. {
  843. if (join_state == JOIN_FORCE)
  844. {
  845. visual[visual_len].attributes
  846. |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT
  847. | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED;
  848. }
  849. if (join_state == NOJOIN)
  850. {
  851. visual[visual_len].attributes
  852. |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT;
  853. visual[visual_len].attributes
  854. &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED;
  855. }
  856. join_state = JOIN_DEFAULT;
  857. zwj_propagate_to_previous = 1;
  858. visual[visual_len].bidi_level = cur_level;
  859. if (cur_override != OVERRIDE_NEUTRAL)
  860. visual[visual_len].bidi_type =
  861. (cur_override == OVERRIDE_L) ? GRUB_BIDI_TYPE_L
  862. : GRUB_BIDI_TYPE_R;
  863. else
  864. visual[visual_len].bidi_type = type;
  865. visual_len++;
  866. }
  867. }
  868. lptr += p;
  869. }
  870. }
  871. if (bidi_needed)
  872. {
  873. for (run_start = 0; run_start < visual_len; run_start = run_end)
  874. {
  875. unsigned prev_level, next_level, cur_run_level;
  876. unsigned last_type, last_strong_type;
  877. for (run_end = run_start; run_end < visual_len &&
  878. visual[run_end].bidi_level == visual[run_start].bidi_level; run_end++);
  879. if (run_start == 0)
  880. prev_level = base_level;
  881. else
  882. prev_level = visual[run_start - 1].bidi_level;
  883. if (run_end == visual_len)
  884. next_level = base_level;
  885. else
  886. next_level = visual[run_end].bidi_level;
  887. cur_run_level = visual[run_start].bidi_level;
  888. if (prev_level & 1)
  889. last_type = GRUB_BIDI_TYPE_R;
  890. else
  891. last_type = GRUB_BIDI_TYPE_L;
  892. last_strong_type = last_type;
  893. for (i = run_start; i < run_end; i++)
  894. {
  895. switch (visual[i].bidi_type)
  896. {
  897. case GRUB_BIDI_TYPE_NSM:
  898. visual[i].bidi_type = last_type;
  899. break;
  900. case GRUB_BIDI_TYPE_EN:
  901. if (last_strong_type == GRUB_BIDI_TYPE_AL)
  902. visual[i].bidi_type = GRUB_BIDI_TYPE_AN;
  903. break;
  904. case GRUB_BIDI_TYPE_L:
  905. case GRUB_BIDI_TYPE_R:
  906. last_strong_type = visual[i].bidi_type;
  907. break;
  908. case GRUB_BIDI_TYPE_ES:
  909. if (last_type == GRUB_BIDI_TYPE_EN
  910. && i + 1 < run_end
  911. && visual[i + 1].bidi_type == GRUB_BIDI_TYPE_EN)
  912. visual[i].bidi_type = GRUB_BIDI_TYPE_EN;
  913. else
  914. visual[i].bidi_type = GRUB_BIDI_TYPE_ON;
  915. break;
  916. case GRUB_BIDI_TYPE_ET:
  917. {
  918. unsigned j;
  919. if (last_type == GRUB_BIDI_TYPE_EN)
  920. {
  921. visual[i].bidi_type = GRUB_BIDI_TYPE_EN;
  922. break;
  923. }
  924. for (j = i; j < run_end
  925. && visual[j].bidi_type == GRUB_BIDI_TYPE_ET; j++);
  926. if (j != run_end && visual[j].bidi_type == GRUB_BIDI_TYPE_EN)
  927. {
  928. for (; i < run_end
  929. && visual[i].bidi_type == GRUB_BIDI_TYPE_ET; i++)
  930. visual[i].bidi_type = GRUB_BIDI_TYPE_EN;
  931. i--;
  932. break;
  933. }
  934. for (; i < run_end
  935. && visual[i].bidi_type == GRUB_BIDI_TYPE_ET; i++)
  936. visual[i].bidi_type = GRUB_BIDI_TYPE_ON;
  937. i--;
  938. break;
  939. }
  940. break;
  941. case GRUB_BIDI_TYPE_CS:
  942. if (last_type == GRUB_BIDI_TYPE_EN
  943. && i + 1 < run_end
  944. && visual[i + 1].bidi_type == GRUB_BIDI_TYPE_EN)
  945. {
  946. visual[i].bidi_type = GRUB_BIDI_TYPE_EN;
  947. break;
  948. }
  949. if (last_type == GRUB_BIDI_TYPE_AN
  950. && i + 1 < run_end
  951. && (visual[i + 1].bidi_type == GRUB_BIDI_TYPE_AN
  952. || (visual[i + 1].bidi_type == GRUB_BIDI_TYPE_EN
  953. && last_strong_type == GRUB_BIDI_TYPE_AL)))
  954. {
  955. visual[i].bidi_type = GRUB_BIDI_TYPE_EN;
  956. break;
  957. }
  958. visual[i].bidi_type = GRUB_BIDI_TYPE_ON;
  959. break;
  960. case GRUB_BIDI_TYPE_AL:
  961. last_strong_type = visual[i].bidi_type;
  962. visual[i].bidi_type = GRUB_BIDI_TYPE_R;
  963. break;
  964. default: /* Make GCC happy. */
  965. break;
  966. }
  967. last_type = visual[i].bidi_type;
  968. if (visual[i].bidi_type == GRUB_BIDI_TYPE_EN
  969. && last_strong_type == GRUB_BIDI_TYPE_L)
  970. visual[i].bidi_type = GRUB_BIDI_TYPE_L;
  971. }
  972. if (prev_level & 1)
  973. last_type = GRUB_BIDI_TYPE_R;
  974. else
  975. last_type = GRUB_BIDI_TYPE_L;
  976. for (i = run_start; i < run_end; )
  977. {
  978. unsigned j;
  979. unsigned next_type;
  980. for (j = i; j < run_end &&
  981. (visual[j].bidi_type == GRUB_BIDI_TYPE_B
  982. || visual[j].bidi_type == GRUB_BIDI_TYPE_S
  983. || visual[j].bidi_type == GRUB_BIDI_TYPE_WS
  984. || visual[j].bidi_type == GRUB_BIDI_TYPE_ON); j++);
  985. if (j == i)
  986. {
  987. if (visual[i].bidi_type == GRUB_BIDI_TYPE_L)
  988. last_type = GRUB_BIDI_TYPE_L;
  989. else
  990. last_type = GRUB_BIDI_TYPE_R;
  991. i++;
  992. continue;
  993. }
  994. if (j == run_end)
  995. next_type = (next_level & 1) ? GRUB_BIDI_TYPE_R : GRUB_BIDI_TYPE_L;
  996. else
  997. {
  998. if (visual[j].bidi_type == GRUB_BIDI_TYPE_L)
  999. next_type = GRUB_BIDI_TYPE_L;
  1000. else
  1001. next_type = GRUB_BIDI_TYPE_R;
  1002. }
  1003. if (next_type == last_type)
  1004. for (; i < j; i++)
  1005. visual[i].bidi_type = last_type;
  1006. else
  1007. for (; i < j; i++)
  1008. visual[i].bidi_type = (cur_run_level & 1) ? GRUB_BIDI_TYPE_R
  1009. : GRUB_BIDI_TYPE_L;
  1010. }
  1011. }
  1012. for (i = 0; i < visual_len; i++)
  1013. {
  1014. if (!(visual[i].bidi_level & 1) && visual[i].bidi_type == GRUB_BIDI_TYPE_R)
  1015. {
  1016. visual[i].bidi_level++;
  1017. continue;
  1018. }
  1019. if (!(visual[i].bidi_level & 1) && (visual[i].bidi_type == GRUB_BIDI_TYPE_AN
  1020. || visual[i].bidi_type == GRUB_BIDI_TYPE_EN))
  1021. {
  1022. visual[i].bidi_level += 2;
  1023. continue;
  1024. }
  1025. if ((visual[i].bidi_level & 1) && (visual[i].bidi_type == GRUB_BIDI_TYPE_L
  1026. || visual[i].bidi_type == GRUB_BIDI_TYPE_AN
  1027. || visual[i].bidi_type == GRUB_BIDI_TYPE_EN))
  1028. {
  1029. visual[i].bidi_level++;
  1030. continue;
  1031. }
  1032. }
  1033. }
  1034. else
  1035. {
  1036. for (i = 0; i < visual_len; i++)
  1037. visual[i].bidi_level = 0;
  1038. }
  1039. {
  1040. grub_ssize_t ret;
  1041. ret = bidi_line_wrap (visual_out, visual, visual_len,
  1042. getcharwidth, getcharwidth_arg, maxwidth, startwidth, contchar,
  1043. pos, primitive_wrap, log_end);
  1044. grub_free (visual);
  1045. return ret;
  1046. }
  1047. }
  1048. static int
  1049. is_visible (const struct grub_unicode_glyph *gl)
  1050. {
  1051. if (gl->ncomb)
  1052. return 1;
  1053. if (gl->base == GRUB_UNICODE_LRM || gl->base == GRUB_UNICODE_RLM)
  1054. return 0;
  1055. return 1;
  1056. }
  1057. grub_ssize_t
  1058. grub_bidi_logical_to_visual (const grub_uint32_t *logical,
  1059. grub_size_t logical_len,
  1060. struct grub_unicode_glyph **visual_out,
  1061. grub_size_t (*getcharwidth) (const struct grub_unicode_glyph *visual, void *getcharwidth_arg),
  1062. void *getcharwidth_arg,
  1063. grub_size_t max_length, grub_size_t startwidth,
  1064. grub_uint32_t contchar, struct grub_term_pos *pos, int primitive_wrap)
  1065. {
  1066. const grub_uint32_t *line_start = logical, *ptr;
  1067. struct grub_unicode_glyph *visual_ptr;
  1068. *visual_out = visual_ptr = grub_calloc (logical_len + 2,
  1069. 3 * sizeof (visual_ptr[0]));
  1070. if (!visual_ptr)
  1071. return -1;
  1072. for (ptr = logical; ptr <= logical + logical_len; ptr++)
  1073. {
  1074. if (ptr == logical + logical_len || *ptr == '\n')
  1075. {
  1076. grub_ssize_t ret;
  1077. grub_ssize_t i, j;
  1078. ret = grub_bidi_line_logical_to_visual (line_start,
  1079. ptr - line_start,
  1080. visual_ptr,
  1081. getcharwidth,
  1082. getcharwidth_arg,
  1083. max_length,
  1084. startwidth,
  1085. contchar,
  1086. pos,
  1087. primitive_wrap,
  1088. logical_len);
  1089. startwidth = 0;
  1090. if (ret < 0)
  1091. {
  1092. grub_free (*visual_out);
  1093. return ret;
  1094. }
  1095. for (i = 0, j = 0; i < ret; i++)
  1096. if (is_visible(&visual_ptr[i]))
  1097. visual_ptr[j++] = visual_ptr[i];
  1098. visual_ptr += j;
  1099. line_start = ptr;
  1100. if (ptr != logical + logical_len)
  1101. {
  1102. grub_memset (visual_ptr, 0, sizeof (visual_ptr[0]));
  1103. visual_ptr->base = '\n';
  1104. visual_ptr++;
  1105. line_start++;
  1106. }
  1107. }
  1108. }
  1109. return visual_ptr - *visual_out;
  1110. }
  1111. grub_uint32_t
  1112. grub_unicode_mirror_code (grub_uint32_t in)
  1113. {
  1114. int i;
  1115. for (i = 0; grub_unicode_bidi_pairs[i].key; i++)
  1116. if (grub_unicode_bidi_pairs[i].key == in)
  1117. return grub_unicode_bidi_pairs[i].replace;
  1118. return in;
  1119. }
  1120. grub_uint32_t
  1121. grub_unicode_shape_code (grub_uint32_t in, grub_uint8_t attr)
  1122. {
  1123. int i;
  1124. if (!(in >= GRUB_UNICODE_ARABIC_START
  1125. && in < GRUB_UNICODE_ARABIC_END))
  1126. return in;
  1127. for (i = 0; grub_unicode_arabic_shapes[i].code; i++)
  1128. if (grub_unicode_arabic_shapes[i].code == in)
  1129. {
  1130. grub_uint32_t out = 0;
  1131. switch (attr & (GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
  1132. | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED))
  1133. {
  1134. case 0:
  1135. out = grub_unicode_arabic_shapes[i].isolated;
  1136. break;
  1137. case GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED:
  1138. out = grub_unicode_arabic_shapes[i].right_linked;
  1139. break;
  1140. case GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED:
  1141. out = grub_unicode_arabic_shapes[i].left_linked;
  1142. break;
  1143. case GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
  1144. |GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED:
  1145. out = grub_unicode_arabic_shapes[i].both_linked;
  1146. break;
  1147. }
  1148. if (out)
  1149. return out;
  1150. }
  1151. return in;
  1152. }
  1153. const grub_uint32_t *
  1154. grub_unicode_get_comb_start (const grub_uint32_t *str,
  1155. const grub_uint32_t *cur)
  1156. {
  1157. const grub_uint32_t *ptr;
  1158. for (ptr = cur; ptr >= str; ptr--)
  1159. {
  1160. if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1
  1161. && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16)
  1162. continue;
  1163. if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17
  1164. && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256)
  1165. continue;
  1166. enum grub_comb_type comb_type;
  1167. comb_type = grub_unicode_get_comb_type (*ptr);
  1168. if (comb_type)
  1169. continue;
  1170. return ptr;
  1171. }
  1172. return str;
  1173. }
  1174. const grub_uint32_t *
  1175. grub_unicode_get_comb_end (const grub_uint32_t *end,
  1176. const grub_uint32_t *cur)
  1177. {
  1178. const grub_uint32_t *ptr;
  1179. for (ptr = cur; ptr < end; ptr++)
  1180. {
  1181. if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1
  1182. && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16)
  1183. continue;
  1184. if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17
  1185. && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256)
  1186. continue;
  1187. enum grub_comb_type comb_type;
  1188. comb_type = grub_unicode_get_comb_type (*ptr);
  1189. if (comb_type)
  1190. continue;
  1191. return ptr;
  1192. }
  1193. return end;
  1194. }