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