]> git.proxmox.com Git - grub2.git/blob - grub-core/font/font.c
e0597ea4552374a7c468c9fa5ac32ee2fa13015f
[grub2.git] / grub-core / font / font.c
1 /* font.c - Font API and font file loader. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
5 *
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <grub/bufio.h>
21 #include <grub/dl.h>
22 #include <grub/file.h>
23 #include <grub/font.h>
24 #include <grub/misc.h>
25 #include <grub/mm.h>
26 #include <grub/types.h>
27 #include <grub/video.h>
28 #include <grub/bitmap.h>
29 #include <grub/charset.h>
30 #include <grub/unicode.h>
31 #include <grub/fontformat.h>
32
33 GRUB_MOD_LICENSE ("GPLv3+");
34
35 #ifdef USE_ASCII_FAILBACK
36 #include "ascii.h"
37 #endif
38
39 #ifndef FONT_DEBUG
40 #define FONT_DEBUG 0
41 #endif
42
43 struct char_index_entry
44 {
45 grub_uint32_t code;
46 grub_uint8_t storage_flags;
47 grub_uint32_t offset;
48
49 /* Glyph if loaded, or NULL otherwise. */
50 struct grub_font_glyph *glyph;
51 };
52
53 #define FONT_WEIGHT_NORMAL 100
54 #define FONT_WEIGHT_BOLD 200
55 #define ASCII_BITMAP_SIZE 16
56
57 struct grub_font
58 {
59 char *name;
60 grub_file_t file;
61 char *family;
62 short point_size;
63 short weight;
64 short max_char_width;
65 short max_char_height;
66 short ascent;
67 short descent;
68 short leading;
69 grub_uint32_t num_chars;
70 struct char_index_entry *char_index;
71 grub_uint16_t *bmp_idx;
72 };
73
74 /* Definition of font registry. */
75 struct grub_font_node *grub_font_list;
76
77 static int register_font (grub_font_t font);
78 static void font_init (grub_font_t font);
79 static void free_font (grub_font_t font);
80 static void remove_font (grub_font_t font);
81
82 struct font_file_section
83 {
84 /* The file this section is in. */
85 grub_file_t file;
86
87 /* FOURCC name of the section. */
88 char name[4];
89
90 /* Length of the section contents. */
91 grub_uint32_t length;
92
93 /* Set by open_section() on EOF. */
94 int eof;
95 };
96
97 /* Replace unknown glyphs with a rounded question mark. */
98 static grub_uint8_t unknown_glyph_bitmap[] = {
99 /* 76543210 */
100 0x7C, /* ooooo */
101 0x82, /* o o */
102 0xBA, /* o ooo o */
103 0xAA, /* o o o o */
104 0xAA, /* o o o o */
105 0x8A, /* o o o */
106 0x9A, /* o oo o */
107 0x92, /* o o o */
108 0x92, /* o o o */
109 0x92, /* o o o */
110 0x92, /* o o o */
111 0x82, /* o o */
112 0x92, /* o o o */
113 0x82, /* o o */
114 0x7C, /* ooooo */
115 0x00 /* */
116 };
117
118 /* The "unknown glyph" glyph, used as a last resort. */
119 static struct grub_font_glyph *unknown_glyph;
120
121 /* The font structure used when no other font is loaded. This functions
122 as a "Null Object" pattern, so that code everywhere does not have to
123 check for a NULL grub_font_t to avoid dereferencing a null pointer. */
124 static struct grub_font null_font;
125
126 /* Flag to ensure module is initialized only once. */
127 static grub_uint8_t font_loader_initialized;
128
129 #ifdef USE_ASCII_FAILBACK
130 static struct grub_font_glyph *ascii_font_glyph[0x80];
131 #endif
132
133 static struct grub_font_glyph *
134 ascii_glyph_lookup (grub_uint32_t code)
135 {
136 #ifdef USE_ASCII_FAILBACK
137 static int ascii_failback_initialized = 0;
138
139 if (code >= 0x80)
140 return NULL;
141
142 if (ascii_failback_initialized == 0)
143 {
144 int current;
145 for (current = 0; current < 0x80; current++)
146 {
147 ascii_font_glyph[current] =
148 grub_malloc (sizeof (struct grub_font_glyph) + ASCII_BITMAP_SIZE);
149
150 ascii_font_glyph[current]->width = 8;
151 ascii_font_glyph[current]->height = 16;
152 ascii_font_glyph[current]->offset_x = 0;
153 ascii_font_glyph[current]->offset_y = -2;
154 ascii_font_glyph[current]->device_width = 8;
155 ascii_font_glyph[current]->font = NULL;
156
157 grub_memcpy (ascii_font_glyph[current]->bitmap,
158 &ascii_bitmaps[current * ASCII_BITMAP_SIZE],
159 ASCII_BITMAP_SIZE);
160 }
161
162 ascii_failback_initialized = 1;
163 }
164
165 return ascii_font_glyph[code];
166 #else
167 (void) code;
168 return NULL;
169 #endif
170 }
171
172 void
173 grub_font_loader_init (void)
174 {
175 /* Only initialize font loader once. */
176 if (font_loader_initialized)
177 return;
178
179 /* Make glyph for unknown glyph. */
180 unknown_glyph = grub_malloc (sizeof (struct grub_font_glyph)
181 + sizeof (unknown_glyph_bitmap));
182 if (!unknown_glyph)
183 return;
184
185 unknown_glyph->width = 8;
186 unknown_glyph->height = 16;
187 unknown_glyph->offset_x = 0;
188 unknown_glyph->offset_y = -3;
189 unknown_glyph->device_width = 8;
190 grub_memcpy (unknown_glyph->bitmap,
191 unknown_glyph_bitmap, sizeof (unknown_glyph_bitmap));
192
193 /* Initialize the null font. */
194 font_init (&null_font);
195 /* FIXME: Fix this slightly improper cast. */
196 null_font.name = (char *) "<No Font>";
197 null_font.ascent = unknown_glyph->height - 3;
198 null_font.descent = 3;
199 null_font.max_char_width = unknown_glyph->width;
200 null_font.max_char_height = unknown_glyph->height;
201
202 font_loader_initialized = 1;
203 }
204
205 /* Initialize the font object with initial default values. */
206 static void
207 font_init (grub_font_t font)
208 {
209 font->name = 0;
210 font->file = 0;
211 font->family = 0;
212 font->point_size = 0;
213 font->weight = 0;
214
215 /* Default leading value, not in font file yet. */
216 font->leading = 1;
217
218 font->max_char_width = 0;
219 font->max_char_height = 0;
220 font->ascent = 0;
221 font->descent = 0;
222 font->num_chars = 0;
223 font->char_index = 0;
224 font->bmp_idx = 0;
225 }
226
227 /* Open the next section in the file.
228
229 On success, the section name is stored in section->name and the length in
230 section->length, and 0 is returned. On failure, 1 is returned and
231 grub_errno is set appropriately with an error message.
232
233 If 1 is returned due to being at the end of the file, then section->eof is
234 set to 1; otherwise, section->eof is set to 0. */
235 static int
236 open_section (grub_file_t file, struct font_file_section *section)
237 {
238 grub_ssize_t retval;
239 grub_uint32_t raw_length;
240
241 section->file = file;
242 section->eof = 0;
243
244 /* Read the FOURCC section name. */
245 retval = grub_file_read (file, section->name, 4);
246 if (retval >= 0 && retval < 4)
247 {
248 /* EOF encountered. */
249 section->eof = 1;
250 return 1;
251 }
252 else if (retval < 0)
253 {
254 /* Read error. */
255 return 1;
256 }
257
258 /* Read the big-endian 32-bit section length. */
259 retval = grub_file_read (file, &raw_length, 4);
260 if (retval >= 0 && retval < 4)
261 {
262 /* EOF encountered. */
263 section->eof = 1;
264 return 1;
265 }
266 else if (retval < 0)
267 {
268 /* Read error. */
269 return 1;
270 }
271
272 /* Convert byte-order and store in *length. */
273 section->length = grub_be_to_cpu32 (raw_length);
274
275 return 0;
276 }
277
278 /* Size in bytes of each character index (CHIX section)
279 entry in the font file. */
280 #define FONT_CHAR_INDEX_ENTRY_SIZE (4 + 1 + 4)
281
282 /* Load the character index (CHIX) section contents from the font file. This
283 presumes that the position of FILE is positioned immediately after the
284 section length for the CHIX section (i.e., at the start of the section
285 contents). Returns 0 upon success, nonzero for failure (in which case
286 grub_errno is set appropriately). */
287 static int
288 load_font_index (grub_file_t file, grub_uint32_t sect_length, struct
289 grub_font *font)
290 {
291 unsigned i;
292 grub_uint32_t last_code;
293
294 #if FONT_DEBUG >= 2
295 grub_printf ("load_font_index(sect_length=%d)\n", sect_length);
296 #endif
297
298 /* Sanity check: ensure section length is divisible by the entry size. */
299 if ((sect_length % FONT_CHAR_INDEX_ENTRY_SIZE) != 0)
300 {
301 grub_error (GRUB_ERR_BAD_FONT,
302 "font file format error: character index length %d "
303 "is not a multiple of the entry size %d",
304 sect_length, FONT_CHAR_INDEX_ENTRY_SIZE);
305 return 1;
306 }
307
308 /* Calculate the number of characters. */
309 font->num_chars = sect_length / FONT_CHAR_INDEX_ENTRY_SIZE;
310
311 /* Allocate the character index array. */
312 font->char_index = grub_malloc (font->num_chars
313 * sizeof (struct char_index_entry));
314 if (!font->char_index)
315 return 1;
316 font->bmp_idx = grub_malloc (0x10000 * sizeof (grub_uint16_t));
317 if (!font->bmp_idx)
318 return 1;
319 grub_memset (font->bmp_idx, 0xff, 0x10000 * sizeof (grub_uint16_t));
320
321
322 #if FONT_DEBUG >= 2
323 grub_printf ("num_chars=%d)\n", font->num_chars);
324 #endif
325
326 last_code = 0;
327
328 /* Load the character index data from the file. */
329 for (i = 0; i < font->num_chars; i++)
330 {
331 struct char_index_entry *entry = &font->char_index[i];
332
333 /* Read code point value; convert to native byte order. */
334 if (grub_file_read (file, &entry->code, 4) != 4)
335 return 1;
336 entry->code = grub_be_to_cpu32 (entry->code);
337
338 /* Verify that characters are in ascending order. */
339 if (i != 0 && entry->code <= last_code)
340 {
341 grub_error (GRUB_ERR_BAD_FONT,
342 "font characters not in ascending order: %u <= %u",
343 entry->code, last_code);
344 return 1;
345 }
346
347 if (entry->code < 0x10000)
348 font->bmp_idx[entry->code] = i;
349
350 last_code = entry->code;
351
352 /* Read storage flags byte. */
353 if (grub_file_read (file, &entry->storage_flags, 1) != 1)
354 return 1;
355
356 /* Read glyph data offset; convert to native byte order. */
357 if (grub_file_read (file, &entry->offset, 4) != 4)
358 return 1;
359 entry->offset = grub_be_to_cpu32 (entry->offset);
360
361 /* No glyph loaded. Will be loaded on demand and cached thereafter. */
362 entry->glyph = 0;
363
364 #if FONT_DEBUG >= 5
365 /* Print the 1st 10 characters. */
366 if (i < 10)
367 grub_printf ("c=%d o=%d\n", entry->code, entry->offset);
368 #endif
369 }
370
371 return 0;
372 }
373
374 /* Read the contents of the specified section as a string, which is
375 allocated on the heap. Returns 0 if there is an error. */
376 static char *
377 read_section_as_string (struct font_file_section *section)
378 {
379 char *str;
380 grub_ssize_t ret;
381
382 str = grub_malloc (section->length + 1);
383 if (!str)
384 return 0;
385
386 ret = grub_file_read (section->file, str, section->length);
387 if (ret < 0 || ret != (grub_ssize_t) section->length)
388 {
389 grub_free (str);
390 return 0;
391 }
392
393 str[section->length] = '\0';
394 return str;
395 }
396
397 /* Read the contents of the current section as a 16-bit integer value,
398 which is stored into *VALUE.
399 Returns 0 upon success, nonzero upon failure. */
400 static int
401 read_section_as_short (struct font_file_section *section,
402 grub_int16_t * value)
403 {
404 grub_uint16_t raw_value;
405
406 if (section->length != 2)
407 {
408 grub_error (GRUB_ERR_BAD_FONT,
409 "font file format error: section %c%c%c%c length "
410 "is %d but should be 2",
411 section->name[0], section->name[1],
412 section->name[2], section->name[3], section->length);
413 return 1;
414 }
415 if (grub_file_read (section->file, &raw_value, 2) != 2)
416 return 1;
417
418 *value = grub_be_to_cpu16 (raw_value);
419 return 0;
420 }
421
422 /* Load a font and add it to the beginning of the global font list.
423 Returns 0 upon success, nonzero upon failure. */
424 int
425 grub_font_load (const char *filename)
426 {
427 grub_file_t file = 0;
428 struct font_file_section section;
429 char magic[4];
430 grub_font_t font = 0;
431
432 #if FONT_DEBUG >= 1
433 grub_printf ("add_font(%s)\n", filename);
434 #endif
435
436 file = grub_buffile_open (filename, 1024);
437 if (!file)
438 goto fail;
439
440 #if FONT_DEBUG >= 3
441 grub_printf ("file opened\n");
442 #endif
443
444 /* Read the FILE section. It indicates the file format. */
445 if (open_section (file, &section) != 0)
446 goto fail;
447
448 #if FONT_DEBUG >= 3
449 grub_printf ("opened FILE section\n");
450 #endif
451 if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_FILE,
452 sizeof (FONT_FORMAT_SECTION_NAMES_FILE) - 1) != 0)
453 {
454 grub_error (GRUB_ERR_BAD_FONT,
455 "font file format error: 1st section must be FILE");
456 goto fail;
457 }
458
459 #if FONT_DEBUG >= 3
460 grub_printf ("section name ok\n");
461 #endif
462 if (section.length != 4)
463 {
464 grub_error (GRUB_ERR_BAD_FONT,
465 "font file format error (file type ID length is %d "
466 "but should be 4)", section.length);
467 goto fail;
468 }
469
470 #if FONT_DEBUG >= 3
471 grub_printf ("section length ok\n");
472 #endif
473 /* Check the file format type code. */
474 if (grub_file_read (file, magic, 4) != 4)
475 goto fail;
476
477 #if FONT_DEBUG >= 3
478 grub_printf ("read magic ok\n");
479 #endif
480
481 if (grub_memcmp (magic, FONT_FORMAT_PFF2_MAGIC, 4) != 0)
482 {
483 grub_error (GRUB_ERR_BAD_FONT, "invalid font magic %x %x %x %x",
484 magic[0], magic[1], magic[2], magic[3]);
485 goto fail;
486 }
487
488 #if FONT_DEBUG >= 3
489 grub_printf ("compare magic ok\n");
490 #endif
491
492 /* Allocate the font object. */
493 font = (grub_font_t) grub_zalloc (sizeof (struct grub_font));
494 if (!font)
495 goto fail;
496
497 font_init (font);
498 font->file = file;
499
500 #if FONT_DEBUG >= 3
501 grub_printf ("allocate font ok; loading font info\n");
502 #endif
503
504 /* Load the font information. */
505 while (1)
506 {
507 if (open_section (file, &section) != 0)
508 {
509 if (section.eof)
510 break; /* Done reading the font file. */
511 else
512 goto fail;
513 }
514
515 #if FONT_DEBUG >= 2
516 grub_printf ("opened section %c%c%c%c ok\n",
517 section.name[0], section.name[1],
518 section.name[2], section.name[3]);
519 #endif
520
521 if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_FONT_NAME,
522 sizeof (FONT_FORMAT_SECTION_NAMES_FONT_NAME) - 1) == 0)
523 {
524 font->name = read_section_as_string (&section);
525 if (!font->name)
526 goto fail;
527 }
528 else if (grub_memcmp (section.name,
529 FONT_FORMAT_SECTION_NAMES_POINT_SIZE,
530 sizeof (FONT_FORMAT_SECTION_NAMES_POINT_SIZE) -
531 1) == 0)
532 {
533 if (read_section_as_short (&section, &font->point_size) != 0)
534 goto fail;
535 }
536 else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_WEIGHT,
537 sizeof (FONT_FORMAT_SECTION_NAMES_WEIGHT) - 1)
538 == 0)
539 {
540 char *wt;
541 wt = read_section_as_string (&section);
542 if (!wt)
543 continue;
544 /* Convert the weight string 'normal' or 'bold' into a number. */
545 if (grub_strcmp (wt, "normal") == 0)
546 font->weight = FONT_WEIGHT_NORMAL;
547 else if (grub_strcmp (wt, "bold") == 0)
548 font->weight = FONT_WEIGHT_BOLD;
549 grub_free (wt);
550 }
551 else if (grub_memcmp (section.name,
552 FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH,
553 sizeof (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH)
554 - 1) == 0)
555 {
556 if (read_section_as_short (&section, &font->max_char_width) != 0)
557 goto fail;
558 }
559 else if (grub_memcmp (section.name,
560 FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT,
561 sizeof (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT)
562 - 1) == 0)
563 {
564 if (read_section_as_short (&section, &font->max_char_height) != 0)
565 goto fail;
566 }
567 else if (grub_memcmp (section.name,
568 FONT_FORMAT_SECTION_NAMES_ASCENT,
569 sizeof (FONT_FORMAT_SECTION_NAMES_ASCENT) - 1)
570 == 0)
571 {
572 if (read_section_as_short (&section, &font->ascent) != 0)
573 goto fail;
574 }
575 else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_DESCENT,
576 sizeof (FONT_FORMAT_SECTION_NAMES_DESCENT) - 1)
577 == 0)
578 {
579 if (read_section_as_short (&section, &font->descent) != 0)
580 goto fail;
581 }
582 else if (grub_memcmp (section.name,
583 FONT_FORMAT_SECTION_NAMES_CHAR_INDEX,
584 sizeof (FONT_FORMAT_SECTION_NAMES_CHAR_INDEX) -
585 1) == 0)
586 {
587 if (load_font_index (file, section.length, font) != 0)
588 goto fail;
589 }
590 else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_DATA,
591 sizeof (FONT_FORMAT_SECTION_NAMES_DATA) - 1) == 0)
592 {
593 /* When the DATA section marker is reached, we stop reading. */
594 break;
595 }
596 else
597 {
598 /* Unhandled section type, simply skip past it. */
599 #if FONT_DEBUG >= 3
600 grub_printf ("Unhandled section type, skipping.\n");
601 #endif
602 grub_off_t section_end = grub_file_tell (file) + section.length;
603 if ((int) grub_file_seek (file, section_end) == -1)
604 goto fail;
605 }
606 }
607
608 if (!font->name)
609 {
610 grub_dprintf ("font", "Font has no name.\n");
611 font->name = grub_strdup ("Unknown");
612 }
613
614 #if FONT_DEBUG >= 1
615 grub_printf ("Loaded font `%s'.\n"
616 "Ascent=%d Descent=%d MaxW=%d MaxH=%d Number of characters=%d.\n",
617 font->name,
618 font->ascent, font->descent,
619 font->max_char_width, font->max_char_height, font->num_chars);
620 #endif
621
622 if (font->max_char_width == 0
623 || font->max_char_height == 0
624 || font->num_chars == 0
625 || font->char_index == 0 || font->ascent == 0 || font->descent == 0)
626 {
627 grub_error (GRUB_ERR_BAD_FONT,
628 "invalid font file: missing some required data");
629 goto fail;
630 }
631
632 /* Add the font to the global font registry. */
633 if (register_font (font) != 0)
634 goto fail;
635
636 return 0;
637
638 fail:
639 if (file)
640 grub_file_close (file);
641 if (font)
642 font->file = 0;
643
644 free_font (font);
645 return 1;
646 }
647
648 /* Read a 16-bit big-endian integer from FILE, convert it to native byte
649 order, and store it in *VALUE.
650 Returns 0 on success, 1 on failure. */
651 static int
652 read_be_uint16 (grub_file_t file, grub_uint16_t * value)
653 {
654 if (grub_file_read (file, value, 2) != 2)
655 return 1;
656 *value = grub_be_to_cpu16 (*value);
657 return 0;
658 }
659
660 static int
661 read_be_int16 (grub_file_t file, grub_int16_t * value)
662 {
663 /* For the signed integer version, use the same code as for unsigned. */
664 return read_be_uint16 (file, (grub_uint16_t *) value);
665 }
666
667 /* Return a pointer to the character index entry for the glyph corresponding to
668 the codepoint CODE in the font FONT. If not found, return zero. */
669 static inline struct char_index_entry *
670 find_glyph (const grub_font_t font, grub_uint32_t code)
671 {
672 struct char_index_entry *table;
673 grub_size_t lo;
674 grub_size_t hi;
675 grub_size_t mid;
676
677 table = font->char_index;
678
679 /* Use BMP index if possible. */
680 if (code < 0x10000 && font->bmp_idx)
681 {
682 if (font->bmp_idx[code] == 0xffff)
683 return 0;
684 return &table[font->bmp_idx[code]];
685 }
686
687 /* Do a binary search in `char_index', which is ordered by code point. */
688 lo = 0;
689 hi = font->num_chars - 1;
690
691 if (!table)
692 return 0;
693
694 while (lo <= hi)
695 {
696 mid = lo + (hi - lo) / 2;
697 if (code < table[mid].code)
698 hi = mid - 1;
699 else if (code > table[mid].code)
700 lo = mid + 1;
701 else
702 return &table[mid];
703 }
704
705 return 0;
706 }
707
708 /* Get a glyph for the Unicode character CODE in FONT. The glyph is loaded
709 from the font file if has not been loaded yet.
710 Returns a pointer to the glyph if found, or 0 if it is not found. */
711 static struct grub_font_glyph *
712 grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
713 {
714 struct char_index_entry *index_entry;
715
716 index_entry = find_glyph (font, code);
717 if (index_entry)
718 {
719 struct grub_font_glyph *glyph = 0;
720 grub_uint16_t width;
721 grub_uint16_t height;
722 grub_int16_t xoff;
723 grub_int16_t yoff;
724 grub_int16_t dwidth;
725 int len;
726
727 if (index_entry->glyph)
728 /* Return cached glyph. */
729 return index_entry->glyph;
730
731 if (!font->file)
732 /* No open file, can't load any glyphs. */
733 return 0;
734
735 /* Make sure we can find glyphs for error messages. Push active
736 error message to error stack and reset error message. */
737 grub_error_push ();
738
739 grub_file_seek (font->file, index_entry->offset);
740
741 /* Read the glyph width, height, and baseline. */
742 if (read_be_uint16 (font->file, &width) != 0
743 || read_be_uint16 (font->file, &height) != 0
744 || read_be_int16 (font->file, &xoff) != 0
745 || read_be_int16 (font->file, &yoff) != 0
746 || read_be_int16 (font->file, &dwidth) != 0)
747 {
748 remove_font (font);
749 return 0;
750 }
751
752 len = (width * height + 7) / 8;
753 glyph = grub_malloc (sizeof (struct grub_font_glyph) + len);
754 if (!glyph)
755 {
756 remove_font (font);
757 return 0;
758 }
759
760 glyph->font = font;
761 glyph->width = width;
762 glyph->height = height;
763 glyph->offset_x = xoff;
764 glyph->offset_y = yoff;
765 glyph->device_width = dwidth;
766
767 /* Don't try to read empty bitmaps (e.g., space characters). */
768 if (len != 0)
769 {
770 if (grub_file_read (font->file, glyph->bitmap, len) != len)
771 {
772 remove_font (font);
773 return 0;
774 }
775 }
776
777 /* Restore old error message. */
778 grub_error_pop ();
779
780 /* Cache the glyph. */
781 index_entry->glyph = glyph;
782
783 return glyph;
784 }
785
786 return 0;
787 }
788
789 /* Free the memory used by FONT.
790 This should not be called if the font has been made available to
791 users (once it is added to the global font list), since there would
792 be the possibility of a dangling pointer. */
793 static void
794 free_font (grub_font_t font)
795 {
796 if (font)
797 {
798 if (font->file)
799 grub_file_close (font->file);
800 grub_free (font->name);
801 grub_free (font->family);
802 grub_free (font->char_index);
803 grub_free (font->bmp_idx);
804 grub_free (font);
805 }
806 }
807
808 /* Add FONT to the global font registry.
809 Returns 0 upon success, nonzero on failure
810 (the font was not registered). */
811 static int
812 register_font (grub_font_t font)
813 {
814 struct grub_font_node *node = 0;
815
816 node = grub_malloc (sizeof (struct grub_font_node));
817 if (!node)
818 return 1;
819
820 node->value = font;
821 node->next = grub_font_list;
822 grub_font_list = node;
823
824 return 0;
825 }
826
827 /* Remove the font from the global font list. We don't actually free the
828 font's memory since users could be holding references to the font. */
829 static void
830 remove_font (grub_font_t font)
831 {
832 struct grub_font_node **nextp, *cur;
833
834 for (nextp = &grub_font_list, cur = *nextp;
835 cur; nextp = &cur->next, cur = cur->next)
836 {
837 if (cur->value == font)
838 {
839 *nextp = cur->next;
840
841 /* Free the node, but not the font itself. */
842 grub_free (cur);
843
844 return;
845 }
846 }
847 }
848
849 /* Get a font from the list of loaded fonts. This function will return
850 another font if the requested font is not available. If no fonts are
851 loaded, then a special 'null font' is returned, which contains no glyphs,
852 but is not a null pointer so the caller may omit checks for NULL. */
853 grub_font_t
854 grub_font_get (const char *font_name)
855 {
856 struct grub_font_node *node;
857
858 for (node = grub_font_list; node; node = node->next)
859 {
860 grub_font_t font = node->value;
861 if (grub_strcmp (font->name, font_name) == 0)
862 return font;
863 }
864
865 /* If no font by that name is found, return the first font in the list
866 as a fallback. */
867 if (grub_font_list && grub_font_list->value)
868 return grub_font_list->value;
869 else
870 /* The null_font is a last resort. */
871 return &null_font;
872 }
873
874 /* Get the full name of the font. */
875 const char *
876 grub_font_get_name (grub_font_t font)
877 {
878 return font->name;
879 }
880
881 /* Get the maximum width of any character in the font in pixels. */
882 int
883 grub_font_get_max_char_width (grub_font_t font)
884 {
885 return font->max_char_width;
886 }
887
888 /* Get the maximum height of any character in the font in pixels. */
889 int
890 grub_font_get_max_char_height (grub_font_t font)
891 {
892 return font->max_char_height;
893 }
894
895 /* Get the distance in pixels from the top of characters to the baseline. */
896 int
897 grub_font_get_ascent (grub_font_t font)
898 {
899 return font->ascent;
900 }
901
902 /* Get the distance in pixels from the baseline to the lowest descenders
903 (for instance, in a lowercase 'y', 'g', etc.). */
904 int
905 grub_font_get_descent (grub_font_t font)
906 {
907 return font->descent;
908 }
909
910 /* FIXME: not correct for all fonts. */
911 int
912 grub_font_get_xheight (grub_font_t font)
913 {
914 return font->ascent / 2;
915 }
916
917 /* Get the *standard leading* of the font in pixel, which is the spacing
918 between two lines of text. Specifically, it is the space between the
919 descent of one line and the ascent of the next line. This is included
920 in the *height* metric. */
921 int
922 grub_font_get_leading (grub_font_t font)
923 {
924 return font->leading;
925 }
926
927 /* Get the distance in pixels between baselines of adjacent lines of text. */
928 int
929 grub_font_get_height (grub_font_t font)
930 {
931 return font->ascent + font->descent + font->leading;
932 }
933
934 /* Get the glyph for FONT corresponding to the Unicode code point CODE.
935 Returns the ASCII glyph for the code if no other fonts are available.
936 The glyphs are cached once loaded. */
937 struct grub_font_glyph *
938 grub_font_get_glyph (grub_font_t font, grub_uint32_t code)
939 {
940 struct grub_font_glyph *glyph = 0;
941 if (font)
942 glyph = grub_font_get_glyph_internal (font, code);
943 if (glyph == 0)
944 {
945 glyph = ascii_glyph_lookup (code);
946 }
947 return glyph;
948 }
949
950
951 /* Calculate a subject value representing "how similar" two fonts are.
952 This is used to prioritize the order that fonts are scanned for missing
953 glyphs. The object is to select glyphs from the most similar font
954 possible, for the best appearance.
955 The heuristic is crude, but it helps greatly when fonts of similar
956 sizes are used so that tiny 8 point glyphs are not mixed into a string
957 of 24 point text unless there is no other choice. */
958 static int
959 get_font_diversity (grub_font_t a, grub_font_t b)
960 {
961 int d;
962
963 d = 0;
964
965 if (a->ascent && b->ascent)
966 d += grub_abs (a->ascent - b->ascent) * 8;
967 else
968 /* Penalty for missing attributes. */
969 d += 50;
970
971 if (a->max_char_height && b->max_char_height)
972 d += grub_abs (a->max_char_height - b->max_char_height) * 8;
973 else
974 /* Penalty for missing attributes. */
975 d += 50;
976
977 /* Weight is a minor factor. */
978 d += (a->weight != b->weight) ? 5 : 0;
979
980 return d;
981 }
982
983 /* Get a glyph corresponding to the codepoint CODE. If FONT contains the
984 specified glyph, then it is returned. Otherwise, all other loaded fonts
985 are searched until one is found that contains a glyph for CODE.
986 If no glyph is available for CODE in the loaded fonts, then a glyph
987 representing an unknown character is returned.
988 This function never returns NULL.
989 The returned glyph is owned by the font manager and should not be freed
990 by the caller. The glyphs are cached. */
991 struct grub_font_glyph *
992 grub_font_get_glyph_with_fallback (grub_font_t font, grub_uint32_t code)
993 {
994 struct grub_font_glyph *glyph;
995 struct grub_font_node *node;
996 /* Keep track of next node, in case there's an I/O error in
997 grub_font_get_glyph_internal() and the font is removed from the list. */
998 struct grub_font_node *next;
999 /* Information on the best glyph found so far, to help find the glyph in
1000 the best matching to the requested one. */
1001 int best_diversity;
1002 struct grub_font_glyph *best_glyph;
1003
1004 if (font)
1005 {
1006 /* First try to get the glyph from the specified font. */
1007 glyph = grub_font_get_glyph_internal (font, code);
1008 if (glyph)
1009 return glyph;
1010 }
1011
1012 /* Otherwise, search all loaded fonts for the glyph and use the one from
1013 the font that best matches the requested font. */
1014 best_diversity = 10000;
1015 best_glyph = 0;
1016
1017 for (node = grub_font_list; node; node = next)
1018 {
1019 grub_font_t curfont;
1020
1021 curfont = node->value;
1022 next = node->next;
1023
1024 glyph = grub_font_get_glyph_internal (curfont, code);
1025 if (glyph && !font)
1026 return glyph;
1027 if (glyph)
1028 {
1029 int d;
1030
1031 d = get_font_diversity (curfont, font);
1032 if (d < best_diversity)
1033 {
1034 best_diversity = d;
1035 best_glyph = glyph;
1036 }
1037 }
1038 }
1039
1040 return best_glyph;
1041 }
1042
1043 static struct grub_font_glyph *
1044 grub_font_dup_glyph (struct grub_font_glyph *glyph)
1045 {
1046 static struct grub_font_glyph *ret;
1047 ret = grub_malloc (sizeof (*ret) + (glyph->width * glyph->height + 7) / 8);
1048 if (!ret)
1049 return NULL;
1050 grub_memcpy (ret, glyph, sizeof (*ret)
1051 + (glyph->width * glyph->height + 7) / 8);
1052 return ret;
1053 }
1054
1055 /* FIXME: suboptimal. */
1056 static void
1057 grub_font_blit_glyph (struct grub_font_glyph *target,
1058 struct grub_font_glyph *src, unsigned dx, unsigned dy)
1059 {
1060 unsigned src_bit, tgt_bit, src_byte, tgt_byte;
1061 unsigned i, j;
1062 for (i = 0; i < src->height; i++)
1063 {
1064 src_bit = (src->width * i) % 8;
1065 src_byte = (src->width * i) / 8;
1066 tgt_bit = (target->width * (dy + i) + dx) % 8;
1067 tgt_byte = (target->width * (dy + i) + dx) / 8;
1068 for (j = 0; j < src->width; j++)
1069 {
1070 target->bitmap[tgt_byte] |= ((src->bitmap[src_byte] << src_bit)
1071 & 0x80) >> tgt_bit;
1072 src_bit++;
1073 tgt_bit++;
1074 if (src_bit == 8)
1075 {
1076 src_byte++;
1077 src_bit = 0;
1078 }
1079 if (tgt_bit == 8)
1080 {
1081 tgt_byte++;
1082 tgt_bit = 0;
1083 }
1084 }
1085 }
1086 }
1087
1088 static void
1089 grub_font_blit_glyph_mirror (struct grub_font_glyph *target,
1090 struct grub_font_glyph *src,
1091 unsigned dx, unsigned dy)
1092 {
1093 unsigned tgt_bit, src_byte, tgt_byte;
1094 signed src_bit;
1095 unsigned i, j;
1096 for (i = 0; i < src->height; i++)
1097 {
1098 src_bit = (src->width * i + src->width - 1) % 8;
1099 src_byte = (src->width * i + src->width - 1) / 8;
1100 tgt_bit = (target->width * (dy + i) + dx) % 8;
1101 tgt_byte = (target->width * (dy + i) + dx) / 8;
1102 for (j = 0; j < src->width; j++)
1103 {
1104 target->bitmap[tgt_byte] |= ((src->bitmap[src_byte] << src_bit)
1105 & 0x80) >> tgt_bit;
1106 src_bit--;
1107 tgt_bit++;
1108 if (src_bit == -1)
1109 {
1110 src_byte--;
1111 src_bit = 7;
1112 }
1113 if (tgt_bit == 8)
1114 {
1115 tgt_byte++;
1116 tgt_bit = 0;
1117 }
1118 }
1119 }
1120 }
1121
1122 static void
1123 blit_comb (const struct grub_unicode_glyph *glyph_id,
1124 struct grub_font_glyph *glyph,
1125 struct grub_video_signed_rect *bounds_out,
1126 struct grub_font_glyph *main_glyph,
1127 struct grub_font_glyph **combining_glyphs, int *device_width)
1128 {
1129 struct grub_video_signed_rect bounds;
1130 unsigned i;
1131 signed above_rightx, above_righty;
1132 signed above_leftx, above_lefty;
1133 signed below_rightx, below_righty;
1134 signed min_devwidth = 0;
1135 auto void NESTED_FUNC_ATTR do_blit (struct grub_font_glyph *src,
1136 signed dx, signed dy);
1137 void NESTED_FUNC_ATTR do_blit (struct grub_font_glyph *src,
1138 signed dx, signed dy)
1139 {
1140 if (glyph)
1141 grub_font_blit_glyph (glyph, src, dx - glyph->offset_x,
1142 (glyph->height + glyph->offset_y) + dy);
1143 if (dx < bounds.x)
1144 {
1145 bounds.width += bounds.x - dx;
1146 bounds.x = dx;
1147 }
1148 if (bounds.y > -src->height - dy)
1149 {
1150 bounds.height += bounds.y - (-src->height - dy);
1151 bounds.y = (-src->height - dy);
1152 }
1153 if (dx + src->width - bounds.x >= (signed) bounds.width)
1154 bounds.width = dx + src->width - bounds.x + 1;
1155 if ((signed) bounds.height < src->height + (-src->height - dy) - bounds.y)
1156 bounds.height = src->height + (-src->height - dy) - bounds.y;
1157 }
1158
1159 auto void add_device_width (int val);
1160 void add_device_width (int val)
1161 {
1162 if (glyph)
1163 glyph->device_width += val;
1164 if (device_width)
1165 *device_width += val;
1166 }
1167
1168 if (glyph)
1169 glyph->device_width = main_glyph->device_width;
1170 if (device_width)
1171 *device_width = main_glyph->device_width;
1172
1173 bounds.x = main_glyph->offset_x;
1174 bounds.y = main_glyph->offset_y;
1175 bounds.width = main_glyph->width;
1176 bounds.height = main_glyph->height;
1177
1178 above_rightx = main_glyph->offset_x + main_glyph->width;
1179 above_righty = bounds.y + bounds.height;
1180
1181 above_leftx = main_glyph->offset_x;
1182 above_lefty = bounds.y + bounds.height;
1183
1184 below_rightx = bounds.x + bounds.width;
1185 below_righty = bounds.y;
1186
1187 for (i = 0; i < glyph_id->ncomb; i++)
1188 {
1189 grub_int16_t space = 0;
1190 /* Center by default. */
1191 grub_int16_t targetx;
1192
1193 if (!combining_glyphs[i])
1194 continue;
1195 targetx = (bounds.width - combining_glyphs[i]->width) / 2 + bounds.x;
1196 /* CGJ is to avoid diacritics reordering. */
1197 if (glyph_id->combining[i].code
1198 == GRUB_UNICODE_COMBINING_GRAPHEME_JOINER)
1199 continue;
1200 switch (glyph_id->combining[i].type)
1201 {
1202 case GRUB_UNICODE_COMB_OVERLAY:
1203 do_blit (combining_glyphs[i],
1204 targetx,
1205 (bounds.height - combining_glyphs[i]->height) / 2
1206 - (bounds.height + bounds.y));
1207 if (min_devwidth < combining_glyphs[i]->width)
1208 min_devwidth = combining_glyphs[i]->width;
1209 break;
1210
1211 case GRUB_UNICODE_COMB_ATTACHED_ABOVE_RIGHT:
1212 do_blit (combining_glyphs[i], above_rightx, -above_righty);
1213 above_rightx += combining_glyphs[i]->width;
1214 break;
1215
1216 case GRUB_UNICODE_COMB_ABOVE_RIGHT:
1217 do_blit (combining_glyphs[i], above_rightx,
1218 -(above_righty + combining_glyphs[i]->height));
1219 above_rightx += combining_glyphs[i]->width;
1220 break;
1221
1222 case GRUB_UNICODE_COMB_ABOVE_LEFT:
1223 above_leftx -= combining_glyphs[i]->width;
1224 do_blit (combining_glyphs[i], above_leftx,
1225 -(above_lefty + combining_glyphs[i]->height));
1226 break;
1227
1228 case GRUB_UNICODE_COMB_BELOW_RIGHT:
1229 do_blit (combining_glyphs[i], below_rightx, below_righty);
1230 below_rightx += combining_glyphs[i]->width;
1231 break;
1232
1233 case GRUB_UNICODE_COMB_HEBREW_HOLAM:
1234 if (glyph_id->base != GRUB_UNICODE_HEBREW_WAW)
1235 targetx =
1236 main_glyph->offset_x - combining_glyphs[i]->width -
1237 (combining_glyphs[i]->width + 3) / 4;
1238 goto above_on_main;
1239
1240 case GRUB_UNICODE_COMB_HEBREW_SIN_DOT:
1241 targetx = main_glyph->offset_x + combining_glyphs[i]->width / 4;
1242 goto above_on_main;
1243
1244 case GRUB_UNICODE_COMB_HEBREW_SHIN_DOT:
1245 targetx =
1246 main_glyph->width + main_glyph->offset_x -
1247 combining_glyphs[i]->width;
1248 above_on_main:
1249 space = combining_glyphs[i]->offset_y
1250 - grub_font_get_xheight (combining_glyphs[i]->font) - 1;
1251 if (space <= 0)
1252 space = 1 + (grub_font_get_xheight (main_glyph->font)) / 8;
1253 do_blit (combining_glyphs[i], targetx,
1254 -(main_glyph->height + main_glyph->offset_y + space
1255 + combining_glyphs[i]->height));
1256 if (min_devwidth < combining_glyphs[i]->width)
1257 min_devwidth = combining_glyphs[i]->width;
1258 break;
1259
1260 /* TODO: Put dammah, fathah and alif nearer to shadda. */
1261 case GRUB_UNICODE_COMB_SYRIAC_SUPERSCRIPT_ALAPH:
1262 case GRUB_UNICODE_COMB_ARABIC_DAMMAH:
1263 case GRUB_UNICODE_COMB_ARABIC_DAMMATAN:
1264 case GRUB_UNICODE_COMB_ARABIC_FATHATAN:
1265 case GRUB_UNICODE_COMB_ARABIC_FATHAH:
1266 case GRUB_UNICODE_COMB_ARABIC_SUPERSCRIPT_ALIF:
1267 case GRUB_UNICODE_COMB_ARABIC_SUKUN:
1268 case GRUB_UNICODE_COMB_ARABIC_SHADDA:
1269 case GRUB_UNICODE_COMB_HEBREW_RAFE:
1270 case GRUB_UNICODE_STACK_ABOVE:
1271 stacked_above:
1272 space = combining_glyphs[i]->offset_y
1273 - grub_font_get_xheight (combining_glyphs[i]->font) - 1;
1274 if (space <= 0)
1275 space = 1 + (grub_font_get_xheight (main_glyph->font)) / 8;
1276
1277 case GRUB_UNICODE_STACK_ATTACHED_ABOVE:
1278 do_blit (combining_glyphs[i], targetx,
1279 -(bounds.height + bounds.y + space
1280 + combining_glyphs[i]->height));
1281 if (min_devwidth < combining_glyphs[i]->width)
1282 min_devwidth = combining_glyphs[i]->width;
1283 break;
1284
1285 case GRUB_UNICODE_COMB_HEBREW_SHEVA:
1286 case GRUB_UNICODE_COMB_HEBREW_HIRIQ:
1287 case GRUB_UNICODE_COMB_HEBREW_QAMATS:
1288 case GRUB_UNICODE_COMB_HEBREW_TSERE:
1289 case GRUB_UNICODE_COMB_HEBREW_SEGOL:
1290 /* TODO: placement in final kaf and under reish. */
1291
1292 case GRUB_UNICODE_COMB_HEBREW_HATAF_SEGOL:
1293 case GRUB_UNICODE_COMB_HEBREW_HATAF_PATAH:
1294 case GRUB_UNICODE_COMB_HEBREW_HATAF_QAMATS:
1295 case GRUB_UNICODE_COMB_HEBREW_PATAH:
1296 case GRUB_UNICODE_COMB_HEBREW_QUBUTS:
1297 case GRUB_UNICODE_COMB_HEBREW_METEG:
1298 /* TODO: Put kasra and kasratan under shadda. */
1299 case GRUB_UNICODE_COMB_ARABIC_KASRA:
1300 case GRUB_UNICODE_COMB_ARABIC_KASRATAN:
1301 /* I don't know how ypogegrammeni differs from subscript. */
1302 case GRUB_UNICODE_COMB_YPOGEGRAMMENI:
1303 case GRUB_UNICODE_STACK_BELOW:
1304 stacked_below:
1305 space = -(combining_glyphs[i]->offset_y
1306 + combining_glyphs[i]->height);
1307 if (space <= 0)
1308 space = 1 + (grub_font_get_xheight (main_glyph->font)) / 8;
1309
1310 case GRUB_UNICODE_STACK_ATTACHED_BELOW:
1311 do_blit (combining_glyphs[i], targetx, -(bounds.y - space));
1312 if (min_devwidth < combining_glyphs[i]->width)
1313 min_devwidth = combining_glyphs[i]->width;
1314 break;
1315
1316 case GRUB_UNICODE_COMB_MN:
1317 switch (glyph_id->combining[i].code)
1318 {
1319 case GRUB_UNICODE_THAANA_ABAFILI:
1320 case GRUB_UNICODE_THAANA_AABAAFILI:
1321 case GRUB_UNICODE_THAANA_UBUFILI:
1322 case GRUB_UNICODE_THAANA_OOBOOFILI:
1323 case GRUB_UNICODE_THAANA_EBEFILI:
1324 case GRUB_UNICODE_THAANA_EYBEYFILI:
1325 case GRUB_UNICODE_THAANA_OBOFILI:
1326 case GRUB_UNICODE_THAANA_OABOAFILI:
1327 case GRUB_UNICODE_THAANA_SUKUN:
1328 goto stacked_above;
1329 case GRUB_UNICODE_THAANA_IBIFILI:
1330 case GRUB_UNICODE_THAANA_EEBEEFILI:
1331 goto stacked_below;
1332 }
1333 /* Fall through. */
1334 default:
1335 {
1336 /* Default handling. Just draw combining character on top
1337 of base character.
1338 FIXME: support more unicode types correctly.
1339 */
1340 do_blit (combining_glyphs[i],
1341 main_glyph->device_width
1342 + combining_glyphs[i]->offset_x,
1343 -(combining_glyphs[i]->height
1344 + combining_glyphs[i]->offset_y));
1345 add_device_width (combining_glyphs[i]->device_width);
1346 }
1347 }
1348 }
1349 add_device_width ((above_rightx >
1350 below_rightx ? above_rightx : below_rightx) -
1351 (main_glyph->offset_x + main_glyph->width));
1352 add_device_width (above_leftx - main_glyph->offset_x);
1353 if (glyph && glyph->device_width < min_devwidth)
1354 glyph->device_width = min_devwidth;
1355 if (device_width && *device_width < min_devwidth)
1356 *device_width = min_devwidth;
1357
1358 if (bounds_out)
1359 *bounds_out = bounds;
1360 }
1361
1362 static struct grub_font_glyph *
1363 grub_font_construct_dry_run (grub_font_t hinted_font,
1364 const struct grub_unicode_glyph *glyph_id,
1365 struct grub_video_signed_rect *bounds,
1366 struct grub_font_glyph ***combining_glyphs_out,
1367 int *device_width)
1368 {
1369 struct grub_font_glyph *main_glyph = NULL;
1370 struct grub_font_glyph **combining_glyphs;
1371 grub_uint32_t desired_attributes = 0;
1372
1373 if (combining_glyphs_out)
1374 *combining_glyphs_out = NULL;
1375
1376 if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED)
1377 desired_attributes |= GRUB_FONT_CODE_RIGHT_JOINED;
1378
1379 if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED)
1380 desired_attributes |= GRUB_FONT_CODE_LEFT_JOINED;
1381
1382 main_glyph = grub_font_get_glyph_with_fallback (hinted_font, glyph_id->base
1383 | desired_attributes);
1384
1385 if (!main_glyph)
1386 main_glyph = grub_font_get_glyph_with_fallback (hinted_font,
1387 glyph_id->base);
1388
1389 /* Glyph not available in any font. Use ASCII fallback. */
1390 if (!main_glyph)
1391 main_glyph = ascii_glyph_lookup (glyph_id->base);
1392
1393 /* Glyph not available in any font. Return unknown glyph. */
1394 if (!main_glyph)
1395 return NULL;
1396
1397 if (device_width)
1398 *device_width = main_glyph->device_width;
1399
1400 if (!glyph_id->ncomb && !glyph_id->attributes)
1401 return main_glyph;
1402
1403 combining_glyphs = grub_malloc (sizeof (combining_glyphs[0])
1404 * glyph_id->ncomb);
1405 if (glyph_id->ncomb && !combining_glyphs)
1406 {
1407 grub_errno = GRUB_ERR_NONE;
1408 return main_glyph;
1409 }
1410
1411 {
1412 unsigned i;
1413 for (i = 0; i < glyph_id->ncomb; i++)
1414 combining_glyphs[i]
1415 = grub_font_get_glyph_with_fallback (main_glyph->font,
1416 glyph_id->combining[i].code);
1417 }
1418
1419 blit_comb (glyph_id, NULL, bounds, main_glyph, combining_glyphs,
1420 device_width);
1421 if (combining_glyphs_out)
1422 *combining_glyphs_out = combining_glyphs;
1423 else
1424 grub_free (combining_glyphs);
1425
1426 return main_glyph;
1427 }
1428
1429 int
1430 grub_font_get_constructed_device_width (grub_font_t hinted_font,
1431 const struct grub_unicode_glyph
1432 *glyph_id)
1433 {
1434 int ret;
1435 struct grub_font_glyph *main_glyph;
1436 main_glyph = grub_font_construct_dry_run (hinted_font, glyph_id, NULL,
1437 NULL, &ret);
1438 if (!main_glyph)
1439 return unknown_glyph->device_width;
1440 return ret;
1441 }
1442
1443 struct grub_font_glyph *
1444 grub_font_construct_glyph (grub_font_t hinted_font,
1445 const struct grub_unicode_glyph *glyph_id)
1446 {
1447 struct grub_font_glyph *main_glyph;
1448 struct grub_video_signed_rect bounds;
1449 struct grub_font_glyph *glyph;
1450 struct grub_font_glyph **combining_glyphs;
1451
1452 main_glyph = grub_font_construct_dry_run (hinted_font, glyph_id,
1453 &bounds, &combining_glyphs, NULL);
1454
1455 if (!main_glyph)
1456 return grub_font_dup_glyph (unknown_glyph);
1457
1458 if (!combining_glyphs)
1459 return grub_font_dup_glyph (main_glyph);
1460
1461 glyph =
1462 grub_zalloc (sizeof (*glyph) + (bounds.width * bounds.height + 7) / 8);
1463 if (!glyph)
1464 {
1465 grub_errno = GRUB_ERR_NONE;
1466 return grub_font_dup_glyph (main_glyph);
1467 }
1468
1469 glyph->font = main_glyph->font;
1470 glyph->width = bounds.width;
1471 glyph->height = bounds.height;
1472 glyph->offset_x = bounds.x;
1473 glyph->offset_y = bounds.y;
1474
1475 if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR)
1476 grub_font_blit_glyph_mirror (glyph, main_glyph,
1477 main_glyph->offset_x - glyph->offset_x,
1478 (glyph->height + glyph->offset_y)
1479 - (main_glyph->height +
1480 main_glyph->offset_y));
1481 else
1482 grub_font_blit_glyph (glyph, main_glyph,
1483 main_glyph->offset_x - glyph->offset_x,
1484 (glyph->height + glyph->offset_y)
1485 - (main_glyph->height + main_glyph->offset_y));
1486
1487 blit_comb (glyph_id, glyph, NULL, main_glyph, combining_glyphs, NULL);
1488
1489 return glyph;
1490 }
1491
1492 /* Draw the specified glyph at (x, y). The y coordinate designates the
1493 baseline of the character, while the x coordinate designates the left
1494 side location of the character. */
1495 grub_err_t
1496 grub_font_draw_glyph (struct grub_font_glyph * glyph,
1497 grub_video_color_t color, int left_x, int baseline_y)
1498 {
1499 struct grub_video_bitmap glyph_bitmap;
1500
1501 /* Don't try to draw empty glyphs (U+0020, etc.). */
1502 if (glyph->width == 0 || glyph->height == 0)
1503 return GRUB_ERR_NONE;
1504
1505 glyph_bitmap.mode_info.width = glyph->width;
1506 glyph_bitmap.mode_info.height = glyph->height;
1507 glyph_bitmap.mode_info.mode_type
1508 = (1 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP;
1509 glyph_bitmap.mode_info.blit_format = GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED;
1510 glyph_bitmap.mode_info.bpp = 1;
1511
1512 /* Really 1 bit per pixel. */
1513 glyph_bitmap.mode_info.bytes_per_pixel = 0;
1514
1515 /* Packed densely as bits. */
1516 glyph_bitmap.mode_info.pitch = glyph->width;
1517
1518 glyph_bitmap.mode_info.number_of_colors = 2;
1519 glyph_bitmap.mode_info.bg_red = 0;
1520 glyph_bitmap.mode_info.bg_green = 0;
1521 glyph_bitmap.mode_info.bg_blue = 0;
1522 glyph_bitmap.mode_info.bg_alpha = 0;
1523 grub_video_unmap_color (color,
1524 &glyph_bitmap.mode_info.fg_red,
1525 &glyph_bitmap.mode_info.fg_green,
1526 &glyph_bitmap.mode_info.fg_blue,
1527 &glyph_bitmap.mode_info.fg_alpha);
1528 glyph_bitmap.data = glyph->bitmap;
1529
1530 int bitmap_left = left_x + glyph->offset_x;
1531 int bitmap_bottom = baseline_y - glyph->offset_y;
1532 int bitmap_top = bitmap_bottom - glyph->height;
1533
1534 return grub_video_blit_bitmap (&glyph_bitmap, GRUB_VIDEO_BLIT_BLEND,
1535 bitmap_left, bitmap_top,
1536 0, 0, glyph->width, glyph->height);
1537 }