1
/* font.c - Font API and font file loader. */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2003,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
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.
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.
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/>.
20
#include <grub/bufio.h>
22
#include <grub/file.h>
23
#include <grub/font.h>
24
#include <grub/misc.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>
33
#ifdef USE_ASCII_FAILBACK
41
struct char_index_entry
44
grub_uint8_t storage_flags;
47
/* Glyph if loaded, or NULL otherwise. */
48
struct grub_font_glyph *glyph;
51
#define FONT_WEIGHT_NORMAL 100
52
#define FONT_WEIGHT_BOLD 200
53
#define ASCII_BITMAP_SIZE 16
63
short max_char_height;
67
grub_uint32_t num_chars;
68
struct char_index_entry *char_index;
69
grub_uint16_t *bmp_idx;
72
/* Definition of font registry. */
73
struct grub_font_node *grub_font_list;
75
static int register_font (grub_font_t font);
76
static void font_init (grub_font_t font);
77
static void free_font (grub_font_t font);
78
static void remove_font (grub_font_t font);
80
struct font_file_section
82
/* The file this section is in. */
85
/* FOURCC name of the section. */
88
/* Length of the section contents. */
91
/* Set by open_section() on EOF. */
95
/* Replace unknown glyphs with a rounded question mark. */
96
static grub_uint8_t unknown_glyph_bitmap[] = {
116
/* The "unknown glyph" glyph, used as a last resort. */
117
static struct grub_font_glyph *unknown_glyph;
119
/* The font structure used when no other font is loaded. This functions
120
as a "Null Object" pattern, so that code everywhere does not have to
121
check for a NULL grub_font_t to avoid dereferencing a null pointer. */
122
static struct grub_font null_font;
124
/* Flag to ensure module is initialized only once. */
125
static grub_uint8_t font_loader_initialized;
127
#ifdef USE_ASCII_FAILBACK
128
static struct grub_font_glyph *ascii_font_glyph[0x80];
131
static struct grub_font_glyph *
132
ascii_glyph_lookup (grub_uint32_t code)
134
#ifdef USE_ASCII_FAILBACK
135
static int ascii_failback_initialized = 0;
140
if (ascii_failback_initialized == 0)
143
for (current = 0; current < 0x80; current++)
145
ascii_font_glyph[current] =
146
grub_malloc (sizeof (struct grub_font_glyph) + ASCII_BITMAP_SIZE);
148
ascii_font_glyph[current]->width = 8;
149
ascii_font_glyph[current]->height = 16;
150
ascii_font_glyph[current]->offset_x = 0;
151
ascii_font_glyph[current]->offset_y = -2;
152
ascii_font_glyph[current]->device_width = 8;
153
ascii_font_glyph[current]->font = NULL;
155
grub_memcpy (ascii_font_glyph[current]->bitmap,
156
&ascii_bitmaps[current * ASCII_BITMAP_SIZE],
160
ascii_failback_initialized = 1;
163
return ascii_font_glyph[code];
171
grub_font_loader_init (void)
173
/* Only initialize font loader once. */
174
if (font_loader_initialized)
177
/* Make glyph for unknown glyph. */
178
unknown_glyph = grub_malloc (sizeof (struct grub_font_glyph)
179
+ sizeof (unknown_glyph_bitmap));
183
unknown_glyph->width = 8;
184
unknown_glyph->height = 16;
185
unknown_glyph->offset_x = 0;
186
unknown_glyph->offset_y = -3;
187
unknown_glyph->device_width = 8;
188
grub_memcpy (unknown_glyph->bitmap,
189
unknown_glyph_bitmap, sizeof (unknown_glyph_bitmap));
191
/* Initialize the null font. */
192
font_init (&null_font);
193
null_font.name = "<No Font>";
194
null_font.ascent = unknown_glyph->height - 3;
195
null_font.descent = 3;
196
null_font.max_char_width = unknown_glyph->width;
197
null_font.max_char_height = unknown_glyph->height;
199
font_loader_initialized = 1;
202
/* Initialize the font object with initial default values. */
204
font_init (grub_font_t font)
209
font->point_size = 0;
212
/* Default leading value, not in font file yet. */
215
font->max_char_width = 0;
216
font->max_char_height = 0;
220
font->char_index = 0;
224
/* Open the next section in the file.
226
On success, the section name is stored in section->name and the length in
227
section->length, and 0 is returned. On failure, 1 is returned and
228
grub_errno is set appropriately with an error message.
230
If 1 is returned due to being at the end of the file, then section->eof is
231
set to 1; otherwise, section->eof is set to 0. */
233
open_section (grub_file_t file, struct font_file_section *section)
236
grub_uint32_t raw_length;
238
section->file = file;
241
/* Read the FOURCC section name. */
242
retval = grub_file_read (file, section->name, 4);
243
if (retval >= 0 && retval < 4)
245
/* EOF encountered. */
251
grub_error (GRUB_ERR_BAD_FONT,
252
"font format error: can't read section name");
256
/* Read the big-endian 32-bit section length. */
257
retval = grub_file_read (file, &raw_length, 4);
258
if (retval >= 0 && retval < 4)
260
/* EOF encountered. */
266
grub_error (GRUB_ERR_BAD_FONT,
267
"font format error: can't read section length");
271
/* Convert byte-order and store in *length. */
272
section->length = grub_be_to_cpu32 (raw_length);
277
/* Size in bytes of each character index (CHIX section)
278
entry in the font file. */
279
#define FONT_CHAR_INDEX_ENTRY_SIZE (4 + 1 + 4)
281
/* Load the character index (CHIX) section contents from the font file. This
282
presumes that the position of FILE is positioned immediately after the
283
section length for the CHIX section (i.e., at the start of the section
284
contents). Returns 0 upon success, nonzero for failure (in which case
285
grub_errno is set appropriately). */
287
load_font_index (grub_file_t file, grub_uint32_t sect_length, struct
291
grub_uint32_t last_code;
294
grub_printf ("load_font_index(sect_length=%d)\n", sect_length);
297
/* Sanity check: ensure section length is divisible by the entry size. */
298
if ((sect_length % FONT_CHAR_INDEX_ENTRY_SIZE) != 0)
300
grub_error (GRUB_ERR_BAD_FONT,
301
"font file format error: character index length %d "
302
"is not a multiple of the entry size %d",
303
sect_length, FONT_CHAR_INDEX_ENTRY_SIZE);
307
/* Calculate the number of characters. */
308
font->num_chars = sect_length / FONT_CHAR_INDEX_ENTRY_SIZE;
310
/* Allocate the character index array. */
311
font->char_index = grub_malloc (font->num_chars
312
* sizeof (struct char_index_entry));
313
if (!font->char_index)
315
font->bmp_idx = grub_malloc (0x10000 * sizeof (grub_uint16_t));
318
grub_free (font->char_index);
321
grub_memset (font->bmp_idx, 0xff, 0x10000 * sizeof (grub_uint16_t));
325
grub_printf ("num_chars=%d)\n", font->num_chars);
330
/* Load the character index data from the file. */
331
for (i = 0; i < font->num_chars; i++)
333
struct char_index_entry *entry = &font->char_index[i];
335
/* Read code point value; convert to native byte order. */
336
if (grub_file_read (file, &entry->code, 4) != 4)
338
entry->code = grub_be_to_cpu32 (entry->code);
340
/* Verify that characters are in ascending order. */
341
if (i != 0 && entry->code <= last_code)
343
grub_error (GRUB_ERR_BAD_FONT,
344
"font characters not in ascending order: %u <= %u",
345
entry->code, last_code);
349
if (entry->code < 0x10000)
350
font->bmp_idx[entry->code] = i;
352
last_code = entry->code;
354
/* Read storage flags byte. */
355
if (grub_file_read (file, &entry->storage_flags, 1) != 1)
358
/* Read glyph data offset; convert to native byte order. */
359
if (grub_file_read (file, &entry->offset, 4) != 4)
361
entry->offset = grub_be_to_cpu32 (entry->offset);
363
/* No glyph loaded. Will be loaded on demand and cached thereafter. */
367
/* Print the 1st 10 characters. */
369
grub_printf ("c=%d o=%d\n", entry->code, entry->offset);
376
/* Read the contents of the specified section as a string, which is
377
allocated on the heap. Returns 0 if there is an error. */
379
read_section_as_string (struct font_file_section *section)
384
str = grub_malloc (section->length + 1);
388
ret = grub_file_read (section->file, str, section->length);
389
if (ret < 0 || ret != (grub_ssize_t) section->length)
395
str[section->length] = '\0';
399
/* Read the contents of the current section as a 16-bit integer value,
400
which is stored into *VALUE.
401
Returns 0 upon success, nonzero upon failure. */
403
read_section_as_short (struct font_file_section *section,
404
grub_int16_t * value)
406
grub_uint16_t raw_value;
408
if (section->length != 2)
410
grub_error (GRUB_ERR_BAD_FONT,
411
"font file format error: section %c%c%c%c length "
412
"is %d but should be 2",
413
section->name[0], section->name[1],
414
section->name[2], section->name[3], section->length);
417
if (grub_file_read (section->file, &raw_value, 2) != 2)
420
*value = grub_be_to_cpu16 (raw_value);
424
/* Load a font and add it to the beginning of the global font list.
425
Returns 0 upon success, nonzero upon failure. */
427
grub_font_load (const char *filename)
429
grub_file_t file = 0;
430
struct font_file_section section;
432
grub_font_t font = 0;
435
grub_printf ("add_font(%s)\n", filename);
438
file = grub_buffile_open (filename, 1024);
443
grub_printf ("file opened\n");
446
/* Read the FILE section. It indicates the file format. */
447
if (open_section (file, §ion) != 0)
451
grub_printf ("opened FILE section\n");
453
if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_FILE,
454
sizeof (FONT_FORMAT_SECTION_NAMES_FILE) - 1) != 0)
456
grub_error (GRUB_ERR_BAD_FONT,
457
"font file format error: 1st section must be FILE");
462
grub_printf ("section name ok\n");
464
if (section.length != 4)
466
grub_error (GRUB_ERR_BAD_FONT,
467
"font file format error (file type ID length is %d "
468
"but should be 4)", section.length);
473
grub_printf ("section length ok\n");
475
/* Check the file format type code. */
476
if (grub_file_read (file, magic, 4) != 4)
480
grub_printf ("read magic ok\n");
483
if (grub_memcmp (magic, FONT_FORMAT_PFF2_MAGIC, 4) != 0)
485
grub_error (GRUB_ERR_BAD_FONT, "invalid font magic %x %x %x %x",
486
magic[0], magic[1], magic[2], magic[3]);
491
grub_printf ("compare magic ok\n");
494
/* Allocate the font object. */
495
font = (grub_font_t) grub_malloc (sizeof (struct grub_font));
503
grub_printf ("allocate font ok; loading font info\n");
506
/* Load the font information. */
509
if (open_section (file, §ion) != 0)
512
break; /* Done reading the font file. */
518
grub_printf ("opened section %c%c%c%c ok\n",
519
section.name[0], section.name[1],
520
section.name[2], section.name[3]);
523
if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_FONT_NAME,
524
sizeof (FONT_FORMAT_SECTION_NAMES_FONT_NAME) - 1) == 0)
526
font->name = read_section_as_string (§ion);
530
else if (grub_memcmp (section.name,
531
FONT_FORMAT_SECTION_NAMES_POINT_SIZE,
532
sizeof (FONT_FORMAT_SECTION_NAMES_POINT_SIZE) -
535
if (read_section_as_short (§ion, &font->point_size) != 0)
538
else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_WEIGHT,
539
sizeof (FONT_FORMAT_SECTION_NAMES_WEIGHT) - 1)
543
wt = read_section_as_string (§ion);
546
/* Convert the weight string 'normal' or 'bold' into a number. */
547
if (grub_strcmp (wt, "normal") == 0)
548
font->weight = FONT_WEIGHT_NORMAL;
549
else if (grub_strcmp (wt, "bold") == 0)
550
font->weight = FONT_WEIGHT_BOLD;
553
else if (grub_memcmp (section.name,
554
FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH,
555
sizeof (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH)
558
if (read_section_as_short (§ion, &font->max_char_width) != 0)
561
else if (grub_memcmp (section.name,
562
FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT,
563
sizeof (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT)
566
if (read_section_as_short (§ion, &font->max_char_height) != 0)
569
else if (grub_memcmp (section.name,
570
FONT_FORMAT_SECTION_NAMES_ASCENT,
571
sizeof (FONT_FORMAT_SECTION_NAMES_ASCENT) - 1)
574
if (read_section_as_short (§ion, &font->ascent) != 0)
577
else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_DESCENT,
578
sizeof (FONT_FORMAT_SECTION_NAMES_DESCENT) - 1)
581
if (read_section_as_short (§ion, &font->descent) != 0)
584
else if (grub_memcmp (section.name,
585
FONT_FORMAT_SECTION_NAMES_CHAR_INDEX,
586
sizeof (FONT_FORMAT_SECTION_NAMES_CHAR_INDEX) -
589
if (load_font_index (file, section.length, font) != 0)
592
else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_DATA,
593
sizeof (FONT_FORMAT_SECTION_NAMES_DATA) - 1) == 0)
595
/* When the DATA section marker is reached, we stop reading. */
600
/* Unhandled section type, simply skip past it. */
602
grub_printf ("Unhandled section type, skipping.\n");
604
grub_off_t section_end = grub_file_tell (file) + section.length;
605
if ((int) grub_file_seek (file, section_end) == -1)
612
grub_printf ("Note: Font has no name.\n");
613
font->name = grub_strdup ("Unknown");
617
grub_printf ("Loaded font `%s'.\n"
618
"Ascent=%d Descent=%d MaxW=%d MaxH=%d Number of characters=%d.\n",
620
font->ascent, font->descent,
621
font->max_char_width, font->max_char_height, font->num_chars);
624
if (font->max_char_width == 0
625
|| font->max_char_height == 0
626
|| font->num_chars == 0
627
|| font->char_index == 0 || font->ascent == 0 || font->descent == 0)
629
grub_error (GRUB_ERR_BAD_FONT,
630
"invalid font file: missing some required data");
634
/* Add the font to the global font registry. */
635
if (register_font (font) != 0)
645
/* Read a 16-bit big-endian integer from FILE, convert it to native byte
646
order, and store it in *VALUE.
647
Returns 0 on success, 1 on failure. */
649
read_be_uint16 (grub_file_t file, grub_uint16_t * value)
651
if (grub_file_read (file, value, 2) != 2)
653
*value = grub_be_to_cpu16 (*value);
658
read_be_int16 (grub_file_t file, grub_int16_t * value)
660
/* For the signed integer version, use the same code as for unsigned. */
661
return read_be_uint16 (file, (grub_uint16_t *) value);
664
/* Return a pointer to the character index entry for the glyph corresponding to
665
the codepoint CODE in the font FONT. If not found, return zero. */
666
static inline struct char_index_entry *
667
find_glyph (const grub_font_t font, grub_uint32_t code)
669
struct char_index_entry *table;
674
table = font->char_index;
676
/* Use BMP index if possible. */
677
if (code < 0x10000 && font->bmp_idx)
679
if (font->bmp_idx[code] == 0xffff)
681
return &table[font->bmp_idx[code]];
684
/* Do a binary search in `char_index', which is ordered by code point. */
686
hi = font->num_chars - 1;
693
mid = lo + (hi - lo) / 2;
694
if (code < table[mid].code)
696
else if (code > table[mid].code)
705
/* Get a glyph for the Unicode character CODE in FONT. The glyph is loaded
706
from the font file if has not been loaded yet.
707
Returns a pointer to the glyph if found, or 0 if it is not found. */
708
static struct grub_font_glyph *
709
grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
711
struct char_index_entry *index_entry;
713
index_entry = find_glyph (font, code);
716
struct grub_font_glyph *glyph = 0;
718
grub_uint16_t height;
724
if (index_entry->glyph)
725
/* Return cached glyph. */
726
return index_entry->glyph;
729
/* No open file, can't load any glyphs. */
732
/* Make sure we can find glyphs for error messages. Push active
733
error message to error stack and reset error message. */
736
grub_file_seek (font->file, index_entry->offset);
738
/* Read the glyph width, height, and baseline. */
739
if (read_be_uint16 (font->file, &width) != 0
740
|| read_be_uint16 (font->file, &height) != 0
741
|| read_be_int16 (font->file, &xoff) != 0
742
|| read_be_int16 (font->file, &yoff) != 0
743
|| read_be_int16 (font->file, &dwidth) != 0)
749
len = (width * height + 7) / 8;
750
glyph = grub_malloc (sizeof (struct grub_font_glyph) + len);
758
glyph->width = width;
759
glyph->height = height;
760
glyph->offset_x = xoff;
761
glyph->offset_y = yoff;
762
glyph->device_width = dwidth;
764
/* Don't try to read empty bitmaps (e.g., space characters). */
767
if (grub_file_read (font->file, glyph->bitmap, len) != len)
774
/* Restore old error message. */
777
/* Cache the glyph. */
778
index_entry->glyph = glyph;
786
/* Free the memory used by FONT.
787
This should not be called if the font has been made available to
788
users (once it is added to the global font list), since there would
789
be the possibility of a dangling pointer. */
791
free_font (grub_font_t font)
796
grub_file_close (font->file);
797
grub_free (font->name);
798
grub_free (font->family);
799
grub_free (font->char_index);
804
/* Add FONT to the global font registry.
805
Returns 0 upon success, nonzero on failure
806
(the font was not registered). */
808
register_font (grub_font_t font)
810
struct grub_font_node *node = 0;
812
node = grub_malloc (sizeof (struct grub_font_node));
817
node->next = grub_font_list;
818
grub_font_list = node;
823
/* Remove the font from the global font list. We don't actually free the
824
font's memory since users could be holding references to the font. */
826
remove_font (grub_font_t font)
828
struct grub_font_node **nextp, *cur;
830
for (nextp = &grub_font_list, cur = *nextp;
831
cur; nextp = &cur->next, cur = cur->next)
833
if (cur->value == font)
837
/* Free the node, but not the font itself. */
845
/* Get a font from the list of loaded fonts. This function will return
846
another font if the requested font is not available. If no fonts are
847
loaded, then a special 'null font' is returned, which contains no glyphs,
848
but is not a null pointer so the caller may omit checks for NULL. */
850
grub_font_get (const char *font_name)
852
struct grub_font_node *node;
854
for (node = grub_font_list; node; node = node->next)
856
grub_font_t font = node->value;
857
if (grub_strcmp (font->name, font_name) == 0)
861
/* If no font by that name is found, return the first font in the list
863
if (grub_font_list && grub_font_list->value)
864
return grub_font_list->value;
866
/* The null_font is a last resort. */
870
/* Get the full name of the font. */
872
grub_font_get_name (grub_font_t font)
877
/* Get the maximum width of any character in the font in pixels. */
879
grub_font_get_max_char_width (grub_font_t font)
881
return font->max_char_width;
884
/* Get the maximum height of any character in the font in pixels. */
886
grub_font_get_max_char_height (grub_font_t font)
888
return font->max_char_height;
891
/* Get the distance in pixels from the top of characters to the baseline. */
893
grub_font_get_ascent (grub_font_t font)
898
/* Get the distance in pixels from the baseline to the lowest descenders
899
(for instance, in a lowercase 'y', 'g', etc.). */
901
grub_font_get_descent (grub_font_t font)
903
return font->descent;
906
/* FIXME: not correct for all fonts. */
908
grub_font_get_xheight (grub_font_t font)
910
return font->ascent / 2;
913
/* Get the *standard leading* of the font in pixel, which is the spacing
914
between two lines of text. Specifically, it is the space between the
915
descent of one line and the ascent of the next line. This is included
916
in the *height* metric. */
918
grub_font_get_leading (grub_font_t font)
920
return font->leading;
923
/* Get the distance in pixels between baselines of adjacent lines of text. */
925
grub_font_get_height (grub_font_t font)
927
return font->ascent + font->descent + font->leading;
930
/* Get the glyph for FONT corresponding to the Unicode code point CODE.
931
Returns the ASCII glyph for the code if no other fonts are available.
932
The glyphs are cached once loaded. */
933
struct grub_font_glyph *
934
grub_font_get_glyph (grub_font_t font, grub_uint32_t code)
936
struct grub_font_glyph *glyph = 0;
938
glyph = grub_font_get_glyph_internal (font, code);
941
glyph = ascii_glyph_lookup (code);
947
/* Calculate a subject value representing "how similar" two fonts are.
948
This is used to prioritize the order that fonts are scanned for missing
949
glyphs. The object is to select glyphs from the most similar font
950
possible, for the best appearance.
951
The heuristic is crude, but it helps greatly when fonts of similar
952
sizes are used so that tiny 8 point glyphs are not mixed into a string
953
of 24 point text unless there is no other choice. */
955
get_font_diversity (grub_font_t a, grub_font_t b)
961
if (a->ascent && b->ascent)
962
d += grub_abs (a->ascent - b->ascent) * 8;
964
/* Penalty for missing attributes. */
967
if (a->max_char_height && b->max_char_height)
968
d += grub_abs (a->max_char_height - b->max_char_height) * 8;
970
/* Penalty for missing attributes. */
973
/* Weight is a minor factor. */
974
d += (a->weight != b->weight) ? 5 : 0;
979
/* Get a glyph corresponding to the codepoint CODE. If FONT contains the
980
specified glyph, then it is returned. Otherwise, all other loaded fonts
981
are searched until one is found that contains a glyph for CODE.
982
If no glyph is available for CODE in the loaded fonts, then a glyph
983
representing an unknown character is returned.
984
This function never returns NULL.
985
The returned glyph is owned by the font manager and should not be freed
986
by the caller. The glyphs are cached. */
987
struct grub_font_glyph *
988
grub_font_get_glyph_with_fallback (grub_font_t font, grub_uint32_t code)
990
struct grub_font_glyph *glyph;
991
struct grub_font_node *node;
992
/* Keep track of next node, in case there's an I/O error in
993
grub_font_get_glyph_internal() and the font is removed from the list. */
994
struct grub_font_node *next;
995
/* Information on the best glyph found so far, to help find the glyph in
996
the best matching to the requested one. */
998
struct grub_font_glyph *best_glyph;
1002
/* First try to get the glyph from the specified font. */
1003
glyph = grub_font_get_glyph_internal (font, code);
1008
/* Otherwise, search all loaded fonts for the glyph and use the one from
1009
the font that best matches the requested font. */
1010
best_diversity = 10000;
1013
for (node = grub_font_list; node; node = next)
1015
grub_font_t curfont;
1017
curfont = node->value;
1020
glyph = grub_font_get_glyph_internal (curfont, code);
1027
d = get_font_diversity (curfont, font);
1028
if (d < best_diversity)
1039
static struct grub_font_glyph *
1040
grub_font_dup_glyph (struct grub_font_glyph *glyph)
1042
static struct grub_font_glyph *ret;
1043
ret = grub_malloc (sizeof (*ret) + (glyph->width * glyph->height + 7) / 8);
1046
grub_memcpy (ret, glyph, sizeof (*ret)
1047
+ (glyph->width * glyph->height + 7) / 8);
1051
/* FIXME: suboptimal. */
1053
grub_font_blit_glyph (struct grub_font_glyph *target,
1054
struct grub_font_glyph *src, unsigned dx, unsigned dy)
1056
unsigned src_bit, tgt_bit, src_byte, tgt_byte;
1058
for (i = 0; i < src->height; i++)
1060
src_bit = (src->width * i) % 8;
1061
src_byte = (src->width * i) / 8;
1062
tgt_bit = (target->width * (dy + i) + dx) % 8;
1063
tgt_byte = (target->width * (dy + i) + dx) / 8;
1064
for (j = 0; j < src->width; j++)
1066
target->bitmap[tgt_byte] |= ((src->bitmap[src_byte] << src_bit)
1085
grub_font_blit_glyph_mirror (struct grub_font_glyph *target,
1086
struct grub_font_glyph *src,
1087
unsigned dx, unsigned dy)
1089
unsigned tgt_bit, src_byte, tgt_byte;
1092
for (i = 0; i < src->height; i++)
1094
src_bit = (src->width * i + src->width - 1) % 8;
1095
src_byte = (src->width * i + src->width - 1) / 8;
1096
tgt_bit = (target->width * (dy + i) + dx) % 8;
1097
tgt_byte = (target->width * (dy + i) + dx) / 8;
1098
for (j = 0; j < src->width; j++)
1100
target->bitmap[tgt_byte] |= ((src->bitmap[src_byte] << src_bit)
1119
blit_comb (const struct grub_unicode_glyph *glyph_id,
1120
struct grub_font_glyph *glyph,
1121
struct grub_video_signed_rect *bounds_out,
1122
struct grub_font_glyph *main_glyph,
1123
struct grub_font_glyph **combining_glyphs, int *device_width)
1125
struct grub_video_signed_rect bounds;
1127
signed above_rightx, above_righty;
1128
signed above_leftx, above_lefty;
1129
signed below_rightx, below_righty;
1130
signed min_devwidth = 0;
1131
auto void NESTED_FUNC_ATTR do_blit (struct grub_font_glyph *src,
1132
signed dx, signed dy);
1133
void NESTED_FUNC_ATTR do_blit (struct grub_font_glyph *src,
1134
signed dx, signed dy)
1137
grub_font_blit_glyph (glyph, src, dx - glyph->offset_x,
1138
(glyph->height + glyph->offset_y) + dy);
1141
bounds.width += bounds.x - dx;
1144
if (bounds.y > -src->height - dy)
1146
bounds.height += bounds.y - (-src->height - dy);
1147
bounds.y = (-src->height - dy);
1149
if (dx + src->width - bounds.x >= (signed) bounds.width)
1150
bounds.width = dx + src->width - bounds.x + 1;
1151
if ((signed) bounds.height < src->height + (-src->height - dy) - bounds.y)
1152
bounds.height = src->height + (-src->height - dy) - bounds.y;
1155
auto void add_device_width (int val);
1156
void add_device_width (int val)
1159
glyph->device_width += val;
1161
*device_width += val;
1165
glyph->device_width = main_glyph->device_width;
1167
*device_width = main_glyph->device_width;
1169
bounds.x = main_glyph->offset_x;
1170
bounds.y = main_glyph->offset_y;
1171
bounds.width = main_glyph->width;
1172
bounds.height = main_glyph->height;
1174
above_rightx = main_glyph->offset_x + main_glyph->width;
1175
above_righty = bounds.y + bounds.height;
1177
above_leftx = main_glyph->offset_x;
1178
above_lefty = bounds.y + bounds.height;
1180
below_rightx = bounds.x + bounds.width;
1181
below_righty = bounds.y;
1183
for (i = 0; i < glyph_id->ncomb; i++)
1185
grub_int16_t space = 0;
1186
/* Center by default. */
1187
grub_int16_t targetx;
1189
if (!combining_glyphs[i])
1191
targetx = (bounds.width - combining_glyphs[i]->width) / 2 + bounds.x;
1192
/* CGJ is to avoid diacritics reordering. */
1193
if (glyph_id->combining[i].code
1194
== GRUB_UNICODE_COMBINING_GRAPHEME_JOINER)
1196
switch (glyph_id->combining[i].type)
1198
case GRUB_UNICODE_COMB_OVERLAY:
1199
do_blit (combining_glyphs[i],
1201
(bounds.height - combining_glyphs[i]->height) / 2
1202
- (bounds.height + bounds.y));
1203
if (min_devwidth < combining_glyphs[i]->width)
1204
min_devwidth = combining_glyphs[i]->width;
1207
case GRUB_UNICODE_COMB_ATTACHED_ABOVE_RIGHT:
1208
do_blit (combining_glyphs[i], above_rightx, -above_righty);
1209
above_rightx += combining_glyphs[i]->width;
1212
case GRUB_UNICODE_COMB_ABOVE_RIGHT:
1213
do_blit (combining_glyphs[i], above_rightx,
1214
-(above_righty + combining_glyphs[i]->height));
1215
above_rightx += combining_glyphs[i]->width;
1218
case GRUB_UNICODE_COMB_ABOVE_LEFT:
1219
above_leftx -= combining_glyphs[i]->width;
1220
do_blit (combining_glyphs[i], above_leftx,
1221
-(above_lefty + combining_glyphs[i]->height));
1224
case GRUB_UNICODE_COMB_BELOW_RIGHT:
1225
do_blit (combining_glyphs[i], below_rightx, below_righty);
1226
below_rightx += combining_glyphs[i]->width;
1229
case GRUB_UNICODE_COMB_HEBREW_HOLAM:
1230
if (glyph_id->base != GRUB_UNICODE_HEBREW_WAW)
1232
main_glyph->offset_x - combining_glyphs[i]->width -
1233
(combining_glyphs[i]->width + 3) / 4;
1236
case GRUB_UNICODE_COMB_HEBREW_SIN_DOT:
1237
targetx = main_glyph->offset_x + combining_glyphs[i]->width / 4;
1240
case GRUB_UNICODE_COMB_HEBREW_SHIN_DOT:
1242
main_glyph->width + main_glyph->offset_x -
1243
combining_glyphs[i]->width;
1245
space = combining_glyphs[i]->offset_y
1246
- grub_font_get_xheight (combining_glyphs[i]->font) - 1;
1248
space = 1 + (grub_font_get_xheight (main_glyph->font)) / 8;
1249
do_blit (combining_glyphs[i], targetx,
1250
-(main_glyph->height + main_glyph->offset_y + space
1251
+ combining_glyphs[i]->height));
1252
if (min_devwidth < combining_glyphs[i]->width)
1253
min_devwidth = combining_glyphs[i]->width;
1256
/* TODO: Put dammah, fathah and alif nearer to shadda. */
1257
case GRUB_UNICODE_COMB_SYRIAC_SUPERSCRIPT_ALAPH:
1258
case GRUB_UNICODE_COMB_ARABIC_DAMMAH:
1259
case GRUB_UNICODE_COMB_ARABIC_DAMMATAN:
1260
case GRUB_UNICODE_COMB_ARABIC_FATHATAN:
1261
case GRUB_UNICODE_COMB_ARABIC_FATHAH:
1262
case GRUB_UNICODE_COMB_ARABIC_SUPERSCRIPT_ALIF:
1263
case GRUB_UNICODE_COMB_ARABIC_SUKUN:
1264
case GRUB_UNICODE_COMB_ARABIC_SHADDA:
1265
case GRUB_UNICODE_COMB_HEBREW_RAFE:
1266
case GRUB_UNICODE_STACK_ABOVE:
1268
space = combining_glyphs[i]->offset_y
1269
- grub_font_get_xheight (combining_glyphs[i]->font) - 1;
1271
space = 1 + (grub_font_get_xheight (main_glyph->font)) / 8;
1273
case GRUB_UNICODE_STACK_ATTACHED_ABOVE:
1274
do_blit (combining_glyphs[i], targetx,
1275
-(bounds.height + bounds.y + space
1276
+ combining_glyphs[i]->height));
1277
if (min_devwidth < combining_glyphs[i]->width)
1278
min_devwidth = combining_glyphs[i]->width;
1281
case GRUB_UNICODE_COMB_HEBREW_SHEVA:
1282
case GRUB_UNICODE_COMB_HEBREW_HIRIQ:
1283
case GRUB_UNICODE_COMB_HEBREW_QAMATS:
1284
case GRUB_UNICODE_COMB_HEBREW_TSERE:
1285
case GRUB_UNICODE_COMB_HEBREW_SEGOL:
1286
/* TODO: placement in final kaf and under reish. */
1288
case GRUB_UNICODE_COMB_HEBREW_HATAF_SEGOL:
1289
case GRUB_UNICODE_COMB_HEBREW_HATAF_PATAH:
1290
case GRUB_UNICODE_COMB_HEBREW_HATAF_QAMATS:
1291
case GRUB_UNICODE_COMB_HEBREW_PATAH:
1292
case GRUB_UNICODE_COMB_HEBREW_QUBUTS:
1293
case GRUB_UNICODE_COMB_HEBREW_METEG:
1294
/* TODO: Put kasra and kasratan under shadda. */
1295
case GRUB_UNICODE_COMB_ARABIC_KASRA:
1296
case GRUB_UNICODE_COMB_ARABIC_KASRATAN:
1297
/* I don't know how ypogegrammeni differs from subscript. */
1298
case GRUB_UNICODE_COMB_YPOGEGRAMMENI:
1299
case GRUB_UNICODE_STACK_BELOW:
1301
space = -(combining_glyphs[i]->offset_y
1302
+ combining_glyphs[i]->height);
1304
space = 1 + (grub_font_get_xheight (main_glyph->font)) / 8;
1306
case GRUB_UNICODE_STACK_ATTACHED_BELOW:
1307
do_blit (combining_glyphs[i], targetx, -(bounds.y - space));
1308
if (min_devwidth < combining_glyphs[i]->width)
1309
min_devwidth = combining_glyphs[i]->width;
1312
case GRUB_UNICODE_COMB_MN:
1313
switch (glyph_id->combining[i].code)
1315
case GRUB_UNICODE_THAANA_ABAFILI:
1316
case GRUB_UNICODE_THAANA_AABAAFILI:
1317
case GRUB_UNICODE_THAANA_UBUFILI:
1318
case GRUB_UNICODE_THAANA_OOBOOFILI:
1319
case GRUB_UNICODE_THAANA_EBEFILI:
1320
case GRUB_UNICODE_THAANA_EYBEYFILI:
1321
case GRUB_UNICODE_THAANA_OBOFILI:
1322
case GRUB_UNICODE_THAANA_OABOAFILI:
1323
case GRUB_UNICODE_THAANA_SUKUN:
1325
case GRUB_UNICODE_THAANA_IBIFILI:
1326
case GRUB_UNICODE_THAANA_EEBEEFILI:
1332
/* Default handling. Just draw combining character on top
1334
FIXME: support more unicode types correctly.
1336
do_blit (combining_glyphs[i],
1337
main_glyph->device_width
1338
+ combining_glyphs[i]->offset_x,
1339
-(combining_glyphs[i]->height
1340
+ combining_glyphs[i]->offset_y));
1341
add_device_width (combining_glyphs[i]->device_width);
1345
add_device_width ((above_rightx >
1346
below_rightx ? above_rightx : below_rightx) -
1347
(main_glyph->offset_x + main_glyph->width));
1348
add_device_width (above_leftx - main_glyph->offset_x);
1349
if (glyph && glyph->device_width < min_devwidth)
1350
glyph->device_width = min_devwidth;
1351
if (device_width && *device_width < min_devwidth)
1352
*device_width = min_devwidth;
1355
*bounds_out = bounds;
1358
static struct grub_font_glyph *
1359
grub_font_construct_dry_run (grub_font_t hinted_font,
1360
const struct grub_unicode_glyph *glyph_id,
1361
struct grub_video_signed_rect *bounds,
1362
struct grub_font_glyph ***combining_glyphs_out,
1365
struct grub_font_glyph *main_glyph = NULL;
1366
struct grub_font_glyph **combining_glyphs;
1367
grub_uint32_t desired_attributes = 0;
1369
if (combining_glyphs_out)
1370
*combining_glyphs_out = NULL;
1372
if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED)
1373
desired_attributes |= GRUB_FONT_CODE_RIGHT_JOINED;
1375
if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED)
1376
desired_attributes |= GRUB_FONT_CODE_LEFT_JOINED;
1378
main_glyph = grub_font_get_glyph_with_fallback (hinted_font, glyph_id->base
1379
| desired_attributes);
1382
main_glyph = grub_font_get_glyph_with_fallback (hinted_font,
1385
/* Glyph not available in any font. Use ASCII fallback. */
1387
main_glyph = ascii_glyph_lookup (glyph_id->base);
1389
/* Glyph not available in any font. Return unknown glyph. */
1394
*device_width = main_glyph->device_width;
1396
if (!glyph_id->ncomb && !glyph_id->attributes)
1399
combining_glyphs = grub_malloc (sizeof (combining_glyphs[0])
1401
if (glyph_id->ncomb && !combining_glyphs)
1403
grub_errno = GRUB_ERR_NONE;
1409
for (i = 0; i < glyph_id->ncomb; i++)
1411
= grub_font_get_glyph_with_fallback (main_glyph->font,
1412
glyph_id->combining[i].code);
1415
blit_comb (glyph_id, NULL, bounds, main_glyph, combining_glyphs,
1417
if (combining_glyphs_out)
1418
*combining_glyphs_out = combining_glyphs;
1420
grub_free (combining_glyphs);
1426
grub_font_get_constructed_device_width (grub_font_t hinted_font,
1427
const struct grub_unicode_glyph
1431
struct grub_font_glyph *main_glyph;
1432
main_glyph = grub_font_construct_dry_run (hinted_font, glyph_id, NULL,
1435
return unknown_glyph->device_width;
1439
struct grub_font_glyph *
1440
grub_font_construct_glyph (grub_font_t hinted_font,
1441
const struct grub_unicode_glyph *glyph_id)
1443
struct grub_font_glyph *main_glyph;
1444
struct grub_video_signed_rect bounds;
1445
struct grub_font_glyph *glyph;
1446
struct grub_font_glyph **combining_glyphs;
1448
main_glyph = grub_font_construct_dry_run (hinted_font, glyph_id,
1449
&bounds, &combining_glyphs, NULL);
1452
return grub_font_dup_glyph (unknown_glyph);
1454
if (!combining_glyphs)
1455
return grub_font_dup_glyph (main_glyph);
1458
grub_zalloc (sizeof (*glyph) + (bounds.width * bounds.height + 7) / 8);
1461
grub_errno = GRUB_ERR_NONE;
1462
return grub_font_dup_glyph (main_glyph);
1465
glyph->font = main_glyph->font;
1466
glyph->width = bounds.width;
1467
glyph->height = bounds.height;
1468
glyph->offset_x = bounds.x;
1469
glyph->offset_y = bounds.y;
1471
if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR)
1472
grub_font_blit_glyph_mirror (glyph, main_glyph,
1473
main_glyph->offset_x - glyph->offset_x,
1474
(glyph->height + glyph->offset_y)
1475
- (main_glyph->height +
1476
main_glyph->offset_y));
1478
grub_font_blit_glyph (glyph, main_glyph,
1479
main_glyph->offset_x - glyph->offset_x,
1480
(glyph->height + glyph->offset_y)
1481
- (main_glyph->height + main_glyph->offset_y));
1483
blit_comb (glyph_id, glyph, NULL, main_glyph, combining_glyphs, NULL);
1488
/* Draw the specified glyph at (x, y). The y coordinate designates the
1489
baseline of the character, while the x coordinate designates the left
1490
side location of the character. */
1492
grub_font_draw_glyph (struct grub_font_glyph * glyph,
1493
grub_video_color_t color, int left_x, int baseline_y)
1495
struct grub_video_bitmap glyph_bitmap;
1497
/* Don't try to draw empty glyphs (U+0020, etc.). */
1498
if (glyph->width == 0 || glyph->height == 0)
1499
return GRUB_ERR_NONE;
1501
glyph_bitmap.mode_info.width = glyph->width;
1502
glyph_bitmap.mode_info.height = glyph->height;
1503
glyph_bitmap.mode_info.mode_type
1504
= (1 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP;
1505
glyph_bitmap.mode_info.blit_format = GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED;
1506
glyph_bitmap.mode_info.bpp = 1;
1508
/* Really 1 bit per pixel. */
1509
glyph_bitmap.mode_info.bytes_per_pixel = 0;
1511
/* Packed densely as bits. */
1512
glyph_bitmap.mode_info.pitch = glyph->width;
1514
glyph_bitmap.mode_info.number_of_colors = 2;
1515
glyph_bitmap.mode_info.bg_red = 0;
1516
glyph_bitmap.mode_info.bg_green = 0;
1517
glyph_bitmap.mode_info.bg_blue = 0;
1518
glyph_bitmap.mode_info.bg_alpha = 0;
1519
grub_video_unmap_color (color,
1520
&glyph_bitmap.mode_info.fg_red,
1521
&glyph_bitmap.mode_info.fg_green,
1522
&glyph_bitmap.mode_info.fg_blue,
1523
&glyph_bitmap.mode_info.fg_alpha);
1524
glyph_bitmap.data = glyph->bitmap;
1526
int bitmap_left = left_x + glyph->offset_x;
1527
int bitmap_bottom = baseline_y - glyph->offset_y;
1528
int bitmap_top = bitmap_bottom - glyph->height;
1530
return grub_video_blit_bitmap (&glyph_bitmap, GRUB_VIDEO_BLIT_BLEND,
1531
bitmap_left, bitmap_top,
1532
0, 0, glyph->width, glyph->height);