/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
/*
Current problems with Unicode rendering:
- B and BN bidi type characters (ignored)
- Mc type characters with combining class 0 (poorly combined)
- Mn type characters with combining class 0 (poorly combined)
- Me type characters with combining class 0 (poorly combined)
- Cf type characters (ignored)
- Cc type characters (ignored)
- Line-breaking rules (e.g. Zs type characters)
- Indic languages
- non-Semitic shaping (rarely used)
- Zl and Zp characters
- Combining characters of types 7, 8, 9, 21, 35, 36, 84, 91, 103, 107,
118, 122, 129, 130, 132, 218, 224, 226, 233, 234
- Private use characters (not really a problem)
- Variations (no font support)
- Vertical text
- Ligatures
Font information ignored:
- Kerning
- Justification data
- Glyph posititioning
- Baseline data
Most underline diacritics aren't displayed in gfxterm
*/
#ifdef HAVE_UNIFONT_WIDTHSPEC
#include "widthspec.h"
#endif
int
{
if (*count)
{
if ((c & GRUB_UINT8_2_LEADINGBITS) != GRUB_UINT8_1_LEADINGBIT)
{
*count = 0;
/* invalid */
return 0;
}
else
{
*code <<= 6;
*code |= (c & GRUB_UINT8_6_TRAILINGBITS);
(*count)--;
return 1;
}
}
if ((c & GRUB_UINT8_1_LEADINGBIT) == 0)
{
*code = c;
return 1;
}
if ((c & GRUB_UINT8_3_LEADINGBITS) == GRUB_UINT8_2_LEADINGBITS)
{
*count = 1;
*code = c & GRUB_UINT8_5_TRAILINGBITS;
return 1;
}
if ((c & GRUB_UINT8_4_LEADINGBITS) == GRUB_UINT8_3_LEADINGBITS)
{
*count = 2;
*code = c & GRUB_UINT8_4_TRAILINGBITS;
return 1;
}
if ((c & GRUB_UINT8_5_LEADINGBITS) == GRUB_UINT8_4_LEADINGBITS)
{
*count = 3;
*code = c & GRUB_UINT8_3_TRAILINGBITS;
return 1;
}
return 0;
}
/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE
bytes (if SRCSIZE is -1, it is ignored) in length to a UTF-16 string.
Return the number of characters converted. DEST must be able to hold
at least DESTSIZE characters. If an invalid sequence is found, return -1.
If SRCEND is not NULL, then *SRCEND is set to the next byte after the
last byte used in SRC. */
const grub_uint8_t **srcend)
{
grub_uint16_t *p = dest;
int count = 0;
if (srcend)
{
srcsize--;
{
code = '?';
count = 0;
/* Character c may be valid, don't eat it. */
if (was_count)
src--;
}
if (count != 0)
continue;
if (code == 0)
break;
break;
if (code >= GRUB_UCS2_LIMIT)
{
*p++ = GRUB_UTF16_UPPER_SURROGATE (code);
*p++ = GRUB_UTF16_LOWER_SURROGATE (code);
destsize -= 2;
}
else
{
*p++ = code;
destsize--;
}
}
if (srcend)
return p - dest;
}
/* Returns -2 if not enough space, -1 on invalid character. */
{
return -2;
if (code <= 0x007F)
{
return 1;
}
if (code <= 0x07FF)
{
return -2;
return 2;
}
{
/* No surrogates in UCS-4... */
return -1;
}
if (code < 0x10000)
{
return -2;
return 3;
}
{
return -2;
return 4;
}
}
/* Convert UCS-4 to UTF-8. */
void
{
/* Keep last char for \0. */
{
grub_ssize_t s;
if (s == -2)
break;
if (s == -1)
{
*dest++ = '?';
continue;
}
dest += s;
}
*dest = 0;
}
/* Convert UCS-4 to UTF-8. */
char *
{
while (remaining--)
{
if (code <= 0x007F)
cnt++;
else if (code <= 0x07FF)
cnt += 2;
/* No surrogates in UCS-4... */
cnt++;
else if (code < 0x10000)
cnt += 3;
else
cnt += 4;
}
cnt++;
if (!ret)
return 0;
return (char *) ret;
}
int
{
int count = 0;
while (srcsize)
{
srcsize--;
return 0;
if (count != 0)
continue;
if (code == 0)
return 1;
if (code > GRUB_UNICODE_LAST_VALID)
return 0;
}
return 1;
}
int
{
if (!*unicode_msg)
return -1;
if (last_position)
return msg_len;
}
/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE
bytes (if SRCSIZE is -1, it is ignored) in length to a UCS-4 string.
Return the number of characters converted. DEST must be able to hold
at least DESTSIZE characters.
If SRCEND is not NULL, then *SRCEND is set to the next byte after the
last byte used in SRC. */
const grub_uint8_t **srcend)
{
grub_uint32_t *p = dest;
int count = 0;
if (srcend)
{
srcsize--;
{
code = '?';
count = 0;
/* Character c may be valid, don't eat it. */
if (was_count)
src--;
}
if (count != 0)
continue;
if (code == 0)
break;
*p++ = code;
destsize--;
}
if (srcend)
return p - dest;
}
static void
unpack_join (void)
{
unsigned i;
if (!join_types)
{
return;
}
&& i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
}
static void
unpack_bidi (void)
{
unsigned i;
if (!bidi_types)
{
return;
}
&& i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
if (cur->bidi_mirror)
else
}
static inline enum grub_bidi_type
{
if (!bidi_types)
unpack_bidi ();
if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
return bidi_types[c] & 0x7f;
return GRUB_BIDI_TYPE_L;
}
static inline enum grub_join_type
{
if (!join_types)
unpack_join ();
if (join_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
return join_types[c];
return GRUB_JOIN_TYPE_NONJOINING;
}
static inline int
{
if (!bidi_types)
unpack_bidi ();
if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
return !!(bidi_types[c] & 0x80);
return cur->bidi_mirror;
return 0;
}
enum grub_comb_type
{
if (!comb_types)
{
unsigned i;
if (comb_types)
&& i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
else
}
if (comb_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
return comb_types[c];
return GRUB_UNICODE_COMB_NONE;
}
#ifdef HAVE_UNIFONT_WIDTHSPEC
{
if (grub_unicode_get_comb_type (c->base))
return 0;
return 2;
else
return 1;
}
#endif
static inline int
{
/* Shadda is numerically higher than most of Arabic diacritics but has
to be rendered before them. */
if (a == GRUB_UNICODE_COMB_ARABIC_SHADDA
&& b <= GRUB_UNICODE_COMB_ARABIC_KASRA
&& b >= GRUB_UNICODE_COMB_ARABIC_FATHATAN)
return 0;
if (b == GRUB_UNICODE_COMB_ARABIC_SHADDA
&& a <= GRUB_UNICODE_COMB_ARABIC_KASRA
&& a >= GRUB_UNICODE_COMB_ARABIC_FATHATAN)
return 1;
return a > b;
}
struct grub_unicode_glyph *out)
{
int haveout = 0;
unsigned last_comb_pointer = 0;
{
/* Variation selectors >= 17 are outside of BMP and SMP.
Handle variation selectors first to avoid potentially costly lookups.
*/
if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1
{
if (haveout)
continue;
}
{
if (haveout)
continue;
}
if (comb_type)
{
struct grub_unicode_combining *n;
unsigned j;
if (!haveout)
continue;
if (comb_type == GRUB_UNICODE_COMB_MC
|| comb_type == GRUB_UNICODE_COMB_MN)
if (!n)
{
continue;
}
break;
continue;
}
if (haveout)
haveout = 1;
out->attributes = 0;
}
}
static grub_ssize_t
struct grub_unicode_glyph *visual,
{
unsigned line_start = 0;
unsigned k;
{
struct grub_unicode_glyph t;
unsigned i, tl;
{
}
}
if (!visual_len)
return 0;
for (k = 0; k <= visual_len; k++)
{
if (getcharwidth && k != visual_len)
{
last_space = k;
}
if (((grub_ssize_t) maxwidth > 0
{
unsigned max_level = 0;
k = last_space;
{
k = 0;
}
else
{
unsigned i;
for (i = line_start; i < k; i++)
{
min_odd_level = levels[i];
}
}
{
unsigned j;
/* FIXME: can be optimized. */
for (j = max_level; j >= min_odd_level; j--)
{
unsigned in = 0;
unsigned i;
for (i = line_start; i < k; i++)
{
in = i;
}
}
}
{
unsigned i;
for (i = line_start; i < k; i++)
{
&& levels[i])
{
}
}
}
{
int left_join = 0;
unsigned i;
for (i = line_start; i < k; i++)
{
if (!(visual[i].attributes
&& (join_type == GRUB_JOIN_TYPE_LEFT
|| join_type == GRUB_JOIN_TYPE_DUAL))
{
if (left_join)
visual[i].attributes
else
visual[i].attributes
}
|| join_type == GRUB_JOIN_TYPE_LEFT)
left_join = 0;
if (join_type == GRUB_JOIN_TYPE_RIGHT
|| join_type == GRUB_JOIN_TYPE_DUAL
|| join_type == GRUB_JOIN_TYPE_CAUSING)
left_join = 1;
}
}
{
int right_join = 0;
signed i;
for (i = k - 1; i >= (signed) line_start; i--)
{
if (!(visual[i].attributes
&& (join_type == GRUB_JOIN_TYPE_RIGHT
|| join_type == GRUB_JOIN_TYPE_DUAL))
{
if (right_join)
visual[i].attributes
else
visual[i].attributes
}
|| join_type == GRUB_JOIN_TYPE_RIGHT)
right_join = 0;
if (join_type == GRUB_JOIN_TYPE_LEFT
|| join_type == GRUB_JOIN_TYPE_DUAL
|| join_type == GRUB_JOIN_TYPE_CAUSING)
right_join = 1;
}
}
(k - line_start) * sizeof (visual[0]));
outptr += k - line_start;
if (k != visual_len)
{
outptr++;
}
if ((signed) k == last_space)
k++;
line_start = k;
}
}
return outptr - visual_out;
}
static grub_ssize_t
struct grub_unicode_glyph *visual_out,
{
unsigned *levels;
unsigned base_level;
unsigned i;
unsigned stack_depth = 0;
unsigned invalid_pushes = 0;
unsigned visual_len = 0;
unsigned cur_level;
int bidi_needed = 0;
{
{
return;
}
stack_depth++;
}
auto void pop_stack (void);
void pop_stack (void)
{
if (invalid_pushes)
{
return;
}
if (!stack_depth)
return;
stack_depth--;
}
if (!levels)
return -1;
if (!resolved_types)
{
return -1;
}
if (!visual)
{
return -1;
}
for (i = 0; i < logical_len; i++)
{
|| type == GRUB_BIDI_TYPE_R)
break;
}
base_level = 1;
else
base_level = 0;
{
int zwj_propagate_to_previous = 0;
{
grub_size_t p;
if (*lptr == GRUB_UNICODE_ZWJ)
{
{
}
lptr++;
continue;
}
if (*lptr == GRUB_UNICODE_ZWNJ)
{
{
}
join_state = NOJOIN;
lptr++;
continue;
}
/* The tags: deprecated, never used. */
continue;
&visual[visual_len]);
switch (type)
{
case GRUB_BIDI_TYPE_RLE:
bidi_needed = 1;
break;
case GRUB_BIDI_TYPE_RLO:
bidi_needed = 1;
break;
case GRUB_BIDI_TYPE_LRE:
break;
case GRUB_BIDI_TYPE_LRO:
break;
case GRUB_BIDI_TYPE_PDF:
pop_stack ();
break;
case GRUB_BIDI_TYPE_BN:
break;
case GRUB_BIDI_TYPE_R:
case GRUB_BIDI_TYPE_AL:
bidi_needed = 1;
default:
{
if (join_state == JOIN_FORCE)
{
}
if (join_state == NOJOIN)
{
}
if (cur_override != OVERRIDE_NEUTRAL)
else
visual_len++;
}
}
lptr += p;
}
}
if (bidi_needed)
{
{
if (run_start == 0)
else
if (run_end == visual_len)
else
if (prev_level & 1)
else
{
switch (resolved_types[i])
{
case GRUB_BIDI_TYPE_NSM:
resolved_types[i] = last_type;
break;
case GRUB_BIDI_TYPE_EN:
if (last_strong_type == GRUB_BIDI_TYPE_AL)
break;
case GRUB_BIDI_TYPE_L:
case GRUB_BIDI_TYPE_R:
break;
case GRUB_BIDI_TYPE_ES:
if (last_type == GRUB_BIDI_TYPE_EN
&& i + 1 < run_end
else
break;
case GRUB_BIDI_TYPE_ET:
{
unsigned j;
if (last_type == GRUB_BIDI_TYPE_EN)
{
break;
}
for (j = i; j < run_end
&& resolved_types[j] == GRUB_BIDI_TYPE_ET; j++);
{
for (; i < run_end
&& resolved_types[i] == GRUB_BIDI_TYPE_ET; i++)
i--;
break;
}
for (; i < run_end
&& resolved_types[i] == GRUB_BIDI_TYPE_ET; i++)
i--;
break;
}
break;
case GRUB_BIDI_TYPE_CS:
if (last_type == GRUB_BIDI_TYPE_EN
&& i + 1 < run_end
{
break;
}
if (last_type == GRUB_BIDI_TYPE_AN
&& i + 1 < run_end
&& last_strong_type == GRUB_BIDI_TYPE_AL)))
{
break;
}
break;
case GRUB_BIDI_TYPE_AL:
break;
default: /* Make GCC happy. */
break;
}
last_type = resolved_types[i];
if (resolved_types[i] == GRUB_BIDI_TYPE_EN
&& last_strong_type == GRUB_BIDI_TYPE_L)
}
if (prev_level & 1)
else
{
unsigned j;
unsigned next_type;
for (j = i; j < run_end &&
(resolved_types[j] == GRUB_BIDI_TYPE_B
|| resolved_types[j] == GRUB_BIDI_TYPE_S
|| resolved_types[j] == GRUB_BIDI_TYPE_WS
|| resolved_types[j] == GRUB_BIDI_TYPE_ON); j++);
if (j == i)
{
if (resolved_types[i] == GRUB_BIDI_TYPE_L)
else
i++;
continue;
}
if (j == run_end)
else
{
if (resolved_types[j] == GRUB_BIDI_TYPE_L)
else
}
for (; i < j; i++)
resolved_types[i] = last_type;
else
for (; i < j; i++)
}
}
for (i = 0; i < visual_len; i++)
{
{
levels[i]++;
continue;
}
|| resolved_types[i] == GRUB_BIDI_TYPE_EN))
{
levels[i] += 2;
continue;
}
|| resolved_types[i] == GRUB_BIDI_TYPE_AN
|| resolved_types[i] == GRUB_BIDI_TYPE_EN))
{
levels[i]++;
continue;
}
}
}
else
{
for (i = 0; i < visual_len; i++)
levels[i] = 0;
}
{
return ret;
}
}
struct grub_unicode_glyph **visual_out,
{
* logical_len);
if (!visual_ptr)
return -1;
{
{
ptr - line_start,
startwidth = 0;
if (ret < 0)
{
grub_free (*visual_out);
return ret;
}
visual_ptr += ret;
line_start = ptr;
{
visual_ptr++;
line_start++;
}
}
}
return visual_ptr - *visual_out;
}
{
int i;
for (i = 0; grub_unicode_bidi_pairs[i].key; i++)
return grub_unicode_bidi_pairs[i].replace;
return in;
}
{
int i;
if (!(in >= GRUB_UNICODE_ARABIC_START
&& in < GRUB_UNICODE_ARABIC_END))
return in;
for (i = 0; grub_unicode_arabic_shapes[i].code; i++)
{
switch (attr & (GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
{
case 0:
break;
break;
break;
break;
}
if (out)
return out;
}
return in;
}