~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/font/font.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* font.c - Font API and font file loader.  */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2003,2005,2006,2007,2008,2009,2010  Free Software Foundation, Inc.
 
5
 *
 
6
 *  GRUB is free software: you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation, either version 3 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  GRUB is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
#include <grub/bufio.h>
 
21
#include <grub/dl.h>
 
22
#include <grub/file.h>
 
23
#include <grub/font.h>
 
24
#include <grub/misc.h>
 
25
#include <grub/mm.h>
 
26
#include <grub/types.h>
 
27
#include <grub/video.h>
 
28
#include <grub/bitmap.h>
 
29
#include <grub/charset.h>
 
30
#include <grub/unicode.h>
 
31
#include <grub/fontformat.h>
 
32
 
 
33
#ifdef USE_ASCII_FAILBACK
 
34
#include "ascii.h"
 
35
#endif
 
36
 
 
37
#ifndef FONT_DEBUG
 
38
#define FONT_DEBUG 0
 
39
#endif
 
40
 
 
41
struct char_index_entry
 
42
{
 
43
  grub_uint32_t code;
 
44
  grub_uint8_t storage_flags;
 
45
  grub_uint32_t offset;
 
46
 
 
47
  /* Glyph if loaded, or NULL otherwise.  */
 
48
  struct grub_font_glyph *glyph;
 
49
};
 
50
 
 
51
#define FONT_WEIGHT_NORMAL 100
 
52
#define FONT_WEIGHT_BOLD 200
 
53
#define ASCII_BITMAP_SIZE 16
 
54
 
 
55
struct grub_font
 
56
{
 
57
  char *name;
 
58
  grub_file_t file;
 
59
  char *family;
 
60
  short point_size;
 
61
  short weight;
 
62
  short max_char_width;
 
63
  short max_char_height;
 
64
  short ascent;
 
65
  short descent;
 
66
  short leading;
 
67
  grub_uint32_t num_chars;
 
68
  struct char_index_entry *char_index;
 
69
  grub_uint16_t *bmp_idx;
 
70
};
 
71
 
 
72
/* Definition of font registry.  */
 
73
struct grub_font_node *grub_font_list;
 
74
 
 
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);
 
79
 
 
80
struct font_file_section
 
81
{
 
82
  /* The file this section is in.  */
 
83
  grub_file_t file;
 
84
 
 
85
  /* FOURCC name of the section.  */
 
86
  char name[4];
 
87
 
 
88
  /* Length of the section contents.  */
 
89
  grub_uint32_t length;
 
90
 
 
91
  /* Set by open_section() on EOF.  */
 
92
  int eof;
 
93
};
 
94
 
 
95
/* Replace unknown glyphs with a rounded question mark.  */
 
96
static grub_uint8_t unknown_glyph_bitmap[] = {
 
97
  /*       76543210 */
 
98
  0x7C,                         /*  ooooo   */
 
99
  0x82,                         /* o     o  */
 
100
  0xBA,                         /* o ooo o  */
 
101
  0xAA,                         /* o o o o  */
 
102
  0xAA,                         /* o o o o  */
 
103
  0x8A,                         /* o   o o  */
 
104
  0x9A,                         /* o  oo o  */
 
105
  0x92,                         /* o  o  o  */
 
106
  0x92,                         /* o  o  o  */
 
107
  0x92,                         /* o  o  o  */
 
108
  0x92,                         /* o  o  o  */
 
109
  0x82,                         /* o     o  */
 
110
  0x92,                         /* o  o  o  */
 
111
  0x82,                         /* o     o  */
 
112
  0x7C,                         /*  ooooo   */
 
113
  0x00                          /*          */
 
114
};
 
115
 
 
116
/* The "unknown glyph" glyph, used as a last resort.  */
 
117
static struct grub_font_glyph *unknown_glyph;
 
118
 
 
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;
 
123
 
 
124
/* Flag to ensure module is initialized only once.  */
 
125
static grub_uint8_t font_loader_initialized;
 
126
 
 
127
#ifdef USE_ASCII_FAILBACK
 
128
static struct grub_font_glyph *ascii_font_glyph[0x80];
 
129
#endif
 
130
 
 
131
static struct grub_font_glyph *
 
132
ascii_glyph_lookup (grub_uint32_t code)
 
133
{
 
134
#ifdef USE_ASCII_FAILBACK
 
135
  static int ascii_failback_initialized = 0;
 
136
 
 
137
  if (code >= 0x80)
 
138
    return NULL;
 
139
 
 
140
  if (ascii_failback_initialized == 0)
 
141
    {
 
142
      int current;
 
143
      for (current = 0; current < 0x80; current++)
 
144
        {
 
145
          ascii_font_glyph[current] =
 
146
            grub_malloc (sizeof (struct grub_font_glyph) + ASCII_BITMAP_SIZE);
 
147
 
 
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;
 
154
 
 
155
          grub_memcpy (ascii_font_glyph[current]->bitmap,
 
156
                       &ascii_bitmaps[current * ASCII_BITMAP_SIZE],
 
157
                       ASCII_BITMAP_SIZE);
 
158
        }
 
159
 
 
160
      ascii_failback_initialized = 1;
 
161
    }
 
162
 
 
163
  return ascii_font_glyph[code];
 
164
#else
 
165
  (void) code;
 
166
  return NULL;
 
167
#endif
 
168
}
 
169
 
 
170
void
 
171
grub_font_loader_init (void)
 
172
{
 
173
  /* Only initialize font loader once.  */
 
174
  if (font_loader_initialized)
 
175
    return;
 
176
 
 
177
  /* Make glyph for unknown glyph.  */
 
178
  unknown_glyph = grub_malloc (sizeof (struct grub_font_glyph)
 
179
                               + sizeof (unknown_glyph_bitmap));
 
180
  if (!unknown_glyph)
 
181
    return;
 
182
 
 
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));
 
190
 
 
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;
 
198
 
 
199
  font_loader_initialized = 1;
 
200
}
 
201
 
 
202
/* Initialize the font object with initial default values.  */
 
203
static void
 
204
font_init (grub_font_t font)
 
205
{
 
206
  font->name = 0;
 
207
  font->file = 0;
 
208
  font->family = 0;
 
209
  font->point_size = 0;
 
210
  font->weight = 0;
 
211
 
 
212
  /* Default leading value, not in font file yet.  */
 
213
  font->leading = 1;
 
214
 
 
215
  font->max_char_width = 0;
 
216
  font->max_char_height = 0;
 
217
  font->ascent = 0;
 
218
  font->descent = 0;
 
219
  font->num_chars = 0;
 
220
  font->char_index = 0;
 
221
  font->bmp_idx = 0;
 
222
}
 
223
 
 
224
/* Open the next section in the file.
 
225
 
 
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.
 
229
 
 
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.  */
 
232
static int
 
233
open_section (grub_file_t file, struct font_file_section *section)
 
234
{
 
235
  grub_ssize_t retval;
 
236
  grub_uint32_t raw_length;
 
237
 
 
238
  section->file = file;
 
239
  section->eof = 0;
 
240
 
 
241
  /* Read the FOURCC section name.  */
 
242
  retval = grub_file_read (file, section->name, 4);
 
243
  if (retval >= 0 && retval < 4)
 
244
    {
 
245
      /* EOF encountered.  */
 
246
      section->eof = 1;
 
247
      return 1;
 
248
    }
 
249
  else if (retval < 0)
 
250
    {
 
251
      grub_error (GRUB_ERR_BAD_FONT,
 
252
                  "font format error: can't read section name");
 
253
      return 1;
 
254
    }
 
255
 
 
256
  /* Read the big-endian 32-bit section length.  */
 
257
  retval = grub_file_read (file, &raw_length, 4);
 
258
  if (retval >= 0 && retval < 4)
 
259
    {
 
260
      /* EOF encountered.  */
 
261
      section->eof = 1;
 
262
      return 1;
 
263
    }
 
264
  else if (retval < 0)
 
265
    {
 
266
      grub_error (GRUB_ERR_BAD_FONT,
 
267
                  "font format error: can't read section length");
 
268
      return 1;
 
269
    }
 
270
 
 
271
  /* Convert byte-order and store in *length.  */
 
272
  section->length = grub_be_to_cpu32 (raw_length);
 
273
 
 
274
  return 0;
 
275
}
 
276
 
 
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)
 
280
 
 
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).  */
 
286
static int
 
287
load_font_index (grub_file_t file, grub_uint32_t sect_length, struct
 
288
                 grub_font *font)
 
289
{
 
290
  unsigned i;
 
291
  grub_uint32_t last_code;
 
292
 
 
293
#if FONT_DEBUG >= 2
 
294
  grub_printf ("load_font_index(sect_length=%d)\n", sect_length);
 
295
#endif
 
296
 
 
297
  /* Sanity check: ensure section length is divisible by the entry size.  */
 
298
  if ((sect_length % FONT_CHAR_INDEX_ENTRY_SIZE) != 0)
 
299
    {
 
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);
 
304
      return 1;
 
305
    }
 
306
 
 
307
  /* Calculate the number of characters.  */
 
308
  font->num_chars = sect_length / FONT_CHAR_INDEX_ENTRY_SIZE;
 
309
 
 
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)
 
314
    return 1;
 
315
  font->bmp_idx = grub_malloc (0x10000 * sizeof (grub_uint16_t));
 
316
  if (!font->bmp_idx)
 
317
    {
 
318
      grub_free (font->char_index);
 
319
      return 1;
 
320
    }
 
321
  grub_memset (font->bmp_idx, 0xff, 0x10000 * sizeof (grub_uint16_t));
 
322
 
 
323
 
 
324
#if FONT_DEBUG >= 2
 
325
  grub_printf ("num_chars=%d)\n", font->num_chars);
 
326
#endif
 
327
 
 
328
  last_code = 0;
 
329
 
 
330
  /* Load the character index data from the file.  */
 
331
  for (i = 0; i < font->num_chars; i++)
 
332
    {
 
333
      struct char_index_entry *entry = &font->char_index[i];
 
334
 
 
335
      /* Read code point value; convert to native byte order.  */
 
336
      if (grub_file_read (file, &entry->code, 4) != 4)
 
337
        return 1;
 
338
      entry->code = grub_be_to_cpu32 (entry->code);
 
339
 
 
340
      /* Verify that characters are in ascending order.  */
 
341
      if (i != 0 && entry->code <= last_code)
 
342
        {
 
343
          grub_error (GRUB_ERR_BAD_FONT,
 
344
                      "font characters not in ascending order: %u <= %u",
 
345
                      entry->code, last_code);
 
346
          return 1;
 
347
        }
 
348
 
 
349
      if (entry->code < 0x10000)
 
350
        font->bmp_idx[entry->code] = i;
 
351
 
 
352
      last_code = entry->code;
 
353
 
 
354
      /* Read storage flags byte.  */
 
355
      if (grub_file_read (file, &entry->storage_flags, 1) != 1)
 
356
        return 1;
 
357
 
 
358
      /* Read glyph data offset; convert to native byte order.  */
 
359
      if (grub_file_read (file, &entry->offset, 4) != 4)
 
360
        return 1;
 
361
      entry->offset = grub_be_to_cpu32 (entry->offset);
 
362
 
 
363
      /* No glyph loaded.  Will be loaded on demand and cached thereafter.  */
 
364
      entry->glyph = 0;
 
365
 
 
366
#if FONT_DEBUG >= 5
 
367
      /* Print the 1st 10 characters.  */
 
368
      if (i < 10)
 
369
        grub_printf ("c=%d o=%d\n", entry->code, entry->offset);
 
370
#endif
 
371
    }
 
372
 
 
373
  return 0;
 
374
}
 
375
 
 
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.  */
 
378
static char *
 
379
read_section_as_string (struct font_file_section *section)
 
380
{
 
381
  char *str;
 
382
  grub_ssize_t ret;
 
383
 
 
384
  str = grub_malloc (section->length + 1);
 
385
  if (!str)
 
386
    return 0;
 
387
 
 
388
  ret = grub_file_read (section->file, str, section->length);
 
389
  if (ret < 0 || ret != (grub_ssize_t) section->length)
 
390
    {
 
391
      grub_free (str);
 
392
      return 0;
 
393
    }
 
394
 
 
395
  str[section->length] = '\0';
 
396
  return str;
 
397
}
 
398
 
 
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.  */
 
402
static int
 
403
read_section_as_short (struct font_file_section *section,
 
404
                       grub_int16_t * value)
 
405
{
 
406
  grub_uint16_t raw_value;
 
407
 
 
408
  if (section->length != 2)
 
409
    {
 
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);
 
415
      return 1;
 
416
    }
 
417
  if (grub_file_read (section->file, &raw_value, 2) != 2)
 
418
    return 1;
 
419
 
 
420
  *value = grub_be_to_cpu16 (raw_value);
 
421
  return 0;
 
422
}
 
423
 
 
424
/* Load a font and add it to the beginning of the global font list.
 
425
   Returns 0 upon success, nonzero upon failure.  */
 
426
int
 
427
grub_font_load (const char *filename)
 
428
{
 
429
  grub_file_t file = 0;
 
430
  struct font_file_section section;
 
431
  char magic[4];
 
432
  grub_font_t font = 0;
 
433
 
 
434
#if FONT_DEBUG >= 1
 
435
  grub_printf ("add_font(%s)\n", filename);
 
436
#endif
 
437
 
 
438
  file = grub_buffile_open (filename, 1024);
 
439
  if (!file)
 
440
    goto fail;
 
441
 
 
442
#if FONT_DEBUG >= 3
 
443
  grub_printf ("file opened\n");
 
444
#endif
 
445
 
 
446
  /* Read the FILE section.  It indicates the file format.  */
 
447
  if (open_section (file, &section) != 0)
 
448
    goto fail;
 
449
 
 
450
#if FONT_DEBUG >= 3
 
451
  grub_printf ("opened FILE section\n");
 
452
#endif
 
453
  if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_FILE,
 
454
                   sizeof (FONT_FORMAT_SECTION_NAMES_FILE) - 1) != 0)
 
455
    {
 
456
      grub_error (GRUB_ERR_BAD_FONT,
 
457
                  "font file format error: 1st section must be FILE");
 
458
      goto fail;
 
459
    }
 
460
 
 
461
#if FONT_DEBUG >= 3
 
462
  grub_printf ("section name ok\n");
 
463
#endif
 
464
  if (section.length != 4)
 
465
    {
 
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);
 
469
      goto fail;
 
470
    }
 
471
 
 
472
#if FONT_DEBUG >= 3
 
473
  grub_printf ("section length ok\n");
 
474
#endif
 
475
  /* Check the file format type code.  */
 
476
  if (grub_file_read (file, magic, 4) != 4)
 
477
    goto fail;
 
478
 
 
479
#if FONT_DEBUG >= 3
 
480
  grub_printf ("read magic ok\n");
 
481
#endif
 
482
 
 
483
  if (grub_memcmp (magic, FONT_FORMAT_PFF2_MAGIC, 4) != 0)
 
484
    {
 
485
      grub_error (GRUB_ERR_BAD_FONT, "invalid font magic %x %x %x %x",
 
486
                  magic[0], magic[1], magic[2], magic[3]);
 
487
      goto fail;
 
488
    }
 
489
 
 
490
#if FONT_DEBUG >= 3
 
491
  grub_printf ("compare magic ok\n");
 
492
#endif
 
493
 
 
494
  /* Allocate the font object.  */
 
495
  font = (grub_font_t) grub_malloc (sizeof (struct grub_font));
 
496
  if (!font)
 
497
    goto fail;
 
498
 
 
499
  font_init (font);
 
500
  font->file = file;
 
501
 
 
502
#if FONT_DEBUG >= 3
 
503
  grub_printf ("allocate font ok; loading font info\n");
 
504
#endif
 
505
 
 
506
  /* Load the font information.  */
 
507
  while (1)
 
508
    {
 
509
      if (open_section (file, &section) != 0)
 
510
        {
 
511
          if (section.eof)
 
512
            break;              /* Done reading the font file.  */
 
513
          else
 
514
            goto fail;
 
515
        }
 
516
 
 
517
#if FONT_DEBUG >= 2
 
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]);
 
521
#endif
 
522
 
 
523
      if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_FONT_NAME,
 
524
                       sizeof (FONT_FORMAT_SECTION_NAMES_FONT_NAME) - 1) == 0)
 
525
        {
 
526
          font->name = read_section_as_string (&section);
 
527
          if (!font->name)
 
528
            goto fail;
 
529
        }
 
530
      else if (grub_memcmp (section.name,
 
531
                            FONT_FORMAT_SECTION_NAMES_POINT_SIZE,
 
532
                            sizeof (FONT_FORMAT_SECTION_NAMES_POINT_SIZE) -
 
533
                            1) == 0)
 
534
        {
 
535
          if (read_section_as_short (&section, &font->point_size) != 0)
 
536
            goto fail;
 
537
        }
 
538
      else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_WEIGHT,
 
539
                            sizeof (FONT_FORMAT_SECTION_NAMES_WEIGHT) - 1)
 
540
               == 0)
 
541
        {
 
542
          char *wt;
 
543
          wt = read_section_as_string (&section);
 
544
          if (!wt)
 
545
            continue;
 
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;
 
551
          grub_free (wt);
 
552
        }
 
553
      else if (grub_memcmp (section.name,
 
554
                            FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH,
 
555
                            sizeof (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH)
 
556
                            - 1) == 0)
 
557
        {
 
558
          if (read_section_as_short (&section, &font->max_char_width) != 0)
 
559
            goto fail;
 
560
        }
 
561
      else if (grub_memcmp (section.name,
 
562
                            FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT,
 
563
                            sizeof (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT)
 
564
                            - 1) == 0)
 
565
        {
 
566
          if (read_section_as_short (&section, &font->max_char_height) != 0)
 
567
            goto fail;
 
568
        }
 
569
      else if (grub_memcmp (section.name,
 
570
                            FONT_FORMAT_SECTION_NAMES_ASCENT,
 
571
                            sizeof (FONT_FORMAT_SECTION_NAMES_ASCENT) - 1)
 
572
               == 0)
 
573
        {
 
574
          if (read_section_as_short (&section, &font->ascent) != 0)
 
575
            goto fail;
 
576
        }
 
577
      else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_DESCENT,
 
578
                            sizeof (FONT_FORMAT_SECTION_NAMES_DESCENT) - 1)
 
579
               == 0)
 
580
        {
 
581
          if (read_section_as_short (&section, &font->descent) != 0)
 
582
            goto fail;
 
583
        }
 
584
      else if (grub_memcmp (section.name,
 
585
                            FONT_FORMAT_SECTION_NAMES_CHAR_INDEX,
 
586
                            sizeof (FONT_FORMAT_SECTION_NAMES_CHAR_INDEX) -
 
587
                            1) == 0)
 
588
        {
 
589
          if (load_font_index (file, section.length, font) != 0)
 
590
            goto fail;
 
591
        }
 
592
      else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_DATA,
 
593
                            sizeof (FONT_FORMAT_SECTION_NAMES_DATA) - 1) == 0)
 
594
        {
 
595
          /* When the DATA section marker is reached, we stop reading.  */
 
596
          break;
 
597
        }
 
598
      else
 
599
        {
 
600
          /* Unhandled section type, simply skip past it.  */
 
601
#if FONT_DEBUG >= 3
 
602
          grub_printf ("Unhandled section type, skipping.\n");
 
603
#endif
 
604
          grub_off_t section_end = grub_file_tell (file) + section.length;
 
605
          if ((int) grub_file_seek (file, section_end) == -1)
 
606
            goto fail;
 
607
        }
 
608
    }
 
609
 
 
610
  if (!font->name)
 
611
    {
 
612
      grub_printf ("Note: Font has no name.\n");
 
613
      font->name = grub_strdup ("Unknown");
 
614
    }
 
615
 
 
616
#if FONT_DEBUG >= 1
 
617
  grub_printf ("Loaded font `%s'.\n"
 
618
               "Ascent=%d Descent=%d MaxW=%d MaxH=%d Number of characters=%d.\n",
 
619
               font->name,
 
620
               font->ascent, font->descent,
 
621
               font->max_char_width, font->max_char_height, font->num_chars);
 
622
#endif
 
623
 
 
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)
 
628
    {
 
629
      grub_error (GRUB_ERR_BAD_FONT,
 
630
                  "invalid font file: missing some required data");
 
631
      goto fail;
 
632
    }
 
633
 
 
634
  /* Add the font to the global font registry.  */
 
635
  if (register_font (font) != 0)
 
636
    goto fail;
 
637
 
 
638
  return 0;
 
639
 
 
640
fail:
 
641
  free_font (font);
 
642
  return 1;
 
643
}
 
644
 
 
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.  */
 
648
static int
 
649
read_be_uint16 (grub_file_t file, grub_uint16_t * value)
 
650
{
 
651
  if (grub_file_read (file, value, 2) != 2)
 
652
    return 1;
 
653
  *value = grub_be_to_cpu16 (*value);
 
654
  return 0;
 
655
}
 
656
 
 
657
static int
 
658
read_be_int16 (grub_file_t file, grub_int16_t * value)
 
659
{
 
660
  /* For the signed integer version, use the same code as for unsigned.  */
 
661
  return read_be_uint16 (file, (grub_uint16_t *) value);
 
662
}
 
663
 
 
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)
 
668
{
 
669
  struct char_index_entry *table;
 
670
  grub_size_t lo;
 
671
  grub_size_t hi;
 
672
  grub_size_t mid;
 
673
 
 
674
  table = font->char_index;
 
675
 
 
676
  /* Use BMP index if possible.  */
 
677
  if (code < 0x10000 && font->bmp_idx)
 
678
    {
 
679
      if (font->bmp_idx[code] == 0xffff)
 
680
        return 0;
 
681
      return &table[font->bmp_idx[code]];
 
682
    }
 
683
 
 
684
  /* Do a binary search in `char_index', which is ordered by code point.  */
 
685
  lo = 0;
 
686
  hi = font->num_chars - 1;
 
687
 
 
688
  if (!table)
 
689
    return 0;
 
690
 
 
691
  while (lo <= hi)
 
692
    {
 
693
      mid = lo + (hi - lo) / 2;
 
694
      if (code < table[mid].code)
 
695
        hi = mid - 1;
 
696
      else if (code > table[mid].code)
 
697
        lo = mid + 1;
 
698
      else
 
699
        return &table[mid];
 
700
    }
 
701
 
 
702
  return 0;
 
703
}
 
704
 
 
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)
 
710
{
 
711
  struct char_index_entry *index_entry;
 
712
 
 
713
  index_entry = find_glyph (font, code);
 
714
  if (index_entry)
 
715
    {
 
716
      struct grub_font_glyph *glyph = 0;
 
717
      grub_uint16_t width;
 
718
      grub_uint16_t height;
 
719
      grub_int16_t xoff;
 
720
      grub_int16_t yoff;
 
721
      grub_int16_t dwidth;
 
722
      int len;
 
723
 
 
724
      if (index_entry->glyph)
 
725
        /* Return cached glyph.  */
 
726
        return index_entry->glyph;
 
727
 
 
728
      if (!font->file)
 
729
        /* No open file, can't load any glyphs.  */
 
730
        return 0;
 
731
 
 
732
      /* Make sure we can find glyphs for error messages.  Push active
 
733
         error message to error stack and reset error message.  */
 
734
      grub_error_push ();
 
735
 
 
736
      grub_file_seek (font->file, index_entry->offset);
 
737
 
 
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)
 
744
        {
 
745
          remove_font (font);
 
746
          return 0;
 
747
        }
 
748
 
 
749
      len = (width * height + 7) / 8;
 
750
      glyph = grub_malloc (sizeof (struct grub_font_glyph) + len);
 
751
      if (!glyph)
 
752
        {
 
753
          remove_font (font);
 
754
          return 0;
 
755
        }
 
756
 
 
757
      glyph->font = font;
 
758
      glyph->width = width;
 
759
      glyph->height = height;
 
760
      glyph->offset_x = xoff;
 
761
      glyph->offset_y = yoff;
 
762
      glyph->device_width = dwidth;
 
763
 
 
764
      /* Don't try to read empty bitmaps (e.g., space characters).  */
 
765
      if (len != 0)
 
766
        {
 
767
          if (grub_file_read (font->file, glyph->bitmap, len) != len)
 
768
            {
 
769
              remove_font (font);
 
770
              return 0;
 
771
            }
 
772
        }
 
773
 
 
774
      /* Restore old error message.  */
 
775
      grub_error_pop ();
 
776
 
 
777
      /* Cache the glyph.  */
 
778
      index_entry->glyph = glyph;
 
779
 
 
780
      return glyph;
 
781
    }
 
782
 
 
783
  return 0;
 
784
}
 
785
 
 
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.  */
 
790
static void
 
791
free_font (grub_font_t font)
 
792
{
 
793
  if (font)
 
794
    {
 
795
      if (font->file)
 
796
        grub_file_close (font->file);
 
797
      grub_free (font->name);
 
798
      grub_free (font->family);
 
799
      grub_free (font->char_index);
 
800
      grub_free (font);
 
801
    }
 
802
}
 
803
 
 
804
/* Add FONT to the global font registry.
 
805
   Returns 0 upon success, nonzero on failure
 
806
   (the font was not registered).  */
 
807
static int
 
808
register_font (grub_font_t font)
 
809
{
 
810
  struct grub_font_node *node = 0;
 
811
 
 
812
  node = grub_malloc (sizeof (struct grub_font_node));
 
813
  if (!node)
 
814
    return 1;
 
815
 
 
816
  node->value = font;
 
817
  node->next = grub_font_list;
 
818
  grub_font_list = node;
 
819
 
 
820
  return 0;
 
821
}
 
822
 
 
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.  */
 
825
static void
 
826
remove_font (grub_font_t font)
 
827
{
 
828
  struct grub_font_node **nextp, *cur;
 
829
 
 
830
  for (nextp = &grub_font_list, cur = *nextp;
 
831
       cur; nextp = &cur->next, cur = cur->next)
 
832
    {
 
833
      if (cur->value == font)
 
834
        {
 
835
          *nextp = cur->next;
 
836
 
 
837
          /* Free the node, but not the font itself.  */
 
838
          grub_free (cur);
 
839
 
 
840
          return;
 
841
        }
 
842
    }
 
843
}
 
844
 
 
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.  */
 
849
grub_font_t
 
850
grub_font_get (const char *font_name)
 
851
{
 
852
  struct grub_font_node *node;
 
853
 
 
854
  for (node = grub_font_list; node; node = node->next)
 
855
    {
 
856
      grub_font_t font = node->value;
 
857
      if (grub_strcmp (font->name, font_name) == 0)
 
858
        return font;
 
859
    }
 
860
 
 
861
  /* If no font by that name is found, return the first font in the list
 
862
     as a fallback.  */
 
863
  if (grub_font_list && grub_font_list->value)
 
864
    return grub_font_list->value;
 
865
  else
 
866
    /* The null_font is a last resort.  */
 
867
    return &null_font;
 
868
}
 
869
 
 
870
/* Get the full name of the font.  */
 
871
const char *
 
872
grub_font_get_name (grub_font_t font)
 
873
{
 
874
  return font->name;
 
875
}
 
876
 
 
877
/* Get the maximum width of any character in the font in pixels.  */
 
878
int
 
879
grub_font_get_max_char_width (grub_font_t font)
 
880
{
 
881
  return font->max_char_width;
 
882
}
 
883
 
 
884
/* Get the maximum height of any character in the font in pixels.  */
 
885
int
 
886
grub_font_get_max_char_height (grub_font_t font)
 
887
{
 
888
  return font->max_char_height;
 
889
}
 
890
 
 
891
/* Get the distance in pixels from the top of characters to the baseline.  */
 
892
int
 
893
grub_font_get_ascent (grub_font_t font)
 
894
{
 
895
  return font->ascent;
 
896
}
 
897
 
 
898
/* Get the distance in pixels from the baseline to the lowest descenders
 
899
   (for instance, in a lowercase 'y', 'g', etc.).  */
 
900
int
 
901
grub_font_get_descent (grub_font_t font)
 
902
{
 
903
  return font->descent;
 
904
}
 
905
 
 
906
/* FIXME: not correct for all fonts.  */
 
907
int
 
908
grub_font_get_xheight (grub_font_t font)
 
909
{
 
910
  return font->ascent / 2;
 
911
}
 
912
 
 
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.  */
 
917
int
 
918
grub_font_get_leading (grub_font_t font)
 
919
{
 
920
  return font->leading;
 
921
}
 
922
 
 
923
/* Get the distance in pixels between baselines of adjacent lines of text.  */
 
924
int
 
925
grub_font_get_height (grub_font_t font)
 
926
{
 
927
  return font->ascent + font->descent + font->leading;
 
928
}
 
929
 
 
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)
 
935
{
 
936
  struct grub_font_glyph *glyph = 0;
 
937
  if (font)
 
938
    glyph = grub_font_get_glyph_internal (font, code);
 
939
  if (glyph == 0)
 
940
    {
 
941
      glyph = ascii_glyph_lookup (code);
 
942
    }
 
943
  return glyph;
 
944
}
 
945
 
 
946
 
 
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.  */
 
954
static int
 
955
get_font_diversity (grub_font_t a, grub_font_t b)
 
956
{
 
957
  int d;
 
958
 
 
959
  d = 0;
 
960
 
 
961
  if (a->ascent && b->ascent)
 
962
    d += grub_abs (a->ascent - b->ascent) * 8;
 
963
  else
 
964
    /* Penalty for missing attributes.  */
 
965
    d += 50;
 
966
 
 
967
  if (a->max_char_height && b->max_char_height)
 
968
    d += grub_abs (a->max_char_height - b->max_char_height) * 8;
 
969
  else
 
970
    /* Penalty for missing attributes.  */
 
971
    d += 50;
 
972
 
 
973
  /* Weight is a minor factor. */
 
974
  d += (a->weight != b->weight) ? 5 : 0;
 
975
 
 
976
  return d;
 
977
}
 
978
 
 
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)
 
989
{
 
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.  */
 
997
  int best_diversity;
 
998
  struct grub_font_glyph *best_glyph;
 
999
 
 
1000
  if (font)
 
1001
    {
 
1002
      /* First try to get the glyph from the specified font.  */
 
1003
      glyph = grub_font_get_glyph_internal (font, code);
 
1004
      if (glyph)
 
1005
        return glyph;
 
1006
    }
 
1007
 
 
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;
 
1011
  best_glyph = 0;
 
1012
 
 
1013
  for (node = grub_font_list; node; node = next)
 
1014
    {
 
1015
      grub_font_t curfont;
 
1016
 
 
1017
      curfont = node->value;
 
1018
      next = node->next;
 
1019
 
 
1020
      glyph = grub_font_get_glyph_internal (curfont, code);
 
1021
      if (glyph && !font)
 
1022
        return glyph;
 
1023
      if (glyph)
 
1024
        {
 
1025
          int d;
 
1026
 
 
1027
          d = get_font_diversity (curfont, font);
 
1028
          if (d < best_diversity)
 
1029
            {
 
1030
              best_diversity = d;
 
1031
              best_glyph = glyph;
 
1032
            }
 
1033
        }
 
1034
    }
 
1035
 
 
1036
  return best_glyph;
 
1037
}
 
1038
 
 
1039
static struct grub_font_glyph *
 
1040
grub_font_dup_glyph (struct grub_font_glyph *glyph)
 
1041
{
 
1042
  static struct grub_font_glyph *ret;
 
1043
  ret = grub_malloc (sizeof (*ret) + (glyph->width * glyph->height + 7) / 8);
 
1044
  if (!ret)
 
1045
    return NULL;
 
1046
  grub_memcpy (ret, glyph, sizeof (*ret)
 
1047
               + (glyph->width * glyph->height + 7) / 8);
 
1048
  return ret;
 
1049
}
 
1050
 
 
1051
/* FIXME: suboptimal.  */
 
1052
static void
 
1053
grub_font_blit_glyph (struct grub_font_glyph *target,
 
1054
                      struct grub_font_glyph *src, unsigned dx, unsigned dy)
 
1055
{
 
1056
  unsigned src_bit, tgt_bit, src_byte, tgt_byte;
 
1057
  unsigned i, j;
 
1058
  for (i = 0; i < src->height; i++)
 
1059
    {
 
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++)
 
1065
        {
 
1066
          target->bitmap[tgt_byte] |= ((src->bitmap[src_byte] << src_bit)
 
1067
                                       & 0x80) >> tgt_bit;
 
1068
          src_bit++;
 
1069
          tgt_bit++;
 
1070
          if (src_bit == 8)
 
1071
            {
 
1072
              src_byte++;
 
1073
              src_bit = 0;
 
1074
            }
 
1075
          if (tgt_bit == 8)
 
1076
            {
 
1077
              tgt_byte++;
 
1078
              tgt_bit = 0;
 
1079
            }
 
1080
        }
 
1081
    }
 
1082
}
 
1083
 
 
1084
static void
 
1085
grub_font_blit_glyph_mirror (struct grub_font_glyph *target,
 
1086
                             struct grub_font_glyph *src,
 
1087
                             unsigned dx, unsigned dy)
 
1088
{
 
1089
  unsigned tgt_bit, src_byte, tgt_byte;
 
1090
  signed src_bit;
 
1091
  unsigned i, j;
 
1092
  for (i = 0; i < src->height; i++)
 
1093
    {
 
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++)
 
1099
        {
 
1100
          target->bitmap[tgt_byte] |= ((src->bitmap[src_byte] << src_bit)
 
1101
                                       & 0x80) >> tgt_bit;
 
1102
          src_bit--;
 
1103
          tgt_bit++;
 
1104
          if (src_bit == -1)
 
1105
            {
 
1106
              src_byte--;
 
1107
              src_bit = 7;
 
1108
            }
 
1109
          if (tgt_bit == 8)
 
1110
            {
 
1111
              tgt_byte++;
 
1112
              tgt_bit = 0;
 
1113
            }
 
1114
        }
 
1115
    }
 
1116
}
 
1117
 
 
1118
static void
 
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)
 
1124
{
 
1125
  struct grub_video_signed_rect bounds;
 
1126
  unsigned i;
 
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)
 
1135
  {
 
1136
    if (glyph)
 
1137
      grub_font_blit_glyph (glyph, src, dx - glyph->offset_x,
 
1138
                            (glyph->height + glyph->offset_y) + dy);
 
1139
    if (dx < bounds.x)
 
1140
      {
 
1141
        bounds.width += bounds.x - dx;
 
1142
        bounds.x = dx;
 
1143
      }
 
1144
    if (bounds.y > -src->height - dy)
 
1145
      {
 
1146
        bounds.height += bounds.y - (-src->height - dy);
 
1147
        bounds.y = (-src->height - dy);
 
1148
      }
 
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;
 
1153
  }
 
1154
 
 
1155
  auto void add_device_width (int val);
 
1156
  void add_device_width (int val)
 
1157
  {
 
1158
    if (glyph)
 
1159
      glyph->device_width += val;
 
1160
    if (device_width)
 
1161
      *device_width += val;
 
1162
  }
 
1163
 
 
1164
  if (glyph)
 
1165
    glyph->device_width = main_glyph->device_width;
 
1166
  if (device_width)
 
1167
    *device_width = main_glyph->device_width;
 
1168
 
 
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;
 
1173
 
 
1174
  above_rightx = main_glyph->offset_x + main_glyph->width;
 
1175
  above_righty = bounds.y + bounds.height;
 
1176
 
 
1177
  above_leftx = main_glyph->offset_x;
 
1178
  above_lefty = bounds.y + bounds.height;
 
1179
 
 
1180
  below_rightx = bounds.x + bounds.width;
 
1181
  below_righty = bounds.y;
 
1182
 
 
1183
  for (i = 0; i < glyph_id->ncomb; i++)
 
1184
    {
 
1185
      grub_int16_t space = 0;
 
1186
      /* Center by default.  */
 
1187
      grub_int16_t targetx;
 
1188
 
 
1189
      if (!combining_glyphs[i])
 
1190
        continue;
 
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)
 
1195
        continue;
 
1196
      switch (glyph_id->combining[i].type)
 
1197
        {
 
1198
        case GRUB_UNICODE_COMB_OVERLAY:
 
1199
          do_blit (combining_glyphs[i],
 
1200
                   targetx,
 
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;
 
1205
          break;
 
1206
 
 
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;
 
1210
          break;
 
1211
 
 
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;
 
1216
          break;
 
1217
 
 
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));
 
1222
          break;
 
1223
 
 
1224
        case GRUB_UNICODE_COMB_BELOW_RIGHT:
 
1225
          do_blit (combining_glyphs[i], below_rightx, below_righty);
 
1226
          below_rightx += combining_glyphs[i]->width;
 
1227
          break;
 
1228
 
 
1229
        case GRUB_UNICODE_COMB_HEBREW_HOLAM:
 
1230
          if (glyph_id->base != GRUB_UNICODE_HEBREW_WAW)
 
1231
            targetx =
 
1232
              main_glyph->offset_x - combining_glyphs[i]->width -
 
1233
              (combining_glyphs[i]->width + 3) / 4;
 
1234
          goto above_on_main;
 
1235
 
 
1236
        case GRUB_UNICODE_COMB_HEBREW_SIN_DOT:
 
1237
          targetx = main_glyph->offset_x + combining_glyphs[i]->width / 4;
 
1238
          goto above_on_main;
 
1239
 
 
1240
        case GRUB_UNICODE_COMB_HEBREW_SHIN_DOT:
 
1241
          targetx =
 
1242
            main_glyph->width + main_glyph->offset_x -
 
1243
            combining_glyphs[i]->width;
 
1244
        above_on_main:
 
1245
          space = combining_glyphs[i]->offset_y
 
1246
            - grub_font_get_xheight (combining_glyphs[i]->font) - 1;
 
1247
          if (space <= 0)
 
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;
 
1254
          break;
 
1255
 
 
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:
 
1267
        stacked_above:
 
1268
          space = combining_glyphs[i]->offset_y
 
1269
            - grub_font_get_xheight (combining_glyphs[i]->font) - 1;
 
1270
          if (space <= 0)
 
1271
            space = 1 + (grub_font_get_xheight (main_glyph->font)) / 8;
 
1272
 
 
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;
 
1279
          break;
 
1280
 
 
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.  */
 
1287
 
 
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:
 
1300
        stacked_below:
 
1301
          space = -(combining_glyphs[i]->offset_y
 
1302
                    + combining_glyphs[i]->height);
 
1303
          if (space <= 0)
 
1304
            space = 1 + (grub_font_get_xheight (main_glyph->font)) / 8;
 
1305
 
 
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;
 
1310
          break;
 
1311
 
 
1312
        case GRUB_UNICODE_COMB_MN:
 
1313
          switch (glyph_id->combining[i].code)
 
1314
            {
 
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:
 
1324
              goto stacked_above;
 
1325
            case GRUB_UNICODE_THAANA_IBIFILI:
 
1326
            case GRUB_UNICODE_THAANA_EEBEEFILI:
 
1327
              goto stacked_below;
 
1328
            }
 
1329
          /* Fall through.  */
 
1330
        default:
 
1331
          {
 
1332
            /* Default handling. Just draw combining character on top
 
1333
               of base character.
 
1334
               FIXME: support more unicode types correctly.
 
1335
             */
 
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);
 
1342
          }
 
1343
        }
 
1344
    }
 
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;
 
1353
 
 
1354
  if (bounds_out)
 
1355
    *bounds_out = bounds;
 
1356
}
 
1357
 
 
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,
 
1363
                             int *device_width)
 
1364
{
 
1365
  struct grub_font_glyph *main_glyph = NULL;
 
1366
  struct grub_font_glyph **combining_glyphs;
 
1367
  grub_uint32_t desired_attributes = 0;
 
1368
 
 
1369
  if (combining_glyphs_out)
 
1370
    *combining_glyphs_out = NULL;
 
1371
 
 
1372
  if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED)
 
1373
    desired_attributes |= GRUB_FONT_CODE_RIGHT_JOINED;
 
1374
 
 
1375
  if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED)
 
1376
    desired_attributes |= GRUB_FONT_CODE_LEFT_JOINED;
 
1377
 
 
1378
  main_glyph = grub_font_get_glyph_with_fallback (hinted_font, glyph_id->base
 
1379
                                                  | desired_attributes);
 
1380
 
 
1381
  if (!main_glyph)
 
1382
    main_glyph = grub_font_get_glyph_with_fallback (hinted_font,
 
1383
                                                    glyph_id->base);
 
1384
 
 
1385
  /* Glyph not available in any font.  Use ASCII fallback.  */
 
1386
  if (!main_glyph)
 
1387
    main_glyph = ascii_glyph_lookup (glyph_id->base);
 
1388
 
 
1389
  /* Glyph not available in any font.  Return unknown glyph.  */
 
1390
  if (!main_glyph)
 
1391
    return NULL;
 
1392
 
 
1393
  if (device_width)
 
1394
    *device_width = main_glyph->device_width;
 
1395
 
 
1396
  if (!glyph_id->ncomb && !glyph_id->attributes)
 
1397
    return main_glyph;
 
1398
 
 
1399
  combining_glyphs = grub_malloc (sizeof (combining_glyphs[0])
 
1400
                                  * glyph_id->ncomb);
 
1401
  if (glyph_id->ncomb && !combining_glyphs)
 
1402
    {
 
1403
      grub_errno = GRUB_ERR_NONE;
 
1404
      return main_glyph;
 
1405
    }
 
1406
 
 
1407
  {
 
1408
    unsigned i;
 
1409
    for (i = 0; i < glyph_id->ncomb; i++)
 
1410
      combining_glyphs[i]
 
1411
        = grub_font_get_glyph_with_fallback (main_glyph->font,
 
1412
                                             glyph_id->combining[i].code);
 
1413
  }
 
1414
 
 
1415
  blit_comb (glyph_id, NULL, bounds, main_glyph, combining_glyphs,
 
1416
             device_width);
 
1417
  if (combining_glyphs_out)
 
1418
    *combining_glyphs_out = combining_glyphs;
 
1419
  else
 
1420
    grub_free (combining_glyphs);
 
1421
 
 
1422
  return main_glyph;
 
1423
}
 
1424
 
 
1425
int
 
1426
grub_font_get_constructed_device_width (grub_font_t hinted_font,
 
1427
                                        const struct grub_unicode_glyph
 
1428
                                        *glyph_id)
 
1429
{
 
1430
  int ret;
 
1431
  struct grub_font_glyph *main_glyph;
 
1432
  main_glyph = grub_font_construct_dry_run (hinted_font, glyph_id, NULL,
 
1433
                                            NULL, &ret);
 
1434
  if (!main_glyph)
 
1435
    return unknown_glyph->device_width;
 
1436
  return ret;
 
1437
}
 
1438
 
 
1439
struct grub_font_glyph *
 
1440
grub_font_construct_glyph (grub_font_t hinted_font,
 
1441
                           const struct grub_unicode_glyph *glyph_id)
 
1442
{
 
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;
 
1447
 
 
1448
  main_glyph = grub_font_construct_dry_run (hinted_font, glyph_id,
 
1449
                                            &bounds, &combining_glyphs, NULL);
 
1450
 
 
1451
  if (!main_glyph)
 
1452
    return grub_font_dup_glyph (unknown_glyph);
 
1453
 
 
1454
  if (!combining_glyphs)
 
1455
    return grub_font_dup_glyph (main_glyph);
 
1456
 
 
1457
  glyph =
 
1458
    grub_zalloc (sizeof (*glyph) + (bounds.width * bounds.height + 7) / 8);
 
1459
  if (!glyph)
 
1460
    {
 
1461
      grub_errno = GRUB_ERR_NONE;
 
1462
      return grub_font_dup_glyph (main_glyph);
 
1463
    }
 
1464
 
 
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;
 
1470
 
 
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));
 
1477
  else
 
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));
 
1482
 
 
1483
  blit_comb (glyph_id, glyph, NULL, main_glyph, combining_glyphs, NULL);
 
1484
 
 
1485
  return glyph;
 
1486
}
 
1487
 
 
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.  */
 
1491
grub_err_t
 
1492
grub_font_draw_glyph (struct grub_font_glyph * glyph,
 
1493
                      grub_video_color_t color, int left_x, int baseline_y)
 
1494
{
 
1495
  struct grub_video_bitmap glyph_bitmap;
 
1496
 
 
1497
  /* Don't try to draw empty glyphs (U+0020, etc.).  */
 
1498
  if (glyph->width == 0 || glyph->height == 0)
 
1499
    return GRUB_ERR_NONE;
 
1500
 
 
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;
 
1507
 
 
1508
  /* Really 1 bit per pixel.  */
 
1509
  glyph_bitmap.mode_info.bytes_per_pixel = 0;
 
1510
 
 
1511
  /* Packed densely as bits.  */
 
1512
  glyph_bitmap.mode_info.pitch = glyph->width;
 
1513
 
 
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;
 
1525
 
 
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;
 
1529
 
 
1530
  return grub_video_blit_bitmap (&glyph_bitmap, GRUB_VIDEO_BLIT_BLEND,
 
1531
                                 bitmap_left, bitmap_top,
 
1532
                                 0, 0, glyph->width, glyph->height);
 
1533
}