Ensure all lines that should be omitted from public includes are marked
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / normal / charset.c
blob85ead53c4630c106ab4863bbe7de3135057058db
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
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.
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.
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/>.
20 Current problems with Unicode rendering:
21 - B and BN bidi type characters (ignored)
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)
25 - Cf type characters (ignored)
26 - Cc type characters (ignored)
27 - Line-breaking rules (e.g. Zs type characters)
28 - Indic languages
29 - non-Semitic shaping (rarely used)
30 - Zl and Zp characters
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
33 - Private use characters (not really a problem)
34 - Variations (no font support)
35 - Vertical text
36 - Ligatures
37 Font information ignored:
38 - Kerning
39 - Justification data
40 - Glyph posititioning
41 - Baseline data
42 Most underline diacritics aren't displayed in gfxterm
45 /* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE
46 bytes (if SRCSIZE is -1, it is ignored) in length to a UTF-16 string.
47 Return the number of characters converted. DEST must be able to hold
48 at least DESTSIZE characters. If an invalid sequence is found, return -1.
49 If SRCEND is not NULL, then *SRCEND is set to the next byte after the
50 last byte used in SRC. */
52 #include <grub/charset.h>
53 #include <grub/mm.h>
54 #include <grub/misc.h>
55 #include <grub/unicode.h>
56 #include <grub/term.h>
57 #include <grub/normal.h>
59 #ifdef HAVE_UNIFONT_WIDTHSPEC
60 #include "widthspec.h"
61 #endif
63 grub_ssize_t
64 grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize,
65 const grub_uint8_t *src, grub_size_t srcsize,
66 const grub_uint8_t **srcend)
68 grub_uint16_t *p = dest;
69 int count = 0;
70 grub_uint32_t code = 0;
72 if (srcend)
73 *srcend = src;
75 while (srcsize && destsize)
77 grub_uint32_t c = *src++;
78 if (srcsize != (grub_size_t)-1)
79 srcsize--;
80 if (count)
82 if ((c & GRUB_UINT8_2_LEADINGBITS) != GRUB_UINT8_1_LEADINGBIT)
84 /* invalid */
85 return -1;
87 else
89 code <<= 6;
90 code |= (c & GRUB_UINT8_6_TRAILINGBITS);
91 count--;
94 else
96 if (c == 0)
97 break;
99 if ((c & GRUB_UINT8_1_LEADINGBIT) == 0)
100 code = c;
101 else if ((c & GRUB_UINT8_3_LEADINGBITS) == GRUB_UINT8_2_LEADINGBITS)
103 count = 1;
104 code = c & GRUB_UINT8_5_TRAILINGBITS;
106 else if ((c & GRUB_UINT8_4_LEADINGBITS) == GRUB_UINT8_3_LEADINGBITS)
108 count = 2;
109 code = c & GRUB_UINT8_4_TRAILINGBITS;
111 else if ((c & GRUB_UINT8_5_LEADINGBITS) == GRUB_UINT8_4_LEADINGBITS)
113 count = 3;
114 code = c & GRUB_UINT8_3_TRAILINGBITS;
116 else
117 return -1;
120 if (count == 0)
122 if (destsize < 2 && code >= GRUB_UCS2_LIMIT)
123 break;
124 if (code >= GRUB_UCS2_LIMIT)
126 *p++ = GRUB_UTF16_UPPER_SURROGATE (code);
127 *p++ = GRUB_UTF16_LOWER_SURROGATE (code);
128 destsize -= 2;
130 else
132 *p++ = code;
133 destsize--;
138 if (srcend)
139 *srcend = src;
140 return p - dest;
143 /* Convert UCS-4 to UTF-8. */
144 void
145 grub_ucs4_to_utf8 (grub_uint32_t *src, grub_size_t size,
146 grub_uint8_t *dest, grub_size_t destsize)
148 /* Keep last char for \0. */
149 grub_uint8_t *destend = dest + destsize - 1;
151 while (size-- && dest < destend)
153 grub_uint32_t code = *src++;
155 if (code <= 0x007F)
156 *dest++ = code;
157 else if (code <= 0x07FF)
159 if (dest + 1 >= destend)
160 break;
161 *dest++ = (code >> 6) | 0xC0;
162 *dest++ = (code & 0x3F) | 0x80;
164 else if ((code >= 0xDC00 && code <= 0xDFFF)
165 || (code >= 0xD800 && code <= 0xDBFF))
167 /* No surrogates in UCS-4... */
168 *dest++ = '?';
170 else if (code < 0x10000)
172 if (dest + 2 >= destend)
173 break;
174 *dest++ = (code >> 12) | 0xE0;
175 *dest++ = ((code >> 6) & 0x3F) | 0x80;
176 *dest++ = (code & 0x3F) | 0x80;
178 else
180 if (dest + 3 >= destend)
181 break;
182 *dest++ = (code >> 18) | 0xF0;
183 *dest++ = ((code >> 12) & 0x3F) | 0x80;
184 *dest++ = ((code >> 6) & 0x3F) | 0x80;
185 *dest++ = (code & 0x3F) | 0x80;
188 *dest = 0;
191 /* Convert UCS-4 to UTF-8. */
192 char *
193 grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size)
195 grub_size_t remaining;
196 grub_uint32_t *ptr;
197 grub_size_t cnt = 0;
198 grub_uint8_t *ret;
200 remaining = size;
201 ptr = src;
202 while (remaining--)
204 grub_uint32_t code = *ptr++;
206 if (code <= 0x007F)
207 cnt++;
208 else if (code <= 0x07FF)
209 cnt += 2;
210 else if ((code >= 0xDC00 && code <= 0xDFFF)
211 || (code >= 0xD800 && code <= 0xDBFF))
212 /* No surrogates in UCS-4... */
213 cnt++;
214 else if (code < 0x10000)
215 cnt += 3;
216 else
217 cnt += 4;
219 cnt++;
221 ret = grub_malloc (cnt);
222 if (!ret)
223 return 0;
225 grub_ucs4_to_utf8 (src, size, ret, cnt);
227 return (char *) ret;
231 grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize)
233 grub_uint32_t code = 0;
234 int count = 0;
236 while (srcsize)
238 grub_uint32_t c = *src++;
239 if (srcsize != (grub_size_t)-1)
240 srcsize--;
241 if (count)
243 if ((c & 0xc0) != 0x80)
245 /* invalid */
246 return 0;
248 else
250 code <<= 6;
251 code |= (c & 0x3f);
252 count--;
255 else
257 if (c == 0)
258 break;
260 if ((c & 0x80) == 0x00)
261 code = c;
262 else if ((c & 0xe0) == 0xc0)
264 count = 1;
265 code = c & 0x1f;
267 else if ((c & 0xf0) == 0xe0)
269 count = 2;
270 code = c & 0x0f;
272 else if ((c & 0xf8) == 0xf0)
274 count = 3;
275 code = c & 0x07;
277 else
278 return 0;
282 return 1;
286 grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg,
287 grub_uint32_t **last_position)
289 grub_size_t msg_len = grub_strlen (msg);
291 *unicode_msg = grub_malloc (msg_len * sizeof (grub_uint32_t));
293 if (!*unicode_msg)
294 return -1;
296 msg_len = grub_utf8_to_ucs4 (*unicode_msg, msg_len,
297 (grub_uint8_t *) msg, -1, 0);
299 if (last_position)
300 *last_position = *unicode_msg + msg_len;
302 return msg_len;
305 /* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE
306 bytes (if SRCSIZE is -1, it is ignored) in length to a UCS-4 string.
307 Return the number of characters converted. DEST must be able to hold
308 at least DESTSIZE characters.
309 If SRCEND is not NULL, then *SRCEND is set to the next byte after the
310 last byte used in SRC. */
311 grub_size_t
312 grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
313 const grub_uint8_t *src, grub_size_t srcsize,
314 const grub_uint8_t **srcend)
316 grub_uint32_t *p = dest;
317 int count = 0;
318 grub_uint32_t code = 0;
320 if (srcend)
321 *srcend = src;
323 while (srcsize && destsize)
325 grub_uint32_t c = *src++;
326 if (srcsize != (grub_size_t)-1)
327 srcsize--;
328 if (count)
330 if ((c & 0xc0) != 0x80)
332 /* invalid */
333 code = '?';
334 /* Character c may be valid, don't eat it. */
335 src--;
336 if (srcsize != (grub_size_t)-1)
337 srcsize++;
338 count = 0;
340 else
342 code <<= 6;
343 code |= (c & 0x3f);
344 count--;
347 else
349 if (c == 0)
350 break;
352 if ((c & 0x80) == 0x00)
353 code = c;
354 else if ((c & 0xe0) == 0xc0)
356 count = 1;
357 code = c & 0x1f;
359 else if ((c & 0xf0) == 0xe0)
361 count = 2;
362 code = c & 0x0f;
364 else if ((c & 0xf8) == 0xf0)
366 count = 3;
367 code = c & 0x07;
369 else
371 /* invalid */
372 code = '?';
373 count = 0;
377 if (count == 0)
379 *p++ = code;
380 destsize--;
384 if (srcend)
385 *srcend = src;
386 return p - dest;
389 static grub_uint8_t *join_types = NULL;
391 static void
392 unpack_join (void)
394 unsigned i;
395 struct grub_unicode_compact_range *cur;
397 join_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
398 if (!join_types)
400 grub_errno = GRUB_ERR_NONE;
401 return;
403 for (cur = grub_unicode_compact; cur->end; cur++)
404 for (i = cur->start; i <= cur->end
405 && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
406 join_types[i] = cur->join_type;
409 static grub_uint8_t *bidi_types = NULL;
411 static void
412 unpack_bidi (void)
414 unsigned i;
415 struct grub_unicode_compact_range *cur;
417 bidi_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
418 if (!bidi_types)
420 grub_errno = GRUB_ERR_NONE;
421 return;
423 for (cur = grub_unicode_compact; cur->end; cur++)
424 for (i = cur->start; i <= cur->end
425 && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
426 if (cur->bidi_mirror)
427 bidi_types[i] = cur->bidi_type | 0x80;
428 else
429 bidi_types[i] = cur->bidi_type | 0x00;
432 static inline enum grub_bidi_type
433 get_bidi_type (grub_uint32_t c)
435 struct grub_unicode_compact_range *cur;
437 if (!bidi_types)
438 unpack_bidi ();
440 if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
441 return bidi_types[c] & 0x7f;
443 for (cur = grub_unicode_compact; cur->end; cur++)
444 if (cur->start <= c && c <= cur->end)
445 return cur->bidi_type;
447 return GRUB_BIDI_TYPE_L;
450 static inline enum grub_join_type
451 get_join_type (grub_uint32_t c)
453 struct grub_unicode_compact_range *cur;
455 if (!join_types)
456 unpack_join ();
458 if (join_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
459 return join_types[c];
461 for (cur = grub_unicode_compact; cur->end; cur++)
462 if (cur->start <= c && c <= cur->end)
463 return cur->join_type;
465 return GRUB_JOIN_TYPE_NONJOINING;
468 static inline int
469 is_mirrored (grub_uint32_t c)
471 struct grub_unicode_compact_range *cur;
473 if (!bidi_types)
474 unpack_bidi ();
476 if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
477 return !!(bidi_types[c] & 0x80);
479 for (cur = grub_unicode_compact; cur->end; cur++)
480 if (cur->start <= c && c <= cur->end)
481 return cur->bidi_mirror;
483 return 0;
486 enum grub_comb_type
487 grub_unicode_get_comb_type (grub_uint32_t c)
489 static grub_uint8_t *comb_types = NULL;
490 struct grub_unicode_compact_range *cur;
492 if (!comb_types)
494 unsigned i;
495 comb_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
496 if (comb_types)
497 for (cur = grub_unicode_compact; cur->end; cur++)
498 for (i = cur->start; i <= cur->end
499 && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
500 comb_types[i] = cur->comb_type;
501 else
502 grub_errno = GRUB_ERR_NONE;
505 if (comb_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
506 return comb_types[c];
508 for (cur = grub_unicode_compact; cur->end; cur++)
509 if (cur->start <= c && c <= cur->end)
510 return cur->comb_type;
512 return GRUB_UNICODE_COMB_NONE;
515 #ifdef HAVE_UNIFONT_WIDTHSPEC
517 grub_ssize_t
518 grub_unicode_estimate_width (const struct grub_unicode_glyph *c)
520 if (grub_unicode_get_comb_type (c->base))
521 return 0;
522 if (widthspec[c->base >> 3] & (1 << (c->base & 7)))
523 return 2;
524 else
525 return 1;
528 #endif
530 static inline int
531 is_type_after (enum grub_comb_type a, enum grub_comb_type b)
533 /* Shadda is numerically higher than most of Arabic diacritics but has
534 to be rendered before them. */
535 if (a == GRUB_UNICODE_COMB_ARABIC_SHADDA
536 && b <= GRUB_UNICODE_COMB_ARABIC_KASRA
537 && b >= GRUB_UNICODE_COMB_ARABIC_FATHATAN)
538 return 0;
539 if (b == GRUB_UNICODE_COMB_ARABIC_SHADDA
540 && a <= GRUB_UNICODE_COMB_ARABIC_KASRA
541 && a >= GRUB_UNICODE_COMB_ARABIC_FATHATAN)
542 return 1;
543 return a > b;
546 grub_size_t
547 grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
548 struct grub_unicode_glyph *out)
550 int haveout = 0;
551 const grub_uint32_t *ptr;
552 unsigned last_comb_pointer = 0;
554 grub_memset (out, 0, sizeof (*out));
556 for (ptr = in; ptr < in + inlen; ptr++)
558 /* Variation selectors >= 17 are outside of BMP and SMP.
559 Handle variation selectors first to avoid potentially costly lookups.
561 if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1
562 && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16)
564 if (haveout)
565 out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_1 + 1;
566 continue;
569 if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17
570 && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256)
572 if (haveout)
573 out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_17 + 17;
574 continue;
577 enum grub_comb_type comb_type;
578 comb_type = grub_unicode_get_comb_type (*ptr);
579 if (comb_type)
581 struct grub_unicode_combining *n;
582 unsigned j;
584 if (!haveout)
585 continue;
587 if (comb_type == GRUB_UNICODE_COMB_MC
588 || comb_type == GRUB_UNICODE_COMB_ME
589 || comb_type == GRUB_UNICODE_COMB_MN)
590 last_comb_pointer = out->ncomb;
591 n = grub_realloc (out->combining,
592 sizeof (n[0]) * (out->ncomb + 1));
593 if (!n)
595 grub_errno = GRUB_ERR_NONE;
596 continue;
598 out->combining = n;
600 for (j = last_comb_pointer; j < out->ncomb; j++)
601 if (is_type_after (out->combining[j].type, comb_type))
602 break;
603 grub_memmove (out->combining + j + 1,
604 out->combining + j,
605 (out->ncomb - j)
606 * sizeof (out->combining[0]));
607 out->combining = n;
608 out->combining[j].code = *ptr;
609 out->combining[j].type = comb_type;
610 out->ncomb++;
611 continue;
613 if (haveout)
614 return ptr - in;
615 haveout = 1;
616 out->base = *ptr;
617 out->variant = 0;
618 out->attributes = 0;
619 out->ncomb = 0;
620 out->estimated_width = 1;
621 out->combining = NULL;
623 return ptr - in;
626 static grub_ssize_t
627 bidi_line_wrap (struct grub_unicode_glyph *visual_out,
628 struct grub_unicode_glyph *visual,
629 grub_size_t visual_len, unsigned *levels,
630 grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
631 grub_size_t maxwidth, grub_size_t startwidth)
633 struct grub_unicode_glyph *outptr = visual_out;
634 unsigned line_start = 0;
635 grub_ssize_t line_width = startwidth;
636 unsigned k;
637 grub_ssize_t last_space = -1;
638 grub_ssize_t last_space_width = 0;
640 auto void revert (unsigned start, unsigned end);
641 void revert (unsigned start, unsigned end)
643 struct grub_unicode_glyph t;
644 unsigned i, tl;
645 for (i = 0; i <= (end - start) / 2; i++)
647 t = visual[start + i];
648 visual[start + i] = visual[end - i];
649 visual[end - i] = t;
650 tl = levels[start + i];
651 levels[start + i] = levels[end - i];
652 levels[end - i] = tl;
656 if (!visual_len)
657 return 0;
659 for (k = 0; k <= visual_len; k++)
661 grub_ssize_t last_width = 0;
663 if (getcharwidth && k != visual_len)
664 line_width += last_width = getcharwidth (&visual[k]);
666 if (k != visual_len && visual[k].base == ' ')
668 last_space = k;
669 last_space_width = line_width;
672 if (((grub_ssize_t) maxwidth > 0
673 && line_width > (grub_ssize_t) maxwidth) || k == visual_len)
675 unsigned min_odd_level = 0xffffffff;
676 unsigned max_level = 0;
678 if (k != visual_len && last_space > (signed) line_start)
679 k = last_space;
680 else if (k != visual_len && line_start == 0 && startwidth != 0)
682 k = 0;
683 last_space_width = startwidth;
685 else
686 last_space_width = line_width - last_width;
689 unsigned i;
690 for (i = line_start; i < k; i++)
692 if (levels[i] > max_level)
693 max_level = levels[i];
694 if (levels[i] < min_odd_level && (levels[i] & 1))
695 min_odd_level = levels[i];
700 unsigned j;
701 /* FIXME: can be optimized. */
702 for (j = max_level; j >= min_odd_level; j--)
704 unsigned in = 0;
705 unsigned i;
706 for (i = line_start; i < k; i++)
708 if (i != line_start && levels[i] >= j && levels[i-1] < j)
709 in = i;
710 if (levels[i] >= j && (i + 1 == k || levels[i+1] < j))
711 revert (in, i);
717 unsigned i;
718 for (i = line_start; i < k; i++)
720 if (is_mirrored (visual[i].base) && levels[i])
721 visual[i].attributes |= GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR;
722 if ((visual[i].attributes & GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN)
723 && levels[i])
725 int left, right;
726 left = visual[i].attributes
727 & (GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED
728 | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT);
729 right = visual[i].attributes
730 & (GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
731 | GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT);
732 visual[i].attributes &= ~GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN;
733 left <<= GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN_LEFT_TO_RIGHT_SHIFT;
734 right >>= GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN_LEFT_TO_RIGHT_SHIFT;
735 visual[i].attributes |= (left | right);
741 int left_join = 0;
742 unsigned i;
743 for (i = line_start; i < k; i++)
745 enum grub_join_type join_type = get_join_type (visual[i].base);
746 if (!(visual[i].attributes
747 & GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT)
748 && (join_type == GRUB_JOIN_TYPE_LEFT
749 || join_type == GRUB_JOIN_TYPE_DUAL))
751 if (left_join)
752 visual[i].attributes
753 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED;
754 else
755 visual[i].attributes
756 &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED;
758 if (join_type == GRUB_JOIN_TYPE_NONJOINING
759 || join_type == GRUB_JOIN_TYPE_LEFT)
760 left_join = 0;
761 if (join_type == GRUB_JOIN_TYPE_RIGHT
762 || join_type == GRUB_JOIN_TYPE_DUAL
763 || join_type == GRUB_JOIN_TYPE_CAUSING)
764 left_join = 1;
769 int right_join = 0;
770 signed i;
771 for (i = k - 1; i >= (signed) line_start; i--)
773 enum grub_join_type join_type = get_join_type (visual[i].base);
774 if (!(visual[i].attributes
775 & GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT)
776 && (join_type == GRUB_JOIN_TYPE_RIGHT
777 || join_type == GRUB_JOIN_TYPE_DUAL))
779 if (right_join)
780 visual[i].attributes
781 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED;
782 else
783 visual[i].attributes
784 &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED;
786 if (join_type == GRUB_JOIN_TYPE_NONJOINING
787 || join_type == GRUB_JOIN_TYPE_RIGHT)
788 right_join = 0;
789 if (join_type == GRUB_JOIN_TYPE_LEFT
790 || join_type == GRUB_JOIN_TYPE_DUAL
791 || join_type == GRUB_JOIN_TYPE_CAUSING)
792 right_join = 1;
796 grub_memcpy (outptr, &visual[line_start],
797 (k - line_start) * sizeof (visual[0]));
798 outptr += k - line_start;
799 if (k != visual_len)
801 grub_memset (outptr, 0, sizeof (visual[0]));
802 outptr->base = '\n';
803 outptr++;
806 if ((signed) k == last_space)
807 k++;
809 line_start = k;
810 line_width -= last_space_width;
814 return outptr - visual_out;
818 static grub_ssize_t
819 grub_bidi_line_logical_to_visual (const grub_uint32_t *logical,
820 grub_size_t logical_len,
821 struct grub_unicode_glyph *visual_out,
822 grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
823 grub_size_t maxwidth, grub_size_t startwidth)
825 enum grub_bidi_type type = GRUB_BIDI_TYPE_L;
826 enum override_status {OVERRIDE_NEUTRAL = 0, OVERRIDE_R, OVERRIDE_L};
827 unsigned *levels;
828 enum grub_bidi_type *resolved_types;
829 unsigned base_level;
830 enum override_status cur_override;
831 unsigned i;
832 unsigned stack_level[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3];
833 enum override_status stack_override[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3];
834 unsigned stack_depth = 0;
835 unsigned invalid_pushes = 0;
836 unsigned visual_len = 0;
837 unsigned run_start, run_end;
838 struct grub_unicode_glyph *visual;
839 unsigned cur_level;
840 int bidi_needed = 0;
842 auto void push_stack (unsigned new_override, unsigned new_level);
843 void push_stack (unsigned new_override, unsigned new_level)
845 if (new_level > GRUB_BIDI_MAX_EXPLICIT_LEVEL)
847 invalid_pushes++;
848 return;
850 stack_level[stack_depth] = cur_level;
851 stack_override[stack_depth] = cur_override;
852 stack_depth++;
853 cur_level = new_level;
854 cur_override = new_override;
857 auto void pop_stack (void);
858 void pop_stack (void)
860 if (invalid_pushes)
862 invalid_pushes--;
863 return;
865 if (!stack_depth)
866 return;
867 stack_depth--;
868 cur_level = stack_level[stack_depth];
869 cur_override = stack_override[stack_depth];
872 levels = grub_malloc (sizeof (levels[0]) * logical_len);
873 if (!levels)
874 return -1;
876 resolved_types = grub_malloc (sizeof (resolved_types[0]) * logical_len);
877 if (!resolved_types)
879 grub_free (levels);
880 return -1;
883 visual = grub_malloc (sizeof (visual[0]) * logical_len);
884 if (!visual)
886 grub_free (resolved_types);
887 grub_free (levels);
888 return -1;
891 for (i = 0; i < logical_len; i++)
893 type = get_bidi_type (logical[i]);
894 if (type == GRUB_BIDI_TYPE_L || type == GRUB_BIDI_TYPE_AL
895 || type == GRUB_BIDI_TYPE_R)
896 break;
898 if (type == GRUB_BIDI_TYPE_R || type == GRUB_BIDI_TYPE_AL)
899 base_level = 1;
900 else
901 base_level = 0;
903 cur_level = base_level;
904 cur_override = OVERRIDE_NEUTRAL;
906 const grub_uint32_t *lptr;
907 enum {JOIN_DEFAULT, NOJOIN, JOIN_FORCE} join_state = JOIN_DEFAULT;
908 int zwj_propagate_to_previous = 0;
909 for (lptr = logical; lptr < logical + logical_len;)
911 grub_size_t p;
913 if (*lptr == GRUB_UNICODE_ZWJ)
915 if (zwj_propagate_to_previous)
917 visual[visual_len - 1].attributes
918 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT
919 | GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED;
921 zwj_propagate_to_previous = 0;
922 join_state = JOIN_FORCE;
923 lptr++;
924 continue;
927 if (*lptr == GRUB_UNICODE_ZWNJ)
929 if (zwj_propagate_to_previous)
931 visual[visual_len - 1].attributes
932 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT;
933 visual[visual_len - 1].attributes
934 &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED;
936 zwj_propagate_to_previous = 0;
937 join_state = NOJOIN;
938 lptr++;
939 continue;
942 p = grub_unicode_aglomerate_comb (lptr, logical + logical_len - lptr,
943 &visual[visual_len]);
945 type = get_bidi_type (visual[visual_len].base);
946 switch (type)
948 case GRUB_BIDI_TYPE_RLE:
949 bidi_needed = 1;
950 push_stack (cur_override, (cur_level | 1) + 1);
951 break;
952 case GRUB_BIDI_TYPE_RLO:
953 bidi_needed = 1;
954 push_stack (OVERRIDE_R, (cur_level | 1) + 1);
955 break;
956 case GRUB_BIDI_TYPE_LRE:
957 push_stack (cur_override, (cur_level & ~1) + 2);
958 break;
959 case GRUB_BIDI_TYPE_LRO:
960 push_stack (OVERRIDE_L, (cur_level & ~1) + 2);
961 break;
962 case GRUB_BIDI_TYPE_PDF:
963 pop_stack ();
964 break;
965 case GRUB_BIDI_TYPE_BN:
966 break;
967 case GRUB_BIDI_TYPE_R:
968 case GRUB_BIDI_TYPE_AL:
969 bidi_needed = 1;
970 default:
972 if (join_state == JOIN_FORCE)
974 visual[visual_len].attributes
975 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT
976 | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED;
979 if (join_state == NOJOIN)
981 visual[visual_len].attributes
982 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT;
983 visual[visual_len].attributes
984 &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED;
987 join_state = JOIN_DEFAULT;
988 zwj_propagate_to_previous = 1;
990 levels[visual_len] = cur_level;
991 if (cur_override != OVERRIDE_NEUTRAL)
992 resolved_types[visual_len] =
993 (cur_override == OVERRIDE_L) ? GRUB_BIDI_TYPE_L
994 : GRUB_BIDI_TYPE_R;
995 else
996 resolved_types[visual_len] = type;
997 visual_len++;
1000 lptr += p;
1004 if (bidi_needed)
1006 for (run_start = 0; run_start < visual_len; run_start = run_end)
1008 unsigned prev_level, next_level, cur_run_level;
1009 unsigned last_type, last_strong_type;
1010 for (run_end = run_start; run_end < visual_len &&
1011 levels[run_end] == levels[run_start]; run_end++);
1012 if (run_start == 0)
1013 prev_level = base_level;
1014 else
1015 prev_level = levels[run_start - 1];
1016 if (run_end == visual_len)
1017 next_level = base_level;
1018 else
1019 next_level = levels[run_end];
1020 cur_run_level = levels[run_start];
1021 if (prev_level & 1)
1022 last_type = GRUB_BIDI_TYPE_R;
1023 else
1024 last_type = GRUB_BIDI_TYPE_L;
1025 last_strong_type = last_type;
1026 for (i = run_start; i < run_end; i++)
1028 switch (resolved_types[i])
1030 case GRUB_BIDI_TYPE_NSM:
1031 resolved_types[i] = last_type;
1032 break;
1033 case GRUB_BIDI_TYPE_EN:
1034 if (last_strong_type == GRUB_BIDI_TYPE_AL)
1035 resolved_types[i] = GRUB_BIDI_TYPE_AN;
1036 break;
1037 case GRUB_BIDI_TYPE_L:
1038 case GRUB_BIDI_TYPE_R:
1039 last_strong_type = resolved_types[i];
1040 break;
1041 case GRUB_BIDI_TYPE_ES:
1042 if (last_type == GRUB_BIDI_TYPE_EN
1043 && i + 1 < run_end
1044 && resolved_types[i + 1] == GRUB_BIDI_TYPE_EN)
1045 resolved_types[i] = GRUB_BIDI_TYPE_EN;
1046 else
1047 resolved_types[i] = GRUB_BIDI_TYPE_ON;
1048 break;
1049 case GRUB_BIDI_TYPE_ET:
1051 unsigned j;
1052 if (last_type == GRUB_BIDI_TYPE_EN)
1054 resolved_types[i] = GRUB_BIDI_TYPE_EN;
1055 break;
1057 for (j = i; j < run_end
1058 && resolved_types[j] == GRUB_BIDI_TYPE_ET; j++);
1059 if (j != run_end && resolved_types[j] == GRUB_BIDI_TYPE_EN)
1061 for (; i < run_end
1062 && resolved_types[i] == GRUB_BIDI_TYPE_ET; i++)
1063 resolved_types[i] = GRUB_BIDI_TYPE_EN;
1064 i--;
1065 break;
1067 for (; i < run_end
1068 && resolved_types[i] == GRUB_BIDI_TYPE_ET; i++)
1069 resolved_types[i] = GRUB_BIDI_TYPE_ON;
1070 i--;
1071 break;
1073 break;
1074 case GRUB_BIDI_TYPE_CS:
1075 if (last_type == GRUB_BIDI_TYPE_EN
1076 && i + 1 < run_end
1077 && resolved_types[i + 1] == GRUB_BIDI_TYPE_EN)
1079 resolved_types[i] = GRUB_BIDI_TYPE_EN;
1080 break;
1082 if (last_type == GRUB_BIDI_TYPE_AN
1083 && i + 1 < run_end
1084 && (resolved_types[i + 1] == GRUB_BIDI_TYPE_AN
1085 || (resolved_types[i + 1] == GRUB_BIDI_TYPE_EN
1086 && last_strong_type == GRUB_BIDI_TYPE_AL)))
1088 resolved_types[i] = GRUB_BIDI_TYPE_EN;
1089 break;
1091 resolved_types[i] = GRUB_BIDI_TYPE_ON;
1092 break;
1093 case GRUB_BIDI_TYPE_AL:
1094 last_strong_type = resolved_types[i];
1095 resolved_types[i] = GRUB_BIDI_TYPE_R;
1096 break;
1097 default: /* Make GCC happy. */
1098 break;
1100 last_type = resolved_types[i];
1101 if (resolved_types[i] == GRUB_BIDI_TYPE_EN
1102 && last_strong_type == GRUB_BIDI_TYPE_L)
1103 resolved_types[i] = GRUB_BIDI_TYPE_L;
1105 if (prev_level & 1)
1106 last_type = GRUB_BIDI_TYPE_R;
1107 else
1108 last_type = GRUB_BIDI_TYPE_L;
1109 for (i = run_start; i < run_end; )
1111 unsigned j;
1112 unsigned next_type;
1113 for (j = i; j < run_end &&
1114 (resolved_types[j] == GRUB_BIDI_TYPE_B
1115 || resolved_types[j] == GRUB_BIDI_TYPE_S
1116 || resolved_types[j] == GRUB_BIDI_TYPE_WS
1117 || resolved_types[j] == GRUB_BIDI_TYPE_ON); j++);
1118 if (j == i)
1120 if (resolved_types[i] == GRUB_BIDI_TYPE_L)
1121 last_type = GRUB_BIDI_TYPE_L;
1122 else
1123 last_type = GRUB_BIDI_TYPE_R;
1124 i++;
1125 continue;
1127 if (j == run_end)
1128 next_type = (next_level & 1) ? GRUB_BIDI_TYPE_R : GRUB_BIDI_TYPE_L;
1129 else
1131 if (resolved_types[j] == GRUB_BIDI_TYPE_L)
1132 next_type = GRUB_BIDI_TYPE_L;
1133 else
1134 next_type = GRUB_BIDI_TYPE_R;
1136 if (next_type == last_type)
1137 for (; i < j; i++)
1138 resolved_types[i] = last_type;
1139 else
1140 for (; i < j; i++)
1141 resolved_types[i] = (cur_run_level & 1) ? GRUB_BIDI_TYPE_R
1142 : GRUB_BIDI_TYPE_L;
1146 for (i = 0; i < visual_len; i++)
1148 if (!(levels[i] & 1) && resolved_types[i] == GRUB_BIDI_TYPE_R)
1150 levels[i]++;
1151 continue;
1153 if (!(levels[i] & 1) && (resolved_types[i] == GRUB_BIDI_TYPE_AN
1154 || resolved_types[i] == GRUB_BIDI_TYPE_EN))
1156 levels[i] += 2;
1157 continue;
1159 if ((levels[i] & 1) && (resolved_types[i] == GRUB_BIDI_TYPE_L
1160 || resolved_types[i] == GRUB_BIDI_TYPE_AN
1161 || resolved_types[i] == GRUB_BIDI_TYPE_EN))
1163 levels[i]++;
1164 continue;
1168 else
1170 for (i = 0; i < visual_len; i++)
1171 levels[i] = 0;
1173 grub_free (resolved_types);
1176 grub_ssize_t ret;
1177 ret = bidi_line_wrap (visual_out, visual, visual_len, levels,
1178 getcharwidth, maxwidth, startwidth);
1179 grub_free (levels);
1180 grub_free (visual);
1181 return ret;
1185 grub_ssize_t
1186 grub_bidi_logical_to_visual (const grub_uint32_t *logical,
1187 grub_size_t logical_len,
1188 struct grub_unicode_glyph **visual_out,
1189 grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
1190 grub_size_t max_length, grub_size_t startwidth)
1192 const grub_uint32_t *line_start = logical, *ptr;
1193 struct grub_unicode_glyph *visual_ptr;
1194 *visual_out = visual_ptr = grub_malloc (2 * sizeof (visual_ptr[0])
1195 * logical_len);
1196 if (!visual_ptr)
1197 return -1;
1198 for (ptr = logical; ptr <= logical + logical_len; ptr++)
1200 if (ptr == logical + logical_len || *ptr == '\n')
1202 grub_ssize_t ret;
1203 ret = grub_bidi_line_logical_to_visual (line_start,
1204 ptr - line_start,
1205 visual_ptr,
1206 getcharwidth,
1207 max_length,
1208 startwidth);
1209 startwidth = 0;
1211 if (ret < 0)
1213 grub_free (*visual_out);
1214 return ret;
1216 visual_ptr += ret;
1217 line_start = ptr;
1218 if (ptr != logical + logical_len)
1220 grub_memset (visual_ptr, 0, sizeof (visual_ptr[0]));
1221 visual_ptr->base = '\n';
1222 visual_ptr++;
1223 line_start++;
1227 return visual_ptr - *visual_out;
1230 grub_uint32_t
1231 grub_unicode_mirror_code (grub_uint32_t in)
1233 int i;
1234 for (i = 0; grub_unicode_bidi_pairs[i].key; i++)
1235 if (grub_unicode_bidi_pairs[i].key == in)
1236 return grub_unicode_bidi_pairs[i].replace;
1237 return in;
1240 grub_uint32_t
1241 grub_unicode_shape_code (grub_uint32_t in, grub_uint8_t attr)
1243 int i;
1244 if (!(in >= GRUB_UNICODE_ARABIC_START
1245 && in < GRUB_UNICODE_ARABIC_END))
1246 return in;
1248 for (i = 0; grub_unicode_arabic_shapes[i].code; i++)
1249 if (grub_unicode_arabic_shapes[i].code == in)
1251 grub_uint32_t out = 0;
1252 switch (attr & (GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
1253 | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED))
1255 case 0:
1256 out = grub_unicode_arabic_shapes[i].isolated;
1257 break;
1258 case GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED:
1259 out = grub_unicode_arabic_shapes[i].right_linked;
1260 break;
1261 case GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED:
1262 out = grub_unicode_arabic_shapes[i].left_linked;
1263 break;
1264 case GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
1265 |GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED:
1266 out = grub_unicode_arabic_shapes[i].both_linked;
1267 break;
1269 if (out)
1270 return out;
1273 return in;