* conf/powerpc-ieee1275.rmk (kernel_elf_LDFLAGS): Change link address
[grub2/phcoder/solaris.git] / font / manager.c
blob28f63ae75fdd4b95403f15dc6c1233ec4cd072de
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2003,2005,2006,2007 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/file.h>
20 #include <grub/misc.h>
21 #include <grub/dl.h>
22 #include <grub/normal.h>
23 #include <grub/types.h>
24 #include <grub/mm.h>
25 #include <grub/font.h>
26 #include <grub/bufio.h>
28 struct entry
30 grub_uint32_t code;
31 grub_uint32_t offset;
34 struct font
36 struct font *next;
37 grub_file_t file;
38 grub_uint32_t num;
39 struct entry table[0];
42 static struct font *font_list;
44 /* Fill unknown glyph's with rounded question mark. */
45 static grub_uint8_t unknown_glyph[16] =
46 { /* 76543210 */
47 0x7C, /* ooooo */
48 0x82, /* o o */
49 0xBA, /* o ooo o */
50 0xAA, /* o o o o */
51 0xAA, /* o o o o */
52 0x8A, /* o o o */
53 0x9A, /* o oo o */
54 0x92, /* o o o */
55 0x92, /* o o o */
56 0x92, /* o o o */
57 0x92, /* o o o */
58 0x82, /* o o */
59 0x92, /* o o o */
60 0x82, /* o o */
61 0x7C, /* ooooo */
62 0x00 /* */
65 static int
66 add_font (const char *filename)
68 grub_file_t file = 0;
69 char magic[4];
70 grub_uint32_t num, i;
71 struct font *font = 0;
73 file = grub_buffile_open (filename, 0);
74 if (! file)
75 goto fail;
77 if (grub_file_read (file, magic, 4) != 4)
78 goto fail;
80 if (grub_memcmp (magic, GRUB_FONT_MAGIC, 4) != 0)
82 grub_error (GRUB_ERR_BAD_FONT, "invalid font magic");
83 goto fail;
86 if (grub_file_read (file, (char *) &num, 4) != 4)
87 goto fail;
89 num = grub_le_to_cpu32 (num);
90 font = (struct font *) grub_malloc (sizeof (struct font)
91 + sizeof (struct entry) * num);
92 if (! font)
93 goto fail;
95 font->file = file;
96 font->num = num;
98 for (i = 0; i < num; i++)
100 grub_uint32_t code, offset;
102 if (grub_file_read (file, (char *) &code, 4) != 4)
103 goto fail;
105 if (grub_file_read (file, (char *) &offset, 4) != 4)
106 goto fail;
108 font->table[i].code = grub_le_to_cpu32 (code);
109 font->table[i].offset = grub_le_to_cpu32 (offset);
112 font->next = font_list;
113 font_list = font;
115 return 1;
117 fail:
118 if (font)
119 grub_free (font);
121 if (file)
122 grub_file_close (file);
124 return 0;
127 static void
128 remove_font (struct font *font)
130 struct font **p, *q;
132 for (p = &font_list, q = *p; q; p = &(q->next), q = q->next)
133 if (q == font)
135 *p = q->next;
137 grub_file_close (font->file);
138 grub_free (font);
140 break;
144 /* Return the offset of the glyph corresponding to the codepoint CODE
145 in the font FONT. If no found, return zero. */
146 static grub_uint32_t
147 find_glyph (const struct font *font, grub_uint32_t code)
149 grub_uint32_t start = 0;
150 grub_uint32_t end = font->num - 1;
151 const struct entry *table = font->table;
153 /* This shouldn't happen. */
154 if (font->num == 0)
155 return 0;
157 /* Do a binary search. */
158 while (start <= end)
160 grub_uint32_t i = (start + end) / 2;
162 if (table[i].code < code)
163 start = i + 1;
164 else if (table[i].code > code)
165 end = i - 1;
166 else
167 return table[i].offset;
170 return 0;
173 /* Set the glyph to something stupid. */
174 static void
175 fill_with_default_glyph (grub_font_glyph_t glyph)
177 unsigned i;
179 /* Use pre-defined pattern to fill unknown glyphs. */
180 for (i = 0; i < 16; i++)
181 glyph->bitmap[i] = unknown_glyph[i];
183 glyph->char_width = 1;
184 glyph->width = glyph->char_width * 8;
185 glyph->height = 16;
186 glyph->baseline = (16 * 3) / 4;
189 /* Get a glyph corresponding to the codepoint CODE. Always fill glyph
190 information with something, even if no glyph is found. */
192 grub_font_get_glyph (grub_uint32_t code,
193 grub_font_glyph_t glyph)
195 struct font *font;
196 grub_uint8_t bitmap[32];
198 /* FIXME: It is necessary to cache glyphs! */
200 restart:
201 for (font = font_list; font; font = font->next)
203 grub_uint32_t offset;
205 offset = find_glyph (font, code);
206 if (offset)
208 grub_uint32_t w;
209 int len;
211 /* Make sure we can find glyphs for error messages. Push active
212 error message to error stack and reset error message. */
213 grub_error_push ();
215 grub_file_seek (font->file, offset);
216 if ((len = grub_file_read (font->file, (char *) &w, sizeof (w)))
217 != sizeof (w))
219 remove_font (font);
220 goto restart;
223 w = grub_le_to_cpu32 (w);
224 if (w != 1 && w != 2)
226 /* grub_error (GRUB_ERR_BAD_FONT, "invalid width"); */
227 remove_font (font);
228 goto restart;
231 if (grub_file_read (font->file, (char *) bitmap, w * 16)
232 != (grub_ssize_t) w * 16)
234 remove_font (font);
235 goto restart;
238 /* Fill glyph with information. */
239 grub_memcpy (glyph->bitmap, bitmap, w * 16);
241 glyph->char_width = w;
242 glyph->width = glyph->char_width * 8;
243 glyph->height = 16;
244 glyph->baseline = (16 * 3) / 4;
246 /* Restore old error message. */
247 grub_error_pop ();
249 return 1;
253 /* Uggh... No font was found. */
254 fill_with_default_glyph (glyph);
255 return 0;
258 static grub_err_t
259 font_command (struct grub_arg_list *state __attribute__ ((unused)),
260 int argc __attribute__ ((unused)),
261 char **args __attribute__ ((unused)))
263 if (argc == 0)
264 return grub_error (GRUB_ERR_BAD_ARGUMENT, "no font specified");
266 while (argc--)
267 if (! add_font (*args++))
268 return 1;
270 return 0;
273 GRUB_MOD_INIT(font_manager)
275 grub_register_command ("font", font_command, GRUB_COMMAND_FLAG_BOTH,
276 "font FILE...",
277 "Specify one or more font files to display.", 0);
280 GRUB_MOD_FINI(font_manager)
282 grub_unregister_command ("font");