bidi works in terminal in grub-emu

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-03-15 21:14:11 +01:00
parent dfed5c6bb4
commit 0a239a8211
23 changed files with 1101 additions and 799 deletions

View file

@ -53,7 +53,6 @@ grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc,
grub_utf8_to_ucs4_alloc (command_help, &unicode_command_help, grub_utf8_to_ucs4_alloc (command_help, &unicode_command_help,
&unicode_last_position); &unicode_last_position);
FOR_ACTIVE_TERM_OUTPUTS(term) FOR_ACTIVE_TERM_OUTPUTS(term)
{ {
unsigned stringwidth; unsigned stringwidth;
@ -66,10 +65,15 @@ grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc,
while (unicode_last_screen_position < unicode_last_position && while (unicode_last_screen_position < unicode_last_position &&
stringwidth < ((grub_term_width (term) / 2) - 2)) stringwidth < ((grub_term_width (term) / 2) - 2))
{ {
struct grub_unicode_glyph glyph;
unicode_last_screen_position
+= grub_unicode_aglomerate_comb (unicode_last_screen_position,
unicode_last_position
- unicode_last_screen_position,
&glyph);
stringwidth stringwidth
+= grub_term_getcharwidth (term, += grub_term_getcharwidth (term, &glyph);
*unicode_last_screen_position);
unicode_last_screen_position++;
} }
grub_print_ucs4 (unicode_command_help, grub_print_ucs4 (unicode_command_help,
@ -78,6 +82,7 @@ grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc,
grub_print_spaces (term, grub_term_width (term) / 2 grub_print_spaces (term, grub_term_width (term) / 2
- stringwidth); - stringwidth);
} }
if (cnt % 2) if (cnt % 2)
grub_printf ("\n"); grub_printf ("\n");
cnt++; cnt++;

View file

@ -636,7 +636,7 @@ keystatus_mod_LDFLAGS = $(COMMON_LDFLAGS)
normal_mod_SOURCES = normal/main.c normal/cmdline.c normal/dyncmd.c \ normal_mod_SOURCES = normal/main.c normal/cmdline.c normal/dyncmd.c \
normal/auth.c normal/autofs.c normal/handler.c \ normal/auth.c normal/autofs.c normal/handler.c \
normal/color.c normal/completion.c normal/datetime.c normal/menu.c \ normal/color.c normal/completion.c normal/datetime.c normal/menu.c \
normal/menu_entry.c normal/menu_text.c \ normal/menu_entry.c normal/menu_text.c lib/charset.c \
normal/misc.c normal/crypto.c normal/term.c normal/context.c normal/misc.c normal/crypto.c normal/term.c normal/context.c
normal_mod_CFLAGS = $(COMMON_CFLAGS) normal_mod_CFLAGS = $(COMMON_CFLAGS)
normal_mod_LDFLAGS = $(COMMON_LDFLAGS) normal_mod_LDFLAGS = $(COMMON_LDFLAGS)
@ -769,11 +769,6 @@ setjmp_mod_SOURCES = lib/$(target_cpu)/setjmp.S
setjmp_mod_ASFLAGS = $(COMMON_ASFLAGS) setjmp_mod_ASFLAGS = $(COMMON_ASFLAGS)
setjmp_mod_LDFLAGS = $(COMMON_LDFLAGS) setjmp_mod_LDFLAGS = $(COMMON_LDFLAGS)
pkglib_MODULES += charset.mod
charset_mod_SOURCES = lib/charset.c
charset_mod_CFLAGS = $(COMMON_CFLAGS)
charset_mod_LDFLAGS = $(COMMON_LDFLAGS)
pkglib_MODULES += terminal.mod pkglib_MODULES += terminal.mod
terminal_mod_SOURCES = commands/terminal.c terminal_mod_SOURCES = commands/terminal.c
terminal_mod_CFLAGS = $(COMMON_CFLAGS) terminal_mod_CFLAGS = $(COMMON_CFLAGS)

View file

@ -1135,41 +1135,13 @@ grub_font_blit_glyph_mirror (struct grub_font_glyph *target,
} }
} }
static inline enum grub_comb_type
get_comb_type (grub_uint32_t c)
{
static grub_uint8_t *comb_types = NULL;
struct grub_unicode_compact_range *cur;
if (!comb_types)
{
unsigned i;
comb_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
if (comb_types)
for (cur = grub_unicode_compact; cur->end; cur++)
for (i = cur->start; i <= cur->end
&& i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
comb_types[i] = cur->comb_type;
else
grub_errno = GRUB_ERR_NONE;
}
if (comb_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
return comb_types[c];
for (cur = grub_unicode_compact; cur->end; cur++)
if (cur->start <= c && c <= cur->end)
return cur->comb_type;
return GRUB_BIDI_TYPE_L;
}
static void static void
blit_comb (const struct grub_unicode_glyph *glyph_id, blit_comb (const struct grub_unicode_glyph *glyph_id,
struct grub_font_glyph *glyph, struct grub_font_glyph *glyph,
struct grub_video_signed_rect *bounds_out, struct grub_video_signed_rect *bounds_out,
struct grub_font_glyph *main_glyph, struct grub_font_glyph *main_glyph,
struct grub_font_glyph **combining_glyphs) struct grub_font_glyph **combining_glyphs,
int *device_width)
{ {
struct grub_video_signed_rect bounds; struct grub_video_signed_rect bounds;
unsigned i; unsigned i;
@ -1203,14 +1175,23 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
{ {
if (glyph && glyph->device_width < val) if (glyph && glyph->device_width < val)
glyph->device_width = val; glyph->device_width = val;
if (device_width && *device_width < val)
*device_width = val;
} }
auto void add_device_width (int val); auto void add_device_width (int val);
void add_device_width (int val) void add_device_width (int val)
{ {
if (glyph) if (glyph)
glyph->device_width += val; glyph->device_width += val;
if (device_width)
*device_width += val;
} }
if (glyph)
glyph->device_width = main_glyph->device_width;
if (device_width)
*device_width = main_glyph->device_width;
bounds.x = main_glyph->offset_x; bounds.x = main_glyph->offset_x;
bounds.y = main_glyph->offset_y; bounds.y = main_glyph->offset_y;
bounds.width = main_glyph->width; bounds.width = main_glyph->width;
@ -1231,7 +1212,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
/* CGJ is to avoid diacritics reordering. */ /* CGJ is to avoid diacritics reordering. */
if (glyph_id->combining[i] == GRUB_UNICODE_COMBINING_GRAPHEME_JOINER) if (glyph_id->combining[i] == GRUB_UNICODE_COMBINING_GRAPHEME_JOINER)
continue; continue;
combtype = get_comb_type (glyph_id->combining[i]); combtype = grub_unicode_get_comb_type (glyph_id->combining[i]);
switch (combtype) switch (combtype)
{ {
case GRUB_UNICODE_COMB_OVERLAY: case GRUB_UNICODE_COMB_OVERLAY:
@ -1302,14 +1283,17 @@ blit_comb (const struct grub_unicode_glyph *glyph_id,
} }
static struct grub_font_glyph * static struct grub_font_glyph *
grub_font_construct_glyph (grub_font_t hinted_font, grub_font_construct_dry_run (grub_font_t hinted_font,
const struct grub_unicode_glyph *glyph_id) const struct grub_unicode_glyph *glyph_id,
struct grub_video_signed_rect *bounds,
struct grub_font_glyph ***combining_glyphs_out,
int *device_width)
{ {
grub_font_t font;
struct grub_video_signed_rect bounds;
struct grub_font_glyph *main_glyph; struct grub_font_glyph *main_glyph;
struct grub_font_glyph **combining_glyphs; struct grub_font_glyph **combining_glyphs;
struct grub_font_glyph *glyph;
if (combining_glyphs_out)
*combining_glyphs_out = NULL;
main_glyph = grub_font_get_glyph_with_fallback (hinted_font, glyph_id->base); main_glyph = grub_font_get_glyph_with_fallback (hinted_font, glyph_id->base);
@ -1319,29 +1303,69 @@ grub_font_construct_glyph (grub_font_t hinted_font,
/* Glyph not available in any font. Return unknown glyph. */ /* Glyph not available in any font. Return unknown glyph. */
if (!main_glyph) if (!main_glyph)
return grub_font_dup_glyph (unknown_glyph); return NULL;
if (device_width)
*device_width = main_glyph->device_width;
if (!glyph_id->ncomb && !glyph_id->attributes) if (!glyph_id->ncomb && !glyph_id->attributes)
return grub_font_dup_glyph (main_glyph); return main_glyph;
combining_glyphs = grub_malloc (sizeof (combining_glyphs[0]) combining_glyphs = grub_malloc (sizeof (combining_glyphs[0])
* glyph_id->ncomb); * glyph_id->ncomb);
if (glyph_id->ncomb && !combining_glyphs) if (glyph_id->ncomb && !combining_glyphs)
{ {
grub_errno = GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE;
return grub_font_dup_glyph (main_glyph); return main_glyph;
} }
font = main_glyph->font;
{ {
unsigned i; unsigned i;
for (i = 0; i < glyph_id->ncomb; i++) for (i = 0; i < glyph_id->ncomb; i++)
combining_glyphs[i] combining_glyphs[i]
= grub_font_get_glyph_with_fallback (font, glyph_id->combining[i]); = grub_font_get_glyph_with_fallback (main_glyph->font,
glyph_id->combining[i]);
} }
blit_comb (glyph_id, NULL, &bounds, main_glyph, combining_glyphs); blit_comb (glyph_id, NULL, bounds, main_glyph, combining_glyphs, device_width);
if (combining_glyphs_out)
*combining_glyphs_out = combining_glyphs;
else
grub_free (combining_glyphs);
return main_glyph;
}
int
grub_font_get_constructed_device_width (grub_font_t hinted_font,
const struct grub_unicode_glyph *glyph_id)
{
int ret;
struct grub_font_glyph *main_glyph;
main_glyph = grub_font_construct_dry_run (hinted_font, glyph_id, NULL,
NULL, &ret);
if (!main_glyph)
return unknown_glyph->device_width;
return ret;
}
struct grub_font_glyph *
grub_font_construct_glyph (grub_font_t hinted_font,
const struct grub_unicode_glyph *glyph_id)
{
struct grub_font_glyph *main_glyph;
struct grub_video_signed_rect bounds;
struct grub_font_glyph *glyph;
struct grub_font_glyph **combining_glyphs;
main_glyph = grub_font_construct_dry_run (hinted_font, glyph_id,
&bounds, &combining_glyphs, NULL);
if (!main_glyph)
return grub_font_dup_glyph (unknown_glyph);
if (!combining_glyphs)
return grub_font_dup_glyph (main_glyph);
glyph = grub_zalloc (sizeof (*glyph) + (bounds.width * bounds.height + 7) / 8); glyph = grub_zalloc (sizeof (*glyph) + (bounds.width * bounds.height + 7) / 8);
if (!glyph) if (!glyph)
@ -1350,12 +1374,11 @@ grub_font_construct_glyph (grub_font_t hinted_font,
return grub_font_dup_glyph (main_glyph); return grub_font_dup_glyph (main_glyph);
} }
glyph->font = font; glyph->font = main_glyph->font;
glyph->width = bounds.width; glyph->width = bounds.width;
glyph->height = bounds.height; glyph->height = bounds.height;
glyph->offset_x = bounds.x; glyph->offset_x = bounds.x;
glyph->offset_y = bounds.y; glyph->offset_y = bounds.y;
glyph->device_width = main_glyph->device_width;
if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR) if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR)
grub_font_blit_glyph_mirror (glyph, main_glyph, grub_font_blit_glyph_mirror (glyph, main_glyph,
@ -1368,7 +1391,7 @@ grub_font_construct_glyph (grub_font_t hinted_font,
(glyph->height + glyph->offset_y) (glyph->height + glyph->offset_y)
- (main_glyph->height + main_glyph->offset_y)); - (main_glyph->height + main_glyph->offset_y));
blit_comb (glyph_id, glyph, NULL, main_glyph, combining_glyphs); blit_comb (glyph_id, glyph, NULL, main_glyph, combining_glyphs, NULL);
return glyph; return glyph;
} }
@ -1423,465 +1446,6 @@ grub_font_draw_glyph (struct grub_font_glyph *glyph,
glyph->width, glyph->height); glyph->width, glyph->height);
} }
static grub_uint8_t *bidi_types = NULL;
static void
unpack_bidi (void)
{
unsigned i;
struct grub_unicode_compact_range *cur;
bidi_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
if (!bidi_types)
{
grub_errno = GRUB_ERR_NONE;
return;
}
for (cur = grub_unicode_compact; cur->end; cur++)
for (i = cur->start; i <= cur->end
&& i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
if (cur->bidi_mirror)
bidi_types[i] = cur->bidi_type | 0x80;
else
bidi_types[i] = cur->bidi_type | 0x00;
}
static inline enum grub_bidi_type
get_bidi_type (grub_uint32_t c)
{
struct grub_unicode_compact_range *cur;
if (!bidi_types)
unpack_bidi ();
if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
return bidi_types[c] & 0x7f;
for (cur = grub_unicode_compact; cur->end; cur++)
if (cur->start <= c && c <= cur->end)
return cur->bidi_type;
return GRUB_BIDI_TYPE_L;
}
static inline int
is_mirrored (grub_uint32_t c)
{
struct grub_unicode_compact_range *cur;
if (!bidi_types)
unpack_bidi ();
if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
return !!(bidi_types[c] & 0x80);
for (cur = grub_unicode_compact; cur->end; cur++)
if (cur->start <= c && c <= cur->end)
return cur->bidi_mirror;
return 0;
}
static grub_ssize_t
grub_err_bidi_logical_to_visual (grub_uint32_t *logical,
grub_size_t logical_len,
struct grub_unicode_glyph **visual_out)
{
enum grub_bidi_type type = GRUB_BIDI_TYPE_L;
enum override_status {OVERRIDE_NEUTRAL = 0, OVERRIDE_R, OVERRIDE_L};
unsigned *levels;
enum grub_bidi_type *resolved_types;
unsigned base_level;
enum override_status cur_override;
unsigned i;
unsigned stack_level[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3];
enum override_status stack_override[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3];
unsigned stack_depth = 0;
unsigned invalid_pushes = 0;
unsigned visual_len = 0;
unsigned run_start, run_end;
struct grub_unicode_glyph *visual;
unsigned cur_level;
auto void push_stack (unsigned new_override, unsigned new_level);
void push_stack (unsigned new_override, unsigned new_level)
{
if (new_level > GRUB_BIDI_MAX_EXPLICIT_LEVEL)
{
invalid_pushes++;
return;
}
stack_level[stack_depth] = cur_level;
stack_override[stack_depth] = cur_override;
stack_depth++;
cur_level = new_level;
cur_override = new_override;
}
auto void pop_stack (void);
void pop_stack (void)
{
if (invalid_pushes)
{
invalid_pushes--;
return;
}
if (!stack_depth)
return;
stack_depth--;
cur_level = stack_level[stack_depth];
cur_override = stack_override[stack_depth];
}
auto void revert (unsigned start, unsigned end);
void revert (unsigned start, unsigned end)
{
struct grub_unicode_glyph t;
unsigned k, tl;
for (k = 0; k <= (end - start) / 2; k++)
{
t = visual[start+k];
visual[start+k] = visual[end-k];
visual[end-k] = t;
tl = levels[start+k];
levels[start+k] = levels[end-k];
levels[end-k] = tl;
}
}
levels = grub_malloc (sizeof (levels[0]) * logical_len);
if (!levels)
return -1;
resolved_types = grub_malloc (sizeof (resolved_types[0]) * logical_len);
if (!resolved_types)
{
grub_free (levels);
return -1;
}
visual = grub_malloc (sizeof (visual[0]) * logical_len);
if (!visual)
{
grub_free (resolved_types);
grub_free (levels);
return -1;
}
for (i = 0; i < logical_len; i++)
{
type = get_bidi_type (logical[i]);
if (type == GRUB_BIDI_TYPE_L || type == GRUB_BIDI_TYPE_AL
|| type == GRUB_BIDI_TYPE_R)
break;
}
if (type == GRUB_BIDI_TYPE_R || type == GRUB_BIDI_TYPE_AL)
base_level = 1;
else
base_level = 0;
cur_level = base_level;
cur_override = OVERRIDE_NEUTRAL;
{
unsigned last_comb_pointer = 0;
for (i = 0; i < logical_len; i++)
{
/* Variation selectors >= 17 are outside of BMP and SMP.
Handle variation selectors first to avoid potentially costly lookups.
*/
if (logical[i] >= GRUB_UNICODE_VARIATION_SELECTOR_1
&& logical[i] <= GRUB_UNICODE_VARIATION_SELECTOR_16)
{
if (!visual_len)
continue;
visual[visual_len - 1].variant
= logical[i] - GRUB_UNICODE_VARIATION_SELECTOR_1 + 1;
}
if (logical[i] >= GRUB_UNICODE_VARIATION_SELECTOR_17
&& logical[i] <= GRUB_UNICODE_VARIATION_SELECTOR_256)
{
if (!visual_len)
continue;
visual[visual_len - 1].variant
= logical[i] - GRUB_UNICODE_VARIATION_SELECTOR_17 + 17;
continue;
}
type = get_bidi_type (logical[i]);
switch (type)
{
case GRUB_BIDI_TYPE_RLE:
push_stack (cur_override, (cur_level | 1) + 1);
break;
case GRUB_BIDI_TYPE_RLO:
push_stack (OVERRIDE_R, (cur_level | 1) + 1);
break;
case GRUB_BIDI_TYPE_LRE:
push_stack (cur_override, (cur_level & ~1) + 2);
break;
case GRUB_BIDI_TYPE_LRO:
push_stack (OVERRIDE_L, (cur_level & ~1) + 2);
break;
case GRUB_BIDI_TYPE_PDF:
pop_stack ();
break;
case GRUB_BIDI_TYPE_BN:
break;
default:
{
enum grub_comb_type comb_type;
comb_type = get_comb_type (logical[i]);
if (comb_type)
{
grub_uint32_t *n;
unsigned j;
if (!visual_len)
break;
if (comb_type == GRUB_UNICODE_COMB_MC
|| comb_type == GRUB_UNICODE_COMB_ME
|| comb_type == GRUB_UNICODE_COMB_MN)
last_comb_pointer = visual[visual_len - 1].ncomb;
n = grub_realloc (visual[visual_len - 1].combining,
sizeof (grub_uint32_t)
* (visual[visual_len - 1].ncomb + 1));
if (!n)
{
grub_errno = GRUB_ERR_NONE;
break;
}
for (j = last_comb_pointer;
j < visual[visual_len - 1].ncomb; j++)
if (get_comb_type (visual[visual_len - 1].combining[j])
> comb_type)
break;
grub_memmove (visual[visual_len - 1].combining + j + 1,
visual[visual_len - 1].combining + j,
(visual[visual_len - 1].ncomb - j)
* sizeof (visual[visual_len - 1].combining[0]));
visual[visual_len - 1].combining = n;
visual[visual_len - 1].combining[j] = logical[i];
visual[visual_len - 1].ncomb++;
break;
}
last_comb_pointer = 0;
levels[visual_len] = cur_level;
if (cur_override != OVERRIDE_NEUTRAL)
resolved_types[visual_len] =
(cur_override == OVERRIDE_L) ? GRUB_BIDI_TYPE_L
: GRUB_BIDI_TYPE_R;
else
resolved_types[visual_len] = type;
visual[visual_len].base = logical[i];
visual[visual_len].variant = 0;
visual[visual_len].attributes = 0;
visual[visual_len].ncomb = 0;
visual[visual_len].combining = NULL;
visual_len++;
}
}
}
}
for (run_start = 0; run_start < visual_len; run_start = run_end)
{
unsigned prev_level, next_level, cur_run_level;
unsigned last_type, last_strong_type;
for (run_end = run_start; run_end < visual_len &&
levels[run_end] == levels[run_start]; run_end++);
if (run_start == 0)
prev_level = base_level;
else
prev_level = levels[run_start - 1];
if (run_end == visual_len)
next_level = base_level;
else
next_level = levels[run_end];
cur_run_level = levels[run_start];
if (prev_level & 1)
last_type = GRUB_BIDI_TYPE_R;
else
last_type = GRUB_BIDI_TYPE_L;
last_strong_type = last_type;
for (i = run_start; i < run_end; i++)
{
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)
resolved_types[i] = GRUB_BIDI_TYPE_AN;
break;
case GRUB_BIDI_TYPE_L:
case GRUB_BIDI_TYPE_R:
last_strong_type = resolved_types[i];
break;
case GRUB_BIDI_TYPE_ES:
if (last_type == GRUB_BIDI_TYPE_EN
&& i + 1 < run_end
&& resolved_types[i + 1] == GRUB_BIDI_TYPE_EN)
resolved_types[i] = GRUB_BIDI_TYPE_EN;
else
resolved_types[i] = GRUB_BIDI_TYPE_ON;
break;
case GRUB_BIDI_TYPE_ET:
{
unsigned j;
if (last_type == GRUB_BIDI_TYPE_EN)
{
resolved_types[i] = GRUB_BIDI_TYPE_EN;
break;
}
for (j = i; j < run_end
&& resolved_types[j] == GRUB_BIDI_TYPE_ET; j++);
if (j != run_end && resolved_types[j] == GRUB_BIDI_TYPE_EN)
{
for (; i < run_end
&& resolved_types[i] == GRUB_BIDI_TYPE_ET; i++)
resolved_types[i] = GRUB_BIDI_TYPE_EN;
i--;
break;
}
for (; i < run_end
&& resolved_types[i] == GRUB_BIDI_TYPE_ET; i++)
resolved_types[i] = GRUB_BIDI_TYPE_ON;
i--;
break;
}
break;
case GRUB_BIDI_TYPE_CS:
if (last_type == GRUB_BIDI_TYPE_EN
&& i + 1 < run_end
&& resolved_types[i + 1] == GRUB_BIDI_TYPE_EN)
{
resolved_types[i] = GRUB_BIDI_TYPE_EN;
break;
}
if (last_type == GRUB_BIDI_TYPE_AN
&& i + 1 < run_end
&& (resolved_types[i + 1] == GRUB_BIDI_TYPE_AN
|| (resolved_types[i + 1] == GRUB_BIDI_TYPE_EN
&& last_strong_type == GRUB_BIDI_TYPE_AL)))
{
resolved_types[i] = GRUB_BIDI_TYPE_EN;
break;
}
resolved_types[i] = GRUB_BIDI_TYPE_ON;
break;
case GRUB_BIDI_TYPE_AL:
last_strong_type = resolved_types[i];
resolved_types[i] = GRUB_BIDI_TYPE_R;
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)
resolved_types[i] = GRUB_BIDI_TYPE_L;
}
if (prev_level & 1)
last_type = GRUB_BIDI_TYPE_R;
else
last_type = GRUB_BIDI_TYPE_L;
for (i = run_start; i < run_end; )
{
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)
last_type = GRUB_BIDI_TYPE_L;
else
last_type = GRUB_BIDI_TYPE_R;
i++;
continue;
}
if (j == run_end)
next_type = (next_level & 1) ? GRUB_BIDI_TYPE_R : GRUB_BIDI_TYPE_L;
else
{
if (resolved_types[j] == GRUB_BIDI_TYPE_L)
next_type = GRUB_BIDI_TYPE_L;
else
next_type = GRUB_BIDI_TYPE_R;
}
if (next_type == last_type)
for (; i < j; i++)
resolved_types[i] = last_type;
else
for (; i < j; i++)
resolved_types[i] = (cur_run_level & 1) ? GRUB_BIDI_TYPE_R
: GRUB_BIDI_TYPE_L;
}
}
for (i = 0; i < visual_len; i++)
{
if (!(levels[i] & 1) && resolved_types[i] == GRUB_BIDI_TYPE_R)
{
levels[i]++;
continue;
}
if (!(levels[i] & 1) && (resolved_types[i] == GRUB_BIDI_TYPE_AN
|| resolved_types[i] == GRUB_BIDI_TYPE_EN))
{
levels[i] += 2;
continue;
}
if ((levels[i] & 1) && (resolved_types[i] == GRUB_BIDI_TYPE_L
|| resolved_types[i] == GRUB_BIDI_TYPE_AN
|| resolved_types[i] == GRUB_BIDI_TYPE_EN))
{
levels[i]++;
continue;
}
}
grub_free (resolved_types);
/* TODO: put line-wrapping here. */
{
unsigned min_odd_level = 0xffffffff;
unsigned max_level = 0;
unsigned j;
for (i = 0; i < visual_len; i++)
{
if (levels[i] > max_level)
max_level = levels[i];
if (levels[i] < min_odd_level && (levels[i] & 1))
min_odd_level = levels[i];
}
/* FIXME: can be optimized. */
for (j = max_level; j >= min_odd_level; j--)
{
unsigned in = 0;
for (i = 0; i < visual_len; i++)
{
if (i != 0 && levels[i] >= j && levels[i-1] < j)
in = i;
if (levels[i] >= j && (i + 1 == visual_len || levels[i+1] < j))
revert (in, i);
}
}
}
for (i = 0; i < visual_len; i++)
if (is_mirrored (visual[i].base) && levels[i])
visual[i].attributes |= GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR;
grub_free (levels);
*visual_out = visual;
return visual_len;
}
/* Draw a UTF-8 string of text on the current video render target. /* Draw a UTF-8 string of text on the current video render target.
The x coordinate specifies the starting x position for the first character, The x coordinate specifies the starting x position for the first character,
while the y coordinate specifies the baseline position. while the y coordinate specifies the baseline position.
@ -1902,7 +1466,7 @@ grub_font_draw_string (const char *str, grub_font_t font,
if (logical_len < 0) if (logical_len < 0)
return grub_errno; return grub_errno;
visual_len = grub_err_bidi_logical_to_visual (logical, logical_len, &visual); visual_len = grub_bidi_logical_to_visual (logical, logical_len, &visual, 0, 0);
grub_free (logical); grub_free (logical);
if (visual_len < 0) if (visual_len < 0)
return grub_errno; return grub_errno;

View file

@ -118,10 +118,8 @@ grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize);
int grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg, int grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg,
grub_uint32_t **last_position); grub_uint32_t **last_position);
grub_size_t grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
grub_size_t destsize, const grub_uint8_t *src, grub_size_t srcsize,
const grub_uint8_t *src,
grub_size_t srcsize,
const grub_uint8_t **srcend); const grub_uint8_t **srcend);
#endif #endif

View file

@ -22,6 +22,7 @@
#include <grub/types.h> #include <grub/types.h>
#include <grub/video.h> #include <grub/video.h>
#include <grub/file.h> #include <grub/file.h>
#include <grub/unicode.h>
/* Forward declaration of opaque structure grub_font. /* Forward declaration of opaque structure grub_font.
Users only pass struct grub_font pointers to the font module functions, Users only pass struct grub_font pointers to the font module functions,
@ -117,4 +118,11 @@ grub_err_t EXPORT_FUNC (grub_font_draw_string) (const char *str,
grub_video_color_t color, grub_video_color_t color,
int left_x, int baseline_y); int left_x, int baseline_y);
int
EXPORT_FUNC (grub_font_get_constructed_device_width) (grub_font_t hinted_font,
const struct grub_unicode_glyph *glyph_id);
struct grub_font_glyph *
EXPORT_FUNC (grub_font_construct_glyph) (grub_font_t hinted_font,
const struct grub_unicode_glyph *glyph_id);
#endif /* ! GRUB_FONT_HEADER */ #endif /* ! GRUB_FONT_HEADER */

View file

@ -25,8 +25,10 @@
extern grub_uint8_t grub_console_cur_color; extern grub_uint8_t grub_console_cur_color;
void grub_console_putchar (grub_uint32_t c); void
grub_ssize_t grub_console_getcharwidth (grub_uint32_t c); grub_console_putchar (const struct grub_unicode_glyph *c);
grub_ssize_t
grub_console_getcharwidth (const struct grub_unicode_glyph *c);
grub_uint16_t grub_console_getwh (void); grub_uint16_t grub_console_getwh (void);
void grub_console_setcolorstate (grub_term_color_state state); void grub_console_setcolorstate (grub_term_color_state state);
void grub_console_setcolor (grub_uint8_t normal_color, grub_uint8_t highlight_color); void grub_console_setcolor (grub_uint8_t normal_color, grub_uint8_t highlight_color);

View file

@ -113,4 +113,6 @@ void grub_set_more (int onoff);
int grub_normal_get_line_counter (void); int grub_normal_get_line_counter (void);
void grub_install_newline_hook (void); void grub_install_newline_hook (void);
void grub_xputs_normal (const char *str);
#endif /* ! GRUB_NORMAL_HEADER */ #endif /* ! GRUB_NORMAL_HEADER */

View file

@ -39,6 +39,7 @@
#include <grub/symbol.h> #include <grub/symbol.h>
#include <grub/types.h> #include <grub/types.h>
#include <grub/handler.h> #include <grub/handler.h>
#include <grub/unicode.h>
/* These are used to represent the various color states we use. */ /* These are used to represent the various color states we use. */
typedef enum typedef enum
@ -164,11 +165,11 @@ struct grub_term_output
grub_err_t (*fini) (void); grub_err_t (*fini) (void);
/* Put a character. C is encoded in Unicode. */ /* Put a character. C is encoded in Unicode. */
void (*putchar) (grub_uint32_t c); void (*putchar) (const struct grub_unicode_glyph *c);
/* Get the number of columns occupied by a given character C. C is /* Get the number of columns occupied by a given character C. C is
encoded in Unicode. */ encoded in Unicode. */
grub_ssize_t (*getcharwidth) (grub_uint32_t c); grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *c);
/* Get the screen size. The return value is ((Width << 8) | Height). */ /* Get the screen size. The return value is ((Width << 8) | Height). */
grub_uint16_t (*getwh) (void); grub_uint16_t (*getwh) (void);
@ -261,8 +262,7 @@ grub_term_unregister_output (grub_term_output_t term)
#define FOR_ACTIVE_TERM_OUTPUTS(var) for (var = grub_term_outputs; var; var = var->next) #define FOR_ACTIVE_TERM_OUTPUTS(var) for (var = grub_term_outputs; var; var = var->next)
#define FOR_DISABLED_TERM_OUTPUTS(var) for (var = grub_term_outputs_disabled; var; var = var->next) #define FOR_DISABLED_TERM_OUTPUTS(var) for (var = grub_term_outputs_disabled; var; var = var->next)
void EXPORT_FUNC(grub_putcode) (grub_uint32_t code, void grub_putcode (grub_uint32_t code, struct grub_term_output *term);
struct grub_term_output *term);
int EXPORT_FUNC(grub_getkey) (void); int EXPORT_FUNC(grub_getkey) (void);
int EXPORT_FUNC(grub_checkkey) (void); int EXPORT_FUNC(grub_checkkey) (void);
int EXPORT_FUNC(grub_getkeystatus) (void); int EXPORT_FUNC(grub_getkeystatus) (void);
@ -379,7 +379,8 @@ grub_term_cls (struct grub_term_output *term)
} }
static inline grub_ssize_t static inline grub_ssize_t
grub_term_getcharwidth (struct grub_term_output *term, grub_uint32_t c) grub_term_getcharwidth (struct grub_term_output *term,
const struct grub_unicode_glyph *c)
{ {
if (term->getcharwidth) if (term->getcharwidth)
return term->getcharwidth (c); return term->getcharwidth (c);

View file

@ -55,6 +55,7 @@ enum grub_bidi_type
enum grub_comb_type enum grub_comb_type
{ {
GRUB_UNICODE_COMB_NONE = 0,
GRUB_UNICODE_COMB_OVERLAY = 1, GRUB_UNICODE_COMB_OVERLAY = 1,
GRUB_UNICODE_STACK_ATTACHED_BELOW = 202, GRUB_UNICODE_STACK_ATTACHED_BELOW = 202,
GRUB_UNICODE_STACK_ATTACHED_ABOVE = 214, GRUB_UNICODE_STACK_ATTACHED_ABOVE = 214,
@ -93,4 +94,21 @@ extern struct grub_unicode_compact_range grub_unicode_compact[];
/* Unicode mandates an arbitrary limit. */ /* Unicode mandates an arbitrary limit. */
#define GRUB_BIDI_MAX_EXPLICIT_LEVEL 61 #define GRUB_BIDI_MAX_EXPLICIT_LEVEL 61
grub_ssize_t
grub_bidi_logical_to_visual (const grub_uint32_t *logical,
grub_size_t logical_len,
struct grub_unicode_glyph **visual_out,
grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
grub_size_t max_length);
enum grub_comb_type
grub_unicode_get_comb_type (grub_uint32_t c);
grub_size_t
grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
struct grub_unicode_glyph *out);
struct grub_unicode_glyph *
grub_unicode_glyph_from_code (grub_uint32_t code);
struct grub_unicode_glyph *
grub_unicode_glyph_dup (const struct grub_unicode_glyph *in);
#endif #endif

View file

@ -31,23 +31,33 @@ struct grub_term_input *grub_term_inputs;
void (*grub_newline_hook) (void) = NULL; void (*grub_newline_hook) (void) = NULL;
/* Put a Unicode character. */ /* Put a Unicode character. */
void static void
grub_putcode (grub_uint32_t code, struct grub_term_output *term) grub_putcode_dumb (grub_uint32_t code,
struct grub_term_output *term)
{ {
struct grub_unicode_glyph c =
{
.base = code,
.variant = 0,
.attributes = 0,
.ncomb = 0,
.combining = 0
};
if (code == '\t' && term->getxy) if (code == '\t' && term->getxy)
{ {
int n; int n;
n = 8 - ((term->getxy () >> 8) & 7); n = 8 - ((term->getxy () >> 8) & 7);
while (n--) while (n--)
grub_putcode (' ', term); grub_putcode_dumb (' ', term);
return; return;
} }
(term->putchar) (code); (term->putchar) (&c);
if (code == '\n') if (code == '\n')
(term->putchar) ('\r'); grub_putcode_dumb ('\r', term);
} }
static void static void
@ -56,12 +66,12 @@ grub_xputs_dumb (const char *str)
for (; *str; str++) for (; *str; str++)
{ {
grub_term_output_t term; grub_term_output_t term;
grub_uint32_t code = *str;
if (code > 0x7f)
code = '?';
char c = *str;
if ((unsigned char) c > 0x7f)
c = '?';
FOR_ACTIVE_TERM_OUTPUTS(term) FOR_ACTIVE_TERM_OUTPUTS(term)
grub_putcode (c, term); grub_putcode_dumb (code, term);
} }
} }
@ -126,7 +136,7 @@ grub_cls (void)
{ {
if ((term->flags & GRUB_TERM_DUMB) || (grub_env_get ("debug"))) if ((term->flags & GRUB_TERM_DUMB) || (grub_env_get ("debug")))
{ {
grub_putcode ('\n', term); grub_putcode_dumb ('\n', term);
grub_term_refresh (term); grub_term_refresh (term);
} }
else else

View file

@ -26,6 +26,9 @@
#include <grub/charset.h> #include <grub/charset.h>
#include <grub/mm.h> #include <grub/mm.h>
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/unicode.h>
#include <grub/term.h>
#include <grub/normal.h>
grub_ssize_t grub_ssize_t
grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize,
@ -361,3 +364,783 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
*srcend = src; *srcend = src;
return p - dest; return p - dest;
} }
static grub_uint8_t *bidi_types = NULL;
static void
unpack_bidi (void)
{
unsigned i;
struct grub_unicode_compact_range *cur;
bidi_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
if (!bidi_types)
{
grub_errno = GRUB_ERR_NONE;
return;
}
for (cur = grub_unicode_compact; cur->end; cur++)
for (i = cur->start; i <= cur->end
&& i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
if (cur->bidi_mirror)
bidi_types[i] = cur->bidi_type | 0x80;
else
bidi_types[i] = cur->bidi_type | 0x00;
}
static inline enum grub_bidi_type
get_bidi_type (grub_uint32_t c)
{
struct grub_unicode_compact_range *cur;
if (!bidi_types)
unpack_bidi ();
if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
return bidi_types[c] & 0x7f;
for (cur = grub_unicode_compact; cur->end; cur++)
if (cur->start <= c && c <= cur->end)
return cur->bidi_type;
return GRUB_BIDI_TYPE_L;
}
static inline int
is_mirrored (grub_uint32_t c)
{
struct grub_unicode_compact_range *cur;
if (!bidi_types)
unpack_bidi ();
if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
return !!(bidi_types[c] & 0x80);
for (cur = grub_unicode_compact; cur->end; cur++)
if (cur->start <= c && c <= cur->end)
return cur->bidi_mirror;
return 0;
}
enum grub_comb_type
grub_unicode_get_comb_type (grub_uint32_t c)
{
static grub_uint8_t *comb_types = NULL;
struct grub_unicode_compact_range *cur;
if (!comb_types)
{
unsigned i;
comb_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
if (comb_types)
for (cur = grub_unicode_compact; cur->end; cur++)
for (i = cur->start; i <= cur->end
&& i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
comb_types[i] = cur->comb_type;
else
grub_errno = GRUB_ERR_NONE;
}
if (comb_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
return comb_types[c];
for (cur = grub_unicode_compact; cur->end; cur++)
if (cur->start <= c && c <= cur->end)
return cur->comb_type;
return GRUB_UNICODE_COMB_NONE;
}
grub_size_t
grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
struct grub_unicode_glyph *out)
{
int haveout = 0;
const grub_uint32_t *ptr;
unsigned last_comb_pointer = 0;
grub_memset (out, 0, sizeof (*out));
for (ptr = in; ptr < in + inlen; ptr++)
{
/* 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
&& *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16)
{
if (haveout)
out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_1 + 1;
continue;
}
if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17
&& *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256)
{
if (haveout)
out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_17 + 17;
continue;
}
enum grub_comb_type comb_type;
comb_type = grub_unicode_get_comb_type (*ptr);
if (comb_type)
{
grub_uint32_t *n;
unsigned j;
if (!haveout)
continue;
if (comb_type == GRUB_UNICODE_COMB_MC
|| comb_type == GRUB_UNICODE_COMB_ME
|| comb_type == GRUB_UNICODE_COMB_MN)
last_comb_pointer = out->ncomb;
n = grub_realloc (out->combining,
sizeof (grub_uint32_t) * (out->ncomb + 1));
if (!n)
{
grub_errno = GRUB_ERR_NONE;
continue;
}
for (j = last_comb_pointer; j < out->ncomb; j++)
if (grub_unicode_get_comb_type (out->combining[j]) > comb_type)
break;
grub_memmove (out->combining + j + 1,
out->combining + j,
(out->ncomb - j)
* sizeof (out->combining[0]));
out->combining = n;
out->combining[j] = *ptr;
out->ncomb++;
continue;
}
if (haveout)
return ptr - in;
haveout = 1;
out->base = *ptr;
out->variant = 0;
out->attributes = 0;
out->ncomb = 0;
out->combining = NULL;
}
return ptr - in;
}
static grub_ssize_t
grub_bidi_line_logical_to_visual (const grub_uint32_t *logical,
grub_size_t logical_len,
struct grub_unicode_glyph *visual_out,
grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
grub_size_t maxwidth)
{
enum grub_bidi_type type = GRUB_BIDI_TYPE_L;
enum override_status {OVERRIDE_NEUTRAL = 0, OVERRIDE_R, OVERRIDE_L};
unsigned *levels;
enum grub_bidi_type *resolved_types;
unsigned base_level;
enum override_status cur_override;
unsigned i;
unsigned stack_level[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3];
enum override_status stack_override[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3];
unsigned stack_depth = 0;
unsigned invalid_pushes = 0;
unsigned visual_len = 0;
unsigned run_start, run_end;
struct grub_unicode_glyph *visual;
unsigned cur_level;
auto void push_stack (unsigned new_override, unsigned new_level);
void push_stack (unsigned new_override, unsigned new_level)
{
if (new_level > GRUB_BIDI_MAX_EXPLICIT_LEVEL)
{
invalid_pushes++;
return;
}
stack_level[stack_depth] = cur_level;
stack_override[stack_depth] = cur_override;
stack_depth++;
cur_level = new_level;
cur_override = new_override;
}
auto void pop_stack (void);
void pop_stack (void)
{
if (invalid_pushes)
{
invalid_pushes--;
return;
}
if (!stack_depth)
return;
stack_depth--;
cur_level = stack_level[stack_depth];
cur_override = stack_override[stack_depth];
}
auto void revert (unsigned start, unsigned end);
void revert (unsigned start, unsigned end)
{
struct grub_unicode_glyph t;
unsigned k, tl;
for (k = 0; k <= (end - start) / 2; k++)
{
t = visual[start+k];
visual[start+k] = visual[end-k];
visual[end-k] = t;
tl = levels[start+k];
levels[start+k] = levels[end-k];
levels[end-k] = tl;
}
}
levels = grub_malloc (sizeof (levels[0]) * logical_len);
if (!levels)
return -1;
resolved_types = grub_malloc (sizeof (resolved_types[0]) * logical_len);
if (!resolved_types)
{
grub_free (levels);
return -1;
}
visual = grub_malloc (sizeof (visual[0]) * logical_len);
if (!visual)
{
grub_free (resolved_types);
grub_free (levels);
return -1;
}
for (i = 0; i < logical_len; i++)
{
type = get_bidi_type (logical[i]);
if (type == GRUB_BIDI_TYPE_L || type == GRUB_BIDI_TYPE_AL
|| type == GRUB_BIDI_TYPE_R)
break;
}
if (type == GRUB_BIDI_TYPE_R || type == GRUB_BIDI_TYPE_AL)
base_level = 1;
else
base_level = 0;
cur_level = base_level;
cur_override = OVERRIDE_NEUTRAL;
{
const grub_uint32_t *lptr;
for (lptr = logical; lptr < logical + logical_len;)
{
grub_size_t p = grub_unicode_aglomerate_comb (lptr, logical
+ logical_len - lptr,
&visual[visual_len]);
type = get_bidi_type (visual[visual_len].base);
switch (type)
{
case GRUB_BIDI_TYPE_RLE:
push_stack (cur_override, (cur_level | 1) + 1);
break;
case GRUB_BIDI_TYPE_RLO:
push_stack (OVERRIDE_R, (cur_level | 1) + 1);
break;
case GRUB_BIDI_TYPE_LRE:
push_stack (cur_override, (cur_level & ~1) + 2);
break;
case GRUB_BIDI_TYPE_LRO:
push_stack (OVERRIDE_L, (cur_level & ~1) + 2);
break;
case GRUB_BIDI_TYPE_PDF:
pop_stack ();
break;
case GRUB_BIDI_TYPE_BN:
break;
default:
{
levels[visual_len] = cur_level;
if (cur_override != OVERRIDE_NEUTRAL)
resolved_types[visual_len] =
(cur_override == OVERRIDE_L) ? GRUB_BIDI_TYPE_L
: GRUB_BIDI_TYPE_R;
else
resolved_types[visual_len] = type;
visual_len++;
}
}
lptr += p;
}
}
for (run_start = 0; run_start < visual_len; run_start = run_end)
{
unsigned prev_level, next_level, cur_run_level;
unsigned last_type, last_strong_type;
for (run_end = run_start; run_end < visual_len &&
levels[run_end] == levels[run_start]; run_end++);
if (run_start == 0)
prev_level = base_level;
else
prev_level = levels[run_start - 1];
if (run_end == visual_len)
next_level = base_level;
else
next_level = levels[run_end];
cur_run_level = levels[run_start];
if (prev_level & 1)
last_type = GRUB_BIDI_TYPE_R;
else
last_type = GRUB_BIDI_TYPE_L;
last_strong_type = last_type;
for (i = run_start; i < run_end; i++)
{
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)
resolved_types[i] = GRUB_BIDI_TYPE_AN;
break;
case GRUB_BIDI_TYPE_L:
case GRUB_BIDI_TYPE_R:
last_strong_type = resolved_types[i];
break;
case GRUB_BIDI_TYPE_ES:
if (last_type == GRUB_BIDI_TYPE_EN
&& i + 1 < run_end
&& resolved_types[i + 1] == GRUB_BIDI_TYPE_EN)
resolved_types[i] = GRUB_BIDI_TYPE_EN;
else
resolved_types[i] = GRUB_BIDI_TYPE_ON;
break;
case GRUB_BIDI_TYPE_ET:
{
unsigned j;
if (last_type == GRUB_BIDI_TYPE_EN)
{
resolved_types[i] = GRUB_BIDI_TYPE_EN;
break;
}
for (j = i; j < run_end
&& resolved_types[j] == GRUB_BIDI_TYPE_ET; j++);
if (j != run_end && resolved_types[j] == GRUB_BIDI_TYPE_EN)
{
for (; i < run_end
&& resolved_types[i] == GRUB_BIDI_TYPE_ET; i++)
resolved_types[i] = GRUB_BIDI_TYPE_EN;
i--;
break;
}
for (; i < run_end
&& resolved_types[i] == GRUB_BIDI_TYPE_ET; i++)
resolved_types[i] = GRUB_BIDI_TYPE_ON;
i--;
break;
}
break;
case GRUB_BIDI_TYPE_CS:
if (last_type == GRUB_BIDI_TYPE_EN
&& i + 1 < run_end
&& resolved_types[i + 1] == GRUB_BIDI_TYPE_EN)
{
resolved_types[i] = GRUB_BIDI_TYPE_EN;
break;
}
if (last_type == GRUB_BIDI_TYPE_AN
&& i + 1 < run_end
&& (resolved_types[i + 1] == GRUB_BIDI_TYPE_AN
|| (resolved_types[i + 1] == GRUB_BIDI_TYPE_EN
&& last_strong_type == GRUB_BIDI_TYPE_AL)))
{
resolved_types[i] = GRUB_BIDI_TYPE_EN;
break;
}
resolved_types[i] = GRUB_BIDI_TYPE_ON;
break;
case GRUB_BIDI_TYPE_AL:
last_strong_type = resolved_types[i];
resolved_types[i] = GRUB_BIDI_TYPE_R;
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)
resolved_types[i] = GRUB_BIDI_TYPE_L;
}
if (prev_level & 1)
last_type = GRUB_BIDI_TYPE_R;
else
last_type = GRUB_BIDI_TYPE_L;
for (i = run_start; i < run_end; )
{
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)
last_type = GRUB_BIDI_TYPE_L;
else
last_type = GRUB_BIDI_TYPE_R;
i++;
continue;
}
if (j == run_end)
next_type = (next_level & 1) ? GRUB_BIDI_TYPE_R : GRUB_BIDI_TYPE_L;
else
{
if (resolved_types[j] == GRUB_BIDI_TYPE_L)
next_type = GRUB_BIDI_TYPE_L;
else
next_type = GRUB_BIDI_TYPE_R;
}
if (next_type == last_type)
for (; i < j; i++)
resolved_types[i] = last_type;
else
for (; i < j; i++)
resolved_types[i] = (cur_run_level & 1) ? GRUB_BIDI_TYPE_R
: GRUB_BIDI_TYPE_L;
}
}
for (i = 0; i < visual_len; i++)
{
if (!(levels[i] & 1) && resolved_types[i] == GRUB_BIDI_TYPE_R)
{
levels[i]++;
continue;
}
if (!(levels[i] & 1) && (resolved_types[i] == GRUB_BIDI_TYPE_AN
|| resolved_types[i] == GRUB_BIDI_TYPE_EN))
{
levels[i] += 2;
continue;
}
if ((levels[i] & 1) && (resolved_types[i] == GRUB_BIDI_TYPE_L
|| resolved_types[i] == GRUB_BIDI_TYPE_AN
|| resolved_types[i] == GRUB_BIDI_TYPE_EN))
{
levels[i]++;
continue;
}
}
grub_free (resolved_types);
if (!visual_len)
{
grub_free (levels);
grub_free (visual);
return 0;
}
{
struct grub_unicode_glyph *outptr = visual_out;
unsigned line_start = 0;
grub_ssize_t line_width = 0;
unsigned k;
for (k = 0; k <= visual_len; k++)
{
grub_ssize_t last_width = 0;
if (getcharwidth && k != visual_len)
line_width += last_width = getcharwidth (&visual[k]);
if (((grub_ssize_t) maxwidth > 0
&& line_width > (grub_ssize_t) maxwidth) || k == visual_len)
{
unsigned min_odd_level = 0xffffffff;
unsigned max_level = 0;
unsigned j;
for (i = line_start; i < k; i++)
{
if (levels[i] > max_level)
max_level = levels[i];
if (levels[i] < min_odd_level && (levels[i] & 1))
min_odd_level = levels[i];
}
/* FIXME: can be optimized. */
for (j = max_level; j >= min_odd_level; j--)
{
unsigned in = 0;
for (i = line_start; i < k; i++)
{
if (i != line_start && levels[i] >= j && levels[i-1] < j)
in = i;
if (levels[i] >= j && (i + 1 == k || levels[i+1] < j))
revert (in, i);
}
}
for (i = line_start; i < k; i++)
if (is_mirrored (visual[i].base) && levels[i])
visual[i].attributes |= GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR;
grub_memcpy (outptr, &visual[line_start],
(k - line_start) * sizeof (visual[0]));
outptr += k - line_start;
if (k != visual_len)
{
grub_memset (outptr, 0, sizeof (visual[0]));
outptr->base = '\n';
outptr++;
}
line_start = k;
line_width = last_width;
}
}
grub_free (levels);
grub_free (visual);
return outptr - visual_out;
}
}
grub_ssize_t
grub_bidi_logical_to_visual (const grub_uint32_t *logical,
grub_size_t logical_len,
struct grub_unicode_glyph **visual_out,
grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
grub_size_t max_length)
{
const grub_uint32_t *line_start = logical, *ptr;
struct grub_unicode_glyph *visual_ptr;
*visual_out = visual_ptr = grub_malloc (2 * sizeof (visual_ptr[0])
* logical_len);
for (ptr = logical; ptr <= logical + logical_len; ptr++)
{
if (ptr == logical + logical_len || *ptr == '\n')
{
grub_ssize_t ret;
ret = grub_bidi_line_logical_to_visual (line_start,
ptr - line_start,
visual_ptr,
getcharwidth,
max_length);
if (ret < 0)
{
grub_free (*visual_out);
return ret;
}
visual_ptr += ret;
line_start = ptr;
if (ptr != logical + logical_len)
{
grub_memset (visual_ptr, 0, sizeof (visual_ptr[0]));
visual_ptr->base = '\n';
visual_ptr++;
}
}
}
return visual_ptr - *visual_out;
}
struct grub_unicode_glyph *
grub_unicode_glyph_dup (const struct grub_unicode_glyph *in)
{
struct grub_unicode_glyph *out = grub_malloc (sizeof (*out));
if (!out)
return NULL;
grub_memcpy (out, in, sizeof (*in));
out->combining = grub_malloc (in->ncomb * sizeof (*in));
if (!out->combining)
{
grub_free (out);
return NULL;
}
grub_memcpy (out->combining, in->combining, in->ncomb * sizeof (*in));
return out;
}
struct grub_unicode_glyph *
grub_unicode_glyph_from_code (grub_uint32_t code)
{
struct grub_unicode_glyph *ret;
ret = grub_malloc (sizeof (*ret));
if (!ret)
return NULL;
ret->base = code;
ret->variant = 0;
ret->attributes = 0;
ret->ncomb = 0;
ret->combining = 0;
return ret;
}
static grub_uint32_t
map_code (grub_uint32_t in, struct grub_term_output *term)
{
if (in <= 0x7f)
return in;
if ((term->flags & GRUB_TERM_CODE_TYPE_MASK) == GRUB_TERM_CODE_TYPE_VGA)
{
switch (in)
{
case GRUB_TERM_DISP_LEFT:
return 0x1b;
case GRUB_TERM_DISP_UP:
return 0x18;
case GRUB_TERM_DISP_RIGHT:
return 0x1a;
case GRUB_TERM_DISP_DOWN:
return 0x19;
case GRUB_TERM_DISP_HLINE:
return 0xc4;
case GRUB_TERM_DISP_VLINE:
return 0xb3;
case GRUB_TERM_DISP_UL:
return 0xda;
case GRUB_TERM_DISP_UR:
return 0xbf;
case GRUB_TERM_DISP_LL:
return 0xc0;
case GRUB_TERM_DISP_LR:
return 0xd9;
}
return '?';
}
else
{
/* Better than nothing. */
switch (in)
{
case GRUB_TERM_DISP_LEFT:
return '<';
case GRUB_TERM_DISP_UP:
return '^';
case GRUB_TERM_DISP_RIGHT:
return '>';
case GRUB_TERM_DISP_DOWN:
return 'v';
case GRUB_TERM_DISP_HLINE:
return '-';
case GRUB_TERM_DISP_VLINE:
return '|';
case GRUB_TERM_DISP_UL:
case GRUB_TERM_DISP_UR:
case GRUB_TERM_DISP_LL:
case GRUB_TERM_DISP_LR:
return '+';
}
return '?';
}
return in;
}
/* Put a Unicode character. */
void
grub_putcode (grub_uint32_t code,
struct grub_term_output *term)
{
struct grub_unicode_glyph c =
{
.variant = 0,
.attributes = 0,
.ncomb = 0,
.combining = 0
};
if (grub_unicode_get_comb_type (code) != GRUB_UNICODE_COMB_NONE)
return;
if (code == '\t' && term->getxy)
{
int n;
n = 8 - ((term->getxy () >> 8) & 7);
while (n--)
grub_putcode (' ', term);
return;
}
c.base = map_code (code, term);
(term->putchar) (&c);
if (code == '\n')
grub_putcode ('\r', term);
}
void
grub_print_ucs4 (const grub_uint32_t * str,
const grub_uint32_t * last_position,
struct grub_term_output *term)
{
if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
== GRUB_TERM_CODE_TYPE_UCS4_VISUAL)
{
grub_ssize_t visual_len;
struct grub_unicode_glyph *visual;
struct grub_unicode_glyph *visual_ptr;
visual_len = grub_bidi_logical_to_visual (str,
last_position - str,
&visual,
term->getcharwidth,
grub_term_width (term));
if (visual_len < 0)
{
grub_print_error ();
return;
}
for (visual_ptr = visual; visual_ptr < visual + visual_len; visual_ptr++)
{
struct grub_unicode_glyph glyph_r = {
.base = '\r',
.variant = 0,
.attributes = 0,
.ncomb = 0,
.combining = 0
};
term->putchar (visual_ptr);
if (visual_ptr->base == '\n')
term->putchar (&glyph_r);
grub_free (visual_ptr->combining);
}
grub_free (visual);
return;
}
/* FIXME: UTF-8 terminals. */
{
const grub_uint32_t *ptr;
for (ptr = str; ptr < last_position; ptr++)
grub_putcode (*ptr, term);
}
}
void
grub_xputs_normal (const char *str)
{
grub_term_output_t term;
FOR_ACTIVE_TERM_OUTPUTS(term)
{
grub_uint32_t *unicode_str, *unicode_last_position;
grub_utf8_to_ucs4_alloc (str, &unicode_str,
&unicode_last_position);
grub_print_ucs4 (unicode_str, unicode_last_position, term);
grub_free (unicode_str);
}
}

View file

@ -644,10 +644,15 @@ grub_env_write_pager (struct grub_env_var *var __attribute__ ((unused)),
return grub_strdup (val); return grub_strdup (val);
} }
static void (*grub_xputs_saved) (const char *str);
GRUB_MOD_INIT(normal) GRUB_MOD_INIT(normal)
{ {
grub_context_init (); grub_context_init ();
grub_xputs_saved = grub_xputs;
grub_xputs = grub_xputs_normal;
/* Normal mode shouldn't be unloaded. */ /* Normal mode shouldn't be unloaded. */
if (mod) if (mod)
grub_dl_ref (mod); grub_dl_ref (mod);
@ -676,6 +681,8 @@ GRUB_MOD_FINI(normal)
{ {
grub_context_fini (); grub_context_fini ();
grub_xputs = grub_xputs_saved;
grub_set_history (0); grub_set_history (0);
grub_register_variable_hook ("pager", 0, 0); grub_register_variable_hook ("pager", 0, 0);
grub_fs_autoload_hook = 0; grub_fs_autoload_hook = 0;

View file

@ -46,18 +46,6 @@ print_spaces (int number_spaces, struct grub_term_output *term)
grub_putcode (' ', term); grub_putcode (' ', term);
} }
void
grub_print_ucs4 (const grub_uint32_t * str,
const grub_uint32_t * last_position,
struct grub_term_output *term)
{
while (str < last_position)
{
grub_putcode (*str, term);
str++;
}
}
grub_ssize_t grub_ssize_t
grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position, grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position,
struct grub_term_output *term) struct grub_term_output *term)
@ -66,8 +54,9 @@ grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position,
while (str < last_position) while (str < last_position)
{ {
width += grub_term_getcharwidth (term, *str); struct grub_unicode_glyph glyph;
str++; str += grub_unicode_aglomerate_comb (str, last_position - str, &glyph);
width += grub_term_getcharwidth (term, &glyph);
} }
return width; return width;
} }
@ -83,8 +72,18 @@ grub_print_message_indented (const char *msg, int margin_left, int margin_right,
int msg_len; int msg_len;
line_len = grub_term_width (term) - grub_term_getcharwidth (term, 'm') * {
(margin_left + margin_right); struct grub_unicode_glyph pseudo_glyph = {
.base = ' ',
.variant = 0,
.attributes = 0,
.ncomb = 0,
.combining = 0
};
line_len = grub_term_width (term)
- grub_term_getcharwidth (term, &pseudo_glyph)
* (margin_left + margin_right);
}
msg_len = grub_utf8_to_ucs4_alloc (msg, &unicode_msg, &last_position); msg_len = grub_utf8_to_ucs4_alloc (msg, &unicode_msg, &last_position);
@ -252,34 +251,53 @@ print_entry (int y, int highlight, grub_menu_entry_t entry,
grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y); grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y);
int last_printed = 0;
for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0; for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0;
x < (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term) x < (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
- GRUB_TERM_MARGIN); - GRUB_TERM_MARGIN);)
i++)
{ {
if (i < len if (i < len
&& x <= (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term) && x <= (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
- GRUB_TERM_MARGIN - 1)) - GRUB_TERM_MARGIN - 1))
{ {
grub_ssize_t width; grub_ssize_t width;
struct grub_unicode_glyph glyph;
width = grub_term_getcharwidth (term, unicode_title[i]); i += grub_unicode_aglomerate_comb (unicode_title + i,
len - i, &glyph);
if (x + width > (int) (GRUB_TERM_LEFT_BORDER_X width = grub_term_getcharwidth (term, &glyph);
if (x + width <= (int) (GRUB_TERM_LEFT_BORDER_X
+ grub_term_border_width (term) + grub_term_border_width (term)
- GRUB_TERM_MARGIN - 1)) - GRUB_TERM_MARGIN - 1))
grub_putcode (GRUB_TERM_DISP_RIGHT, term); last_printed = i;
else
grub_putcode (unicode_title[i], term);
x += width; x += width;
} }
else else
{ break;
grub_putcode (' ', term);
x++;
}
} }
grub_print_ucs4 (unicode_title,
unicode_title + last_printed, term);
if (last_printed != len)
{
grub_putcode (GRUB_TERM_DISP_RIGHT, term);
struct grub_unicode_glyph pseudo_glyph = {
.base = GRUB_TERM_DISP_RIGHT,
.variant = 0,
.attributes = 0,
.ncomb = 0,
.combining = 0
};
x += grub_term_getcharwidth (term, &pseudo_glyph);
}
for (; x < (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
- GRUB_TERM_MARGIN); x++)
grub_putcode (' ', term);
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
grub_putcode (' ', term); grub_putcode (' ', term);

View file

@ -48,7 +48,7 @@ struct grub_dirty_region
struct grub_colored_char struct grub_colored_char
{ {
/* An Unicode codepoint. */ /* An Unicode codepoint. */
grub_uint32_t code; struct grub_unicode_glyph *code;
/* Color values. */ /* Color values. */
grub_video_color_t fg_color; grub_video_color_t fg_color;
@ -147,6 +147,9 @@ static unsigned char calculate_character_width (struct grub_font_glyph *glyph);
static void grub_gfxterm_refresh (void); static void grub_gfxterm_refresh (void);
static grub_ssize_t
grub_gfxterm_getcharwidth (const struct grub_unicode_glyph *c);
static void static void
set_term_color (grub_uint8_t term_color) set_term_color (grub_uint8_t term_color)
{ {
@ -176,7 +179,10 @@ set_term_color (grub_uint8_t term_color)
static void static void
clear_char (struct grub_colored_char *c) clear_char (struct grub_colored_char *c)
{ {
c->code = ' '; grub_free (c->code);
c->code = grub_unicode_glyph_from_code (' ');
if (!c->code)
grub_errno = GRUB_ERR_NONE;
c->fg_color = virtual_screen.fg_color; c->fg_color = virtual_screen.fg_color;
c->bg_color = virtual_screen.bg_color; c->bg_color = virtual_screen.bg_color;
c->width = 0; c->width = 0;
@ -265,7 +271,10 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y,
/* Clear out text buffer. */ /* Clear out text buffer. */
for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++) for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
clear_char (&(virtual_screen.text_buffer[i])); {
virtual_screen.text_buffer[i].code = 0;
clear_char (&(virtual_screen.text_buffer[i]));
}
return grub_errno; return grub_errno;
} }
@ -610,7 +619,12 @@ paint_char (unsigned cx, unsigned cy)
p -= p->index; p -= p->index;
/* Get glyph for character. */ /* Get glyph for character. */
glyph = grub_font_get_glyph (virtual_screen.font, p->code); glyph = grub_font_construct_glyph (virtual_screen.font, p->code);
if (!glyph)
{
grub_errno = GRUB_ERR_NONE;
return;
}
ascent = grub_font_get_ascent (virtual_screen.font); ascent = grub_font_get_ascent (virtual_screen.font);
width = virtual_screen.normal_char_width * calculate_character_width(glyph); width = virtual_screen.normal_char_width * calculate_character_width(glyph);
@ -631,6 +645,7 @@ paint_char (unsigned cx, unsigned cy)
/* Mark character to be drawn. */ /* Mark character to be drawn. */
dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y, dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y,
width, height); width, height);
grub_free (glyph);
} }
static inline void static inline void
@ -777,6 +792,15 @@ scroll_up (void)
{ {
unsigned int i; unsigned int i;
/* Clear first line in text buffer. */
for (i = 0;
i < virtual_screen.columns;
i++)
{
virtual_screen.text_buffer[i].code = 0;
clear_char (&(virtual_screen.text_buffer[i]));
}
/* Scroll text buffer with one line to up. */ /* Scroll text buffer with one line to up. */
grub_memmove (virtual_screen.text_buffer, grub_memmove (virtual_screen.text_buffer,
virtual_screen.text_buffer + virtual_screen.columns, virtual_screen.text_buffer + virtual_screen.columns,
@ -788,15 +812,18 @@ scroll_up (void)
for (i = virtual_screen.columns * (virtual_screen.rows - 1); for (i = virtual_screen.columns * (virtual_screen.rows - 1);
i < virtual_screen.columns * virtual_screen.rows; i < virtual_screen.columns * virtual_screen.rows;
i++) i++)
clear_char (&(virtual_screen.text_buffer[i])); {
virtual_screen.text_buffer[i].code = 0;
clear_char (&(virtual_screen.text_buffer[i]));
}
virtual_screen.total_scroll++; virtual_screen.total_scroll++;
} }
static void static void
grub_gfxterm_putchar (grub_uint32_t c) grub_gfxterm_putchar (const struct grub_unicode_glyph *c)
{ {
if (c == '\a') if (c->base == '\a')
/* FIXME */ /* FIXME */
return; return;
@ -804,9 +831,9 @@ grub_gfxterm_putchar (grub_uint32_t c)
if (virtual_screen.cursor_state) if (virtual_screen.cursor_state)
draw_cursor (0); draw_cursor (0);
if (c == '\b' || c == '\n' || c == '\r') if (c->base == '\b' || c->base == '\n' || c->base == '\r')
{ {
switch (c) switch (c->base)
{ {
case '\b': case '\b':
if (virtual_screen.cursor_x > 0) if (virtual_screen.cursor_x > 0)
@ -827,26 +854,30 @@ grub_gfxterm_putchar (grub_uint32_t c)
} }
else else
{ {
struct grub_font_glyph *glyph;
struct grub_colored_char *p; struct grub_colored_char *p;
unsigned char char_width; unsigned char char_width;
/* Get properties of the character. */
glyph = grub_font_get_glyph (virtual_screen.font, c);
/* Calculate actual character width for glyph. This is number of /* Calculate actual character width for glyph. This is number of
times of normal_font_width. */ times of normal_font_width. */
char_width = calculate_character_width(glyph); char_width = grub_gfxterm_getcharwidth (c);
/* If we are about to exceed line length, wrap to next line. */ /* If we are about to exceed line length, wrap to next line. */
if (virtual_screen.cursor_x + char_width > virtual_screen.columns) if (virtual_screen.cursor_x + char_width > virtual_screen.columns)
grub_gfxterm_putchar ('\n'); {
if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
scroll_up ();
else
virtual_screen.cursor_y++;
}
/* Find position on virtual screen, and fill information. */ /* Find position on virtual screen, and fill information. */
p = (virtual_screen.text_buffer + p = (virtual_screen.text_buffer +
virtual_screen.cursor_x + virtual_screen.cursor_x +
virtual_screen.cursor_y * virtual_screen.columns); virtual_screen.cursor_y * virtual_screen.columns);
p->code = c; grub_free (p->code);
p->code = grub_unicode_glyph_dup (c);
if (!p->code)
grub_errno = GRUB_ERR_NONE;
p->fg_color = virtual_screen.fg_color; p->fg_color = virtual_screen.fg_color;
p->bg_color = virtual_screen.bg_color; p->bg_color = virtual_screen.bg_color;
p->width = char_width - 1; p->width = char_width - 1;
@ -859,7 +890,10 @@ grub_gfxterm_putchar (grub_uint32_t c)
for (i = 1; i < char_width; i++) for (i = 1; i < char_width; i++)
{ {
p[i].code = ' '; grub_free (p[i].code);
p[i].code = grub_unicode_glyph_from_code (' ');
if (!p[i].code)
grub_errno = GRUB_ERR_NONE;
p[i].width = char_width - 1; p[i].width = char_width - 1;
p[i].index = i; p[i].index = i;
} }
@ -924,18 +958,16 @@ calculate_character_width (struct grub_font_glyph *glyph)
} }
static grub_ssize_t static grub_ssize_t
grub_gfxterm_getcharwidth (grub_uint32_t c) grub_gfxterm_getcharwidth (const struct grub_unicode_glyph *c)
{ {
struct grub_font_glyph *glyph; int dev_width;
unsigned char char_width; dev_width = grub_font_get_constructed_device_width (virtual_screen.font, c);
/* Get properties of the character. */ if (dev_width == 0)
glyph = grub_font_get_glyph (virtual_screen.font, c); return 1;
/* Calculate actual character width for glyph. */ return (dev_width + (virtual_screen.normal_char_width - 1))
char_width = calculate_character_width (glyph); / virtual_screen.normal_char_width;
return char_width;
} }
static grub_uint16_t static grub_uint16_t
@ -1174,7 +1206,7 @@ static struct grub_term_output grub_video_term =
.getcolor = grub_virtual_screen_getcolor, .getcolor = grub_virtual_screen_getcolor,
.setcursor = grub_gfxterm_setcursor, .setcursor = grub_gfxterm_setcursor,
.refresh = grub_gfxterm_refresh, .refresh = grub_gfxterm_refresh,
.flags = 0, .flags = GRUB_TERM_CODE_TYPE_UCS4_VISUAL,
.next = 0 .next = 0
}; };

View file

@ -65,7 +65,8 @@ static struct grub_term_output grub_console_term_output =
.setcolorstate = grub_console_setcolorstate, .setcolorstate = grub_console_setcolorstate,
.setcolor = grub_console_setcolor, .setcolor = grub_console_setcolor,
.getcolor = grub_console_getcolor, .getcolor = grub_console_getcolor,
.setcursor = grub_console_setcursor .setcursor = grub_console_setcursor,
.flags = GRUB_TERM_CODE_TYPE_VGA
}; };
void void

View file

@ -214,45 +214,7 @@ grub_virtual_screen_get_glyph (grub_uint32_t code,
unsigned *width) unsigned *width)
{ {
if (code > 0x7f) if (code > 0x7f)
{ return grub_font_get_glyph_any (code, bitmap, width);
/* Map some unicode characters to the VGA font, if possible. */
switch (code)
{
case 0x2190: /* left arrow */
code = 0x1b;
break;
case 0x2191: /* up arrow */
code = 0x18;
break;
case 0x2192: /* right arrow */
code = 0x1a;
break;
case 0x2193: /* down arrow */
code = 0x19;
break;
case 0x2501: /* horizontal line */
code = 0xc4;
break;
case 0x2503: /* vertical line */
code = 0xb3;
break;
case 0x250F: /* upper-left corner */
code = 0xda;
break;
case 0x2513: /* upper-right corner */
code = 0xbf;
break;
case 0x2517: /* lower-left corner */
code = 0xc0;
break;
case 0x251B: /* lower-right corner */
code = 0xd9;
break;
default:
return grub_font_get_glyph_any (code, bitmap, width);
}
}
/* TODO This is wrong for the new font module. Should it be fixed? */ /* TODO This is wrong for the new font module. Should it be fixed? */
if (bitmap) if (bitmap)
@ -592,7 +554,7 @@ static struct grub_term_output grub_vesafb_term =
.cls = grub_vesafb_cls, .cls = grub_vesafb_cls,
.setcolorstate = grub_virtual_screen_setcolorstate, .setcolorstate = grub_virtual_screen_setcolorstate,
.setcursor = grub_vesafb_setcursor, .setcursor = grub_vesafb_setcursor,
.flags = 0, .flags = GRUB_TERM_CODE_TYPE_VGA
}; };
GRUB_MOD_INIT(vesafb) GRUB_MOD_INIT(vesafb)

View file

@ -287,23 +287,23 @@ scroll_up (void)
} }
static void static void
grub_vga_putchar (grub_uint32_t c) grub_vga_putchar (const struct grub_unicode_glyph *c)
{ {
#if DEBUG_VGA #if DEBUG_VGA
static int show = 1; static int show = 1;
#endif #endif
if (c == '\a') if (c->base == '\a')
/* FIXME */ /* FIXME */
return; return;
if (c == '\b' || c == '\n' || c == '\r') if (c->base == '\b' || c->base == '\n' || c->base == '\r')
{ {
/* Erase current cursor, if any. */ /* Erase current cursor, if any. */
if (cursor_state) if (cursor_state)
write_char (); write_char ();
switch (c) switch (c->base)
{ {
case '\b': case '\b':
if (xpos > 0) if (xpos > 0)
@ -331,13 +331,19 @@ grub_vga_putchar (grub_uint32_t c)
struct colored_char *p; struct colored_char *p;
unsigned char_width = 1; unsigned char_width = 1;
glyph = grub_font_get_glyph(font, c); glyph = grub_font_get_glyph(font, c->base);
if (xpos + char_width > TEXT_WIDTH) if (xpos + char_width > TEXT_WIDTH)
grub_vga_putchar ('\n'); {
xpos = 0;
if (ypos >= TEXT_HEIGHT - 1)
scroll_up ();
else
ypos++;
}
p = text_buf + xpos + ypos * TEXT_WIDTH; p = text_buf + xpos + ypos * TEXT_WIDTH;
p->code = c; p->code = c->base;
p->fg_color = fg_color; p->fg_color = fg_color;
p->bg_color = bg_color; p->bg_color = bg_color;
p->width = char_width - 1; p->width = char_width - 1;
@ -387,12 +393,12 @@ grub_vga_putchar (grub_uint32_t c)
} }
static grub_ssize_t static grub_ssize_t
grub_vga_getcharwidth (grub_uint32_t c) grub_vga_getcharwidth (const struct grub_unicode_glyph *c)
{ {
#if 0 #if 0
struct grub_font_glyph glyph; struct grub_font_glyph glyph;
glyph = grub_font_get_glyph (c); glyph = grub_font_get_glyph (c->base);
return glyph.char_width; return glyph.char_width;
#else #else
@ -499,7 +505,7 @@ static struct grub_term_output grub_vga_term =
.cls = grub_vga_cls, .cls = grub_vga_cls,
.setcolorstate = grub_vga_setcolorstate, .setcolorstate = grub_vga_setcolorstate,
.setcursor = grub_vga_setcursor, .setcursor = grub_vga_setcursor,
.flags = 0, .flags = GRUB_TERM_CODE_TYPE_UCS4_VISUAL,
}; };
GRUB_MOD_INIT(vga) GRUB_MOD_INIT(vga)

View file

@ -164,6 +164,7 @@ static struct grub_term_output grub_vga_text_term =
.setcolor = grub_console_setcolor, .setcolor = grub_console_setcolor,
.getcolor = grub_console_getcolor, .getcolor = grub_console_getcolor,
.setcursor = grub_vga_text_setcursor, .setcursor = grub_vga_text_setcursor,
.flags = GRUB_TERM_CODE_TYPE_VGA
}; };
GRUB_MOD_INIT(vga_text) GRUB_MOD_INIT(vga_text)

View file

@ -25,62 +25,14 @@ static grub_uint8_t grub_console_standard_color = 0x7;
static grub_uint8_t grub_console_normal_color = 0x7; static grub_uint8_t grub_console_normal_color = 0x7;
static grub_uint8_t grub_console_highlight_color = 0x70; static grub_uint8_t grub_console_highlight_color = 0x70;
static grub_uint32_t
map_char (grub_uint32_t c)
{
if (c > 0x7f)
{
/* Map some unicode characters to the VGA font, if possible. */
switch (c)
{
case 0x2190: /* left arrow */
c = 0x1b;
break;
case 0x2191: /* up arrow */
c = 0x18;
break;
case 0x2192: /* right arrow */
c = 0x1a;
break;
case 0x2193: /* down arrow */
c = 0x19;
break;
case 0x2501: /* horizontal line */
c = 0xc4;
break;
case 0x2503: /* vertical line */
c = 0xb3;
break;
case 0x250F: /* upper-left corner */
c = 0xda;
break;
case 0x2513: /* upper-right corner */
c = 0xbf;
break;
case 0x2517: /* lower-left corner */
c = 0xc0;
break;
case 0x251B: /* lower-right corner */
c = 0xd9;
break;
default:
c = '?';
break;
}
}
return c;
}
void void
grub_console_putchar (grub_uint32_t c) grub_console_putchar (const struct grub_unicode_glyph *c)
{ {
grub_console_real_putchar (map_char (c)); grub_console_real_putchar (c->base);
} }
grub_ssize_t grub_ssize_t
grub_console_getcharwidth (grub_uint32_t c __attribute__ ((unused))) grub_console_getcharwidth (const struct grub_unicode_glyph *c __attribute__ ((unused)))
{ {
/* For now, every printable character has the width 1. */ /* For now, every printable character has the width 1. */
return 1; return 1;

View file

@ -317,55 +317,12 @@ serial_hw_init (void)
/* The serial version of putchar. */ /* The serial version of putchar. */
static void static void
grub_serial_putchar (grub_uint32_t c) grub_serial_putchar (const struct grub_unicode_glyph *c)
{ {
/* Keep track of the cursor. */ /* Keep track of the cursor. */
if (keep_track) if (keep_track)
{ {
/* The serial terminal does not have VGA fonts. */ switch (c->base)
if (c > 0x7F)
{
/* Better than nothing. */
switch (c)
{
case GRUB_TERM_DISP_LEFT:
c = '<';
break;
case GRUB_TERM_DISP_UP:
c = '^';
break;
case GRUB_TERM_DISP_RIGHT:
c = '>';
break;
case GRUB_TERM_DISP_DOWN:
c = 'v';
break;
case GRUB_TERM_DISP_HLINE:
c = '-';
break;
case GRUB_TERM_DISP_VLINE:
c = '|';
break;
case GRUB_TERM_DISP_UL:
case GRUB_TERM_DISP_UR:
case GRUB_TERM_DISP_LL:
case GRUB_TERM_DISP_LR:
c = '+';
break;
default:
c = '?';
break;
}
}
switch (c)
{ {
case '\a': case '\a':
break; break;
@ -388,19 +345,22 @@ grub_serial_putchar (grub_uint32_t c)
default: default:
if (xpos >= TEXT_WIDTH) if (xpos >= TEXT_WIDTH)
{ {
grub_serial_putchar ('\r'); xpos = 0;
grub_serial_putchar ('\n'); if (ypos < TEXT_HEIGHT - 1)
ypos++;
serial_hw_put ('\r');
serial_hw_put ('\n');
} }
xpos++; xpos++;
break; break;
} }
} }
serial_hw_put (c); serial_hw_put (c->base);
} }
static grub_ssize_t static grub_ssize_t
grub_serial_getcharwidth (grub_uint32_t c __attribute__ ((unused))) grub_serial_getcharwidth (const struct grub_unicode_glyph *c __attribute__ ((unused)))
{ {
return 1; return 1;
} }
@ -491,7 +451,7 @@ static struct grub_term_output grub_serial_term_output =
.cls = grub_serial_cls, .cls = grub_serial_cls,
.setcolorstate = grub_serial_setcolorstate, .setcolorstate = grub_serial_setcolorstate,
.setcursor = grub_serial_setcursor, .setcursor = grub_serial_setcursor,
.flags = 0, .flags = GRUB_TERM_CODE_TYPE_UTF8_LOGICAL,
}; };

View file

@ -111,7 +111,17 @@ static void
putstr (const char *str, grub_term_output_t oterm) putstr (const char *str, grub_term_output_t oterm)
{ {
while (*str) while (*str)
grub_putcode (*str++, oterm); {
struct grub_unicode_glyph c =
{
.base = *str++,
.variant = 0,
.attributes = 0,
.ncomb = 0,
.combining = 0
};
oterm->putchar (&c);
}
} }
/* Move the cursor to the given position starting with "0". */ /* Move the cursor to the given position starting with "0". */

View file

@ -64,54 +64,13 @@ static grub_uint8_t color_map[NUM_COLORS] =
static int use_color; static int use_color;
static void static void
grub_ncurses_putchar (grub_uint32_t c) grub_ncurses_putchar (const struct grub_unicode_glyph *c)
{ {
/* Better than nothing. */ addch (c->base | grub_console_attr);
switch (c)
{
case GRUB_TERM_DISP_LEFT:
c = '<';
break;
case GRUB_TERM_DISP_UP:
c = '^';
break;
case GRUB_TERM_DISP_RIGHT:
c = '>';
break;
case GRUB_TERM_DISP_DOWN:
c = 'v';
break;
case GRUB_TERM_DISP_HLINE:
c = '-';
break;
case GRUB_TERM_DISP_VLINE:
c = '|';
break;
case GRUB_TERM_DISP_UL:
case GRUB_TERM_DISP_UR:
case GRUB_TERM_DISP_LL:
case GRUB_TERM_DISP_LR:
c = '+';
break;
default:
/* ncurses does not support Unicode. */
if (c > 0x7f)
c = '?';
break;
}
addch (c | grub_console_attr);
} }
static grub_ssize_t static grub_ssize_t
grub_ncurses_getcharwidth (grub_uint32_t code __attribute__ ((unused))) grub_ncurses_getcharwidth (const struct grub_unicode_glyph * c __attribute__ ((unused)))
{ {
return 1; return 1;
} }
@ -367,7 +326,8 @@ static struct grub_term_output grub_ncurses_term_output =
.setcolor = grub_ncurses_setcolor, .setcolor = grub_ncurses_setcolor,
.getcolor = grub_ncurses_getcolor, .getcolor = grub_ncurses_getcolor,
.setcursor = grub_ncurses_setcursor, .setcursor = grub_ncurses_setcursor,
.refresh = grub_ncurses_refresh .refresh = grub_ncurses_refresh,
.flags = GRUB_TERM_CODE_TYPE_ASCII
}; };
void void

View file

@ -63,6 +63,11 @@ grub_arch_dl_check_header (void *ehdr)
return GRUB_ERR_BAD_MODULE; return GRUB_ERR_BAD_MODULE;
} }
void grub_hostfs_init (void);
void grub_hostfs_fini (void);
void grub_host_init (void);
void grub_host_fini (void);
grub_err_t grub_err_t
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
{ {
@ -75,7 +80,14 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
void void
grub_reboot (void) grub_reboot (void)
{ {
longjmp (main_env, 1); grub_fini_all ();
grub_hostfs_fini ();
grub_host_fini ();
grub_machine_fini ();
exit (0);
// longjmp (main_env, 1);
} }
void void
@ -146,11 +158,6 @@ usage (int status)
} }
void grub_hostfs_init (void);
void grub_hostfs_fini (void);
void grub_host_init (void);
void grub_host_fini (void);
int int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {