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