2008-10-30 Colin D Bennett
New font engine supporting large and proportional fonts, PFF2 file
format.
* commands/videotest.c (grub_cmd_videotest): Use new font API, test
drawing UTF-8 Unicode text.
* conf/common.rmk (font_mod_SOURCES): Update source file list.
* font/font.c: New file.
* font/font_cmd.c: New file.
* font/manager.c: Deleted.
* include/grub/font.h: Update copyright years.
(GRUB_FONT_MAGIC): Removed.
(grub_font): New forward declaration of struct.
(grub_font_t): New typedef.
(grub_font_node): New struct.
(grub_font_list): New global symbol.
(grub_font_glyph): Updated data structure to support larger, variable
size fonts and to support font metrics.
(grub_font_glyph_t): Removed.
(grub_font_loader_init): New prototype.
(grub_font_load): New prototype.
(grub_font_get): New prototype.
(grub_font_get_name): New prototype.
(grub_font_get_max_char_width): New prototype.
(grub_font_get_max_char_height): New prototype.
(grub_font_get_ascent): New prototype.
(grub_font_get_descent): New prototype.
(grub_font_get_leading): New prototype.
(grub_font_get_height): New prototype.
(grub_font_get_string_width): New prototype.
(grub_font_load): New prototype.
(grub_font_get_glyph): New prototype.
(grub_font_get_glyph_with_fallback): New prototype.
(grub_font_draw_glyph): New prototype.
(grub_font_draw_string): New prototype.
* include/grub/misc.h (grub_utf8_to_ucs4): Added parameters.
* include/grub/video.h (grub_font_glyph): Removed forward struct
declaration.
(GRUB_VIDEO_MODE_TYPE_ALPHA): Changed bit mask value to make space for
1BIT_BITMAP.
(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED): Likewise.
(GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP): New bit mask constant.
(GRUB_VIDEO_MODE_TYPE_COLOR_MASK): Updated to a wider mask to make
space for 1BIT_BITMAP.
(GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED): New blit format enum value.
(grub_video_mode_info): Added bg_red, bg_green, bg_blue, bg_alpha,
fg_red, fg_green, fg_blue, and fg_alpha fields.
* kern/misc.c (grub_utf8_to_ucs4): Support null-terminated UTF-8
strings and allow limiting the number of Unicode characters decoded.
* kern/term.c (grub_putchar): Pass additional arguments to
grub_utf8_to_ucs4.
* normal/menu.c (print_entry): Pass destination maximum length to
grub_utf8_to_ucs4.
* term/gfxterm.c (DEFAULT_CHAR_WIDTH): Removed.
(DEFAULT_CHAR_HEIGHT): Removed.
(grub_virtual_screen): Added font field.
(grub_virtual_screen_setup): Add font_name parameter. Initialize
terminal font information.
(grub_gfxterm_init): Get font name from gfxterm_font environment
variable. Pass font name to grub_virtual_screen_setup.
(write_char): Place glyphs using their baseline, based on the font
ascent.
(write_cursor): Draw cursor using font ascent as a reference.
(grub_gfxterm_putchar): Use new font API. Breaks bi-width font
support.
(grub_gfxterm_getcharwidth): Assume all characters are 1 character in
width. Breaks bi-width font support.
(grub_vga_getcharwidth): Always return a width of 1.
* term/i386/pc/vesafb.c (grub_virtual_screen_get_glyph): Use new font
API. Breaks vesafb glyph drawing, since it copied the glyph data
directly, but now glyphs use a different storage format.
This code shouldn't compile, but GRUB builds ok!
* term/i386/pc/vga.c (font): New static variable.
(grub_vga_mod_init): Get a font using the new font API.
(write_char): Broken. Commented out code with #if 0 since it will need
to be rewritten to handle the new glyph storage format if we want to
maintain the vga terminal.
(grub_vga_putchar): Update to use new font API; breaks support for
bi-width fonts.
* video/i386/pc/vbe.c (grub_video_vbe_map_rgb): Support
GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP.
(grub_video_vbe_map_rgba): Likewise.
(grub_video_vbe_unmap_color_int): Likewise.
(grub_video_vbe_blit_glyph): Deleted.
(grub_video_vbe_adapter): Deleted blit_glyph member.
* video/i386/pc/vbeutil.c (get_data_ptr): Add a comment to the switch
statement indicating why it is unimplemented for 1-bit bitmaps.
(get_pixel): Support 1-bit bitmaps.
(set_pixel): Support 1-bit bitmaps.
* video/video.c (grub_video_blit_glyph): Renamed coordinate arguments
for clarity.
(grub_video_draw_string): New function.
=== modified file 'commands/videotest.c'
--- commands/videotest.c 2007-07-21 22:32:33 +0000
+++ commands/videotest.c 2008-10-31 03:46:58 +0000
@@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2006,2007 Free Software Foundation, Inc.
+ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,17 +36,21 @@
GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != GRUB_ERR_NONE)
return grub_errno;
- grub_getkey ();
-
grub_video_color_t color;
unsigned int x;
unsigned int y;
unsigned int width;
unsigned int height;
int i;
- struct grub_font_glyph glyph;
+ grub_font_t sansbig;
+ grub_font_t sans;
+ grub_font_t sanssmall;
+ grub_font_t fixed;
+ struct grub_font_glyph *glyph;
struct grub_video_render_target *text_layer;
grub_video_color_t palette[16];
+ const char *str;
+ int texty;
grub_video_get_viewport (&x, &y, &width, &height);
@@ -65,8 +69,15 @@
color = grub_video_map_rgb (0, 255, 255);
grub_video_fill_rect (color, 100, 100, 100, 100);
- grub_font_get_glyph ('*', &glyph);
- grub_video_blit_glyph (&glyph, color, 200 ,0);
+ sansbig = grub_font_get ("Helvetica Bold 24");
+ sans = grub_font_get ("Helvetica Bold 14");
+ sanssmall = grub_font_get ("Helvetica 8");
+ fixed = grub_font_get ("Fixed 20");
+ if (! sansbig || ! sans || ! sanssmall || ! fixed)
+ return grub_error (GRUB_ERR_BAD_FONT, "No font loaded.");
+
+ glyph = grub_font_get_glyph (fixed, '*');
+ grub_font_draw_glyph (glyph, color, 200 ,0);
grub_video_set_viewport (x + 150, y + 150,
width - 150 * 2, height - 150 * 2);
@@ -77,18 +88,69 @@
color = grub_video_map_rgb (255, 255, 255);
- grub_font_get_glyph ('A', &glyph);
- grub_video_blit_glyph (&glyph, color, 16, 16);
- grub_font_get_glyph ('B', &glyph);
- grub_video_blit_glyph (&glyph, color, 16 * 2, 16);
-
- grub_font_get_glyph ('*', &glyph);
+ texty = 32;
+ grub_font_draw_string ("The quick brown fox jumped over the lazy dog.",
+ sans, color, 16, texty);
+ texty += grub_font_get_descent (sans) + grub_font_get_leading (sans);
+
+ texty += grub_font_get_ascent (fixed);
+ grub_font_draw_string ("The quick brown fox jumped over the lazy dog.",
+ fixed, color, 16, texty);
+ texty += grub_font_get_descent (fixed) + grub_font_get_leading (fixed);
+
+ /* To convert Unicode characters into UTF-8 for this test, the following
+ command is useful:
+ echo -ne '\x00\x00\x26\x3A' | iconv -f UTF-32BE -t UTF-8 | od -t x1
+ This converts the Unicode character U+263A to UTF-8. */
+
+ /* Characters used:
+ Code point Description UTF-8 encoding
+ ----------- ------------------------------ --------------
+ U+263A unfilled smiley face E2 98 BA
+ U+00A1 inverted exclamation point C2 A1
+ U+00A3 British pound currency symbol C2 A3
+ U+03C4 Greek tau CF 84
+ U+00E4 lowercase letter a with umlaut C3 A4
+ U+2124 set 'Z' symbol (integers) E2 84 A4
+ U+2287 subset symbol E2 8A 87
+ U+211D set 'R' symbol (real numbers) E2 84 9D */
+
+ str =
+ "Unicode test: happy\xE2\x98\xBA \xC2\xA3 5.00"
+ " \xC2\xA1\xCF\x84\xC3\xA4u! "
+ " \xE2\x84\xA4\xE2\x8A\x87\xE2\x84\x9D";
+ color = grub_video_map_rgb (128, 128, 255);
+
+ /* All characters in the string exist in the 'Fixed 20' (10x20) font. */
+ texty += grub_font_get_ascent(fixed);
+ grub_font_draw_string (str, fixed, color, 16, texty);
+ texty += grub_font_get_descent (fixed) + grub_font_get_leading (fixed);
+
+ /* Some character don't exist in the Helvetica font, so the font engine
+ will fall back to using glyphs from another font that does contain them.
+ TODO The font engine should be smart about selecting a replacement font
+ and prioritize fonts with similar sizes. */
+
+ texty += grub_font_get_ascent(sansbig);
+ grub_font_draw_string (str, sansbig, color, 16, texty);
+ texty += grub_font_get_descent (sansbig) + grub_font_get_leading (sansbig);
+
+ texty += grub_font_get_ascent(sans);
+ grub_font_draw_string (str, sans, color, 16, texty);
+ texty += grub_font_get_descent (sans) + grub_font_get_leading (sans);
+
+ texty += grub_font_get_ascent(sanssmall);
+ grub_font_draw_string (str, sanssmall, color, 16, texty);
+ texty += (grub_font_get_descent (sanssmall)
+ + grub_font_get_leading (sanssmall));
+
+ glyph = grub_font_get_glyph (fixed, '*');
for (i = 0; i < 16; i++)
{
color = grub_video_map_color (i);
palette[i] = color;
- grub_video_blit_glyph (&glyph, color, 16 + i * 16, 32);
+ grub_font_draw_glyph (glyph, color, 16 + i * 16, 220);
}
grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
=== modified file 'conf/common.rmk'
--- conf/common.rmk 2008-09-29 13:57:05 +0000
+++ conf/common.rmk 2008-10-30 18:24:32 +0000
@@ -364,7 +364,7 @@
help_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For font.mod.
-font_mod_SOURCES = font/manager.c
+font_mod_SOURCES = font/font_cmd.c font/font.c
font_mod_CFLAGS = $(COMMON_CFLAGS)
font_mod_LDFLAGS = $(COMMON_LDFLAGS)
=== added file 'font/font.c'
--- font/font.c 1970-01-01 00:00:00 +0000
+++ font/font.c 2008-10-31 03:46:01 +0000
@@ -0,0 +1,1004 @@
+/* font.c - Font API and font file loader. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2005,2006,2007,2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * 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 .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef FONT_DEBUG
+#define FONT_DEBUG 0
+#endif
+
+struct char_index_entry
+{
+ grub_uint32_t code;
+ grub_uint8_t storage_flags;
+ grub_uint32_t offset;
+ struct grub_font_glyph *glyph; /* Glyph if loaded, or null. */
+};
+
+#define FONT_WEIGHT_NORMAL 100
+#define FONT_WEIGHT_BOLD 200
+
+struct grub_font
+{
+ char *name;
+ grub_file_t file;
+ char *family;
+ short point_size;
+ short weight;
+ short max_char_width;
+ short max_char_height;
+ short ascent;
+ short descent;
+ short leading;
+ grub_uint32_t num_chars;
+ struct char_index_entry *char_index;
+};
+
+
+/*============================================================*/
+/* Font loader */
+
+
+/* Definition of font registry. */
+struct grub_font_node *grub_font_list;
+
+static int register_font (grub_font_t font);
+static void font_init (grub_font_t font);
+static void free_font (grub_font_t font);
+static void remove_font (grub_font_t font);
+
+struct font_file_section
+{
+ grub_file_t file; /* The file this section is in. */
+ char name[4]; /* FOURCC name of the section. */
+ grub_uint32_t length; /* Length of the section contents. */
+ int eof; /* Set by open_section() on EOF. */
+};
+
+/* Font file format constants. */
+static const char pff2_magic[4] = { 'P', 'F', 'F', '2' };
+static const char section_names_file[4] = { 'F', 'I', 'L', 'E' };
+static const char section_names_font_name[4] = { 'N', 'A', 'M', 'E' };
+static const char section_names_point_size[4] = { 'P', 'T', 'S', 'Z' };
+static const char section_names_weight[4] = { 'W', 'E', 'I', 'G' };
+static const char section_names_max_char_width[4] = { 'M', 'A', 'X', 'W' };
+static const char section_names_max_char_height[4] = { 'M', 'A', 'X', 'H' };
+static const char section_names_ascent[4] = { 'A', 'S', 'C', 'E' };
+static const char section_names_descent[4] = { 'D', 'E', 'S', 'C' };
+static const char section_names_char_index[4] = { 'C', 'H', 'I', 'X' };
+static const char section_names_data[4] = { 'D', 'A', 'T', 'A' };
+
+/* Replace unknown glyphs with a rounded question mark. */
+static grub_uint8_t unknown_glyph_bitmap[] =
+{
+ /* 76543210 */
+ 0x7C, /* ooooo */
+ 0x82, /* o o */
+ 0xBA, /* o ooo o */
+ 0xAA, /* o o o o */
+ 0xAA, /* o o o o */
+ 0x8A, /* o o o */
+ 0x9A, /* o oo o */
+ 0x92, /* o o o */
+ 0x92, /* o o o */
+ 0x92, /* o o o */
+ 0x92, /* o o o */
+ 0x82, /* o o */
+ 0x92, /* o o o */
+ 0x82, /* o o */
+ 0x7C, /* ooooo */
+ 0x00 /* */
+};
+
+/* The "unknown glyph" glyph, used as a last resort. */
+static struct grub_font_glyph *unknown_glyph;
+/* The font structure used when no other font is loaded. This functions
+ as a "Null Object" pattern, so that code everywhere does not have to
+ check for a NULL grub_font_t to avoid dereferencing a null pointer. */
+static struct grub_font null_font;
+/* Flag to ensure module is initialized only once. */
+static grub_uint8_t font_loader_initialized;
+
+void
+grub_font_loader_init (void)
+{
+ if (font_loader_initialized)
+ return; /* Only initialize font loader once. */
+
+ unknown_glyph = grub_malloc(sizeof(struct grub_font_glyph)
+ + sizeof(unknown_glyph_bitmap));
+ if (! unknown_glyph)
+ return;
+
+ unknown_glyph->width = 8;
+ unknown_glyph->height = 16;
+ unknown_glyph->offset_x = 0;
+ unknown_glyph->offset_y = 0;
+ unknown_glyph->device_width = 8;
+ grub_memcpy(unknown_glyph->bitmap,
+ unknown_glyph_bitmap, sizeof(unknown_glyph_bitmap));
+
+ font_init (&null_font); /* Initialize the null font. */
+ null_font.name = "";
+ null_font.ascent = unknown_glyph->height;
+ null_font.descent = 1;
+ null_font.max_char_width = unknown_glyph->width;
+ null_font.max_char_height = unknown_glyph->height;
+
+ font_loader_initialized = 1;
+}
+
+/* Initialize the font object with initial default values. */
+static void
+font_init (grub_font_t font)
+{
+ font->name = 0;
+ font->file = 0;
+ font->family = 0;
+ font->point_size = 0;
+ font->weight = 0;
+ font->leading = 1; /* Default leading value, not in font file yet. */
+ font->max_char_width = 0;
+ font->max_char_height = 0;
+ font->ascent = 0;
+ font->descent = 0;
+ font->num_chars = 0;
+ font->char_index = 0;
+}
+
+/* Open the next section in the file.
+
+ On success, the section name is stored in section->name and the length in
+ section->length, and 0 is returned. On failure, 1 is returned and
+ grub_errno is set approriately with an error message.
+
+ If 1 is returned due to being at the end of the file, then section->eof is
+ set to 1; otherwise, section->eof is set to 0. */
+static int
+open_section (grub_file_t file, struct font_file_section *section)
+{
+ grub_ssize_t retval;
+ grub_uint32_t raw_length;
+
+ section->file = file;
+ section->eof = 0;
+
+ /* Read the FOURCC section name. */
+ retval = grub_file_read (file, section->name, 4);
+ if (retval >= 0 && retval < 4)
+ {
+ section->eof = 1;
+ return 1; /* EOF encountered. */
+ }
+ else if (retval < 0)
+ {
+ grub_error (GRUB_ERR_BAD_FONT,
+ "Font format error: can't read section name");
+ return 1; /* Read error. */
+ }
+
+ /* Read the big-endian 32-bit section length. */
+ retval = grub_file_read (file, (char *) &raw_length, 4);
+ if (retval >= 0 && retval < 4)
+ {
+ section->eof = 1;
+ return 1; /* EOF encountered. */
+ }
+ else if (retval < 0)
+ {
+ grub_error (GRUB_ERR_BAD_FONT,
+ "Font format error: can't read section length");
+ return 1; /* Read error. */
+ }
+
+ /* Convert byte-order and store in *length. */
+ section->length = grub_be_to_cpu32 (raw_length);
+
+ return 0;
+}
+
+/* Size in bytes of each character index (CHIX section)
+ entry in the font file. */
+#define FONT_CHAR_INDEX_ENTRY_SIZE (4 + 1 + 4)
+
+/* Load the character index (CHIX) section contents from the font file. This
+ presumes that the position of FILE is positioned immediately after the
+ section length for the CHIX section (i.e., at the start of the section
+ contents). Returns 0 upon success, nonzero for failure (in which case
+ grub_errno is set appropriately). */
+static int
+load_font_index (grub_file_t file, grub_uint32_t sect_length, struct
+ grub_font *font)
+{
+ unsigned i;
+
+#if FONT_DEBUG >= 2
+ grub_printf("load_font_index(sect_length=%d)\n", sect_length);
+#endif
+
+ /* Sanity check: ensure section length is divisible by the entry size. */
+ if (sect_length % FONT_CHAR_INDEX_ENTRY_SIZE != 0)
+ {
+ grub_error (GRUB_ERR_BAD_FONT,
+ "Font file format error: character index length %d "
+ "is not a multiple of the entry size %d",
+ sect_length, FONT_CHAR_INDEX_ENTRY_SIZE);
+ return 1; /* Invalid index section length. */
+ }
+
+ /* Calculate the number of characters. */
+ font->num_chars = sect_length / FONT_CHAR_INDEX_ENTRY_SIZE;
+
+ /* Allocate the character index array. */
+ font->char_index = grub_malloc (font->num_chars
+ * sizeof (struct char_index_entry));
+ if (!font->char_index)
+ return 1; /* Error allocating memory. */
+
+#if FONT_DEBUG >= 2
+ grub_printf("num_chars=%d)\n", font->num_chars);
+#endif
+
+ /* Load the character index data from the file. */
+ for (i = 0; i < font->num_chars; i++)
+ {
+ struct char_index_entry *entry = &font->char_index[i];
+
+ /* Read code point value; convert to native byte order. */
+ if (grub_file_read (file, (char *) &entry->code, 4) != 4)
+ return 1;
+ entry->code = grub_be_to_cpu32 (entry->code);
+
+ /* Read storage flags byte. */
+ if (grub_file_read (file, (char *) &entry->storage_flags, 1) != 1)
+ return 1;
+
+ /* Read glyph data offset; convert to native byte order. */
+ if (grub_file_read (file, (char *) &entry->offset, 4) != 4)
+ return 1;
+ entry->offset = grub_be_to_cpu32 (entry->offset);
+
+ /* No glyph loaded. Will be loaded on demand and cached thereafter. */
+ entry->glyph = 0;
+
+#if FONT_DEBUG >= 5
+ if (i < 10) /* Print the 1st 10 characters. */
+ grub_printf("c=%d o=%d\n", entry->code, entry->offset);
+#endif
+ }
+
+ return 0; /* Index loaded OK. */
+}
+
+/* Read the contents of the specified section as a string, which is
+ allocated on the heap. Returns 0 if there is an error. */
+static char *
+read_section_as_string (struct font_file_section *section)
+{
+ char *str;
+ grub_ssize_t ret;
+
+ str = grub_malloc (section->length + 1);
+ if (!str)
+ return 0;
+
+ ret = grub_file_read (section->file, str, section->length);
+ if (ret < 0 || ret != (grub_ssize_t) section->length)
+ {
+ grub_free (str);
+ return 0;
+ }
+
+ str[section->length] = '\0';
+ return str;
+}
+
+/* Read the contents of the current section as a 16-bit integer value,
+ which is stored into *VALUE.
+ Returns 0 upon success, nonzero upon failure. */
+static int
+read_section_as_short (struct font_file_section *section, grub_int16_t *value)
+{
+ grub_uint16_t raw_value;
+
+ if (section->length != 2)
+ {
+ grub_error (GRUB_ERR_BAD_FONT,
+ "Font file format error: section %c%c%c%c length "
+ "is %d but should be 2",
+ section->name[0], section->name[1],
+ section->name[2], section->name[3],
+ section->length);
+ return 1; /* An error occurred. */
+ }
+ if (grub_file_read (section->file, (char *) &raw_value, 2) != 2)
+ return 1; /* An error occurred. */
+
+ *value = grub_be_to_cpu16 (raw_value);
+ return 0; /* Successfully read the value. */
+}
+
+/* Load a font and add it to the beginning of the global font list.
+ Returns 0 upon success, nonzero upon failure. */
+int
+grub_font_load (const char *filename)
+{
+ grub_file_t file = 0;
+ struct font_file_section section;
+ char magic[4];
+ grub_font_t font = 0;
+
+#if FONT_DEBUG >= 1
+ grub_printf("add_font(%s)\n", filename);
+#endif
+
+ file = grub_buffile_open (filename, 1024);
+ if (!file)
+ goto fail;
+
+#if FONT_DEBUG >= 3
+ grub_printf("file opened\n");
+#endif
+
+ /* Read the FILE section. It indicates the file format. */
+ if (open_section (file, §ion) != 0)
+ goto fail;
+
+#if FONT_DEBUG >= 3
+ grub_printf("opened FILE section\n");
+#endif
+ if (grub_memcmp (section.name, section_names_file, 4) != 0)
+ {
+ grub_error (GRUB_ERR_BAD_FONT,
+ "Font file format error: 1st section must be FILE");
+ goto fail;
+ }
+
+#if FONT_DEBUG >= 3
+ grub_printf("section name ok\n");
+#endif
+ if (section.length != 4)
+ {
+ grub_error (GRUB_ERR_BAD_FONT,
+ "Font file format error (file type ID length is %d "
+ "but should be 4)", section.length);
+ goto fail;
+ }
+
+#if FONT_DEBUG >= 3
+ grub_printf("section length ok\n");
+#endif
+ /* Check the file format type code. */
+ if (grub_file_read (file, magic, 4) != 4)
+ goto fail;
+
+#if FONT_DEBUG >= 3
+ grub_printf("read magic ok\n");
+#endif
+
+ if (grub_memcmp (magic, pff2_magic, 4) != 0)
+ {
+ grub_error (GRUB_ERR_BAD_FONT, "Invalid font magic %x %x %x %x",
+ magic[0], magic[1], magic[2], magic[3]);
+ goto fail;
+ }
+
+#if FONT_DEBUG >= 3
+ grub_printf("compare magic ok\n");
+#endif
+
+ /* Allocate the font object. */
+ font = (grub_font_t) grub_malloc (sizeof (struct grub_font));
+ if (!font)
+ goto fail;
+
+ font_init (font);
+ font->file = file;
+
+#if FONT_DEBUG >= 3
+ grub_printf("allocate font ok; loading font info\n");
+#endif
+
+ /* Load the font information. */
+ while (1)
+ {
+ if (open_section (file, §ion) != 0)
+ {
+ if (section.eof)
+ break; /* Done reading the font file. */
+ else
+ goto fail;
+ }
+
+#if FONT_DEBUG >= 2
+ grub_printf("opened section %c%c%c%c ok\n",
+ section.name[0], section.name[1],
+ section.name[2], section.name[3]);
+#endif
+
+ if (grub_memcmp (section.name, section_names_font_name, 4) == 0)
+ {
+ font->name = read_section_as_string (§ion);
+ if (!font->name)
+ goto fail;
+ }
+ else if (grub_memcmp (section.name, section_names_point_size, 4) == 0)
+ {
+ if (read_section_as_short (§ion, &font->point_size) != 0)
+ goto fail;
+ }
+ else if (grub_memcmp (section.name, section_names_weight, 4) == 0)
+ {
+ char *wt;
+ wt = read_section_as_string (§ion);
+ if (!wt)
+ continue;
+ /* Convert the weight string 'normal' or 'bold' into a number. */
+ if (grub_strcmp (wt, "normal") == 0)
+ font->weight = FONT_WEIGHT_NORMAL;
+ else if (grub_strcmp (wt, "bold") == 0)
+ font->weight = FONT_WEIGHT_BOLD;
+ grub_free (wt);
+ }
+ else if (grub_memcmp (section.name, section_names_max_char_width, 4) == 0)
+ {
+ if (read_section_as_short (§ion, &font->max_char_width) != 0)
+ goto fail;
+ }
+ else if (grub_memcmp (section.name, section_names_max_char_height, 4) == 0)
+ {
+ if (read_section_as_short (§ion, &font->max_char_height) != 0)
+ goto fail;
+ }
+ else if (grub_memcmp (section.name, section_names_ascent, 4) == 0)
+ {
+ if (read_section_as_short (§ion, &font->ascent) != 0)
+ goto fail;
+ }
+ else if (grub_memcmp (section.name, section_names_descent, 4) == 0)
+ {
+ if (read_section_as_short (§ion, &font->descent) != 0)
+ goto fail;
+ }
+ else if (grub_memcmp (section.name, section_names_char_index, 4) == 0)
+ {
+ /* Load the font index. */
+ if (load_font_index (file, section.length, font) != 0)
+ goto fail;
+ }
+ else if (grub_memcmp (section.name, section_names_data, 4) == 0)
+ {
+ /* When the DATA section marker is reached, we stop reading. */
+ break;
+ }
+ else
+ {
+ /* Unhandled section type, simply skip past it. */
+#if FONT_DEBUG >= 3
+ grub_printf("Unhandled section type, skipping.\n");
+#endif
+ grub_off_t section_end = grub_file_tell (file) + section.length;
+ if ((int) grub_file_seek (file, section_end) == -1)
+ goto fail;
+ }
+ }
+
+ if (!font->name)
+ {
+ grub_printf ("Note: Font has no name.\n");
+ font->name = grub_strdup ("Unknown");
+ }
+
+#if FONT_DEBUG >= 1
+ grub_printf ("Loaded font `%s'.\n"
+ "Ascent=%d Descent=%d MaxW=%d MaxH=%d Number of characters=%d.\n",
+ font->name,
+ font->ascent, font->descent,
+ font->max_char_width, font->max_char_height,
+ font->num_chars);
+#endif
+
+ if (font->max_char_width == 0
+ || font->max_char_height == 0
+ || font->num_chars == 0
+ || font->char_index == 0
+ || font->ascent == 0
+ || font->descent == 0)
+ {
+ grub_error (GRUB_ERR_BAD_FONT,
+ "Invalid font file: missing some required data.");
+ goto fail;
+ }
+
+ /* Add the font to the global font registry. */
+ if (register_font (font) != 0)
+ goto fail;
+
+ return 0; /* Font loaded ok. */
+
+fail:
+ free_font (font);
+ return 1; /* Failed to load font. */
+}
+
+/* Read a 16-bit big-endian integer from FILE, convert it to native byte
+ order, and store it in *VALUE.
+ Returns 0 on success, 1 on failure. */
+static int
+read_be_uint16 (grub_file_t file, grub_uint16_t * value)
+{
+ if (grub_file_read (file, (char *) value, 2) != 2)
+ return 1;
+ *value = grub_be_to_cpu16 (*value);
+ return 0;
+}
+
+static int
+read_be_int16 (grub_file_t file, grub_int16_t * value)
+{
+ /* For the signed integer version, use the same code as for unsigned. */
+ return read_be_uint16 (file, (grub_uint16_t *) value);
+}
+
+/* Return a pointer to the character index entry for the glyph corresponding to
+ the codepoint CODE in the font FONT. If not found, return zero. */
+static struct char_index_entry *
+find_glyph (const grub_font_t font, grub_uint32_t code)
+{
+ grub_uint32_t i;
+ grub_uint32_t len = font->num_chars;
+ struct char_index_entry *table = font->char_index;
+
+ /* Do a linear search. */
+ for (i = 0; i < len; i++)
+ {
+ if (table[i].code == code)
+ return &table[i];
+ }
+
+ return 0; /* No entry found for code point CODE. */
+}
+
+/* Get a glyph for the Unicode character CODE in FONT. The glyph is loaded
+ from the font file if has not been loaded yet.
+ Returns a pointer to the glyph if found, or 0 if it is not found. */
+static struct grub_font_glyph *
+grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
+{
+ struct char_index_entry *index_entry;
+
+ index_entry = find_glyph (font, code);
+ if (index_entry)
+ {
+ struct grub_font_glyph *glyph = 0;
+ grub_uint16_t width;
+ grub_uint16_t height;
+ grub_int16_t xoff;
+ grub_int16_t yoff;
+ grub_int16_t dwidth;
+ int len;
+
+ if (index_entry->glyph)
+ return index_entry->glyph; /* Return cached glyph. */
+
+ if (! font->file)
+ return 0; /* No open file, can't load any glyphs. */
+
+ /* Make sure we can find glyphs for error messages. Push active
+ error message to error stack and reset error message. */
+ grub_error_push ();
+
+ grub_file_seek (font->file, index_entry->offset);
+
+ /* Read the glyph width, height, and baseline. */
+ if (read_be_uint16(font->file, &width) != 0
+ || read_be_uint16(font->file, &height) != 0
+ || read_be_int16(font->file, &xoff) != 0
+ || read_be_int16(font->file, &yoff) != 0
+ || read_be_int16(font->file, &dwidth) != 0)
+ {
+ remove_font (font);
+ return 0;
+ }
+
+ len = (width * height + 7) / 8;
+ glyph = grub_malloc (sizeof (struct grub_font_glyph) + len);
+ if (! glyph)
+ {
+ remove_font (font);
+ return 0;
+ }
+
+ glyph->font = font;
+ glyph->width = width;
+ glyph->height = height;
+ glyph->offset_x = xoff;
+ glyph->offset_y = yoff;
+ glyph->device_width = dwidth;
+
+ /* Don't try to read empty bitmaps (e.g., space characters). */
+ if (len != 0)
+ {
+ if (grub_file_read (font->file, (char *) glyph->bitmap, len) != len)
+ {
+ remove_font (font);
+ return 0;
+ }
+ }
+
+ /* Restore old error message. */
+ grub_error_pop ();
+
+ /* Cache the glyph. */
+ index_entry->glyph = glyph;
+
+ return glyph; /* Glyph loaded ok. */
+ }
+
+ return 0;
+}
+
+/* Free the memory used by FONT.
+ This should not be called if the font has been made available to
+ users (once it is added to the global font list), since there would
+ be the possibility of a dangling pointer. */
+static void
+free_font (grub_font_t font)
+{
+ if (font)
+ {
+ if (font->file)
+ grub_file_close (font->file);
+ grub_free (font->name);
+ grub_free (font->family);
+ grub_free (font->char_index);
+ grub_free (font);
+ }
+}
+
+/* Add FONT to the global font registry.
+ Returns 0 upon success, nonzero on failure
+ (the font was not registered). */
+static int
+register_font (grub_font_t font)
+{
+ struct grub_font_node *node = 0;
+
+ node = grub_malloc (sizeof (struct grub_font_node));
+ if (! node)
+ return 1; /* Error. */
+
+ node->value = font;
+ node->next = grub_font_list;
+ grub_font_list = node;
+
+ return 0; /* Success. */
+}
+
+/* Remove the font from the global font list. We don't actually free the
+ font's memory since users could be holding references to the font. */
+static void
+remove_font (grub_font_t font)
+{
+ struct grub_font_node **nextp, *cur;
+
+ for (nextp = &grub_font_list, cur = *nextp;
+ cur;
+ nextp = &cur->next, cur = cur->next)
+ {
+ if (cur->value == font)
+ {
+ *nextp = cur->next;
+
+ /* Free the node, but not the font itself. */
+ grub_free (cur);
+
+ return;
+ }
+ }
+}
+
+
+/*============================================================*/
+/* Public font API */
+
+/* Get a font from the list of loaded fonts. This function will return
+ another font if the requested font is not available. If no fonts are
+ loaded, then a special 'null font' is returned, which contains no glyphs,
+ but is not a null pointer so the caller may omit checks for NULL. */
+grub_font_t
+grub_font_get (const char *font_name)
+{
+ struct grub_font_node *node;
+
+ for (node = grub_font_list; node; node = node->next)
+ {
+ grub_font_t font = node->value;
+ if (grub_strcmp (font->name, font_name) == 0)
+ return font;
+ }
+
+ /* If no font by that name is found, return the first font in the list
+ as a fallback. */
+ if (grub_font_list && grub_font_list->value)
+ return grub_font_list->value;
+ else
+ return &null_font; /* The null_font is a last resort. */
+}
+
+/* Get the full name of the font. For instance, "Helvetica Bold 12". */
+const char *
+grub_font_get_name (grub_font_t font)
+{
+ return font->name;
+}
+
+/* Get the maximum width of any character in the font in pixels. */
+int
+grub_font_get_max_char_width (grub_font_t font)
+{
+ return font->max_char_width;
+}
+
+/* Get the maximum height of any character in the font in pixels. */
+int
+grub_font_get_max_char_height (grub_font_t font)
+{
+ return font->max_char_height;
+}
+
+/* Get the distance in pixels from the top of characters to the baseline. */
+int
+grub_font_get_ascent (grub_font_t font)
+{
+ return font->ascent;
+}
+
+/* Get the distance in pixels from the baseline to the lowest descenders
+ (for instance, in a lowercase 'y', 'g', etc.). */
+int
+grub_font_get_descent (grub_font_t font)
+{
+ return font->descent;
+}
+
+/* Get the *standard leading* of the font in pixel, which is the spacing
+ between two lines of text. Specifically, it is the space between the
+ descent of one line and the ascent of the next line. This is included
+ in the *height* metric. */
+int
+grub_font_get_leading (grub_font_t font)
+{
+ return font->leading;
+}
+
+/* Get the distance in pixels between baselines of adjacent lines of text. */
+int
+grub_font_get_height (grub_font_t font)
+{
+ return font->ascent + font->descent + font->leading;
+}
+
+/* Get the width in pixels of the specified UTF-8 string, when rendered in
+ in the specified font (but falling back on other fonts for glyphs that
+ are missing). */
+int
+grub_font_get_string_width (grub_font_t font, const char *str)
+{
+ int width;
+ struct grub_font_glyph *glyph;
+ grub_uint32_t code;
+ const grub_uint8_t *ptr;
+
+ for (ptr = (const grub_uint8_t *) str, width = 0;
+ grub_utf8_to_ucs4 (&code, 1, ptr, -1, &ptr) > 0; )
+ {
+ glyph = grub_font_get_glyph_with_fallback (font, code);
+ width += glyph->device_width;
+ }
+
+ return width;
+}
+
+/* Get the glyph for FONT corresponding to the Unicode code point CODE.
+ Returns a pointer to an glyph indicating there is no glyph available
+ if CODE does not exist in the font. The glyphs are cached once loaded. */
+struct grub_font_glyph *
+grub_font_get_glyph (grub_font_t font, grub_uint32_t code)
+{
+ struct grub_font_glyph *glyph;
+ glyph = grub_font_get_glyph_internal (font, code);
+ if (glyph == 0)
+ glyph = unknown_glyph;
+ return glyph;
+}
+
+
+/* Calculate a subject value representing "how similar" two fonts are.
+ This is used to prioritize the order that fonts are scanned for missing
+ glyphs. The object is to select glyphs from the most similar font
+ possible, for the best appearance.
+ The heuristic is crude, but it helps greatly when fonts of similar
+ sizes are used so that tiny 8 point glyphs are not mixed into a string
+ of 24 point text unless there is no other choice. */
+static int
+get_font_diversity(grub_font_t a, grub_font_t b)
+{
+ int d;
+
+ d = 0;
+
+ if (a->ascent && b->ascent)
+ d += grub_abs (a->ascent - b->ascent) * 8;
+ else
+ d += 50; /* Penalty for missing attributes. */
+
+ if (a->max_char_height && b->max_char_height)
+ d += grub_abs (a->max_char_height - b->max_char_height) * 8;
+ else
+ d += 50; /* Penalty for missing attributes. */
+
+ d += (a->weight != b->weight) ? 5 : 0; /* Weight is a minor factor. */
+
+ return d;
+}
+
+/* Get a glyph corresponding to the codepoint CODE. If FONT contains the
+ specified glyph, then it is returned. Otherwise, all other loaded fonts
+ are searched until one is found that contains a glyph for CODE.
+ If no glyph is available for CODE in the loaded fonts, then a glyph
+ representing an unknown character is returned.
+ This function never returns NULL.
+ The returned glyph is owned by the font manager and should not be freed
+ by the caller. The glyphs are cached. */
+struct grub_font_glyph *
+grub_font_get_glyph_with_fallback (grub_font_t font, grub_uint32_t code)
+{
+ struct grub_font_glyph *glyph;
+ struct grub_font_node *node;
+ /* Keep track of next node, in case there's an I/O error in
+ grub_font_get_glyph_internal() and the font is removed from the list. */
+ struct grub_font_node *next;
+ /* Information on the best glyph found so far, to help find the glyph in
+ the best matching to the requested one. */
+ int best_diversity;
+ struct grub_font_glyph *best_glyph;
+
+ if (font)
+ {
+ /* First try to get the glyph from the specified font. */
+ glyph = grub_font_get_glyph_internal (font, code);
+ if (glyph)
+ return glyph;
+ }
+
+ /* Otherwise, search all loaded fonts for the glyph and use the one from
+ the font that best matches the requested font. */
+ best_diversity = 10000;
+ best_glyph = 0;
+
+ for (node = grub_font_list; node; node = next)
+ {
+ grub_font_t curfont;
+
+ curfont = node->value;
+ next = node->next;
+
+ glyph = grub_font_get_glyph_internal (curfont, code);
+ if (glyph)
+ {
+ int d;
+
+ d = get_font_diversity (curfont, font);
+ if (d < best_diversity)
+ {
+ best_diversity = d;
+ best_glyph = glyph;
+ }
+ }
+ }
+
+ if (best_glyph)
+ return best_glyph;
+ else
+ return unknown_glyph; /* Ugh... Glyph not available in any font. */
+}
+
+
+/* Draw the specified glyph at (x, y). The y coordinate designates the
+ baseline of the character, while the x coordinate designates the left
+ side location of the character. */
+grub_err_t
+grub_font_draw_glyph (struct grub_font_glyph *glyph,
+ grub_video_color_t color,
+ int left_x, int baseline_y)
+{
+ struct grub_video_bitmap glyph_bitmap;
+
+ /* Don't try to draw empty glyphs (U+0020, etc.). */
+ if (glyph->width == 0 || glyph->height == 0)
+ return GRUB_ERR_NONE;
+
+ glyph_bitmap.mode_info.width = glyph->width;
+ glyph_bitmap.mode_info.height = glyph->height;
+ glyph_bitmap.mode_info.mode_type =
+ (1 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
+ | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP;
+ glyph_bitmap.mode_info.blit_format = GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED;
+ glyph_bitmap.mode_info.bpp = 1;
+ glyph_bitmap.mode_info.bytes_per_pixel = 0; /* Really 1 bit per pixel. */
+ glyph_bitmap.mode_info.pitch = glyph->width; /* Packed densely as bits. */
+ glyph_bitmap.mode_info.number_of_colors = 2;
+ glyph_bitmap.mode_info.bg_red = 0;
+ glyph_bitmap.mode_info.bg_green = 0;
+ glyph_bitmap.mode_info.bg_blue = 0;
+ glyph_bitmap.mode_info.bg_alpha = 0;
+ grub_video_unmap_color(color,
+ &glyph_bitmap.mode_info.fg_red,
+ &glyph_bitmap.mode_info.fg_green,
+ &glyph_bitmap.mode_info.fg_blue,
+ &glyph_bitmap.mode_info.fg_alpha);
+ glyph_bitmap.data = glyph->bitmap;
+
+ int bitmap_left = left_x + glyph->offset_x;
+ int bitmap_bottom = baseline_y - glyph->offset_y;
+ int bitmap_top = bitmap_bottom - glyph->height;
+
+ return grub_video_blit_bitmap (&glyph_bitmap, GRUB_VIDEO_BLIT_BLEND,
+ bitmap_left, bitmap_top,
+ 0, 0,
+ glyph->width, glyph->height);
+}
+
+/* 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,
+ while the y coordinate specifies the baseline position.
+ If the string contains a character that FONT does not contain, then
+ a glyph from another loaded font may be used instead. */
+grub_err_t
+grub_font_draw_string (const char *str, grub_font_t font,
+ grub_video_color_t color,
+ int left_x, int baseline_y)
+{
+ int x;
+ struct grub_font_glyph *glyph;
+ grub_uint32_t code;
+ const grub_uint8_t *ptr;
+
+ for (ptr = (const grub_uint8_t *) str, x = left_x;
+ grub_utf8_to_ucs4 (&code, 1, ptr, -1, &ptr) > 0; )
+ {
+ glyph = grub_font_get_glyph_with_fallback (font, code);
+ if (grub_font_draw_glyph (glyph, color, x, baseline_y)
+ != GRUB_ERR_NONE)
+ return grub_errno;
+ x += glyph->device_width;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
=== added file 'font/font_cmd.c'
--- font/font_cmd.c 1970-01-01 00:00:00 +0000
+++ font/font_cmd.c 2008-10-31 03:44:24 +0000
@@ -0,0 +1,77 @@
+/* font_cmd.c - Font command definition. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2005,2006,2007,2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * 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 .
+ */
+
+#include
+#include
+#include
+#include
+
+static grub_err_t
+loadfont_command (struct grub_arg_list *state __attribute__ ((unused)),
+ int argc,
+ char **args)
+{
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no font specified");
+
+ while (argc--)
+ if (grub_font_load (*args++) != 0)
+ return GRUB_ERR_BAD_FONT;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+lsfonts_command (struct grub_arg_list *state __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ struct grub_font_node *node;
+
+ grub_printf ("Loaded fonts:\n");
+ for (node = grub_font_list; node; node = node->next)
+ {
+ grub_font_t font = node->value;
+ grub_printf ("%s\n", grub_font_get_name (font));
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+GRUB_MOD_INIT(font_manager)
+{
+ grub_font_loader_init ();
+
+ grub_register_command ("loadfont", loadfont_command, GRUB_COMMAND_FLAG_BOTH,
+ "loadfont FILE...",
+ "Specify one or more font files to load.", 0);
+
+ grub_register_command ("lsfonts", lsfonts_command, GRUB_COMMAND_FLAG_BOTH,
+ "lsfonts",
+ "List the loaded fonts.", 0);
+}
+
+GRUB_MOD_FINI(font_manager)
+{
+ /* Should this free fonts, unknown_glyph, etc.? Freeing fonts could
+ be a Bad Thing if there are still references to any of them. */
+
+ grub_unregister_command ("loadfont");
+}
+
=== removed file 'font/manager.c'
--- font/manager.c 2008-08-01 03:06:55 +0000
+++ font/manager.c 1970-01-01 00:00:00 +0000
@@ -1,283 +0,0 @@
-/*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2003,2005,2006,2007 Free Software Foundation, Inc.
- *
- * GRUB is free software: you can redistribute it and/or modify
- * 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 .
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-struct entry
-{
- grub_uint32_t code;
- grub_uint32_t offset;
-};
-
-struct font
-{
- struct font *next;
- grub_file_t file;
- grub_uint32_t num;
- struct entry table[0];
-};
-
-static struct font *font_list;
-
-/* Fill unknown glyph's with rounded question mark. */
-static grub_uint8_t unknown_glyph[16] =
-{ /* 76543210 */
- 0x7C, /* ooooo */
- 0x82, /* o o */
- 0xBA, /* o ooo o */
- 0xAA, /* o o o o */
- 0xAA, /* o o o o */
- 0x8A, /* o o o */
- 0x9A, /* o oo o */
- 0x92, /* o o o */
- 0x92, /* o o o */
- 0x92, /* o o o */
- 0x92, /* o o o */
- 0x82, /* o o */
- 0x92, /* o o o */
- 0x82, /* o o */
- 0x7C, /* ooooo */
- 0x00 /* */
-};
-
-static int
-add_font (const char *filename)
-{
- grub_file_t file = 0;
- char magic[4];
- grub_uint32_t num, i;
- struct font *font = 0;
-
- file = grub_buffile_open (filename, 0);
- if (! file)
- goto fail;
-
- if (grub_file_read (file, magic, 4) != 4)
- goto fail;
-
- if (grub_memcmp (magic, GRUB_FONT_MAGIC, 4) != 0)
- {
- grub_error (GRUB_ERR_BAD_FONT, "invalid font magic");
- goto fail;
- }
-
- if (grub_file_read (file, (char *) &num, 4) != 4)
- goto fail;
-
- num = grub_le_to_cpu32 (num);
- font = (struct font *) grub_malloc (sizeof (struct font)
- + sizeof (struct entry) * num);
- if (! font)
- goto fail;
-
- font->file = file;
- font->num = num;
-
- for (i = 0; i < num; i++)
- {
- grub_uint32_t code, offset;
-
- if (grub_file_read (file, (char *) &code, 4) != 4)
- goto fail;
-
- if (grub_file_read (file, (char *) &offset, 4) != 4)
- goto fail;
-
- font->table[i].code = grub_le_to_cpu32 (code);
- font->table[i].offset = grub_le_to_cpu32 (offset);
- }
-
- font->next = font_list;
- font_list = font;
-
- return 1;
-
- fail:
- if (font)
- grub_free (font);
-
- if (file)
- grub_file_close (file);
-
- return 0;
-}
-
-static void
-remove_font (struct font *font)
-{
- struct font **p, *q;
-
- for (p = &font_list, q = *p; q; p = &(q->next), q = q->next)
- if (q == font)
- {
- *p = q->next;
-
- grub_file_close (font->file);
- grub_free (font);
-
- break;
- }
-}
-
-/* Return the offset of the glyph corresponding to the codepoint CODE
- in the font FONT. If no found, return zero. */
-static grub_uint32_t
-find_glyph (const struct font *font, grub_uint32_t code)
-{
- grub_uint32_t start = 0;
- grub_uint32_t end = font->num - 1;
- const struct entry *table = font->table;
-
- /* This shouldn't happen. */
- if (font->num == 0)
- return 0;
-
- /* Do a binary search. */
- while (start <= end)
- {
- grub_uint32_t i = (start + end) / 2;
-
- if (table[i].code < code)
- start = i + 1;
- else if (table[i].code > code)
- end = i - 1;
- else
- return table[i].offset;
- }
-
- return 0;
-}
-
-/* Set the glyph to something stupid. */
-static void
-fill_with_default_glyph (grub_font_glyph_t glyph)
-{
- unsigned i;
-
- /* Use pre-defined pattern to fill unknown glyphs. */
- for (i = 0; i < 16; i++)
- glyph->bitmap[i] = unknown_glyph[i];
-
- glyph->char_width = 1;
- glyph->width = glyph->char_width * 8;
- glyph->height = 16;
- glyph->baseline = (16 * 3) / 4;
-}
-
-/* Get a glyph corresponding to the codepoint CODE. Always fill glyph
- information with something, even if no glyph is found. */
-int
-grub_font_get_glyph (grub_uint32_t code,
- grub_font_glyph_t glyph)
-{
- struct font *font;
- grub_uint8_t bitmap[32];
-
- /* FIXME: It is necessary to cache glyphs! */
-
- restart:
- for (font = font_list; font; font = font->next)
- {
- grub_uint32_t offset;
-
- offset = find_glyph (font, code);
- if (offset)
- {
- grub_uint32_t w;
- int len;
-
- /* Make sure we can find glyphs for error messages. Push active
- error message to error stack and reset error message. */
- grub_error_push ();
-
- grub_file_seek (font->file, offset);
- if ((len = grub_file_read (font->file, (char *) &w, sizeof (w)))
- != sizeof (w))
- {
- remove_font (font);
- goto restart;
- }
-
- w = grub_le_to_cpu32 (w);
- if (w != 1 && w != 2)
- {
- /* grub_error (GRUB_ERR_BAD_FONT, "invalid width"); */
- remove_font (font);
- goto restart;
- }
-
- if (grub_file_read (font->file, (char *) bitmap, w * 16)
- != (grub_ssize_t) w * 16)
- {
- remove_font (font);
- goto restart;
- }
-
- /* Fill glyph with information. */
- grub_memcpy (glyph->bitmap, bitmap, w * 16);
-
- glyph->char_width = w;
- glyph->width = glyph->char_width * 8;
- glyph->height = 16;
- glyph->baseline = (16 * 3) / 4;
-
- /* Restore old error message. */
- grub_error_pop ();
-
- return 1;
- }
- }
-
- /* Uggh... No font was found. */
- fill_with_default_glyph (glyph);
- return 0;
-}
-
-static grub_err_t
-font_command (struct grub_arg_list *state __attribute__ ((unused)),
- int argc __attribute__ ((unused)),
- char **args __attribute__ ((unused)))
-{
- if (argc == 0)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, "no font specified");
-
- while (argc--)
- if (! add_font (*args++))
- return 1;
-
- return 0;
-}
-
-GRUB_MOD_INIT(font_manager)
-{
- grub_register_command ("font", font_command, GRUB_COMMAND_FLAG_BOTH,
- "font FILE...",
- "Specify one or more font files to display.", 0);
-}
-
-GRUB_MOD_FINI(font_manager)
-{
- grub_unregister_command ("font");
-}
=== modified file 'include/grub/font.h'
--- include/grub/font.h 2007-07-21 22:32:33 +0000
+++ include/grub/font.h 2008-10-31 03:44:24 +0000
@@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2003,2007 Free Software Foundation, Inc.
+ * Copyright (C) 2003,2007,2008 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,34 +20,96 @@
#define GRUB_FONT_HEADER 1
#include
-
-#define GRUB_FONT_MAGIC "PPF\x7f"
+#include
+
+/* Forward declaration of opaque structure grub_font.
+ Users only pass struct grub_font pointers to the font module functions,
+ and do not have knowledge of the structure contents. */
+struct grub_font;
+
+/* Font type used to access font functions. */
+typedef struct grub_font *grub_font_t;
+
+struct grub_font_node
+{
+ struct grub_font_node *next;
+ grub_font_t value;
+};
+
+/* Global font registry. */
+extern struct grub_font_node *grub_font_list;
struct grub_font_glyph
{
- /* Glyph width in pixels. */
- grub_uint8_t width;
-
- /* Glyph height in pixels. */
- grub_uint8_t height;
-
- /* Glyph width in characters. */
- grub_uint8_t char_width;
-
- /* Glyph baseline position in pixels (from up). */
- grub_uint8_t baseline;
-
- /* Glyph bitmap data array of bytes in ((width + 7) / 8) * height.
- Bitmap is formulated by height scanlines, each scanline having
- width number of pixels. Pixels are coded as bits, value 1 meaning
- of opaque pixel and 0 is transparent. If width does not fit byte
- boundary, it will be padded with 0 to make it fit. */
- grub_uint8_t bitmap[32];
+ /* Reference to the font this glyph belongs to. */
+ grub_font_t font;
+
+ /* Glyph bitmap width in pixels. */
+ grub_uint16_t width;
+
+ /* Glyph bitmap height in pixels. */
+ grub_uint16_t height;
+
+ /* Glyph bitmap x offset in pixels. Add to screen coordinate. */
+ grub_int16_t offset_x;
+
+ /* Glyph bitmap y offset in pixels. Subtract from screen coordinate. */
+ grub_int16_t offset_y;
+
+ /* Number of pixels to advance to start the next character. */
+ grub_uint16_t device_width;
+
+ /* Row-major order, packed bits (no padding; rows can break within a byte).
+ The length of the array is (width * height + 7) / 8. Within a
+ byte, the most significant bit is the first (leftmost/uppermost) pixel.
+ Pixels are coded as bits, value 1 meaning of opaque pixel and 0 is
+ transparent. If the length of the array does not fit byte boundary, it
+ will be padded with 0 bits to make it fit. */
+ grub_uint8_t bitmap[0];
};
-typedef struct grub_font_glyph *grub_font_glyph_t;
-
-int grub_font_get_glyph (grub_uint32_t code,
- grub_font_glyph_t glyph);
+/* Initialize the font loader.
+ Must be called before any fonts are loaded or used. */
+void grub_font_loader_init (void);
+
+/* Load a font and add it to the beginning of the global font list.
+ Returns: 0 upon success; nonzero upon failure. */
+int grub_font_load (const char *filename);
+
+/* Get the font that has the specified name. Font names are in the form
+ "Family Name Bold Italic 14", where Bold and Italic are optional.
+ If no font matches the name specified, the most recently loaded font
+ is returned as a fallback. */
+grub_font_t grub_font_get (const char *font_name);
+
+const char *grub_font_get_name (grub_font_t font);
+
+int grub_font_get_max_char_width (grub_font_t font);
+
+int grub_font_get_max_char_height (grub_font_t font);
+
+int grub_font_get_ascent (grub_font_t font);
+
+int grub_font_get_descent (grub_font_t font);
+
+int grub_font_get_leading (grub_font_t font);
+
+int grub_font_get_height (grub_font_t font);
+
+int grub_font_get_string_width (grub_font_t font, const char *str);
+
+struct grub_font_glyph *grub_font_get_glyph (grub_font_t font,
+ grub_uint32_t code);
+
+struct grub_font_glyph *grub_font_get_glyph_with_fallback (grub_font_t font,
+ grub_uint32_t code);
+
+grub_err_t grub_font_draw_glyph (struct grub_font_glyph *glyph,
+ grub_video_color_t color,
+ int left_x, int baseline_y);
+
+grub_err_t grub_font_draw_string (const char *str, grub_font_t font,
+ grub_video_color_t color,
+ int left_x, int baseline_y);
#endif /* ! GRUB_FONT_HEADER */
=== modified file 'include/grub/misc.h'
--- include/grub/misc.h 2008-09-19 05:55:20 +0000
+++ include/grub/misc.h 2008-10-30 18:24:32 +0000
@@ -77,8 +77,10 @@
grub_uint16_t *src,
grub_size_t size);
grub_ssize_t EXPORT_FUNC(grub_utf8_to_ucs4) (grub_uint32_t *dest,
+ grub_size_t destsize,
const grub_uint8_t *src,
- grub_size_t size);
+ grub_size_t srcsize,
+ const grub_uint8_t **srcend);
grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n,
grub_uint32_t d, grub_uint32_t *r);
=== modified file 'include/grub/video.h'
--- include/grub/video.h 2008-10-05 04:28:39 +0000
+++ include/grub/video.h 2008-10-30 18:28:52 +0000
@@ -31,17 +31,17 @@
struct grub_video_render_target;
/* Forward declarations for used data structures. */
-struct grub_font_glyph;
struct grub_video_bitmap;
/* Defines used to describe video mode or rendering target. */
-#define GRUB_VIDEO_MODE_TYPE_ALPHA 0x00000008
-#define GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED 0x00000004
+#define GRUB_VIDEO_MODE_TYPE_ALPHA 0x00000020
+#define GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED 0x00000010
+#define GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP 0x00000004
#define GRUB_VIDEO_MODE_TYPE_INDEX_COLOR 0x00000002
#define GRUB_VIDEO_MODE_TYPE_RGB 0x00000001
/* Defines used to mask flags. */
-#define GRUB_VIDEO_MODE_TYPE_COLOR_MASK 0x00000003
+#define GRUB_VIDEO_MODE_TYPE_COLOR_MASK 0x0000000F
/* Defines used to specify requested bit depth. */
#define GRUB_VIDEO_MODE_TYPE_DEPTH_MASK 0x0000ff00
@@ -72,7 +72,9 @@
GRUB_VIDEO_BLIT_FORMAT_BGR_565,
/* When needed, decode color or just use value as is. */
- GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
+ GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR,
+ /* Two color bitmap; bits packed: rows are not padded to byte boundary. */
+ GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED
};
/* Define blitting operators. */
@@ -135,6 +137,18 @@
/* What is location of reserved color bits. In Index Color mode,
this is 0. */
unsigned int reserved_field_pos;
+
+ /* For 1-bit bitmaps, the background color. Used for bits = 0. */
+ grub_uint8_t bg_red;
+ grub_uint8_t bg_green;
+ grub_uint8_t bg_blue;
+ grub_uint8_t bg_alpha;
+
+ /* For 1-bit bitmaps, the foreground color. Used for bits = 1. */
+ grub_uint8_t fg_red;
+ grub_uint8_t fg_green;
+ grub_uint8_t fg_blue;
+ grub_uint8_t fg_alpha;
};
struct grub_video_palette_data
@@ -188,9 +202,6 @@
grub_err_t (*fill_rect) (grub_video_color_t color, int x, int y,
unsigned int width, unsigned int height);
- grub_err_t (*blit_glyph) (struct grub_font_glyph *glyph,
- grub_video_color_t color, int x, int y);
-
grub_err_t (*blit_bitmap) (struct grub_video_bitmap *bitmap,
enum grub_video_blit_operators oper,
int x, int y, int offset_x, int offset_y,
@@ -260,9 +271,6 @@
grub_err_t grub_video_fill_rect (grub_video_color_t color, int x, int y,
unsigned int width, unsigned int height);
-grub_err_t grub_video_blit_glyph (struct grub_font_glyph *glyph,
- grub_video_color_t color, int x, int y);
-
grub_err_t grub_video_blit_bitmap (struct grub_video_bitmap *bitmap,
enum grub_video_blit_operators oper,
int x, int y, int offset_x, int offset_y,
=== modified file 'kern/misc.c'
--- kern/misc.c 2008-09-19 05:55:20 +0000
+++ kern/misc.c 2008-10-30 18:24:32 +0000
@@ -951,22 +951,29 @@
return dest;
}
-/* Convert an UTF-8 string to an UCS-4 string. Return the number of
- characters converted. DEST must be able to hold at least SIZE
- characters (when the input is unknown). If an invalid sequence is found,
- return -1. */
+/* 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 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. */
grub_ssize_t
-grub_utf8_to_ucs4 (grub_uint32_t *dest, const grub_uint8_t *src,
- grub_size_t size)
+grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
+ const grub_uint8_t *src, grub_size_t srcsize,
+ const grub_uint8_t **srcend)
{
grub_uint32_t *p = dest;
int count = 0;
grub_uint32_t code = 0;
- while (size--)
+ if (*srcend)
+ *srcend = src;
+
+ while (srcsize && destsize)
{
grub_uint32_t c = *src++;
-
+ if (srcsize != -1)
+ srcsize--;
if (count)
{
if ((c & 0xc0) != 0x80)
@@ -983,6 +990,8 @@
}
else
{
+ if (c == 0)
+ break; /* NUL character terminates the string. */
if ((c & 0x80) == 0x00)
code = c;
else if ((c & 0xe0) == 0xc0)
@@ -1011,14 +1020,18 @@
code = c & 0x01;
}
else
- /* invalid */
return -1;
}
if (count == 0)
- *p++ = code;
+ {
+ *p++ = code;
+ destsize--;
+ }
}
+ if (srcend)
+ *srcend = src;
return p - dest;
}
=== modified file 'kern/term.c'
--- kern/term.c 2007-12-25 11:10:47 +0000
+++ kern/term.c 2008-10-30 18:24:32 +0000
@@ -153,7 +153,7 @@
grub_ssize_t ret;
buf[size++] = c;
- ret = grub_utf8_to_ucs4 (&code, buf, size);
+ ret = grub_utf8_to_ucs4 (&code, 1, buf, size, 0);
if (ret > 0)
{
=== modified file 'normal/menu.c'
--- normal/menu.c 2008-08-31 00:48:14 +0000
+++ normal/menu.c 2008-10-30 18:43:35 +0000
@@ -117,19 +117,21 @@
{
int x;
const char *title;
+ grub_size_t title_len;
grub_ssize_t len;
grub_uint32_t *unicode_title;
grub_ssize_t i;
grub_uint8_t old_color_normal, old_color_highlight;
title = entry ? entry->title : "";
- unicode_title = grub_malloc (grub_strlen (title) * sizeof (*unicode_title));
+ title_len = grub_strlen (title);
+ unicode_title = grub_malloc (title_len * sizeof (*unicode_title));
if (! unicode_title)
/* XXX How to show this error? */
return;
- len = grub_utf8_to_ucs4 (unicode_title, (grub_uint8_t *) title,
- grub_strlen (title));
+ len = grub_utf8_to_ucs4 (unicode_title, title_len,
+ (grub_uint8_t *) title, -1, 0);
if (len < 0)
{
/* It is an invalid sequence. */
=== modified file 'term/gfxterm.c'
--- term/gfxterm.c 2008-08-31 03:08:13 +0000
+++ term/gfxterm.c 2008-10-30 18:24:32 +0000
@@ -35,9 +35,6 @@
#define DEFAULT_VIDEO_HEIGHT 480
#define DEFAULT_VIDEO_FLAGS 0
-#define DEFAULT_CHAR_WIDTH 8
-#define DEFAULT_CHAR_HEIGHT 16
-
#define DEFAULT_BORDER_WIDTH 10
#define DEFAULT_STANDARD_COLOR 0x07
@@ -91,6 +88,9 @@
unsigned int cursor_y;
int cursor_state;
+ /* Font settings. */
+ grub_font_t font;
+
/* Terminal color settings. */
grub_uint8_t standard_color_setting;
grub_uint8_t normal_color_setting;
@@ -169,18 +169,25 @@
static grub_err_t
grub_virtual_screen_setup (unsigned int x, unsigned int y,
- unsigned int width, unsigned int height)
+ unsigned int width, unsigned int height,
+ const char *font_name)
{
/* Free old virtual screen. */
grub_virtual_screen_free ();
/* Initialize with default data. */
+ virtual_screen.font = grub_font_get (font_name);
+ if (!virtual_screen.font)
+ return grub_error (GRUB_ERR_BAD_FONT,
+ "No font loaded.");
virtual_screen.width = width;
virtual_screen.height = height;
virtual_screen.offset_x = x;
virtual_screen.offset_y = y;
- virtual_screen.char_width = DEFAULT_CHAR_WIDTH;
- virtual_screen.char_height = DEFAULT_CHAR_HEIGHT;
+ virtual_screen.char_width =
+ grub_font_get_max_char_width (virtual_screen.font);
+ virtual_screen.char_height =
+ grub_font_get_max_char_height (virtual_screen.font);
virtual_screen.cursor_x = 0;
virtual_screen.cursor_y = 0;
virtual_screen.cursor_state = 1;
@@ -226,6 +233,7 @@
static grub_err_t
grub_gfxterm_init (void)
{
+ char *font_name;
char *modevar;
int width = DEFAULT_VIDEO_WIDTH;
int height = DEFAULT_VIDEO_HEIGHT;
@@ -233,6 +241,11 @@
int flags = DEFAULT_VIDEO_FLAGS;
grub_video_color_t color;
+ /* Select the font to use. */
+ font_name = grub_env_get ("gfxterm_font");
+ if (!font_name)
+ font_name = ""; /* Allow fallback to any font. */
+
/* Parse gfxmode environment variable if set. */
modevar = grub_env_get ("gfxmode");
if (modevar)
@@ -472,7 +485,7 @@
/* Create virtual screen. */
if (grub_virtual_screen_setup (DEFAULT_BORDER_WIDTH, DEFAULT_BORDER_WIDTH,
- width, height) != GRUB_ERR_NONE)
+ width, height, font_name) != GRUB_ERR_NONE)
{
grub_video_restore ();
return grub_errno;
@@ -658,11 +671,12 @@
write_char (void)
{
struct grub_colored_char *p;
- struct grub_font_glyph glyph;
+ struct grub_font_glyph *glyph;
grub_video_color_t color;
grub_video_color_t bgcolor;
unsigned int x;
unsigned int y;
+ int ascent;
/* Find out active character. */
p = (virtual_screen.text_buffer
@@ -672,7 +686,8 @@
p -= p->index;
/* Get glyph for character. */
- grub_font_get_glyph (p->code, &glyph);
+ glyph = grub_font_get_glyph (virtual_screen.font, p->code);
+ ascent = grub_font_get_ascent (virtual_screen.font);
color = p->fg_color;
bgcolor = p->bg_color;
@@ -682,13 +697,13 @@
/* Render glyph to text layer. */
grub_video_set_active_render_target (text_layer);
- grub_video_fill_rect (bgcolor, x, y, glyph.width, glyph.height);
- grub_video_blit_glyph (&glyph, color, x, y);
+ grub_video_fill_rect (bgcolor, x, y, glyph->width, glyph->height);
+ grub_font_draw_glyph (glyph, color, x, y + ascent);
grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
/* Mark character to be drawn. */
dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y,
- glyph.width, glyph.height);
+ glyph->width, glyph->height);
}
static void
@@ -702,7 +717,8 @@
/* Determine cursor properties and position on text layer. */
x = virtual_screen.cursor_x * virtual_screen.char_width;
- y = ((virtual_screen.cursor_y + 1) * virtual_screen.char_height) - 3;
+ y = (virtual_screen.cursor_y * virtual_screen.char_height
+ + grub_font_get_ascent (virtual_screen.font));
width = virtual_screen.char_width;
height = 2;
@@ -819,14 +835,18 @@
}
else
{
- struct grub_font_glyph glyph;
+ struct grub_font_glyph *glyph;
struct grub_colored_char *p;
+ unsigned char_width;
/* Get properties of the character. */
- grub_font_get_glyph (c, &glyph);
+ glyph = grub_font_get_glyph (virtual_screen.font, c);
+
+ /* TODO Fix wide characters. Bi-width font support? */
+ char_width = 1;
/* If we are about to exceed line length, wrap to next line. */
- if (virtual_screen.cursor_x + glyph.char_width > virtual_screen.columns)
+ if (virtual_screen.cursor_x + char_width > virtual_screen.columns)
grub_putchar ('\n');
/* Find position on virtual screen, and fill information. */
@@ -836,18 +856,18 @@
p->code = c;
p->fg_color = virtual_screen.fg_color;
p->bg_color = virtual_screen.bg_color;
- p->width = glyph.char_width - 1;
+ p->width = char_width - 1;
p->index = 0;
/* If we have large glyph, add fixup info. */
- if (glyph.char_width > 1)
+ if (char_width > 1)
{
unsigned i;
- for (i = 1; i < glyph.char_width; i++)
+ for (i = 1; i < char_width; i++)
{
p[i].code = ' ';
- p[i].width = glyph.char_width - 1;
+ p[i].width = char_width - 1;
p[i].index = i;
}
}
@@ -856,7 +876,7 @@
write_char ();
/* Make sure we scroll screen when needed and wrap line correctly. */
- virtual_screen.cursor_x += glyph.char_width;
+ virtual_screen.cursor_x += char_width;
if (virtual_screen.cursor_x >= virtual_screen.columns)
{
virtual_screen.cursor_x = 0;
@@ -876,11 +896,16 @@
static grub_ssize_t
grub_gfxterm_getcharwidth (grub_uint32_t c)
{
- struct grub_font_glyph glyph;
-
- grub_font_get_glyph (c, &glyph);
-
- return glyph.char_width;
+#if 0
+ struct grub_font_glyph *glyph;
+
+ glyph = grub_font_get_glyph (c);
+
+ return glyph->char_width;
+#else
+ (void) c; /* Prevent warning. */
+ return 1; /* TODO Fix wide characters. */
+#endif
}
static grub_uint16_t
=== modified file 'term/i386/pc/vesafb.c'
--- term/i386/pc/vesafb.c 2007-12-30 08:52:06 +0000
+++ term/i386/pc/vesafb.c 2008-10-30 18:24:32 +0000
@@ -250,10 +250,11 @@
break;
default:
- return grub_font_get_glyph (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)
grub_memcpy (bitmap,
vga_font + code * virtual_screen.char_height,
=== modified file 'term/i386/pc/vga.c'
--- term/i386/pc/vga.c 2008-01-21 15:48:27 +0000
+++ term/i386/pc/vga.c 2008-10-30 18:24:32 +0000
@@ -65,6 +65,7 @@
static struct colored_char text_buf[TEXT_WIDTH * TEXT_HEIGHT];
static unsigned char saved_map_mask;
static int page = 0;
+static grub_font_t font = 0;
#define SEQUENCER_ADDR_PORT 0x3C4
#define SEQUENCER_DATA_PORT 0x3C5
@@ -161,6 +162,9 @@
saved_map_mask = get_map_mask ();
set_map_mask (0x0f);
set_start_address (PAGE_OFFSET (page));
+ font = grub_font_get (""); /* Choose any font, for now. */
+ if (!font)
+ return grub_error (GRUB_ERR_BAD_FONT, "No font loaded.");
return GRUB_ERR_NONE;
}
@@ -185,7 +189,7 @@
write_char (void)
{
struct colored_char *p = text_buf + xpos + ypos * TEXT_WIDTH;
- struct grub_font_glyph glyph;
+ struct grub_font_glyph *glyph;
unsigned char *mem_base;
unsigned plane;
@@ -194,7 +198,7 @@
p -= p->index;
/* Get glyph for character. */
- grub_font_get_glyph (p->code, &glyph);
+ glyph = grub_font_get_glyph (font, p->code);
for (plane = 0x01; plane <= 0x08; plane <<= 1)
{
@@ -208,19 +212,23 @@
y < CHAR_HEIGHT;
y++, mem += TEXT_WIDTH)
{
+ /* TODO Re-implement glyph drawing for vga module. */
+#if 0
unsigned i;
- for (i = 0; i < glyph.char_width && offset < 32; i++)
+ unsigned char_width = 1; /* TODO Figure out wide characters. */
+ for (i = 0; i < char_width && offset < 32; i++)
{
unsigned char fg_mask, bg_mask;
- fg_mask = (p->fg_color & plane) ? glyph.bitmap[offset] : 0;
- bg_mask = (p->bg_color & plane) ? ~(glyph.bitmap[offset]) : 0;
+ fg_mask = (p->fg_color & plane) ? glyph->bitmap[offset] : 0;
+ bg_mask = (p->bg_color & plane) ? ~(glyph->bitmap[offset]) : 0;
offset++;
if (check_vga_mem (mem + i))
mem[i] = (fg_mask | bg_mask);
}
+#endif /* 0 */
}
}
@@ -320,36 +328,37 @@
}
else
{
- struct grub_font_glyph glyph;
+ struct grub_font_glyph *glyph;
struct colored_char *p;
+ unsigned char_width = 1;
- grub_font_get_glyph(c, &glyph);
+ glyph = grub_font_get_glyph(font, c);
- if (xpos + glyph.char_width > TEXT_WIDTH)
+ if (xpos + char_width > TEXT_WIDTH)
grub_putchar ('\n');
p = text_buf + xpos + ypos * TEXT_WIDTH;
p->code = c;
p->fg_color = fg_color;
p->bg_color = bg_color;
- p->width = glyph.char_width - 1;
+ p->width = char_width - 1;
p->index = 0;
- if (glyph.char_width > 1)
+ if (char_width > 1)
{
unsigned i;
- for (i = 1; i < glyph.char_width; i++)
+ for (i = 1; i < char_width; i++)
{
p[i].code = ' ';
- p[i].width = glyph.char_width - 1;
+ p[i].width = char_width - 1;
p[i].index = i;
}
}
write_char ();
- xpos += glyph.char_width;
+ xpos += char_width;
if (xpos >= TEXT_WIDTH)
{
xpos = 0;
@@ -381,11 +390,16 @@
static grub_ssize_t
grub_vga_getcharwidth (grub_uint32_t c)
{
+#if 0
struct grub_font_glyph glyph;
- grub_font_get_glyph (c, &glyph);
+ glyph = grub_font_get_glyph (c);
return glyph.char_width;
+#else
+ (void) c; /* Prevent warning. */
+ return 1; /* TODO Fix wide characters? */
+#endif
}
static grub_uint16_t
=== modified file 'video/i386/pc/vbe.c'
--- video/i386/pc/vbe.c 2008-10-03 15:25:34 +0000
+++ video/i386/pc/vbe.c 2008-10-30 18:24:32 +0000
@@ -26,7 +26,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -896,6 +895,16 @@
return minindex;
}
+ else if ((render_target->mode_info.mode_type
+ & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) != 0)
+ {
+ if (red == render_target->mode_info.fg_red
+ && green == render_target->mode_info.fg_green
+ && blue == render_target->mode_info.fg_blue)
+ return 1;
+ else
+ return 0;
+ }
else
{
grub_uint32_t value;
@@ -926,6 +935,17 @@
/* No alpha available in index color modes, just use
same value as in only RGB modes. */
return grub_video_vbe_map_rgb (red, green, blue);
+ else if ((render_target->mode_info.mode_type
+ & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) != 0)
+ {
+ if (red == render_target->mode_info.fg_red
+ && green == render_target->mode_info.fg_green
+ && blue == render_target->mode_info.fg_blue
+ && alpha == render_target->mode_info.fg_alpha)
+ return 1;
+ else
+ return 0;
+ }
else
{
grub_uint32_t value;
@@ -988,6 +1008,24 @@
*alpha = framebuffer.palette[color].a;
return;
}
+ else if ((mode_info->mode_type
+ & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) != 0)
+ {
+ if (color & 1)
+ {
+ *red = mode_info->fg_red;
+ *green = mode_info->fg_green;
+ *blue = mode_info->fg_blue;
+ *alpha = mode_info->fg_alpha;
+ }
+ else
+ {
+ *red = mode_info->bg_red;
+ *green = mode_info->bg_green;
+ *blue = mode_info->bg_blue;
+ *alpha = mode_info->bg_alpha;
+ }
+ }
else
{
grub_uint32_t tmp;
@@ -1111,76 +1149,6 @@
return GRUB_ERR_NONE;
}
-// TODO: Remove this method and replace with bitmap based glyphs
-static grub_err_t
-grub_video_vbe_blit_glyph (struct grub_font_glyph * glyph,
- grub_video_color_t color, int x, int y)
-{
- struct grub_video_i386_vbeblit_info target;
- unsigned int width;
- unsigned int charwidth;
- unsigned int height;
- unsigned int i;
- unsigned int j;
- unsigned int x_offset = 0;
- unsigned int y_offset = 0;
-
- /* Make sure there is something to do. */
- if (x >= (int)render_target->viewport.width)
- return GRUB_ERR_NONE;
-
- if (y >= (int)render_target->viewport.height)
- return GRUB_ERR_NONE;
-
- /* Calculate glyph dimensions. */
- width = ((glyph->width + 7) / 8) * 8;
- charwidth = width;
- height = glyph->height;
-
- if (x + (int)width < 0)
- return GRUB_ERR_NONE;
-
- if (y + (int)height < 0)
- return GRUB_ERR_NONE;
-
- /* Do not allow drawing out of viewport. */
- if (x < 0)
- {
- width += x;
- x_offset = (unsigned int)-x;
- x = 0;
- }
- if (y < 0)
- {
- height += y;
- y_offset = (unsigned int)-y;
- y = 0;
- }
-
- if ((x + width) > render_target->viewport.width)
- width = render_target->viewport.width - x;
- if ((y + height) > render_target->viewport.height)
- height = render_target->viewport.height - y;
-
- /* Add viewport offset. */
- x += render_target->viewport.x;
- y += render_target->viewport.y;
-
- /* Use vbeblit_info to encapsulate rendering. */
- target.mode_info = &render_target->mode_info;
- target.data = render_target->data;
-
- /* Draw glyph. */
- for (j = 0; j < height; j++)
- for (i = 0; i < width; i++)
- if ((glyph->bitmap[((i + x_offset) / 8)
- + (j + y_offset) * (charwidth / 8)]
- & (1 << ((charwidth - (i + x_offset) - 1) % 8))))
- set_pixel (&target, x+i, y+j, color);
-
- return GRUB_ERR_NONE;
-}
-
/* NOTE: This function assumes that given coordinates are within bounds of
handled data. */
static void
@@ -1804,7 +1772,6 @@
.map_rgba = grub_video_vbe_map_rgba,
.unmap_color = grub_video_vbe_unmap_color,
.fill_rect = grub_video_vbe_fill_rect,
- .blit_glyph = grub_video_vbe_blit_glyph,
.blit_bitmap = grub_video_vbe_blit_bitmap,
.blit_render_target = grub_video_vbe_blit_render_target,
.scroll = grub_video_vbe_scroll,
=== modified file 'video/i386/pc/vbeutil.c'
--- video/i386/pc/vbeutil.c 2007-07-21 22:32:33 +0000
+++ video/i386/pc/vbeutil.c 2008-10-30 18:24:32 +0000
@@ -52,6 +52,11 @@
+ y * source->mode_info->pitch
+ x;
break;
+
+ /* case 1: */
+ /* For 1-bit bitmaps, addressing needs to be done at the bit level
+ * and it doesn't make sense, in general, to ask for a pointer
+ * to a particular pixel's data. */
}
return ptr;
@@ -86,6 +91,17 @@
color = *(grub_uint8_t *)get_data_ptr (source, x, y);
break;
+ case 1:
+ if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED)
+ {
+ int bit_index = y * source->mode_info->width + x;
+ grub_uint8_t *ptr = (grub_uint8_t *)source->data
+ + bit_index / 8;
+ int bit_pos = 7 - bit_index % 8;
+ color = (*ptr >> bit_pos) & 0x01;
+ }
+ break;
+
default:
break;
}
@@ -143,6 +159,17 @@
}
break;
+ case 1:
+ if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED)
+ {
+ int bit_index = y * source->mode_info->width + x;
+ grub_uint8_t *ptr = (grub_uint8_t *)source->data
+ + bit_index / 8;
+ int bit_pos = 7 - bit_index % 8;
+ *ptr = (*ptr & ~(1 << bit_pos)) | ((color & 0x01) << bit_pos);
+ }
+ break;
+
default:
break;
}
=== modified file 'video/video.c'
--- video/video.c 2008-10-03 15:25:34 +0000
+++ video/video.c 2008-10-30 18:24:32 +0000
@@ -336,17 +336,6 @@
return grub_video_adapter_active->fill_rect (color, x, y, width, height);
}
-/* Blit glyph to screen using specified color. */
-grub_err_t
-grub_video_blit_glyph (struct grub_font_glyph *glyph,
- grub_video_color_t color, int x, int y)
-{
- if (! grub_video_adapter_active)
- return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
-
- return grub_video_adapter_active->blit_glyph (glyph, color, x, y);
-}
-
/* Blit bitmap to screen. */
grub_err_t
grub_video_blit_bitmap (struct grub_video_bitmap *bitmap,