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 #include <grub/charset.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"
56 /* Returns -2 if not enough space, -1 on invalid character. */
58 grub_encode_utf8_character (grub_uint8_t
*dest
, grub_uint8_t
*destend
,
70 if (dest
+ 1 >= destend
)
72 *dest
++ = (code
>> 6) | 0xC0;
73 *dest
++ = (code
& 0x3F) | 0x80;
76 if ((code
>= 0xDC00 && code
<= 0xDFFF)
77 || (code
>= 0xD800 && code
<= 0xDBFF))
79 /* No surrogates in UCS-4... */
84 if (dest
+ 2 >= destend
)
86 *dest
++ = (code
>> 12) | 0xE0;
87 *dest
++ = ((code
>> 6) & 0x3F) | 0x80;
88 *dest
++ = (code
& 0x3F) | 0x80;
92 if (dest
+ 3 >= destend
)
94 *dest
++ = (code
>> 18) | 0xF0;
95 *dest
++ = ((code
>> 12) & 0x3F) | 0x80;
96 *dest
++ = ((code
>> 6) & 0x3F) | 0x80;
97 *dest
++ = (code
& 0x3F) | 0x80;
103 /* Convert UCS-4 to UTF-8. */
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
++;
116 s
= grub_encode_utf8_character (dest
, destend
, code
);
130 /* Returns the number of bytes the string src would occupy is converted
131 to UTF-8, excluding trailing \0. */
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
;
143 grub_uint32_t code
= *ptr
++;
147 else if (code
<= 0x07FF)
149 else if ((code
>= 0xDC00 && code
<= 0xDFFF)
150 || (code
>= 0xD800 && code
<= 0xDBFF))
151 /* No surrogates in UCS-4... */
153 else if (code
< 0x10000)
161 /* Convert UCS-4 to UTF-8. */
163 grub_ucs4_to_utf8_alloc (const grub_uint32_t
*src
, grub_size_t size
)
166 grub_size_t cnt
= grub_get_num_of_utf8_bytes (src
, size
) + 1;
168 ret
= grub_malloc (cnt
);
172 grub_ucs4_to_utf8 (src
, size
, ret
, cnt
);
178 grub_is_valid_utf8 (const grub_uint8_t
*src
, grub_size_t srcsize
)
181 grub_uint32_t code
= 0;
185 if (srcsize
!= (grub_size_t
)-1)
187 if (!grub_utf8_process (*src
++, &code
, &count
))
193 if (code
> GRUB_UNICODE_LAST_VALID
)
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
));
211 msg_len
= grub_utf8_to_ucs4 (*unicode_msg
, msg_len
,
212 (grub_uint8_t
*) msg
, -1, 0);
215 *last_position
= *unicode_msg
+ 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. */
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
;
233 grub_uint32_t code
= 0;
238 while (srcsize
&& destsize
)
240 int was_count
= count
;
241 if (srcsize
!= (grub_size_t
)-1)
243 if (!grub_utf8_process (*src
++, &code
, &count
))
247 /* Character c may be valid, don't eat it. */
264 static grub_uint8_t
*join_types
= NULL
;
270 struct grub_unicode_compact_range
*cur
;
272 join_types
= grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR
);
275 grub_errno
= GRUB_ERR_NONE
;
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
;
290 struct grub_unicode_compact_range
*cur
;
292 bidi_types
= grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR
);
295 grub_errno
= GRUB_ERR_NONE
;
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;
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
;
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
;
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
;
344 is_mirrored (grub_uint32_t c
)
346 struct grub_unicode_compact_range
*cur
;
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
;
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
;
370 comb_types
= grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR
);
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
;
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
393 grub_unicode_estimate_width (const struct grub_unicode_glyph
*c
)
395 if (grub_unicode_get_comb_type (c
->base
))
397 if (widthspec
[c
->base
>> 3] & (1 << (c
->base
& 7)))
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
)
414 if (b
== GRUB_UNICODE_COMB_ARABIC_SHADDA
415 && a
<= GRUB_UNICODE_COMB_ARABIC_KASRA
416 && a
>= GRUB_UNICODE_COMB_ARABIC_FATHATAN
)
422 grub_unicode_aglomerate_comb (const grub_uint32_t
*in
, grub_size_t inlen
,
423 struct grub_unicode_glyph
*out
)
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
))
437 out
->estimated_width
= 1;
438 out
->combining
= NULL
;
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
)
451 out
->variant
= *ptr
- GRUB_UNICODE_VARIATION_SELECTOR_1
+ 1;
454 if (*ptr
>= GRUB_UNICODE_VARIATION_SELECTOR_17
455 && *ptr
<= GRUB_UNICODE_VARIATION_SELECTOR_256
)
458 out
->variant
= *ptr
- GRUB_UNICODE_VARIATION_SELECTOR_17
+ 17;
462 enum grub_comb_type comb_type
;
463 comb_type
= grub_unicode_get_comb_type (*ptr
);
466 struct grub_unicode_combining
*n
;
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));
480 grub_errno
= GRUB_ERR_NONE
;
485 for (j
= last_comb_pointer
; j
< out
->ncomb
; j
++)
486 if (is_type_after (out
->combining
[j
].type
, comb_type
))
488 grub_memmove (out
->combining
+ j
+ 1,
491 * sizeof (out
->combining
[0]));
493 out
->combining
[j
].code
= *ptr
;
494 out
->combining
[j
].type
= comb_type
;
505 out
->estimated_width
= 1;
506 out
->combining
= NULL
;
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
;
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
;
530 for (i
= 0; i
< (end
- start
) / 2 + 1; i
++)
532 t
= visual
[start
+ i
];
533 visual
[start
+ i
] = visual
[end
- i
];
535 tl
= levels
[start
+ i
];
536 levels
[start
+ i
] = levels
[end
- i
];
537 levels
[end
- i
] = tl
;
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'))
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
)
566 else if (k
!= visual_len
&& line_start
== 0 && startwidth
!= 0)
569 last_space_width
= startwidth
;
572 last_space_width
= line_width
- last_width
;
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
];
587 /* FIXME: can be optimized. */
588 for (j
= max_level
; j
> min_odd_level
- 1; j
--)
590 unsigned in
= line_start
;
592 for (i
= line_start
; i
< k
; i
++)
594 if (i
!= line_start
&& levels
[i
] >= j
&& levels
[i
-1] < j
)
596 if (levels
[i
] >= j
&& (i
+ 1 == k
|| levels
[i
+1] < j
))
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
)
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
);
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
))
639 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED
;
642 &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED
;
644 if (join_type
== GRUB_JOIN_TYPE_NONJOINING
645 || join_type
== GRUB_JOIN_TYPE_LEFT
)
647 if (join_type
== GRUB_JOIN_TYPE_RIGHT
648 || join_type
== GRUB_JOIN_TYPE_DUAL
649 || join_type
== GRUB_JOIN_TYPE_CAUSING
)
657 for (i
= k
- 1; i
>= 0 && (unsigned) i
+ 1 > line_start
;
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
))
668 |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
;
671 &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
;
673 if (join_type
== GRUB_JOIN_TYPE_NONJOINING
674 || join_type
== GRUB_JOIN_TYPE_RIGHT
)
676 if (join_type
== GRUB_JOIN_TYPE_LEFT
677 || join_type
== GRUB_JOIN_TYPE_DUAL
678 || join_type
== GRUB_JOIN_TYPE_CAUSING
)
683 grub_memcpy (outptr
, &visual
[line_start
],
684 (k
- line_start
) * sizeof (visual
[0]));
685 outptr
+= k
- line_start
;
688 grub_memset (outptr
, 0, sizeof (visual
[0]));
693 if ((signed) k
== last_space
)
697 line_width
-= last_space_width
;
701 return outptr
- visual_out
;
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
};
715 enum grub_bidi_type
*resolved_types
;
717 enum override_status cur_override
;
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
;
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
)
737 stack_level
[stack_depth
] = cur_level
;
738 stack_override
[stack_depth
] = cur_override
;
740 cur_level
= new_level
;
741 cur_override
= new_override
;
744 auto void pop_stack (void);
745 void pop_stack (void)
755 cur_level
= stack_level
[stack_depth
];
756 cur_override
= stack_override
[stack_depth
];
759 levels
= grub_malloc (sizeof (levels
[0]) * logical_len
);
763 resolved_types
= grub_malloc (sizeof (resolved_types
[0]) * logical_len
);
770 visual
= grub_malloc (sizeof (visual
[0]) * logical_len
);
773 grub_free (resolved_types
);
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
)
785 if (type
== GRUB_BIDI_TYPE_R
|| type
== GRUB_BIDI_TYPE_AL
)
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
;)
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
;
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;
829 /* The tags: deprecated, never used. */
830 if (*lptr
>= GRUB_UNICODE_TAG_START
&& *lptr
<= GRUB_UNICODE_TAG_END
)
833 p
= grub_unicode_aglomerate_comb (lptr
, logical
+ logical_len
- lptr
,
834 &visual
[visual_len
]);
836 type
= get_bidi_type (visual
[visual_len
].base
);
839 case GRUB_BIDI_TYPE_RLE
:
841 push_stack (cur_override
, (cur_level
| 1) + 1);
843 case GRUB_BIDI_TYPE_RLO
:
845 push_stack (OVERRIDE_R
, (cur_level
| 1) + 1);
847 case GRUB_BIDI_TYPE_LRE
:
848 push_stack (cur_override
, (cur_level
& ~1) + 2);
850 case GRUB_BIDI_TYPE_LRO
:
851 push_stack (OVERRIDE_L
, (cur_level
& ~1) + 2);
853 case GRUB_BIDI_TYPE_PDF
:
856 case GRUB_BIDI_TYPE_BN
:
858 case GRUB_BIDI_TYPE_R
:
859 case GRUB_BIDI_TYPE_AL
:
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
887 resolved_types
[visual_len
] = type
;
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
++);
904 prev_level
= base_level
;
906 prev_level
= levels
[run_start
- 1];
907 if (run_end
== visual_len
)
908 next_level
= base_level
;
910 next_level
= levels
[run_end
];
911 cur_run_level
= levels
[run_start
];
913 last_type
= GRUB_BIDI_TYPE_R
;
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
;
924 case GRUB_BIDI_TYPE_EN
:
925 if (last_strong_type
== GRUB_BIDI_TYPE_AL
)
926 resolved_types
[i
] = GRUB_BIDI_TYPE_AN
;
928 case GRUB_BIDI_TYPE_L
:
929 case GRUB_BIDI_TYPE_R
:
930 last_strong_type
= resolved_types
[i
];
932 case GRUB_BIDI_TYPE_ES
:
933 if (last_type
== GRUB_BIDI_TYPE_EN
935 && resolved_types
[i
+ 1] == GRUB_BIDI_TYPE_EN
)
936 resolved_types
[i
] = GRUB_BIDI_TYPE_EN
;
938 resolved_types
[i
] = GRUB_BIDI_TYPE_ON
;
940 case GRUB_BIDI_TYPE_ET
:
943 if (last_type
== GRUB_BIDI_TYPE_EN
)
945 resolved_types
[i
] = GRUB_BIDI_TYPE_EN
;
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
)
953 && resolved_types
[i
] == GRUB_BIDI_TYPE_ET
; i
++)
954 resolved_types
[i
] = GRUB_BIDI_TYPE_EN
;
959 && resolved_types
[i
] == GRUB_BIDI_TYPE_ET
; i
++)
960 resolved_types
[i
] = GRUB_BIDI_TYPE_ON
;
965 case GRUB_BIDI_TYPE_CS
:
966 if (last_type
== GRUB_BIDI_TYPE_EN
968 && resolved_types
[i
+ 1] == GRUB_BIDI_TYPE_EN
)
970 resolved_types
[i
] = GRUB_BIDI_TYPE_EN
;
973 if (last_type
== GRUB_BIDI_TYPE_AN
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
;
982 resolved_types
[i
] = GRUB_BIDI_TYPE_ON
;
984 case GRUB_BIDI_TYPE_AL
:
985 last_strong_type
= resolved_types
[i
];
986 resolved_types
[i
] = GRUB_BIDI_TYPE_R
;
988 default: /* Make GCC happy. */
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
;
997 last_type
= GRUB_BIDI_TYPE_R
;
999 last_type
= GRUB_BIDI_TYPE_L
;
1000 for (i
= run_start
; i
< run_end
; )
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
++);
1011 if (resolved_types
[i
] == GRUB_BIDI_TYPE_L
)
1012 last_type
= GRUB_BIDI_TYPE_L
;
1014 last_type
= GRUB_BIDI_TYPE_R
;
1019 next_type
= (next_level
& 1) ? GRUB_BIDI_TYPE_R
: GRUB_BIDI_TYPE_L
;
1022 if (resolved_types
[j
] == GRUB_BIDI_TYPE_L
)
1023 next_type
= GRUB_BIDI_TYPE_L
;
1025 next_type
= GRUB_BIDI_TYPE_R
;
1027 if (next_type
== last_type
)
1029 resolved_types
[i
] = last_type
;
1032 resolved_types
[i
] = (cur_run_level
& 1) ? GRUB_BIDI_TYPE_R
1037 for (i
= 0; i
< visual_len
; i
++)
1039 if (!(levels
[i
] & 1) && resolved_types
[i
] == GRUB_BIDI_TYPE_R
)
1044 if (!(levels
[i
] & 1) && (resolved_types
[i
] == GRUB_BIDI_TYPE_AN
1045 || resolved_types
[i
] == GRUB_BIDI_TYPE_EN
))
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
))
1061 for (i
= 0; i
< visual_len
; i
++)
1064 grub_free (resolved_types
);
1068 ret
= bidi_line_wrap (visual_out
, visual
, visual_len
, levels
,
1069 getcharwidth
, maxwidth
, startwidth
);
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])
1089 for (ptr
= logical
; ptr
<= logical
+ logical_len
; ptr
++)
1091 if (ptr
== logical
+ logical_len
|| *ptr
== '\n')
1094 ret
= grub_bidi_line_logical_to_visual (line_start
,
1104 grub_free (*visual_out
);
1109 if (ptr
!= logical
+ logical_len
)
1111 grub_memset (visual_ptr
, 0, sizeof (visual_ptr
[0]));
1112 visual_ptr
->base
= '\n';
1118 return visual_ptr
- *visual_out
;
1122 grub_unicode_mirror_code (grub_uint32_t in
)
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
;
1132 grub_unicode_shape_code (grub_uint32_t in
, grub_uint8_t attr
)
1135 if (!(in
>= GRUB_UNICODE_ARABIC_START
1136 && in
< GRUB_UNICODE_ARABIC_END
))
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
))
1147 out
= grub_unicode_arabic_shapes
[i
].isolated
;
1149 case GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
:
1150 out
= grub_unicode_arabic_shapes
[i
].right_linked
;
1152 case GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED
:
1153 out
= grub_unicode_arabic_shapes
[i
].left_linked
;
1155 case GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
1156 |GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED
:
1157 out
= grub_unicode_arabic_shapes
[i
].both_linked
;
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
)
1178 if (*ptr
>= GRUB_UNICODE_VARIATION_SELECTOR_17
1179 && *ptr
<= GRUB_UNICODE_VARIATION_SELECTOR_256
)
1182 enum grub_comb_type comb_type
;
1183 comb_type
= grub_unicode_get_comb_type (*ptr
);