Upgraded GRUB2 to 2.00 release.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / normal / charset.c
blob25593ce81fdedc6217034094d4b32875ead19530
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 #include <grub/charset.h>
46 #include <grub/mm.h>
47 #include <grub/misc.h>
48 #include <grub/unicode.h>
49 #include <grub/term.h>
50 #include <grub/normal.h>
52 #ifdef HAVE_UNIFONT_WIDTHSPEC
53 #include "widthspec.h"
54 #endif
56 /* Returns -2 if not enough space, -1 on invalid character. */
57 grub_ssize_t
58 grub_encode_utf8_character (grub_uint8_t *dest, grub_uint8_t *destend,
59 grub_uint32_t code)
61 if (dest >= destend)
62 return -2;
63 if (code <= 0x007F)
65 *dest++ = code;
66 return 1;
68 if (code <= 0x07FF)
70 if (dest + 1 >= destend)
71 return -2;
72 *dest++ = (code >> 6) | 0xC0;
73 *dest++ = (code & 0x3F) | 0x80;
74 return 2;
76 if ((code >= 0xDC00 && code <= 0xDFFF)
77 || (code >= 0xD800 && code <= 0xDBFF))
79 /* No surrogates in UCS-4... */
80 return -1;
82 if (code < 0x10000)
84 if (dest + 2 >= destend)
85 return -2;
86 *dest++ = (code >> 12) | 0xE0;
87 *dest++ = ((code >> 6) & 0x3F) | 0x80;
88 *dest++ = (code & 0x3F) | 0x80;
89 return 3;
92 if (dest + 3 >= destend)
93 return -2;
94 *dest++ = (code >> 18) | 0xF0;
95 *dest++ = ((code >> 12) & 0x3F) | 0x80;
96 *dest++ = ((code >> 6) & 0x3F) | 0x80;
97 *dest++ = (code & 0x3F) | 0x80;
98 return 4;
103 /* Convert UCS-4 to UTF-8. */
104 grub_size_t
105 grub_ucs4_to_utf8 (const grub_uint32_t *src, grub_size_t size,
106 grub_uint8_t *dest, grub_size_t destsize)
108 /* Keep last char for \0. */
109 grub_uint8_t *destend = dest + destsize - 1;
110 grub_uint8_t *dest0 = dest;
112 while (size-- && dest < destend)
114 grub_uint32_t code = *src++;
115 grub_ssize_t s;
116 s = grub_encode_utf8_character (dest, destend, code);
117 if (s == -2)
118 break;
119 if (s == -1)
121 *dest++ = '?';
122 continue;
124 dest += s;
126 *dest = 0;
127 return dest - dest0;
130 /* Returns the number of bytes the string src would occupy is converted
131 to UTF-8, excluding trailing \0. */
132 grub_size_t
133 grub_get_num_of_utf8_bytes (const grub_uint32_t *src, grub_size_t size)
135 grub_size_t remaining;
136 const grub_uint32_t *ptr;
137 grub_size_t cnt = 0;
139 remaining = size;
140 ptr = src;
141 while (remaining--)
143 grub_uint32_t code = *ptr++;
145 if (code <= 0x007F)
146 cnt++;
147 else if (code <= 0x07FF)
148 cnt += 2;
149 else if ((code >= 0xDC00 && code <= 0xDFFF)
150 || (code >= 0xD800 && code <= 0xDBFF))
151 /* No surrogates in UCS-4... */
152 cnt++;
153 else if (code < 0x10000)
154 cnt += 3;
155 else
156 cnt += 4;
158 return cnt;
161 /* Convert UCS-4 to UTF-8. */
162 char *
163 grub_ucs4_to_utf8_alloc (const grub_uint32_t *src, grub_size_t size)
165 grub_uint8_t *ret;
166 grub_size_t cnt = grub_get_num_of_utf8_bytes (src, size) + 1;
168 ret = grub_malloc (cnt);
169 if (!ret)
170 return 0;
172 grub_ucs4_to_utf8 (src, size, ret, cnt);
174 return (char *) ret;
178 grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize)
180 int count = 0;
181 grub_uint32_t code = 0;
183 while (srcsize)
185 if (srcsize != (grub_size_t)-1)
186 srcsize--;
187 if (!grub_utf8_process (*src++, &code, &count))
188 return 0;
189 if (count != 0)
190 continue;
191 if (code == 0)
192 return 1;
193 if (code > GRUB_UNICODE_LAST_VALID)
194 return 0;
197 return 1;
200 grub_ssize_t
201 grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg,
202 grub_uint32_t **last_position)
204 grub_size_t msg_len = grub_strlen (msg);
206 *unicode_msg = grub_malloc (msg_len * sizeof (grub_uint32_t));
208 if (!*unicode_msg)
209 return -1;
211 msg_len = grub_utf8_to_ucs4 (*unicode_msg, msg_len,
212 (grub_uint8_t *) msg, -1, 0);
214 if (last_position)
215 *last_position = *unicode_msg + msg_len;
217 return msg_len;
220 /* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE
221 bytes (if SRCSIZE is -1, it is ignored) in length to a UCS-4 string.
222 Return the number of characters converted. DEST must be able to hold
223 at least DESTSIZE characters.
224 If SRCEND is not NULL, then *SRCEND is set to the next byte after the
225 last byte used in SRC. */
226 grub_size_t
227 grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
228 const grub_uint8_t *src, grub_size_t srcsize,
229 const grub_uint8_t **srcend)
231 grub_uint32_t *p = dest;
232 int count = 0;
233 grub_uint32_t code = 0;
235 if (srcend)
236 *srcend = src;
238 while (srcsize && destsize)
240 int was_count = count;
241 if (srcsize != (grub_size_t)-1)
242 srcsize--;
243 if (!grub_utf8_process (*src++, &code, &count))
245 code = '?';
246 count = 0;
247 /* Character c may be valid, don't eat it. */
248 if (was_count)
249 src--;
251 if (count != 0)
252 continue;
253 if (code == 0)
254 break;
255 *p++ = code;
256 destsize--;
259 if (srcend)
260 *srcend = src;
261 return p - dest;
264 static grub_uint8_t *join_types = NULL;
266 static void
267 unpack_join (void)
269 unsigned i;
270 struct grub_unicode_compact_range *cur;
272 join_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
273 if (!join_types)
275 grub_errno = GRUB_ERR_NONE;
276 return;
278 for (cur = grub_unicode_compact; cur->len; cur++)
279 for (i = cur->start; i < cur->start + (unsigned) cur->len
280 && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
281 join_types[i] = cur->join_type;
284 static grub_uint8_t *bidi_types = NULL;
286 static void
287 unpack_bidi (void)
289 unsigned i;
290 struct grub_unicode_compact_range *cur;
292 bidi_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
293 if (!bidi_types)
295 grub_errno = GRUB_ERR_NONE;
296 return;
298 for (cur = grub_unicode_compact; cur->len; cur++)
299 for (i = cur->start; i < cur->start + (unsigned) cur->len
300 && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
301 if (cur->bidi_mirror)
302 bidi_types[i] = cur->bidi_type | 0x80;
303 else
304 bidi_types[i] = cur->bidi_type | 0x00;
307 static inline enum grub_bidi_type
308 get_bidi_type (grub_uint32_t c)
310 struct grub_unicode_compact_range *cur;
312 if (!bidi_types)
313 unpack_bidi ();
315 if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
316 return bidi_types[c] & 0x7f;
318 for (cur = grub_unicode_compact; cur->len; cur++)
319 if (cur->start <= c && c < cur->start + (unsigned) cur->len)
320 return cur->bidi_type;
322 return GRUB_BIDI_TYPE_L;
325 static inline enum grub_join_type
326 get_join_type (grub_uint32_t c)
328 struct grub_unicode_compact_range *cur;
330 if (!join_types)
331 unpack_join ();
333 if (join_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
334 return join_types[c];
336 for (cur = grub_unicode_compact; cur->len; cur++)
337 if (cur->start <= c && c < cur->start + (unsigned) cur->len)
338 return cur->join_type;
340 return GRUB_JOIN_TYPE_NONJOINING;
343 static inline int
344 is_mirrored (grub_uint32_t c)
346 struct grub_unicode_compact_range *cur;
348 if (!bidi_types)
349 unpack_bidi ();
351 if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
352 return !!(bidi_types[c] & 0x80);
354 for (cur = grub_unicode_compact; cur->len; cur++)
355 if (cur->start <= c && c < cur->start + (unsigned) cur->len)
356 return cur->bidi_mirror;
358 return 0;
361 enum grub_comb_type
362 grub_unicode_get_comb_type (grub_uint32_t c)
364 static grub_uint8_t *comb_types = NULL;
365 struct grub_unicode_compact_range *cur;
367 if (!comb_types)
369 unsigned i;
370 comb_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
371 if (comb_types)
372 for (cur = grub_unicode_compact; cur->len; cur++)
373 for (i = cur->start; i < cur->start + (unsigned) cur->len
374 && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
375 comb_types[i] = cur->comb_type;
376 else
377 grub_errno = GRUB_ERR_NONE;
380 if (comb_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
381 return comb_types[c];
383 for (cur = grub_unicode_compact; cur->len; cur++)
384 if (cur->start <= c && c < cur->start + (unsigned) cur->len)
385 return cur->comb_type;
387 return GRUB_UNICODE_COMB_NONE;
390 #ifdef HAVE_UNIFONT_WIDTHSPEC
392 grub_ssize_t
393 grub_unicode_estimate_width (const struct grub_unicode_glyph *c)
395 if (grub_unicode_get_comb_type (c->base))
396 return 0;
397 if (widthspec[c->base >> 3] & (1 << (c->base & 7)))
398 return 2;
399 else
400 return 1;
403 #endif
405 static inline int
406 is_type_after (enum grub_comb_type a, enum grub_comb_type b)
408 /* Shadda is numerically higher than most of Arabic diacritics but has
409 to be rendered before them. */
410 if (a == GRUB_UNICODE_COMB_ARABIC_SHADDA
411 && b <= GRUB_UNICODE_COMB_ARABIC_KASRA
412 && b >= GRUB_UNICODE_COMB_ARABIC_FATHATAN)
413 return 0;
414 if (b == GRUB_UNICODE_COMB_ARABIC_SHADDA
415 && a <= GRUB_UNICODE_COMB_ARABIC_KASRA
416 && a >= GRUB_UNICODE_COMB_ARABIC_FATHATAN)
417 return 1;
418 return a > b;
421 grub_size_t
422 grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
423 struct grub_unicode_glyph *out)
425 int haveout = 0;
426 const grub_uint32_t *ptr;
427 unsigned last_comb_pointer = 0;
429 grub_memset (out, 0, sizeof (*out));
431 if (inlen && grub_iscntrl (*in))
433 out->base = *in;
434 out->variant = 0;
435 out->attributes = 0;
436 out->ncomb = 0;
437 out->estimated_width = 1;
438 out->combining = NULL;
439 return 1;
442 for (ptr = in; ptr < in + inlen; ptr++)
444 /* Variation selectors >= 17 are outside of BMP and SMP.
445 Handle variation selectors first to avoid potentially costly lookups.
447 if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1
448 && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16)
450 if (haveout)
451 out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_1 + 1;
452 continue;
454 if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17
455 && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256)
457 if (haveout)
458 out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_17 + 17;
459 continue;
462 enum grub_comb_type comb_type;
463 comb_type = grub_unicode_get_comb_type (*ptr);
464 if (comb_type)
466 struct grub_unicode_combining *n;
467 unsigned j;
469 if (!haveout)
470 continue;
472 if (comb_type == GRUB_UNICODE_COMB_MC
473 || comb_type == GRUB_UNICODE_COMB_ME
474 || comb_type == GRUB_UNICODE_COMB_MN)
475 last_comb_pointer = out->ncomb;
476 n = grub_realloc (out->combining,
477 sizeof (n[0]) * (out->ncomb + 1));
478 if (!n)
480 grub_errno = GRUB_ERR_NONE;
481 continue;
483 out->combining = n;
485 for (j = last_comb_pointer; j < out->ncomb; j++)
486 if (is_type_after (out->combining[j].type, comb_type))
487 break;
488 grub_memmove (out->combining + j + 1,
489 out->combining + j,
490 (out->ncomb - j)
491 * sizeof (out->combining[0]));
492 out->combining = n;
493 out->combining[j].code = *ptr;
494 out->combining[j].type = comb_type;
495 out->ncomb++;
496 continue;
498 if (haveout)
499 return ptr - in;
500 haveout = 1;
501 out->base = *ptr;
502 out->variant = 0;
503 out->attributes = 0;
504 out->ncomb = 0;
505 out->estimated_width = 1;
506 out->combining = NULL;
508 return ptr - in;
511 static grub_ssize_t
512 bidi_line_wrap (struct grub_unicode_glyph *visual_out,
513 struct grub_unicode_glyph *visual,
514 grub_size_t visual_len, unsigned *levels,
515 grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
516 grub_size_t maxwidth, grub_size_t startwidth)
518 struct grub_unicode_glyph *outptr = visual_out;
519 unsigned line_start = 0;
520 grub_ssize_t line_width = startwidth;
521 unsigned k;
522 grub_ssize_t last_space = -1;
523 grub_ssize_t last_space_width = 0;
525 auto void revert (unsigned start, unsigned end);
526 void revert (unsigned start, unsigned end)
528 struct grub_unicode_glyph t;
529 unsigned i, tl;
530 for (i = 0; i < (end - start) / 2 + 1; i++)
532 t = visual[start + i];
533 visual[start + i] = visual[end - i];
534 visual[end - i] = t;
535 tl = levels[start + i];
536 levels[start + i] = levels[end - i];
537 levels[end - i] = tl;
541 if (!visual_len)
542 return 0;
544 for (k = 0; k <= visual_len; k++)
546 grub_ssize_t last_width = 0;
548 if (getcharwidth && k != visual_len)
549 line_width += last_width = getcharwidth (&visual[k]);
551 if (k != visual_len && (visual[k].base == ' '
552 || visual[k].base == '\t'))
554 last_space = k;
555 last_space_width = line_width;
558 if (((grub_ssize_t) maxwidth > 0
559 && line_width > (grub_ssize_t) maxwidth) || k == visual_len)
561 unsigned min_odd_level = 0xffffffff;
562 unsigned max_level = 0;
564 if (k != visual_len && last_space > (signed) line_start)
565 k = last_space;
566 else if (k != visual_len && line_start == 0 && startwidth != 0)
568 k = 0;
569 last_space_width = startwidth;
571 else
572 last_space_width = line_width - last_width;
575 unsigned i;
576 for (i = line_start; i < k; i++)
578 if (levels[i] > max_level)
579 max_level = levels[i];
580 if (levels[i] < min_odd_level && (levels[i] & 1))
581 min_odd_level = levels[i];
586 unsigned j;
587 /* FIXME: can be optimized. */
588 for (j = max_level; j > min_odd_level - 1; j--)
590 unsigned in = line_start;
591 unsigned i;
592 for (i = line_start; i < k; i++)
594 if (i != line_start && levels[i] >= j && levels[i-1] < j)
595 in = i;
596 if (levels[i] >= j && (i + 1 == k || levels[i+1] < j))
597 revert (in, i);
603 unsigned i;
604 for (i = line_start; i < k; i++)
606 if (is_mirrored (visual[i].base) && levels[i])
607 visual[i].attributes |= GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR;
608 if ((visual[i].attributes & GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN)
609 && levels[i])
611 int left, right;
612 left = visual[i].attributes
613 & (GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED
614 | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT);
615 right = visual[i].attributes
616 & (GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
617 | GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT);
618 visual[i].attributes &= ~GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN;
619 left <<= GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN_LEFT_TO_RIGHT_SHIFT;
620 right >>= GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN_LEFT_TO_RIGHT_SHIFT;
621 visual[i].attributes |= (left | right);
627 int left_join = 0;
628 unsigned i;
629 for (i = line_start; i < k; i++)
631 enum grub_join_type join_type = get_join_type (visual[i].base);
632 if (!(visual[i].attributes
633 & GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT)
634 && (join_type == GRUB_JOIN_TYPE_LEFT
635 || join_type == GRUB_JOIN_TYPE_DUAL))
637 if (left_join)
638 visual[i].attributes
639 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED;
640 else
641 visual[i].attributes
642 &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED;
644 if (join_type == GRUB_JOIN_TYPE_NONJOINING
645 || join_type == GRUB_JOIN_TYPE_LEFT)
646 left_join = 0;
647 if (join_type == GRUB_JOIN_TYPE_RIGHT
648 || join_type == GRUB_JOIN_TYPE_DUAL
649 || join_type == GRUB_JOIN_TYPE_CAUSING)
650 left_join = 1;
655 int right_join = 0;
656 signed i;
657 for (i = k - 1; i >= 0 && (unsigned) i + 1 > line_start;
658 i--)
660 enum grub_join_type join_type = get_join_type (visual[i].base);
661 if (!(visual[i].attributes
662 & GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT)
663 && (join_type == GRUB_JOIN_TYPE_RIGHT
664 || join_type == GRUB_JOIN_TYPE_DUAL))
666 if (right_join)
667 visual[i].attributes
668 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED;
669 else
670 visual[i].attributes
671 &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED;
673 if (join_type == GRUB_JOIN_TYPE_NONJOINING
674 || join_type == GRUB_JOIN_TYPE_RIGHT)
675 right_join = 0;
676 if (join_type == GRUB_JOIN_TYPE_LEFT
677 || join_type == GRUB_JOIN_TYPE_DUAL
678 || join_type == GRUB_JOIN_TYPE_CAUSING)
679 right_join = 1;
683 grub_memcpy (outptr, &visual[line_start],
684 (k - line_start) * sizeof (visual[0]));
685 outptr += k - line_start;
686 if (k != visual_len)
688 grub_memset (outptr, 0, sizeof (visual[0]));
689 outptr->base = '\n';
690 outptr++;
693 if ((signed) k == last_space)
694 k++;
696 line_start = k;
697 line_width -= last_space_width;
701 return outptr - visual_out;
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_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
710 grub_size_t maxwidth, grub_size_t startwidth)
712 enum grub_bidi_type type = GRUB_BIDI_TYPE_L;
713 enum override_status {OVERRIDE_NEUTRAL = 0, OVERRIDE_R, OVERRIDE_L};
714 unsigned *levels;
715 enum grub_bidi_type *resolved_types;
716 unsigned base_level;
717 enum override_status cur_override;
718 unsigned i;
719 unsigned stack_level[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3];
720 enum override_status stack_override[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3];
721 unsigned stack_depth = 0;
722 unsigned invalid_pushes = 0;
723 unsigned visual_len = 0;
724 unsigned run_start, run_end;
725 struct grub_unicode_glyph *visual;
726 unsigned cur_level;
727 int bidi_needed = 0;
729 auto void push_stack (unsigned new_override, unsigned new_level);
730 void push_stack (unsigned new_override, unsigned new_level)
732 if (new_level > GRUB_BIDI_MAX_EXPLICIT_LEVEL)
734 invalid_pushes++;
735 return;
737 stack_level[stack_depth] = cur_level;
738 stack_override[stack_depth] = cur_override;
739 stack_depth++;
740 cur_level = new_level;
741 cur_override = new_override;
744 auto void pop_stack (void);
745 void pop_stack (void)
747 if (invalid_pushes)
749 invalid_pushes--;
750 return;
752 if (!stack_depth)
753 return;
754 stack_depth--;
755 cur_level = stack_level[stack_depth];
756 cur_override = stack_override[stack_depth];
759 levels = grub_malloc (sizeof (levels[0]) * logical_len);
760 if (!levels)
761 return -1;
763 resolved_types = grub_malloc (sizeof (resolved_types[0]) * logical_len);
764 if (!resolved_types)
766 grub_free (levels);
767 return -1;
770 visual = grub_malloc (sizeof (visual[0]) * logical_len);
771 if (!visual)
773 grub_free (resolved_types);
774 grub_free (levels);
775 return -1;
778 for (i = 0; i < logical_len; i++)
780 type = get_bidi_type (logical[i]);
781 if (type == GRUB_BIDI_TYPE_L || type == GRUB_BIDI_TYPE_AL
782 || type == GRUB_BIDI_TYPE_R)
783 break;
785 if (type == GRUB_BIDI_TYPE_R || type == GRUB_BIDI_TYPE_AL)
786 base_level = 1;
787 else
788 base_level = 0;
790 cur_level = base_level;
791 cur_override = OVERRIDE_NEUTRAL;
793 const grub_uint32_t *lptr;
794 enum {JOIN_DEFAULT, NOJOIN, JOIN_FORCE} join_state = JOIN_DEFAULT;
795 int zwj_propagate_to_previous = 0;
796 for (lptr = logical; lptr < logical + logical_len;)
798 grub_size_t p;
800 if (*lptr == GRUB_UNICODE_ZWJ)
802 if (zwj_propagate_to_previous)
804 visual[visual_len - 1].attributes
805 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT
806 | GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED;
808 zwj_propagate_to_previous = 0;
809 join_state = JOIN_FORCE;
810 lptr++;
811 continue;
814 if (*lptr == GRUB_UNICODE_ZWNJ)
816 if (zwj_propagate_to_previous)
818 visual[visual_len - 1].attributes
819 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT;
820 visual[visual_len - 1].attributes
821 &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED;
823 zwj_propagate_to_previous = 0;
824 join_state = NOJOIN;
825 lptr++;
826 continue;
829 /* The tags: deprecated, never used. */
830 if (*lptr >= GRUB_UNICODE_TAG_START && *lptr <= GRUB_UNICODE_TAG_END)
831 continue;
833 p = grub_unicode_aglomerate_comb (lptr, logical + logical_len - lptr,
834 &visual[visual_len]);
836 type = get_bidi_type (visual[visual_len].base);
837 switch (type)
839 case GRUB_BIDI_TYPE_RLE:
840 bidi_needed = 1;
841 push_stack (cur_override, (cur_level | 1) + 1);
842 break;
843 case GRUB_BIDI_TYPE_RLO:
844 bidi_needed = 1;
845 push_stack (OVERRIDE_R, (cur_level | 1) + 1);
846 break;
847 case GRUB_BIDI_TYPE_LRE:
848 push_stack (cur_override, (cur_level & ~1) + 2);
849 break;
850 case GRUB_BIDI_TYPE_LRO:
851 push_stack (OVERRIDE_L, (cur_level & ~1) + 2);
852 break;
853 case GRUB_BIDI_TYPE_PDF:
854 pop_stack ();
855 break;
856 case GRUB_BIDI_TYPE_BN:
857 break;
858 case GRUB_BIDI_TYPE_R:
859 case GRUB_BIDI_TYPE_AL:
860 bidi_needed = 1;
861 default:
863 if (join_state == JOIN_FORCE)
865 visual[visual_len].attributes
866 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT
867 | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED;
870 if (join_state == NOJOIN)
872 visual[visual_len].attributes
873 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT;
874 visual[visual_len].attributes
875 &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED;
878 join_state = JOIN_DEFAULT;
879 zwj_propagate_to_previous = 1;
881 levels[visual_len] = cur_level;
882 if (cur_override != OVERRIDE_NEUTRAL)
883 resolved_types[visual_len] =
884 (cur_override == OVERRIDE_L) ? GRUB_BIDI_TYPE_L
885 : GRUB_BIDI_TYPE_R;
886 else
887 resolved_types[visual_len] = type;
888 visual_len++;
891 lptr += p;
895 if (bidi_needed)
897 for (run_start = 0; run_start < visual_len; run_start = run_end)
899 unsigned prev_level, next_level, cur_run_level;
900 unsigned last_type, last_strong_type;
901 for (run_end = run_start; run_end < visual_len &&
902 levels[run_end] == levels[run_start]; run_end++);
903 if (run_start == 0)
904 prev_level = base_level;
905 else
906 prev_level = levels[run_start - 1];
907 if (run_end == visual_len)
908 next_level = base_level;
909 else
910 next_level = levels[run_end];
911 cur_run_level = levels[run_start];
912 if (prev_level & 1)
913 last_type = GRUB_BIDI_TYPE_R;
914 else
915 last_type = GRUB_BIDI_TYPE_L;
916 last_strong_type = last_type;
917 for (i = run_start; i < run_end; i++)
919 switch (resolved_types[i])
921 case GRUB_BIDI_TYPE_NSM:
922 resolved_types[i] = last_type;
923 break;
924 case GRUB_BIDI_TYPE_EN:
925 if (last_strong_type == GRUB_BIDI_TYPE_AL)
926 resolved_types[i] = GRUB_BIDI_TYPE_AN;
927 break;
928 case GRUB_BIDI_TYPE_L:
929 case GRUB_BIDI_TYPE_R:
930 last_strong_type = resolved_types[i];
931 break;
932 case GRUB_BIDI_TYPE_ES:
933 if (last_type == GRUB_BIDI_TYPE_EN
934 && i + 1 < run_end
935 && resolved_types[i + 1] == GRUB_BIDI_TYPE_EN)
936 resolved_types[i] = GRUB_BIDI_TYPE_EN;
937 else
938 resolved_types[i] = GRUB_BIDI_TYPE_ON;
939 break;
940 case GRUB_BIDI_TYPE_ET:
942 unsigned j;
943 if (last_type == GRUB_BIDI_TYPE_EN)
945 resolved_types[i] = GRUB_BIDI_TYPE_EN;
946 break;
948 for (j = i; j < run_end
949 && resolved_types[j] == GRUB_BIDI_TYPE_ET; j++);
950 if (j != run_end && resolved_types[j] == GRUB_BIDI_TYPE_EN)
952 for (; i < run_end
953 && resolved_types[i] == GRUB_BIDI_TYPE_ET; i++)
954 resolved_types[i] = GRUB_BIDI_TYPE_EN;
955 i--;
956 break;
958 for (; i < run_end
959 && resolved_types[i] == GRUB_BIDI_TYPE_ET; i++)
960 resolved_types[i] = GRUB_BIDI_TYPE_ON;
961 i--;
962 break;
964 break;
965 case GRUB_BIDI_TYPE_CS:
966 if (last_type == GRUB_BIDI_TYPE_EN
967 && i + 1 < run_end
968 && resolved_types[i + 1] == GRUB_BIDI_TYPE_EN)
970 resolved_types[i] = GRUB_BIDI_TYPE_EN;
971 break;
973 if (last_type == GRUB_BIDI_TYPE_AN
974 && i + 1 < run_end
975 && (resolved_types[i + 1] == GRUB_BIDI_TYPE_AN
976 || (resolved_types[i + 1] == GRUB_BIDI_TYPE_EN
977 && last_strong_type == GRUB_BIDI_TYPE_AL)))
979 resolved_types[i] = GRUB_BIDI_TYPE_EN;
980 break;
982 resolved_types[i] = GRUB_BIDI_TYPE_ON;
983 break;
984 case GRUB_BIDI_TYPE_AL:
985 last_strong_type = resolved_types[i];
986 resolved_types[i] = GRUB_BIDI_TYPE_R;
987 break;
988 default: /* Make GCC happy. */
989 break;
991 last_type = resolved_types[i];
992 if (resolved_types[i] == GRUB_BIDI_TYPE_EN
993 && last_strong_type == GRUB_BIDI_TYPE_L)
994 resolved_types[i] = GRUB_BIDI_TYPE_L;
996 if (prev_level & 1)
997 last_type = GRUB_BIDI_TYPE_R;
998 else
999 last_type = GRUB_BIDI_TYPE_L;
1000 for (i = run_start; i < run_end; )
1002 unsigned j;
1003 unsigned next_type;
1004 for (j = i; j < run_end &&
1005 (resolved_types[j] == GRUB_BIDI_TYPE_B
1006 || resolved_types[j] == GRUB_BIDI_TYPE_S
1007 || resolved_types[j] == GRUB_BIDI_TYPE_WS
1008 || resolved_types[j] == GRUB_BIDI_TYPE_ON); j++);
1009 if (j == i)
1011 if (resolved_types[i] == GRUB_BIDI_TYPE_L)
1012 last_type = GRUB_BIDI_TYPE_L;
1013 else
1014 last_type = GRUB_BIDI_TYPE_R;
1015 i++;
1016 continue;
1018 if (j == run_end)
1019 next_type = (next_level & 1) ? GRUB_BIDI_TYPE_R : GRUB_BIDI_TYPE_L;
1020 else
1022 if (resolved_types[j] == GRUB_BIDI_TYPE_L)
1023 next_type = GRUB_BIDI_TYPE_L;
1024 else
1025 next_type = GRUB_BIDI_TYPE_R;
1027 if (next_type == last_type)
1028 for (; i < j; i++)
1029 resolved_types[i] = last_type;
1030 else
1031 for (; i < j; i++)
1032 resolved_types[i] = (cur_run_level & 1) ? GRUB_BIDI_TYPE_R
1033 : GRUB_BIDI_TYPE_L;
1037 for (i = 0; i < visual_len; i++)
1039 if (!(levels[i] & 1) && resolved_types[i] == GRUB_BIDI_TYPE_R)
1041 levels[i]++;
1042 continue;
1044 if (!(levels[i] & 1) && (resolved_types[i] == GRUB_BIDI_TYPE_AN
1045 || resolved_types[i] == GRUB_BIDI_TYPE_EN))
1047 levels[i] += 2;
1048 continue;
1050 if ((levels[i] & 1) && (resolved_types[i] == GRUB_BIDI_TYPE_L
1051 || resolved_types[i] == GRUB_BIDI_TYPE_AN
1052 || resolved_types[i] == GRUB_BIDI_TYPE_EN))
1054 levels[i]++;
1055 continue;
1059 else
1061 for (i = 0; i < visual_len; i++)
1062 levels[i] = 0;
1064 grub_free (resolved_types);
1067 grub_ssize_t ret;
1068 ret = bidi_line_wrap (visual_out, visual, visual_len, levels,
1069 getcharwidth, maxwidth, startwidth);
1070 grub_free (levels);
1071 grub_free (visual);
1072 return ret;
1076 grub_ssize_t
1077 grub_bidi_logical_to_visual (const grub_uint32_t *logical,
1078 grub_size_t logical_len,
1079 struct grub_unicode_glyph **visual_out,
1080 grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
1081 grub_size_t max_length, grub_size_t startwidth)
1083 const grub_uint32_t *line_start = logical, *ptr;
1084 struct grub_unicode_glyph *visual_ptr;
1085 *visual_out = visual_ptr = grub_malloc (2 * sizeof (visual_ptr[0])
1086 * logical_len);
1087 if (!visual_ptr)
1088 return -1;
1089 for (ptr = logical; ptr <= logical + logical_len; ptr++)
1091 if (ptr == logical + logical_len || *ptr == '\n')
1093 grub_ssize_t ret;
1094 ret = grub_bidi_line_logical_to_visual (line_start,
1095 ptr - line_start,
1096 visual_ptr,
1097 getcharwidth,
1098 max_length,
1099 startwidth);
1100 startwidth = 0;
1102 if (ret < 0)
1104 grub_free (*visual_out);
1105 return ret;
1107 visual_ptr += ret;
1108 line_start = ptr;
1109 if (ptr != logical + logical_len)
1111 grub_memset (visual_ptr, 0, sizeof (visual_ptr[0]));
1112 visual_ptr->base = '\n';
1113 visual_ptr++;
1114 line_start++;
1118 return visual_ptr - *visual_out;
1121 grub_uint32_t
1122 grub_unicode_mirror_code (grub_uint32_t in)
1124 int i;
1125 for (i = 0; grub_unicode_bidi_pairs[i].key; i++)
1126 if (grub_unicode_bidi_pairs[i].key == in)
1127 return grub_unicode_bidi_pairs[i].replace;
1128 return in;
1131 grub_uint32_t
1132 grub_unicode_shape_code (grub_uint32_t in, grub_uint8_t attr)
1134 int i;
1135 if (!(in >= GRUB_UNICODE_ARABIC_START
1136 && in < GRUB_UNICODE_ARABIC_END))
1137 return in;
1139 for (i = 0; grub_unicode_arabic_shapes[i].code; i++)
1140 if (grub_unicode_arabic_shapes[i].code == in)
1142 grub_uint32_t out = 0;
1143 switch (attr & (GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
1144 | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED))
1146 case 0:
1147 out = grub_unicode_arabic_shapes[i].isolated;
1148 break;
1149 case GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED:
1150 out = grub_unicode_arabic_shapes[i].right_linked;
1151 break;
1152 case GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED:
1153 out = grub_unicode_arabic_shapes[i].left_linked;
1154 break;
1155 case GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
1156 |GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED:
1157 out = grub_unicode_arabic_shapes[i].both_linked;
1158 break;
1160 if (out)
1161 return out;
1164 return in;
1167 const grub_uint32_t *
1168 grub_unicode_get_comb_start (const grub_uint32_t *str,
1169 const grub_uint32_t *cur)
1171 const grub_uint32_t *ptr;
1172 for (ptr = cur; ptr >= str; ptr--)
1174 if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1
1175 && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16)
1176 continue;
1178 if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17
1179 && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256)
1180 continue;
1182 enum grub_comb_type comb_type;
1183 comb_type = grub_unicode_get_comb_type (*ptr);
1184 if (comb_type)
1185 continue;
1186 return ptr;
1188 return str;