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>
34 GRUB_MOD_LICENSE ("GPLv3+");
44 struct char_index_entry
47 grub_uint8_t storage_flags
;
50 /* Glyph if loaded, or NULL otherwise. */
51 struct grub_font_glyph
*glyph
;
54 #define FONT_WEIGHT_NORMAL 100
55 #define FONT_WEIGHT_BOLD 200
56 #define ASCII_BITMAP_SIZE 16
58 /* Definition of font registry. */
59 struct grub_font_node
*grub_font_list
;
61 static int register_font (grub_font_t font
);
62 static void font_init (grub_font_t font
);
63 static void free_font (grub_font_t font
);
64 static void remove_font (grub_font_t font
);
66 struct font_file_section
68 /* The file this section is in. */
71 /* FOURCC name of the section. */
74 /* Length of the section contents. */
77 /* Set by open_section() on EOF. */
81 /* Replace unknown glyphs with a rounded question mark. */
82 static grub_uint8_t unknown_glyph_bitmap
[] = {
102 /* The "unknown glyph" glyph, used as a last resort. */
103 static struct grub_font_glyph
*unknown_glyph
;
105 /* The font structure used when no other font is loaded. This functions
106 as a "Null Object" pattern, so that code everywhere does not have to
107 check for a NULL grub_font_t to avoid dereferencing a null pointer. */
108 static struct grub_font null_font
;
110 /* Flag to ensure module is initialized only once. */
111 static grub_uint8_t font_loader_initialized
;
114 static struct grub_font_glyph
*ascii_font_glyph
[0x80];
117 static struct grub_font_glyph
*
118 ascii_glyph_lookup (grub_uint32_t code
)
121 static int ascii_failback_initialized
= 0;
126 if (ascii_failback_initialized
== 0)
129 for (current
= 0; current
< 0x80; current
++)
131 ascii_font_glyph
[current
] =
132 grub_malloc (sizeof (struct grub_font_glyph
) + ASCII_BITMAP_SIZE
);
134 ascii_font_glyph
[current
]->width
= 8;
135 ascii_font_glyph
[current
]->height
= 16;
136 ascii_font_glyph
[current
]->offset_x
= 0;
137 ascii_font_glyph
[current
]->offset_y
= -2;
138 ascii_font_glyph
[current
]->device_width
= 8;
139 ascii_font_glyph
[current
]->font
= NULL
;
141 grub_memcpy (ascii_font_glyph
[current
]->bitmap
,
142 &ascii_bitmaps
[current
* ASCII_BITMAP_SIZE
],
146 ascii_failback_initialized
= 1;
149 return ascii_font_glyph
[code
];
157 grub_font_loader_init (void)
159 /* Only initialize font loader once. */
160 if (font_loader_initialized
)
163 /* Make glyph for unknown glyph. */
164 unknown_glyph
= grub_malloc (sizeof (struct grub_font_glyph
)
165 + sizeof (unknown_glyph_bitmap
));
169 unknown_glyph
->width
= 8;
170 unknown_glyph
->height
= 16;
171 unknown_glyph
->offset_x
= 0;
172 unknown_glyph
->offset_y
= -3;
173 unknown_glyph
->device_width
= 8;
174 grub_memcpy (unknown_glyph
->bitmap
,
175 unknown_glyph_bitmap
, sizeof (unknown_glyph_bitmap
));
177 /* Initialize the null font. */
178 font_init (&null_font
);
179 /* FIXME: Fix this slightly improper cast. */
180 null_font
.name
= (char *) "<No Font>";
181 null_font
.ascent
= unknown_glyph
->height
- 3;
182 null_font
.descent
= 3;
183 null_font
.max_char_width
= unknown_glyph
->width
;
184 null_font
.max_char_height
= unknown_glyph
->height
;
186 font_loader_initialized
= 1;
189 /* Initialize the font object with initial default values. */
191 font_init (grub_font_t font
)
196 font
->point_size
= 0;
199 /* Default leading value, not in font file yet. */
202 font
->max_char_width
= 0;
203 font
->max_char_height
= 0;
207 font
->char_index
= 0;
211 /* Open the next section in the file.
213 On success, the section name is stored in section->name and the length in
214 section->length, and 0 is returned. On failure, 1 is returned and
215 grub_errno is set appropriately with an error message.
217 If 1 is returned due to being at the end of the file, then section->eof is
218 set to 1; otherwise, section->eof is set to 0. */
220 open_section (grub_file_t file
, struct font_file_section
*section
)
223 grub_uint32_t raw_length
;
225 section
->file
= file
;
228 /* Read the FOURCC section name. */
229 retval
= grub_file_read (file
, section
->name
, 4);
230 if (retval
>= 0 && retval
< 4)
232 /* EOF encountered. */
242 /* Read the big-endian 32-bit section length. */
243 retval
= grub_file_read (file
, &raw_length
, 4);
244 if (retval
>= 0 && retval
< 4)
246 /* EOF encountered. */
256 /* Convert byte-order and store in *length. */
257 section
->length
= grub_be_to_cpu32 (raw_length
);
262 /* Size in bytes of each character index (CHIX section)
263 entry in the font file. */
264 #define FONT_CHAR_INDEX_ENTRY_SIZE (4 + 1 + 4)
266 /* Load the character index (CHIX) section contents from the font file. This
267 presumes that the position of FILE is positioned immediately after the
268 section length for the CHIX section (i.e., at the start of the section
269 contents). Returns 0 upon success, nonzero for failure (in which case
270 grub_errno is set appropriately). */
272 load_font_index (grub_file_t file
, grub_uint32_t sect_length
, struct
276 grub_uint32_t last_code
;
279 grub_dprintf ("font", "load_font_index(sect_length=%d)\n", sect_length
);
282 /* Sanity check: ensure section length is divisible by the entry size. */
283 if ((sect_length
% FONT_CHAR_INDEX_ENTRY_SIZE
) != 0)
285 grub_error (GRUB_ERR_BAD_FONT
,
286 "font file format error: character index length %d "
287 "is not a multiple of the entry size %d",
288 sect_length
, FONT_CHAR_INDEX_ENTRY_SIZE
);
292 /* Calculate the number of characters. */
293 font
->num_chars
= sect_length
/ FONT_CHAR_INDEX_ENTRY_SIZE
;
295 /* Allocate the character index array. */
296 font
->char_index
= grub_malloc (font
->num_chars
297 * sizeof (struct char_index_entry
));
298 if (!font
->char_index
)
300 font
->bmp_idx
= grub_malloc (0x10000 * sizeof (grub_uint16_t
));
303 grub_memset (font
->bmp_idx
, 0xff, 0x10000 * sizeof (grub_uint16_t
));
307 grub_dprintf ("font", "num_chars=%d)\n", font
->num_chars
);
312 /* Load the character index data from the file. */
313 for (i
= 0; i
< font
->num_chars
; i
++)
315 struct char_index_entry
*entry
= &font
->char_index
[i
];
317 /* Read code point value; convert to native byte order. */
318 if (grub_file_read (file
, &entry
->code
, 4) != 4)
320 entry
->code
= grub_be_to_cpu32 (entry
->code
);
322 /* Verify that characters are in ascending order. */
323 if (i
!= 0 && entry
->code
<= last_code
)
325 grub_error (GRUB_ERR_BAD_FONT
,
326 "font characters not in ascending order: %u <= %u",
327 entry
->code
, last_code
);
331 if (entry
->code
< 0x10000)
332 font
->bmp_idx
[entry
->code
] = i
;
334 last_code
= entry
->code
;
336 /* Read storage flags byte. */
337 if (grub_file_read (file
, &entry
->storage_flags
, 1) != 1)
340 /* Read glyph data offset; convert to native byte order. */
341 if (grub_file_read (file
, &entry
->offset
, 4) != 4)
343 entry
->offset
= grub_be_to_cpu32 (entry
->offset
);
345 /* No glyph loaded. Will be loaded on demand and cached thereafter. */
349 /* Print the 1st 10 characters. */
351 grub_dprintf ("font", "c=%d o=%d\n", entry
->code
, entry
->offset
);
358 /* Read the contents of the specified section as a string, which is
359 allocated on the heap. Returns 0 if there is an error. */
361 read_section_as_string (struct font_file_section
*section
)
366 str
= grub_malloc (section
->length
+ 1);
370 ret
= grub_file_read (section
->file
, str
, section
->length
);
371 if (ret
< 0 || ret
!= (grub_ssize_t
) section
->length
)
377 str
[section
->length
] = '\0';
381 /* Read the contents of the current section as a 16-bit integer value,
382 which is stored into *VALUE.
383 Returns 0 upon success, nonzero upon failure. */
385 read_section_as_short (struct font_file_section
*section
,
386 grub_int16_t
* value
)
388 grub_uint16_t raw_value
;
390 if (section
->length
!= 2)
392 grub_error (GRUB_ERR_BAD_FONT
,
393 "font file format error: section %c%c%c%c length "
394 "is %d but should be 2",
395 section
->name
[0], section
->name
[1],
396 section
->name
[2], section
->name
[3], section
->length
);
399 if (grub_file_read (section
->file
, &raw_value
, 2) != 2)
402 *value
= grub_be_to_cpu16 (raw_value
);
406 /* Load a font and add it to the beginning of the global font list.
407 Returns 0 upon success, nonzero upon failure. */
409 grub_font_load (const char *filename
)
411 grub_file_t file
= 0;
412 struct font_file_section section
;
414 grub_font_t font
= 0;
417 grub_dprintf ("font", "add_font(%s)\n", filename
);
420 if (filename
[0] == '(' || filename
[0] == '/' || filename
[0] == '+')
421 file
= grub_buffile_open (filename
, 1024);
424 const char *prefix
= grub_env_get ("prefix");
425 char *fullname
, *ptr
;
428 grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("variable `%s' isn't set"),
432 fullname
= grub_malloc (grub_strlen (prefix
) + grub_strlen (filename
) + 1
433 + sizeof ("/fonts/") + sizeof (".pf2"));
436 ptr
= grub_stpcpy (fullname
, prefix
);
437 ptr
= grub_stpcpy (ptr
, "/fonts/");
438 ptr
= grub_stpcpy (ptr
, filename
);
439 ptr
= grub_stpcpy (ptr
, ".pf2");
441 file
= grub_buffile_open (fullname
, 1024);
442 grub_free (fullname
);
448 grub_dprintf ("font", "file opened\n");
451 /* Read the FILE section. It indicates the file format. */
452 if (open_section (file
, §ion
) != 0)
456 grub_dprintf ("font", "opened FILE section\n");
458 if (grub_memcmp (section
.name
, FONT_FORMAT_SECTION_NAMES_FILE
,
459 sizeof (FONT_FORMAT_SECTION_NAMES_FILE
) - 1) != 0)
461 grub_error (GRUB_ERR_BAD_FONT
,
462 "font file format error: 1st section must be FILE");
467 grub_dprintf ("font", "section name ok\n");
469 if (section
.length
!= 4)
471 grub_error (GRUB_ERR_BAD_FONT
,
472 "font file format error (file type ID length is %d "
473 "but should be 4)", section
.length
);
478 grub_dprintf ("font", "section length ok\n");
480 /* Check the file format type code. */
481 if (grub_file_read (file
, magic
, 4) != 4)
485 grub_dprintf ("font", "read magic ok\n");
488 if (grub_memcmp (magic
, FONT_FORMAT_PFF2_MAGIC
, 4) != 0)
490 grub_error (GRUB_ERR_BAD_FONT
, "invalid font magic %x %x %x %x",
491 magic
[0], magic
[1], magic
[2], magic
[3]);
496 grub_dprintf ("font", "compare magic ok\n");
499 /* Allocate the font object. */
500 font
= (grub_font_t
) grub_zalloc (sizeof (struct grub_font
));
508 grub_dprintf ("font", "allocate font ok; loading font info\n");
511 /* Load the font information. */
514 if (open_section (file
, §ion
) != 0)
517 break; /* Done reading the font file. */
523 grub_dprintf ("font", "opened section %c%c%c%c ok\n",
524 section
.name
[0], section
.name
[1],
525 section
.name
[2], section
.name
[3]);
528 if (grub_memcmp (section
.name
, FONT_FORMAT_SECTION_NAMES_FONT_NAME
,
529 sizeof (FONT_FORMAT_SECTION_NAMES_FONT_NAME
) - 1) == 0)
531 font
->name
= read_section_as_string (§ion
);
535 else if (grub_memcmp (section
.name
,
536 FONT_FORMAT_SECTION_NAMES_POINT_SIZE
,
537 sizeof (FONT_FORMAT_SECTION_NAMES_POINT_SIZE
) -
540 if (read_section_as_short (§ion
, &font
->point_size
) != 0)
543 else if (grub_memcmp (section
.name
, FONT_FORMAT_SECTION_NAMES_WEIGHT
,
544 sizeof (FONT_FORMAT_SECTION_NAMES_WEIGHT
) - 1)
548 wt
= read_section_as_string (§ion
);
551 /* Convert the weight string 'normal' or 'bold' into a number. */
552 if (grub_strcmp (wt
, "normal") == 0)
553 font
->weight
= FONT_WEIGHT_NORMAL
;
554 else if (grub_strcmp (wt
, "bold") == 0)
555 font
->weight
= FONT_WEIGHT_BOLD
;
558 else if (grub_memcmp (section
.name
,
559 FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH
,
560 sizeof (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH
)
563 if (read_section_as_short (§ion
, &font
->max_char_width
) != 0)
566 else if (grub_memcmp (section
.name
,
567 FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT
,
568 sizeof (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT
)
571 if (read_section_as_short (§ion
, &font
->max_char_height
) != 0)
574 else if (grub_memcmp (section
.name
,
575 FONT_FORMAT_SECTION_NAMES_ASCENT
,
576 sizeof (FONT_FORMAT_SECTION_NAMES_ASCENT
) - 1)
579 if (read_section_as_short (§ion
, &font
->ascent
) != 0)
582 else if (grub_memcmp (section
.name
, FONT_FORMAT_SECTION_NAMES_DESCENT
,
583 sizeof (FONT_FORMAT_SECTION_NAMES_DESCENT
) - 1)
586 if (read_section_as_short (§ion
, &font
->descent
) != 0)
589 else if (grub_memcmp (section
.name
,
590 FONT_FORMAT_SECTION_NAMES_CHAR_INDEX
,
591 sizeof (FONT_FORMAT_SECTION_NAMES_CHAR_INDEX
) -
594 if (load_font_index (file
, section
.length
, font
) != 0)
597 else if (grub_memcmp (section
.name
, FONT_FORMAT_SECTION_NAMES_DATA
,
598 sizeof (FONT_FORMAT_SECTION_NAMES_DATA
) - 1) == 0)
600 /* When the DATA section marker is reached, we stop reading. */
605 /* Unhandled section type, simply skip past it. */
607 grub_dprintf ("font", "Unhandled section type, skipping.\n");
609 grub_off_t section_end
= grub_file_tell (file
) + section
.length
;
610 if ((int) grub_file_seek (file
, section_end
) == -1)
617 grub_dprintf ("font", "Font has no name.\n");
618 font
->name
= grub_strdup ("Unknown");
622 grub_dprintf ("font", "Loaded font `%s'.\n"
623 "Ascent=%d Descent=%d MaxW=%d MaxH=%d Number of characters=%d.\n",
625 font
->ascent
, font
->descent
,
626 font
->max_char_width
, font
->max_char_height
, font
->num_chars
);
629 if (font
->max_char_width
== 0
630 || font
->max_char_height
== 0
631 || font
->num_chars
== 0
632 || font
->char_index
== 0 || font
->ascent
== 0 || font
->descent
== 0)
634 grub_error (GRUB_ERR_BAD_FONT
,
635 "invalid font file: missing some required data");
639 /* Add the font to the global font registry. */
640 if (register_font (font
) != 0)
647 grub_file_close (file
);
655 /* Read a 16-bit big-endian integer from FILE, convert it to native byte
656 order, and store it in *VALUE.
657 Returns 0 on success, 1 on failure. */
659 read_be_uint16 (grub_file_t file
, grub_uint16_t
* value
)
661 if (grub_file_read (file
, value
, 2) != 2)
663 *value
= grub_be_to_cpu16 (*value
);
668 read_be_int16 (grub_file_t file
, grub_int16_t
* value
)
670 /* For the signed integer version, use the same code as for unsigned. */
671 return read_be_uint16 (file
, (grub_uint16_t
*) value
);
674 /* Return a pointer to the character index entry for the glyph corresponding to
675 the codepoint CODE in the font FONT. If not found, return zero. */
676 static inline struct char_index_entry
*
677 find_glyph (const grub_font_t font
, grub_uint32_t code
)
679 struct char_index_entry
*table
;
684 table
= font
->char_index
;
686 /* Use BMP index if possible. */
687 if (code
< 0x10000 && font
->bmp_idx
)
689 if (font
->bmp_idx
[code
] == 0xffff)
691 return &table
[font
->bmp_idx
[code
]];
694 /* Do a binary search in `char_index', which is ordered by code point. */
696 hi
= font
->num_chars
- 1;
703 mid
= lo
+ (hi
- lo
) / 2;
704 if (code
< table
[mid
].code
)
706 else if (code
> table
[mid
].code
)
715 /* Get a glyph for the Unicode character CODE in FONT. The glyph is loaded
716 from the font file if has not been loaded yet.
717 Returns a pointer to the glyph if found, or 0 if it is not found. */
718 static struct grub_font_glyph
*
719 grub_font_get_glyph_internal (grub_font_t font
, grub_uint32_t code
)
721 struct char_index_entry
*index_entry
;
723 index_entry
= find_glyph (font
, code
);
726 struct grub_font_glyph
*glyph
= 0;
728 grub_uint16_t height
;
734 if (index_entry
->glyph
)
735 /* Return cached glyph. */
736 return index_entry
->glyph
;
739 /* No open file, can't load any glyphs. */
742 /* Make sure we can find glyphs for error messages. Push active
743 error message to error stack and reset error message. */
746 grub_file_seek (font
->file
, index_entry
->offset
);
748 /* Read the glyph width, height, and baseline. */
749 if (read_be_uint16 (font
->file
, &width
) != 0
750 || read_be_uint16 (font
->file
, &height
) != 0
751 || read_be_int16 (font
->file
, &xoff
) != 0
752 || read_be_int16 (font
->file
, &yoff
) != 0
753 || read_be_int16 (font
->file
, &dwidth
) != 0)
759 len
= (width
* height
+ 7) / 8;
760 glyph
= grub_malloc (sizeof (struct grub_font_glyph
) + len
);
768 glyph
->width
= width
;
769 glyph
->height
= height
;
770 glyph
->offset_x
= xoff
;
771 glyph
->offset_y
= yoff
;
772 glyph
->device_width
= dwidth
;
774 /* Don't try to read empty bitmaps (e.g., space characters). */
777 if (grub_file_read (font
->file
, glyph
->bitmap
, len
) != len
)
785 /* Restore old error message. */
788 /* Cache the glyph. */
789 index_entry
->glyph
= glyph
;
797 /* Free the memory used by FONT.
798 This should not be called if the font has been made available to
799 users (once it is added to the global font list), since there would
800 be the possibility of a dangling pointer. */
802 free_font (grub_font_t font
)
807 grub_file_close (font
->file
);
808 grub_free (font
->name
);
809 grub_free (font
->family
);
810 grub_free (font
->char_index
);
811 grub_free (font
->bmp_idx
);
816 /* Add FONT to the global font registry.
817 Returns 0 upon success, nonzero on failure
818 (the font was not registered). */
820 register_font (grub_font_t font
)
822 struct grub_font_node
*node
= 0;
824 node
= grub_malloc (sizeof (struct grub_font_node
));
829 node
->next
= grub_font_list
;
830 grub_font_list
= node
;
835 /* Remove the font from the global font list. We don't actually free the
836 font's memory since users could be holding references to the font. */
838 remove_font (grub_font_t font
)
840 struct grub_font_node
**nextp
, *cur
;
842 for (nextp
= &grub_font_list
, cur
= *nextp
;
843 cur
; nextp
= &cur
->next
, cur
= cur
->next
)
845 if (cur
->value
== font
)
849 /* Free the node, but not the font itself. */
857 /* Get a font from the list of loaded fonts. This function will return
858 another font if the requested font is not available. If no fonts are
859 loaded, then a special 'null font' is returned, which contains no glyphs,
860 but is not a null pointer so the caller may omit checks for NULL. */
862 grub_font_get (const char *font_name
)
864 struct grub_font_node
*node
;
866 for (node
= grub_font_list
; node
; node
= node
->next
)
868 grub_font_t font
= node
->value
;
869 if (grub_strcmp (font
->name
, font_name
) == 0)
873 /* If no font by that name is found, return the first font in the list
875 if (grub_font_list
&& grub_font_list
->value
)
876 return grub_font_list
->value
;
878 /* The null_font is a last resort. */
882 /* Get the full name of the font. */
884 grub_font_get_name (grub_font_t font
)
889 /* Get the maximum width of any character in the font in pixels. */
891 grub_font_get_max_char_width (grub_font_t font
)
893 return font
->max_char_width
;
896 /* Get the distance in pixels from the baseline to the lowest descenders
897 (for instance, in a lowercase 'y', 'g', etc.). */
899 grub_font_get_descent (grub_font_t font
)
901 return font
->descent
;
904 /* FIXME: not correct for all fonts. */
906 grub_font_get_xheight (grub_font_t font
)
908 return font
->ascent
/ 2;
911 /* Get the *standard leading* of the font in pixel, which is the spacing
912 between two lines of text. Specifically, it is the space between the
913 descent of one line and the ascent of the next line. This is included
914 in the *height* metric. */
916 grub_font_get_leading (grub_font_t font
)
918 return font
->leading
;
921 /* Get the distance in pixels between baselines of adjacent lines of text. */
923 grub_font_get_height (grub_font_t font
)
925 return font
->ascent
+ font
->descent
+ font
->leading
;
928 /* Get the glyph for FONT corresponding to the Unicode code point CODE.
929 Returns the ASCII glyph for the code if no other fonts are available.
930 The glyphs are cached once loaded. */
931 struct grub_font_glyph
*
932 grub_font_get_glyph (grub_font_t font
, grub_uint32_t code
)
934 struct grub_font_glyph
*glyph
= 0;
936 glyph
= grub_font_get_glyph_internal (font
, code
);
939 glyph
= ascii_glyph_lookup (code
);
945 /* Calculate a subject value representing "how similar" two fonts are.
946 This is used to prioritize the order that fonts are scanned for missing
947 glyphs. The object is to select glyphs from the most similar font
948 possible, for the best appearance.
949 The heuristic is crude, but it helps greatly when fonts of similar
950 sizes are used so that tiny 8 point glyphs are not mixed into a string
951 of 24 point text unless there is no other choice. */
953 get_font_diversity (grub_font_t a
, grub_font_t b
)
959 if (a
->ascent
&& b
->ascent
)
960 d
+= grub_abs (a
->ascent
- b
->ascent
) * 8;
962 /* Penalty for missing attributes. */
965 if (a
->max_char_height
&& b
->max_char_height
)
966 d
+= grub_abs (a
->max_char_height
- b
->max_char_height
) * 8;
968 /* Penalty for missing attributes. */
971 /* Weight is a minor factor. */
972 d
+= (a
->weight
!= b
->weight
) ? 5 : 0;
977 /* Get a glyph corresponding to the codepoint CODE. If FONT contains the
978 specified glyph, then it is returned. Otherwise, all other loaded fonts
979 are searched until one is found that contains a glyph for CODE.
980 If no glyph is available for CODE in the loaded fonts, then a glyph
981 representing an unknown character is returned.
982 This function never returns NULL.
983 The returned glyph is owned by the font manager and should not be freed
984 by the caller. The glyphs are cached. */
985 struct grub_font_glyph
*
986 grub_font_get_glyph_with_fallback (grub_font_t font
, grub_uint32_t code
)
988 struct grub_font_glyph
*glyph
;
989 struct grub_font_node
*node
;
990 /* Keep track of next node, in case there's an I/O error in
991 grub_font_get_glyph_internal() and the font is removed from the list. */
992 struct grub_font_node
*next
;
993 /* Information on the best glyph found so far, to help find the glyph in
994 the best matching to the requested one. */
996 struct grub_font_glyph
*best_glyph
;
1000 /* First try to get the glyph from the specified font. */
1001 glyph
= grub_font_get_glyph_internal (font
, code
);
1006 /* Otherwise, search all loaded fonts for the glyph and use the one from
1007 the font that best matches the requested font. */
1008 best_diversity
= 10000;
1011 for (node
= grub_font_list
; node
; node
= next
)
1013 grub_font_t curfont
;
1015 curfont
= node
->value
;
1018 glyph
= grub_font_get_glyph_internal (curfont
, code
);
1025 d
= get_font_diversity (curfont
, font
);
1026 if (d
< best_diversity
)
1038 static struct grub_font_glyph
*
1039 grub_font_dup_glyph (struct grub_font_glyph
*glyph
)
1041 static struct grub_font_glyph
*ret
;
1042 ret
= grub_malloc (sizeof (*ret
) + (glyph
->width
* glyph
->height
+ 7) / 8);
1045 grub_memcpy (ret
, glyph
, sizeof (*ret
)
1046 + (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
)
1118 /* Context for blit_comb. */
1119 struct blit_comb_ctx
1121 struct grub_font_glyph
*glyph
;
1123 struct grub_video_signed_rect bounds
;
1126 /* Helper for blit_comb. */
1128 do_blit (struct grub_font_glyph
*src
, signed dx
, signed dy
,
1129 struct blit_comb_ctx
*ctx
)
1132 grub_font_blit_glyph (ctx
->glyph
, src
, dx
- ctx
->glyph
->offset_x
,
1133 (ctx
->glyph
->height
+ ctx
->glyph
->offset_y
) + dy
);
1134 if (dx
< ctx
->bounds
.x
)
1136 ctx
->bounds
.width
+= ctx
->bounds
.x
- dx
;
1139 if (ctx
->bounds
.y
> -src
->height
- dy
)
1141 ctx
->bounds
.height
+= ctx
->bounds
.y
- (-src
->height
- dy
);
1142 ctx
->bounds
.y
= (-src
->height
- dy
);
1144 if (dx
+ src
->width
- ctx
->bounds
.x
>= (signed) ctx
->bounds
.width
)
1145 ctx
->bounds
.width
= dx
+ src
->width
- ctx
->bounds
.x
+ 1;
1146 if ((signed) ctx
->bounds
.height
< src
->height
+ (-src
->height
- dy
)
1148 ctx
->bounds
.height
= src
->height
+ (-src
->height
- dy
) - ctx
->bounds
.y
;
1151 /* Helper for blit_comb. */
1153 add_device_width (int val
, struct blit_comb_ctx
*ctx
)
1156 ctx
->glyph
->device_width
+= val
;
1157 if (ctx
->device_width
)
1158 *ctx
->device_width
+= val
;
1162 blit_comb (const struct grub_unicode_glyph
*glyph_id
,
1163 struct grub_font_glyph
*glyph
,
1164 struct grub_video_signed_rect
*bounds_out
,
1165 struct grub_font_glyph
*main_glyph
,
1166 struct grub_font_glyph
**combining_glyphs
, int *device_width
)
1168 struct blit_comb_ctx ctx
= {
1170 .device_width
= device_width
1173 signed above_rightx
, above_righty
;
1174 signed above_leftx
, above_lefty
;
1175 signed below_rightx
, below_righty
;
1176 signed min_devwidth
= 0;
1177 const struct grub_unicode_combining
*comb
;
1180 glyph
->device_width
= main_glyph
->device_width
;
1182 *device_width
= main_glyph
->device_width
;
1184 ctx
.bounds
.x
= main_glyph
->offset_x
;
1185 ctx
.bounds
.y
= main_glyph
->offset_y
;
1186 ctx
.bounds
.width
= main_glyph
->width
;
1187 ctx
.bounds
.height
= main_glyph
->height
;
1189 above_rightx
= main_glyph
->offset_x
+ main_glyph
->width
;
1190 above_righty
= ctx
.bounds
.y
+ ctx
.bounds
.height
;
1192 above_leftx
= main_glyph
->offset_x
;
1193 above_lefty
= ctx
.bounds
.y
+ ctx
.bounds
.height
;
1195 below_rightx
= ctx
.bounds
.x
+ ctx
.bounds
.width
;
1196 below_righty
= ctx
.bounds
.y
;
1198 comb
= grub_unicode_get_comb (glyph_id
);
1200 for (i
= 0; i
< glyph_id
->ncomb
; i
++)
1202 grub_int16_t space
= 0;
1203 /* Center by default. */
1204 grub_int16_t targetx
;
1206 if (!combining_glyphs
[i
])
1208 targetx
= (ctx
.bounds
.width
- combining_glyphs
[i
]->width
) / 2 + ctx
.bounds
.x
;
1209 /* CGJ is to avoid diacritics reordering. */
1211 == GRUB_UNICODE_COMBINING_GRAPHEME_JOINER
)
1213 switch (comb
[i
].type
)
1215 case GRUB_UNICODE_COMB_OVERLAY
:
1216 do_blit (combining_glyphs
[i
],
1218 (ctx
.bounds
.height
- combining_glyphs
[i
]->height
) / 2
1219 - (ctx
.bounds
.height
+ ctx
.bounds
.y
), &ctx
);
1220 if (min_devwidth
< combining_glyphs
[i
]->width
)
1221 min_devwidth
= combining_glyphs
[i
]->width
;
1224 case GRUB_UNICODE_COMB_ATTACHED_ABOVE_RIGHT
:
1225 do_blit (combining_glyphs
[i
], above_rightx
, -above_righty
, &ctx
);
1226 above_rightx
+= combining_glyphs
[i
]->width
;
1229 case GRUB_UNICODE_COMB_ABOVE_RIGHT
:
1230 do_blit (combining_glyphs
[i
], above_rightx
,
1231 -(above_righty
+ combining_glyphs
[i
]->height
), &ctx
);
1232 above_rightx
+= combining_glyphs
[i
]->width
;
1235 case GRUB_UNICODE_COMB_ABOVE_LEFT
:
1236 above_leftx
-= combining_glyphs
[i
]->width
;
1237 do_blit (combining_glyphs
[i
], above_leftx
,
1238 -(above_lefty
+ combining_glyphs
[i
]->height
), &ctx
);
1241 case GRUB_UNICODE_COMB_BELOW_RIGHT
:
1242 do_blit (combining_glyphs
[i
], below_rightx
, below_righty
, &ctx
);
1243 below_rightx
+= combining_glyphs
[i
]->width
;
1246 case GRUB_UNICODE_COMB_HEBREW_HOLAM
:
1247 if (glyph_id
->base
!= GRUB_UNICODE_HEBREW_WAW
)
1249 main_glyph
->offset_x
- combining_glyphs
[i
]->width
-
1250 (combining_glyphs
[i
]->width
+ 3) / 4;
1253 case GRUB_UNICODE_COMB_HEBREW_SIN_DOT
:
1254 targetx
= main_glyph
->offset_x
+ combining_glyphs
[i
]->width
/ 4;
1257 case GRUB_UNICODE_COMB_HEBREW_SHIN_DOT
:
1259 main_glyph
->width
+ main_glyph
->offset_x
-
1260 combining_glyphs
[i
]->width
;
1262 space
= combining_glyphs
[i
]->offset_y
1263 - grub_font_get_xheight (combining_glyphs
[i
]->font
) - 1;
1265 space
= 1 + (grub_font_get_xheight (main_glyph
->font
)) / 8;
1266 do_blit (combining_glyphs
[i
], targetx
,
1267 -(main_glyph
->height
+ main_glyph
->offset_y
+ space
1268 + combining_glyphs
[i
]->height
), &ctx
);
1269 if (min_devwidth
< combining_glyphs
[i
]->width
)
1270 min_devwidth
= combining_glyphs
[i
]->width
;
1273 /* TODO: Put dammah, fathah and alif nearer to shadda. */
1274 case GRUB_UNICODE_COMB_SYRIAC_SUPERSCRIPT_ALAPH
:
1275 case GRUB_UNICODE_COMB_ARABIC_DAMMAH
:
1276 case GRUB_UNICODE_COMB_ARABIC_DAMMATAN
:
1277 case GRUB_UNICODE_COMB_ARABIC_FATHATAN
:
1278 case GRUB_UNICODE_COMB_ARABIC_FATHAH
:
1279 case GRUB_UNICODE_COMB_ARABIC_SUPERSCRIPT_ALIF
:
1280 case GRUB_UNICODE_COMB_ARABIC_SUKUN
:
1281 case GRUB_UNICODE_COMB_ARABIC_SHADDA
:
1282 case GRUB_UNICODE_COMB_HEBREW_RAFE
:
1283 case GRUB_UNICODE_STACK_ABOVE
:
1285 space
= combining_glyphs
[i
]->offset_y
1286 - grub_font_get_xheight (combining_glyphs
[i
]->font
) - 1;
1288 space
= 1 + (grub_font_get_xheight (main_glyph
->font
)) / 8;
1290 case GRUB_UNICODE_STACK_ATTACHED_ABOVE
:
1291 do_blit (combining_glyphs
[i
], targetx
,
1292 -(ctx
.bounds
.height
+ ctx
.bounds
.y
+ space
1293 + combining_glyphs
[i
]->height
), &ctx
);
1294 if (min_devwidth
< combining_glyphs
[i
]->width
)
1295 min_devwidth
= combining_glyphs
[i
]->width
;
1298 case GRUB_UNICODE_COMB_HEBREW_DAGESH
:
1299 do_blit (combining_glyphs
[i
], targetx
,
1300 -(ctx
.bounds
.height
/ 2 + ctx
.bounds
.y
1301 + combining_glyphs
[i
]->height
/ 2), &ctx
);
1302 if (min_devwidth
< combining_glyphs
[i
]->width
)
1303 min_devwidth
= combining_glyphs
[i
]->width
;
1306 case GRUB_UNICODE_COMB_HEBREW_SHEVA
:
1307 case GRUB_UNICODE_COMB_HEBREW_HIRIQ
:
1308 case GRUB_UNICODE_COMB_HEBREW_QAMATS
:
1309 case GRUB_UNICODE_COMB_HEBREW_TSERE
:
1310 case GRUB_UNICODE_COMB_HEBREW_SEGOL
:
1311 /* TODO: placement in final kaf and under reish. */
1313 case GRUB_UNICODE_COMB_HEBREW_HATAF_SEGOL
:
1314 case GRUB_UNICODE_COMB_HEBREW_HATAF_PATAH
:
1315 case GRUB_UNICODE_COMB_HEBREW_HATAF_QAMATS
:
1316 case GRUB_UNICODE_COMB_HEBREW_PATAH
:
1317 case GRUB_UNICODE_COMB_HEBREW_QUBUTS
:
1318 case GRUB_UNICODE_COMB_HEBREW_METEG
:
1319 /* TODO: Put kasra and kasratan under shadda. */
1320 case GRUB_UNICODE_COMB_ARABIC_KASRA
:
1321 case GRUB_UNICODE_COMB_ARABIC_KASRATAN
:
1322 /* I don't know how ypogegrammeni differs from subscript. */
1323 case GRUB_UNICODE_COMB_YPOGEGRAMMENI
:
1324 case GRUB_UNICODE_STACK_BELOW
:
1326 space
= -(combining_glyphs
[i
]->offset_y
1327 + combining_glyphs
[i
]->height
);
1329 space
= 1 + (grub_font_get_xheight (main_glyph
->font
)) / 8;
1332 case GRUB_UNICODE_STACK_ATTACHED_BELOW
:
1333 do_blit (combining_glyphs
[i
], targetx
, -(ctx
.bounds
.y
- space
),
1335 if (min_devwidth
< combining_glyphs
[i
]->width
)
1336 min_devwidth
= combining_glyphs
[i
]->width
;
1339 case GRUB_UNICODE_COMB_MN
:
1340 switch (comb
[i
].code
)
1342 case GRUB_UNICODE_THAANA_ABAFILI
:
1343 case GRUB_UNICODE_THAANA_AABAAFILI
:
1344 case GRUB_UNICODE_THAANA_UBUFILI
:
1345 case GRUB_UNICODE_THAANA_OOBOOFILI
:
1346 case GRUB_UNICODE_THAANA_EBEFILI
:
1347 case GRUB_UNICODE_THAANA_EYBEYFILI
:
1348 case GRUB_UNICODE_THAANA_OBOFILI
:
1349 case GRUB_UNICODE_THAANA_OABOAFILI
:
1350 case GRUB_UNICODE_THAANA_SUKUN
:
1352 case GRUB_UNICODE_THAANA_IBIFILI
:
1353 case GRUB_UNICODE_THAANA_EEBEEFILI
:
1359 /* Default handling. Just draw combining character on top
1361 FIXME: support more unicode types correctly.
1363 do_blit (combining_glyphs
[i
],
1364 main_glyph
->device_width
1365 + combining_glyphs
[i
]->offset_x
,
1366 -(combining_glyphs
[i
]->height
1367 + combining_glyphs
[i
]->offset_y
), &ctx
);
1368 add_device_width (combining_glyphs
[i
]->device_width
, &ctx
);
1372 add_device_width ((above_rightx
>
1373 below_rightx
? above_rightx
: below_rightx
) -
1374 (main_glyph
->offset_x
+ main_glyph
->width
), &ctx
);
1375 add_device_width (above_leftx
- main_glyph
->offset_x
, &ctx
);
1376 if (glyph
&& glyph
->device_width
< min_devwidth
)
1377 glyph
->device_width
= min_devwidth
;
1378 if (device_width
&& *device_width
< min_devwidth
)
1379 *device_width
= min_devwidth
;
1382 *bounds_out
= ctx
.bounds
;
1385 static struct grub_font_glyph
*
1386 grub_font_construct_dry_run (grub_font_t hinted_font
,
1387 const struct grub_unicode_glyph
*glyph_id
,
1388 struct grub_video_signed_rect
*bounds
,
1389 struct grub_font_glyph
**combining_glyphs
,
1392 struct grub_font_glyph
*main_glyph
= NULL
;
1393 grub_uint32_t desired_attributes
= 0;
1395 grub_uint32_t base
= glyph_id
->base
;
1396 const struct grub_unicode_combining
*comb
;
1398 if (glyph_id
->attributes
& GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED
)
1399 desired_attributes
|= GRUB_FONT_CODE_RIGHT_JOINED
;
1401 if (glyph_id
->attributes
& GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED
)
1402 desired_attributes
|= GRUB_FONT_CODE_LEFT_JOINED
;
1404 comb
= grub_unicode_get_comb (glyph_id
);
1406 if (base
== 'i' || base
== 'j')
1408 for (i
= 0; i
< glyph_id
->ncomb
; i
++)
1409 if (comb
[i
].type
== GRUB_UNICODE_STACK_ABOVE
)
1411 if (i
< glyph_id
->ncomb
&& base
== 'i')
1412 base
= GRUB_UNICODE_DOTLESS_LOWERCASE_I
;
1413 if (i
< glyph_id
->ncomb
&& base
== 'j')
1414 base
= GRUB_UNICODE_DOTLESS_LOWERCASE_J
;
1417 main_glyph
= grub_font_get_glyph_with_fallback (hinted_font
, base
1418 | desired_attributes
);
1421 main_glyph
= grub_font_get_glyph_with_fallback (hinted_font
,
1424 /* Glyph not available in any font. Use ASCII fallback. */
1426 main_glyph
= ascii_glyph_lookup (base
);
1428 /* Glyph not available in any font. Return unknown glyph. */
1433 *device_width
= main_glyph
->device_width
;
1435 if (!glyph_id
->ncomb
&& !glyph_id
->attributes
)
1438 if (glyph_id
->ncomb
&& !combining_glyphs
)
1440 grub_errno
= GRUB_ERR_NONE
;
1444 for (i
= 0; i
< glyph_id
->ncomb
; i
++)
1446 = grub_font_get_glyph_with_fallback (main_glyph
->font
,
1449 blit_comb (glyph_id
, NULL
, bounds
, main_glyph
, combining_glyphs
,
1455 static struct grub_font_glyph
**render_combining_glyphs
= 0;
1456 static grub_size_t render_max_comb_glyphs
= 0;
1459 ensure_comb_space (const struct grub_unicode_glyph
*glyph_id
)
1461 if (glyph_id
->ncomb
<= render_max_comb_glyphs
)
1464 render_max_comb_glyphs
= 2 * glyph_id
->ncomb
;
1465 if (render_max_comb_glyphs
< 8)
1466 render_max_comb_glyphs
= 8;
1467 grub_free (render_combining_glyphs
);
1468 render_combining_glyphs
= grub_malloc (render_max_comb_glyphs
1469 * sizeof (render_combining_glyphs
[0]));
1470 if (!render_combining_glyphs
)
1475 grub_font_get_constructed_device_width (grub_font_t hinted_font
,
1476 const struct grub_unicode_glyph
1480 struct grub_font_glyph
*main_glyph
;
1482 ensure_comb_space (glyph_id
);
1484 main_glyph
= grub_font_construct_dry_run (hinted_font
, glyph_id
, NULL
,
1485 render_combining_glyphs
, &ret
);
1487 return unknown_glyph
->device_width
;
1491 struct grub_font_glyph
*
1492 grub_font_construct_glyph (grub_font_t hinted_font
,
1493 const struct grub_unicode_glyph
*glyph_id
)
1495 struct grub_font_glyph
*main_glyph
;
1496 struct grub_video_signed_rect bounds
;
1497 static struct grub_font_glyph
*glyph
= 0;
1498 static grub_size_t max_glyph_size
= 0;
1500 ensure_comb_space (glyph_id
);
1502 main_glyph
= grub_font_construct_dry_run (hinted_font
, glyph_id
,
1503 &bounds
, render_combining_glyphs
,
1507 return unknown_glyph
;
1509 if (!render_combining_glyphs
&& glyph_id
->ncomb
)
1512 if (!glyph_id
->ncomb
&& !glyph_id
->attributes
)
1515 if (max_glyph_size
< sizeof (*glyph
) + (bounds
.width
* bounds
.height
+ GRUB_CHAR_BIT
- 1) / GRUB_CHAR_BIT
)
1518 max_glyph_size
= (sizeof (*glyph
) + (bounds
.width
* bounds
.height
+ GRUB_CHAR_BIT
- 1) / GRUB_CHAR_BIT
) * 2;
1519 if (max_glyph_size
< 8)
1521 glyph
= grub_malloc (max_glyph_size
);
1525 grub_errno
= GRUB_ERR_NONE
;
1529 grub_memset (glyph
, 0, sizeof (*glyph
)
1530 + (bounds
.width
* bounds
.height
1531 + GRUB_CHAR_BIT
- 1) / GRUB_CHAR_BIT
);
1533 glyph
->font
= main_glyph
->font
;
1534 glyph
->width
= bounds
.width
;
1535 glyph
->height
= bounds
.height
;
1536 glyph
->offset_x
= bounds
.x
;
1537 glyph
->offset_y
= bounds
.y
;
1539 if (glyph_id
->attributes
& GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR
)
1540 grub_font_blit_glyph_mirror (glyph
, main_glyph
,
1541 main_glyph
->offset_x
- glyph
->offset_x
,
1542 (glyph
->height
+ glyph
->offset_y
)
1543 - (main_glyph
->height
+
1544 main_glyph
->offset_y
));
1546 grub_font_blit_glyph (glyph
, main_glyph
,
1547 main_glyph
->offset_x
- glyph
->offset_x
,
1548 (glyph
->height
+ glyph
->offset_y
)
1549 - (main_glyph
->height
+ main_glyph
->offset_y
));
1551 blit_comb (glyph_id
, glyph
, NULL
, main_glyph
, render_combining_glyphs
, NULL
);
1556 /* Draw the specified glyph at (x, y). The y coordinate designates the
1557 baseline of the character, while the x coordinate designates the left
1558 side location of the character. */
1560 grub_font_draw_glyph (struct grub_font_glyph
* glyph
,
1561 grub_video_color_t color
, int left_x
, int baseline_y
)
1563 struct grub_video_bitmap glyph_bitmap
;
1565 /* Don't try to draw empty glyphs (U+0020, etc.). */
1566 if (glyph
->width
== 0 || glyph
->height
== 0)
1567 return GRUB_ERR_NONE
;
1569 glyph_bitmap
.mode_info
.width
= glyph
->width
;
1570 glyph_bitmap
.mode_info
.height
= glyph
->height
;
1571 glyph_bitmap
.mode_info
.mode_type
1572 = (1 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS
) | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP
;
1573 glyph_bitmap
.mode_info
.blit_format
= GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED
;
1574 glyph_bitmap
.mode_info
.bpp
= 1;
1576 /* Really 1 bit per pixel. */
1577 glyph_bitmap
.mode_info
.bytes_per_pixel
= 0;
1579 /* Packed densely as bits. */
1580 glyph_bitmap
.mode_info
.pitch
= glyph
->width
;
1582 glyph_bitmap
.mode_info
.number_of_colors
= 2;
1583 glyph_bitmap
.mode_info
.bg_red
= 0;
1584 glyph_bitmap
.mode_info
.bg_green
= 0;
1585 glyph_bitmap
.mode_info
.bg_blue
= 0;
1586 glyph_bitmap
.mode_info
.bg_alpha
= 0;
1587 grub_video_unmap_color (color
,
1588 &glyph_bitmap
.mode_info
.fg_red
,
1589 &glyph_bitmap
.mode_info
.fg_green
,
1590 &glyph_bitmap
.mode_info
.fg_blue
,
1591 &glyph_bitmap
.mode_info
.fg_alpha
);
1592 glyph_bitmap
.data
= glyph
->bitmap
;
1594 int bitmap_left
= left_x
+ glyph
->offset_x
;
1595 int bitmap_bottom
= baseline_y
- glyph
->offset_y
;
1596 int bitmap_top
= bitmap_bottom
- glyph
->height
;
1598 return grub_video_blit_bitmap (&glyph_bitmap
, GRUB_VIDEO_BLIT_BLEND
,
1599 bitmap_left
, bitmap_top
,
1600 0, 0, glyph
->width
, glyph
->height
);