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

@ -48,7 +48,7 @@ struct grub_dirty_region
struct grub_colored_char
{
/* An Unicode codepoint. */
grub_uint32_t code;
struct grub_unicode_glyph *code;
/* Color values. */
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 grub_ssize_t
grub_gfxterm_getcharwidth (const struct grub_unicode_glyph *c);
static void
set_term_color (grub_uint8_t term_color)
{
@ -176,7 +179,10 @@ set_term_color (grub_uint8_t term_color)
static void
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->bg_color = virtual_screen.bg_color;
c->width = 0;
@ -265,7 +271,10 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y,
/* Clear out text buffer. */
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;
}
@ -610,7 +619,12 @@ paint_char (unsigned cx, unsigned cy)
p -= p->index;
/* 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);
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. */
dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y,
width, height);
grub_free (glyph);
}
static inline void
@ -777,6 +792,15 @@ scroll_up (void)
{
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. */
grub_memmove (virtual_screen.text_buffer,
virtual_screen.text_buffer + virtual_screen.columns,
@ -788,15 +812,18 @@ scroll_up (void)
for (i = virtual_screen.columns * (virtual_screen.rows - 1);
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]));
}
virtual_screen.total_scroll++;
}
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 */
return;
@ -804,9 +831,9 @@ grub_gfxterm_putchar (grub_uint32_t c)
if (virtual_screen.cursor_state)
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':
if (virtual_screen.cursor_x > 0)
@ -827,26 +854,30 @@ grub_gfxterm_putchar (grub_uint32_t c)
}
else
{
struct grub_font_glyph *glyph;
struct grub_colored_char *p;
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
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 (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. */
p = (virtual_screen.text_buffer +
virtual_screen.cursor_x +
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->bg_color = virtual_screen.bg_color;
p->width = char_width - 1;
@ -859,7 +890,10 @@ grub_gfxterm_putchar (grub_uint32_t c)
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].index = i;
}
@ -924,18 +958,16 @@ calculate_character_width (struct grub_font_glyph *glyph)
}
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;
unsigned char char_width;
int dev_width;
dev_width = grub_font_get_constructed_device_width (virtual_screen.font, c);
/* Get properties of the character. */
glyph = grub_font_get_glyph (virtual_screen.font, c);
if (dev_width == 0)
return 1;
/* Calculate actual character width for glyph. */
char_width = calculate_character_width (glyph);
return char_width;
return (dev_width + (virtual_screen.normal_char_width - 1))
/ virtual_screen.normal_char_width;
}
static grub_uint16_t
@ -1174,7 +1206,7 @@ static struct grub_term_output grub_video_term =
.getcolor = grub_virtual_screen_getcolor,
.setcursor = grub_gfxterm_setcursor,
.refresh = grub_gfxterm_refresh,
.flags = 0,
.flags = GRUB_TERM_CODE_TYPE_UCS4_VISUAL,
.next = 0
};

View file

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

View file

@ -214,45 +214,7 @@ grub_virtual_screen_get_glyph (grub_uint32_t code,
unsigned *width)
{
if (code > 0x7f)
{
/* 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);
}
}
return grub_font_get_glyph_any (code, bitmap, width);
/* TODO This is wrong for the new font module. Should it be fixed? */
if (bitmap)
@ -592,7 +554,7 @@ static struct grub_term_output grub_vesafb_term =
.cls = grub_vesafb_cls,
.setcolorstate = grub_virtual_screen_setcolorstate,
.setcursor = grub_vesafb_setcursor,
.flags = 0,
.flags = GRUB_TERM_CODE_TYPE_VGA
};
GRUB_MOD_INIT(vesafb)

View file

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

View file

@ -164,6 +164,7 @@ static struct grub_term_output grub_vga_text_term =
.setcolor = grub_console_setcolor,
.getcolor = grub_console_getcolor,
.setcursor = grub_vga_text_setcursor,
.flags = GRUB_TERM_CODE_TYPE_VGA
};
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_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
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_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. */
return 1;

View file

@ -317,55 +317,12 @@ serial_hw_init (void)
/* The serial version of putchar. */
static void
grub_serial_putchar (grub_uint32_t c)
grub_serial_putchar (const struct grub_unicode_glyph *c)
{
/* Keep track of the cursor. */
if (keep_track)
{
/* The serial terminal does not have VGA fonts. */
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)
switch (c->base)
{
case '\a':
break;
@ -388,19 +345,22 @@ grub_serial_putchar (grub_uint32_t c)
default:
if (xpos >= TEXT_WIDTH)
{
grub_serial_putchar ('\r');
grub_serial_putchar ('\n');
xpos = 0;
if (ypos < TEXT_HEIGHT - 1)
ypos++;
serial_hw_put ('\r');
serial_hw_put ('\n');
}
xpos++;
break;
}
}
serial_hw_put (c);
serial_hw_put (c->base);
}
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;
}
@ -491,7 +451,7 @@ static struct grub_term_output grub_serial_term_output =
.cls = grub_serial_cls,
.setcolorstate = grub_serial_setcolorstate,
.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)
{
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". */