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)
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)
37 Font information ignored:
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>
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"
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
;
70 grub_uint32_t code
= 0;
75 while (srcsize
&& destsize
)
77 grub_uint32_t c
= *src
++;
78 if (srcsize
!= (grub_size_t
)-1)
82 if ((c
& GRUB_UINT8_2_LEADINGBITS
) != GRUB_UINT8_1_LEADINGBIT
)
90 code
|= (c
& GRUB_UINT8_6_TRAILINGBITS
);
99 if ((c
& GRUB_UINT8_1_LEADINGBIT
) == 0)
101 else if ((c
& GRUB_UINT8_3_LEADINGBITS
) == GRUB_UINT8_2_LEADINGBITS
)
104 code
= c
& GRUB_UINT8_5_TRAILINGBITS
;
106 else if ((c
& GRUB_UINT8_4_LEADINGBITS
) == GRUB_UINT8_3_LEADINGBITS
)
109 code
= c
& GRUB_UINT8_4_TRAILINGBITS
;
111 else if ((c
& GRUB_UINT8_5_LEADINGBITS
) == GRUB_UINT8_4_LEADINGBITS
)
114 code
= c
& GRUB_UINT8_3_TRAILINGBITS
;
122 if (destsize
< 2 && code
>= GRUB_UCS2_LIMIT
)
124 if (code
>= GRUB_UCS2_LIMIT
)
126 *p
++ = GRUB_UTF16_UPPER_SURROGATE (code
);
127 *p
++ = GRUB_UTF16_LOWER_SURROGATE (code
);
143 /* Convert UCS-4 to UTF-8. */
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
++;
157 else if (code
<= 0x07FF)
159 if (dest
+ 1 >= destend
)
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... */
170 else if (code
< 0x10000)
172 if (dest
+ 2 >= destend
)
174 *dest
++ = (code
>> 12) | 0xE0;
175 *dest
++ = ((code
>> 6) & 0x3F) | 0x80;
176 *dest
++ = (code
& 0x3F) | 0x80;
180 if (dest
+ 3 >= destend
)
182 *dest
++ = (code
>> 18) | 0xF0;
183 *dest
++ = ((code
>> 12) & 0x3F) | 0x80;
184 *dest
++ = ((code
>> 6) & 0x3F) | 0x80;
185 *dest
++ = (code
& 0x3F) | 0x80;
191 /* Convert UCS-4 to UTF-8. */
193 grub_ucs4_to_utf8_alloc (grub_uint32_t
*src
, grub_size_t size
)
195 grub_size_t remaining
;
204 grub_uint32_t code
= *ptr
++;
208 else if (code
<= 0x07FF)
210 else if ((code
>= 0xDC00 && code
<= 0xDFFF)
211 || (code
>= 0xD800 && code
<= 0xDBFF))
212 /* No surrogates in UCS-4... */
214 else if (code
< 0x10000)
221 ret
= grub_malloc (cnt
);
225 grub_ucs4_to_utf8 (src
, size
, ret
, cnt
);
231 grub_is_valid_utf8 (const grub_uint8_t
*src
, grub_size_t srcsize
)
233 grub_uint32_t code
= 0;
238 grub_uint32_t c
= *src
++;
239 if (srcsize
!= (grub_size_t
)-1)
243 if ((c
& 0xc0) != 0x80)
260 if ((c
& 0x80) == 0x00)
262 else if ((c
& 0xe0) == 0xc0)
267 else if ((c
& 0xf0) == 0xe0)
272 else if ((c
& 0xf8) == 0xf0)
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
));
296 msg_len
= grub_utf8_to_ucs4 (*unicode_msg
, msg_len
,
297 (grub_uint8_t
*) msg
, -1, 0);
300 *last_position
= *unicode_msg
+ 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. */
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
;
318 grub_uint32_t code
= 0;
323 while (srcsize
&& destsize
)
325 grub_uint32_t c
= *src
++;
326 if (srcsize
!= (grub_size_t
)-1)
330 if ((c
& 0xc0) != 0x80)
334 /* Character c may be valid, don't eat it. */
336 if (srcsize
!= (grub_size_t
)-1)
352 if ((c
& 0x80) == 0x00)
354 else if ((c
& 0xe0) == 0xc0)
359 else if ((c
& 0xf0) == 0xe0)
364 else if ((c
& 0xf8) == 0xf0)
389 static grub_uint8_t
*join_types
= NULL
;
395 struct grub_unicode_compact_range
*cur
;
397 join_types
= grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR
);
400 grub_errno
= GRUB_ERR_NONE
;
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
;
415 struct grub_unicode_compact_range
*cur
;
417 bidi_types
= grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR
);
420 grub_errno
= GRUB_ERR_NONE
;
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;
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
;
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
;
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
;
469 is_mirrored (grub_uint32_t c
)
471 struct grub_unicode_compact_range
*cur
;
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
;
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
;
495 comb_types
= grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR
);
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
;
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
518 grub_unicode_estimate_width (const struct grub_unicode_glyph
*c
)
520 if (grub_unicode_get_comb_type (c
->base
))
522 if (widthspec
[c
->base
>> 3] & (1 << (c
->base
& 7)))
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
)
539 if (b
== GRUB_UNICODE_COMB_ARABIC_SHADDA
540 && a
<= GRUB_UNICODE_COMB_ARABIC_KASRA
541 && a
>= GRUB_UNICODE_COMB_ARABIC_FATHATAN
)
547 grub_unicode_aglomerate_comb (const grub_uint32_t
*in
, grub_size_t inlen
,
548 struct grub_unicode_glyph
*out
)
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
)
565 out
->variant
= *ptr
- GRUB_UNICODE_VARIATION_SELECTOR_1
+ 1;
569 if (*ptr
>= GRUB_UNICODE_VARIATION_SELECTOR_17
570 && *ptr
<= GRUB_UNICODE_VARIATION_SELECTOR_256
)
573 out
->variant
= *ptr
- GRUB_UNICODE_VARIATION_SELECTOR_17
+ 17;
577 enum grub_comb_type comb_type
;
578 comb_type
= grub_unicode_get_comb_type (*ptr
);
581 struct grub_unicode_combining
*n
;
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));
595 grub_errno
= GRUB_ERR_NONE
;
600 for (j
= last_comb_pointer
; j
< out
->ncomb
; j
++)
601 if (is_type_after (out
->combining
[j
].type
, comb_type
))
603 grub_memmove (out
->combining
+ j
+ 1,
606 * sizeof (out
->combining
[0]));
608 out
->combining
[j
].code
= *ptr
;
609 out
->combining
[j
].type
= comb_type
;
620 out
->estimated_width
= 1;
621 out
->combining
= NULL
;
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
;
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
;
645 for (i
= 0; i
<= (end
- start
) / 2; i
++)
647 t
= visual
[start
+ i
];
648 visual
[start
+ i
] = visual
[end
- i
];
650 tl
= levels
[start
+ i
];
651 levels
[start
+ i
] = levels
[end
- i
];
652 levels
[end
- i
] = tl
;
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
== ' ')
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
)
680 else if (k
!= visual_len
&& line_start
== 0 && startwidth
!= 0)
683 last_space_width
= startwidth
;
686 last_space_width
= line_width
- last_width
;
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
];
701 /* FIXME: can be optimized. */
702 for (j
= max_level
; j
>= min_odd_level
; j
--)
706 for (i
= line_start
; i
< k
; i
++)
708 if (i
!= line_start
&& levels
[i
] >= j
&& levels
[i
-1] < j
)
710 if (levels
[i
] >= j
&& (i
+ 1 == k
|| levels
[i
+1] < j
))
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
)
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
);
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
))
753 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED
;
756 &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED
;
758 if (join_type
== GRUB_JOIN_TYPE_NONJOINING
759 || join_type
== GRUB_JOIN_TYPE_LEFT
)
761 if (join_type
== GRUB_JOIN_TYPE_RIGHT
762 || join_type
== GRUB_JOIN_TYPE_DUAL
763 || join_type
== GRUB_JOIN_TYPE_CAUSING
)
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
))
781 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
;
784 &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
;
786 if (join_type
== GRUB_JOIN_TYPE_NONJOINING
787 || join_type
== GRUB_JOIN_TYPE_RIGHT
)
789 if (join_type
== GRUB_JOIN_TYPE_LEFT
790 || join_type
== GRUB_JOIN_TYPE_DUAL
791 || join_type
== GRUB_JOIN_TYPE_CAUSING
)
796 grub_memcpy (outptr
, &visual
[line_start
],
797 (k
- line_start
) * sizeof (visual
[0]));
798 outptr
+= k
- line_start
;
801 grub_memset (outptr
, 0, sizeof (visual
[0]));
806 if ((signed) k
== last_space
)
810 line_width
-= last_space_width
;
814 return outptr
- visual_out
;
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
};
828 enum grub_bidi_type
*resolved_types
;
830 enum override_status cur_override
;
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
;
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
)
850 stack_level
[stack_depth
] = cur_level
;
851 stack_override
[stack_depth
] = cur_override
;
853 cur_level
= new_level
;
854 cur_override
= new_override
;
857 auto void pop_stack (void);
858 void pop_stack (void)
868 cur_level
= stack_level
[stack_depth
];
869 cur_override
= stack_override
[stack_depth
];
872 levels
= grub_malloc (sizeof (levels
[0]) * logical_len
);
876 resolved_types
= grub_malloc (sizeof (resolved_types
[0]) * logical_len
);
883 visual
= grub_malloc (sizeof (visual
[0]) * logical_len
);
886 grub_free (resolved_types
);
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
)
898 if (type
== GRUB_BIDI_TYPE_R
|| type
== GRUB_BIDI_TYPE_AL
)
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
;)
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
;
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;
942 p
= grub_unicode_aglomerate_comb (lptr
, logical
+ logical_len
- lptr
,
943 &visual
[visual_len
]);
945 type
= get_bidi_type (visual
[visual_len
].base
);
948 case GRUB_BIDI_TYPE_RLE
:
950 push_stack (cur_override
, (cur_level
| 1) + 1);
952 case GRUB_BIDI_TYPE_RLO
:
954 push_stack (OVERRIDE_R
, (cur_level
| 1) + 1);
956 case GRUB_BIDI_TYPE_LRE
:
957 push_stack (cur_override
, (cur_level
& ~1) + 2);
959 case GRUB_BIDI_TYPE_LRO
:
960 push_stack (OVERRIDE_L
, (cur_level
& ~1) + 2);
962 case GRUB_BIDI_TYPE_PDF
:
965 case GRUB_BIDI_TYPE_BN
:
967 case GRUB_BIDI_TYPE_R
:
968 case GRUB_BIDI_TYPE_AL
:
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
996 resolved_types
[visual_len
] = type
;
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
++);
1013 prev_level
= base_level
;
1015 prev_level
= levels
[run_start
- 1];
1016 if (run_end
== visual_len
)
1017 next_level
= base_level
;
1019 next_level
= levels
[run_end
];
1020 cur_run_level
= levels
[run_start
];
1022 last_type
= GRUB_BIDI_TYPE_R
;
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
;
1033 case GRUB_BIDI_TYPE_EN
:
1034 if (last_strong_type
== GRUB_BIDI_TYPE_AL
)
1035 resolved_types
[i
] = GRUB_BIDI_TYPE_AN
;
1037 case GRUB_BIDI_TYPE_L
:
1038 case GRUB_BIDI_TYPE_R
:
1039 last_strong_type
= resolved_types
[i
];
1041 case GRUB_BIDI_TYPE_ES
:
1042 if (last_type
== GRUB_BIDI_TYPE_EN
1044 && resolved_types
[i
+ 1] == GRUB_BIDI_TYPE_EN
)
1045 resolved_types
[i
] = GRUB_BIDI_TYPE_EN
;
1047 resolved_types
[i
] = GRUB_BIDI_TYPE_ON
;
1049 case GRUB_BIDI_TYPE_ET
:
1052 if (last_type
== GRUB_BIDI_TYPE_EN
)
1054 resolved_types
[i
] = GRUB_BIDI_TYPE_EN
;
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
)
1062 && resolved_types
[i
] == GRUB_BIDI_TYPE_ET
; i
++)
1063 resolved_types
[i
] = GRUB_BIDI_TYPE_EN
;
1068 && resolved_types
[i
] == GRUB_BIDI_TYPE_ET
; i
++)
1069 resolved_types
[i
] = GRUB_BIDI_TYPE_ON
;
1074 case GRUB_BIDI_TYPE_CS
:
1075 if (last_type
== GRUB_BIDI_TYPE_EN
1077 && resolved_types
[i
+ 1] == GRUB_BIDI_TYPE_EN
)
1079 resolved_types
[i
] = GRUB_BIDI_TYPE_EN
;
1082 if (last_type
== GRUB_BIDI_TYPE_AN
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
;
1091 resolved_types
[i
] = GRUB_BIDI_TYPE_ON
;
1093 case GRUB_BIDI_TYPE_AL
:
1094 last_strong_type
= resolved_types
[i
];
1095 resolved_types
[i
] = GRUB_BIDI_TYPE_R
;
1097 default: /* Make GCC happy. */
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
;
1106 last_type
= GRUB_BIDI_TYPE_R
;
1108 last_type
= GRUB_BIDI_TYPE_L
;
1109 for (i
= run_start
; i
< run_end
; )
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
++);
1120 if (resolved_types
[i
] == GRUB_BIDI_TYPE_L
)
1121 last_type
= GRUB_BIDI_TYPE_L
;
1123 last_type
= GRUB_BIDI_TYPE_R
;
1128 next_type
= (next_level
& 1) ? GRUB_BIDI_TYPE_R
: GRUB_BIDI_TYPE_L
;
1131 if (resolved_types
[j
] == GRUB_BIDI_TYPE_L
)
1132 next_type
= GRUB_BIDI_TYPE_L
;
1134 next_type
= GRUB_BIDI_TYPE_R
;
1136 if (next_type
== last_type
)
1138 resolved_types
[i
] = last_type
;
1141 resolved_types
[i
] = (cur_run_level
& 1) ? GRUB_BIDI_TYPE_R
1146 for (i
= 0; i
< visual_len
; i
++)
1148 if (!(levels
[i
] & 1) && resolved_types
[i
] == GRUB_BIDI_TYPE_R
)
1153 if (!(levels
[i
] & 1) && (resolved_types
[i
] == GRUB_BIDI_TYPE_AN
1154 || resolved_types
[i
] == GRUB_BIDI_TYPE_EN
))
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
))
1170 for (i
= 0; i
< visual_len
; i
++)
1173 grub_free (resolved_types
);
1177 ret
= bidi_line_wrap (visual_out
, visual
, visual_len
, levels
,
1178 getcharwidth
, maxwidth
, startwidth
);
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])
1198 for (ptr
= logical
; ptr
<= logical
+ logical_len
; ptr
++)
1200 if (ptr
== logical
+ logical_len
|| *ptr
== '\n')
1203 ret
= grub_bidi_line_logical_to_visual (line_start
,
1213 grub_free (*visual_out
);
1218 if (ptr
!= logical
+ logical_len
)
1220 grub_memset (visual_ptr
, 0, sizeof (visual_ptr
[0]));
1221 visual_ptr
->base
= '\n';
1227 return visual_ptr
- *visual_out
;
1231 grub_unicode_mirror_code (grub_uint32_t in
)
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
;
1241 grub_unicode_shape_code (grub_uint32_t in
, grub_uint8_t attr
)
1244 if (!(in
>= GRUB_UNICODE_ARABIC_START
1245 && in
< GRUB_UNICODE_ARABIC_END
))
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
))
1256 out
= grub_unicode_arabic_shapes
[i
].isolated
;
1258 case GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
:
1259 out
= grub_unicode_arabic_shapes
[i
].right_linked
;
1261 case GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED
:
1262 out
= grub_unicode_arabic_shapes
[i
].left_linked
;
1264 case GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
1265 |GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED
:
1266 out
= grub_unicode_arabic_shapes
[i
].both_linked
;