]> git.proxmox.com Git - grub2.git/blame - util/grub-mkfont.c
Put recheck back
[grub2.git] / util / grub-mkfont.c
CommitLineData
e52db1f7 1/*
2 * GRUB -- GRand Unified Bootloader
2f1a3acf 3 * Copyright (C) 2009,2010 Free Software Foundation, Inc.
e52db1f7 4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <config.h>
20#include <grub/types.h>
8c411768
BC
21#include <grub/misc.h>
22#include <grub/emu/misc.h>
e52db1f7 23#include <grub/util/misc.h>
e6d428c1 24#include <grub/misc.h>
8a4c07fd 25#include <grub/i18n.h>
de0b7a4e 26#include <grub/fontformat.h>
e6d428c1 27#include <grub/font.h>
3f11c713 28#include <grub/unicode.h>
e52db1f7 29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <getopt.h>
34
35#include <ft2build.h>
36#include FT_FREETYPE_H
e6d428c1
VS
37#include FT_TRUETYPE_TAGS_H
38#include FT_TRUETYPE_TABLES_H
e52db1f7 39#include <freetype/ftsynth.h>
40
3c31d9c0
VS
41#undef __FTERRORS_H__
42#define FT_ERROR_START_LIST const char *ft_errmsgs[] = {
43#define FT_ERRORDEF(e, v, s) [e] = s,
44#define FT_ERROR_END_LIST };
45#include FT_ERRORS_H
46
8a4c07fd
RM
47#include "progname.h"
48
e52db1f7 49#define GRUB_FONT_DEFAULT_SIZE 16
50
51#define GRUB_FONT_RANGE_BLOCK 1024
52
53struct grub_glyph_info
54{
55 struct grub_glyph_info *next;
56 grub_uint32_t char_code;
57 int width;
58 int height;
59 int x_ofs;
60 int y_ofs;
61 int device_width;
62 int bitmap_size;
e6d428c1 63 grub_uint8_t *bitmap;
e52db1f7 64};
65
26ba5c22 66enum file_formats
67{
68 PF2,
6c363dfd
VS
69 ASCII_BITMAPS,
70 WIDTH_SPEC
26ba5c22 71};
72
e52db1f7 73#define GRUB_FONT_FLAG_BOLD 1
74#define GRUB_FONT_FLAG_NOBITMAP 2
75#define GRUB_FONT_FLAG_NOHINTING 4
76#define GRUB_FONT_FLAG_FORCEHINT 8
77
78struct grub_font_info
79{
80 char* name;
81 int style;
82 int desc;
42841caa 83 int asce;
e52db1f7 84 int size;
85 int max_width;
86 int max_height;
87 int min_y;
42841caa 88 int max_y;
e52db1f7 89 int flags;
90 int num_range;
91 grub_uint32_t *ranges;
e6d428c1
VS
92 struct grub_glyph_info *glyphs_unsorted;
93 struct grub_glyph_info *glyphs_sorted;
94 int num_glyphs;
e52db1f7 95};
96
97static struct option options[] =
98{
99 {"output", required_argument, 0, 'o'},
100 {"name", required_argument, 0, 'n'},
101 {"index", required_argument, 0, 'i'},
102 {"range", required_argument, 0, 'r'},
103 {"size", required_argument, 0, 's'},
104 {"desc", required_argument, 0, 'd'},
42841caa 105 {"asce", required_argument, 0, 'c'},
e52db1f7 106 {"bold", no_argument, 0, 'b'},
107 {"no-bitmap", no_argument, 0, 0x100},
108 {"no-hinting", no_argument, 0, 0x101},
109 {"force-autohint", no_argument, 0, 'a'},
110 {"help", no_argument, 0, 'h'},
111 {"version", no_argument, 0, 'V'},
112 {"verbose", no_argument, 0, 'v'},
26ba5c22 113 {"ascii-bitmaps", no_argument, 0, 0x102},
6c363dfd 114 {"width-spec", no_argument, 0, 0x103},
e52db1f7 115 {0, 0, 0, 0}
116};
117
118int font_verbosity;
119
120static void
121usage (int status)
122{
123 if (status)
10f0117b
VS
124 fprintf (stderr, _("Try `%s --help' for more information.\n"),
125 program_name);
e52db1f7 126 else
10f0117b 127 printf (_("\
8a4c07fd 128Usage: %s [OPTIONS] FONT_FILES\n\
e52db1f7 129\nOptions:\n\
130 -o, --output=FILE_NAME set output file name\n\
26ba5c22 131 --ascii-bitmaps save only the ASCII bitmaps\n\
6c363dfd 132 --width-spec create width summary file\n\
e52db1f7 133 -i, --index=N set face index\n\
134 -r, --range=A-B[,C-D] set font range\n\
135 -n, --name=S set font family name\n\
136 -s, --size=N set font size\n\
137 -d, --desc=N set font descent\n\
42841caa 138 -c, --asce=N set font ascent\n\
e52db1f7 139 -b, --bold convert to bold font\n\
6a7eab2c 140 -a, --force-autohint force autohint\n\
e52db1f7 141 --no-hinting disable hinting\n\
142 --no-bitmap ignore bitmap strikes when loading\n\
143 -h, --help display this message and exit\n\
144 -V, --version print version information and exit\n\
145 -v, --verbose print verbose messages\n\
146\n\
10f0117b 147Report bugs to <%s>.\n"), program_name, PACKAGE_BUGREPORT);
e52db1f7 148
149 exit (status);
150}
151
152void
153add_pixel (grub_uint8_t **data, int *mask, int not_blank)
154{
155 if (*mask == 0)
156 {
157 (*data)++;
158 **data = 0;
159 *mask = 128;
160 }
161
162 if (not_blank)
163 **data |= *mask;
164
165 *mask >>= 1;
166}
167
e6d428c1
VS
168static void
169add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face,
a6ab5fb2 170 grub_uint32_t char_code, int nocut)
e52db1f7 171{
e6d428c1 172 struct grub_glyph_info *glyph_info;
e52db1f7 173 int width, height;
a6ab5fb2 174 int cuttop, cutbottom, cutleft, cutright;
e52db1f7 175 grub_uint8_t *data;
176 int mask, i, j, bitmap_size;
177 FT_GlyphSlot glyph;
178 int flag = FT_LOAD_RENDER | FT_LOAD_MONOCHROME;
3c31d9c0 179 FT_Error err;
e52db1f7 180
181 if (font_info->flags & GRUB_FONT_FLAG_NOBITMAP)
182 flag |= FT_LOAD_NO_BITMAP;
183
184 if (font_info->flags & GRUB_FONT_FLAG_NOHINTING)
185 flag |= FT_LOAD_NO_HINTING;
186 else if (font_info->flags & GRUB_FONT_FLAG_FORCEHINT)
187 flag |= FT_LOAD_FORCE_AUTOHINT;
188
3c31d9c0
VS
189 err = FT_Load_Glyph (face, glyph_idx, flag);
190 if (err)
e6d428c1 191 {
10f0117b 192 printf (_("Freetype Error %d loading glyph 0x%x for U+0x%x%s"),
3f11c713
VS
193 err, glyph_idx, char_code & GRUB_FONT_CODE_CHAR_MASK,
194 char_code & GRUB_FONT_CODE_RIGHT_JOINED
10f0117b
VS
195 ? ((char_code & GRUB_FONT_CODE_LEFT_JOINED) ? _(" (medial)"):
196 _(" (leftmost)"))
197 : ((char_code & GRUB_FONT_CODE_LEFT_JOINED) ? _(" (rightmost)"):
3f11c713
VS
198 ""));
199
200 if (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs))
201 printf (": %s\n", ft_errmsgs[err]);
3c31d9c0 202 else
3f11c713 203 printf ("\n");
e6d428c1
VS
204 return;
205 }
e52db1f7 206
207 glyph = face->glyph;
208
209 if (font_info->flags & GRUB_FONT_FLAG_BOLD)
210 FT_GlyphSlot_Embolden (glyph);
211
72f12cdc
VS
212 if (glyph->next)
213 printf ("%x\n", char_code);
214
a6ab5fb2
VS
215 if (nocut)
216 cuttop = cutbottom = cutleft = cutright = 0;
217 else
e52db1f7 218 {
a6ab5fb2
VS
219 for (cuttop = 0; cuttop < glyph->bitmap.rows; cuttop++)
220 {
221 for (j = 0; j < glyph->bitmap.width; j++)
222 if (glyph->bitmap.buffer[j / 8 + cuttop * glyph->bitmap.pitch]
223 & (1 << (7 - (j & 7))))
224 break;
225 if (j != glyph->bitmap.width)
226 break;
227 }
e52db1f7 228
a6ab5fb2
VS
229 for (cutbottom = glyph->bitmap.rows - 1; cutbottom >= 0; cutbottom--)
230 {
231 for (j = 0; j < glyph->bitmap.width; j++)
232 if (glyph->bitmap.buffer[j / 8 + cutbottom * glyph->bitmap.pitch]
233 & (1 << (7 - (j & 7))))
234 break;
235 if (j != glyph->bitmap.width)
236 break;
237 }
238 cutbottom = glyph->bitmap.rows - 1 - cutbottom;
239 if (cutbottom + cuttop >= glyph->bitmap.rows)
240 cutbottom = 0;
241
242 for (cutleft = 0; cutleft < glyph->bitmap.width; cutleft++)
243 {
244 for (j = 0; j < glyph->bitmap.rows; j++)
245 if (glyph->bitmap.buffer[cutleft / 8 + j * glyph->bitmap.pitch]
246 & (1 << (7 - (cutleft & 7))))
247 break;
248 if (j != glyph->bitmap.rows)
249 break;
250 }
251 for (cutright = glyph->bitmap.width - 1; cutright >= 0; cutright--)
252 {
253 for (j = 0; j < glyph->bitmap.rows; j++)
254 if (glyph->bitmap.buffer[cutright / 8 + j * glyph->bitmap.pitch]
255 & (1 << (7 - (cutright & 7))))
256 break;
257 if (j != glyph->bitmap.rows)
258 break;
259 }
260 cutright = glyph->bitmap.width - 1 - cutright;
261 if (cutright + cutleft >= glyph->bitmap.width)
262 cutright = 0;
263 }
e52db1f7 264
a6ab5fb2
VS
265 width = glyph->bitmap.width - cutleft - cutright;
266 height = glyph->bitmap.rows - cutbottom - cuttop;
e52db1f7 267
268 bitmap_size = ((width * height + 7) / 8);
e6d428c1
VS
269 glyph_info = xmalloc (sizeof (struct grub_glyph_info));
270 glyph_info->bitmap = xmalloc (bitmap_size);
e52db1f7 271 glyph_info->bitmap_size = bitmap_size;
272
e6d428c1
VS
273 glyph_info->next = font_info->glyphs_unsorted;
274 font_info->glyphs_unsorted = glyph_info;
275 font_info->num_glyphs++;
e52db1f7 276
277 glyph_info->char_code = char_code;
278 glyph_info->width = width;
279 glyph_info->height = height;
a6ab5fb2
VS
280 glyph_info->x_ofs = glyph->bitmap_left + cutleft;
281 glyph_info->y_ofs = glyph->bitmap_top - height - cuttop;
e52db1f7 282 glyph_info->device_width = glyph->metrics.horiAdvance / 64;
283
284 if (width > font_info->max_width)
285 font_info->max_width = width;
286
287 if (height > font_info->max_height)
288 font_info->max_height = height;
289
42841caa 290 if (glyph_info->y_ofs < font_info->min_y && glyph_info->y_ofs > -font_info->size)
e52db1f7 291 font_info->min_y = glyph_info->y_ofs;
292
42841caa
VS
293 if (glyph_info->y_ofs + height > font_info->max_y)
294 font_info->max_y = glyph_info->y_ofs + height;
295
e52db1f7 296 mask = 0;
297 data = &glyph_info->bitmap[0] - 1;
a6ab5fb2
VS
298 for (j = cuttop; j < height + cuttop; j++)
299 for (i = cutleft; i < width + cutleft; i++)
e52db1f7 300 add_pixel (&data, &mask,
301 glyph->bitmap.buffer[i / 8 + j * glyph->bitmap.pitch] &
302 (1 << (7 - (i & 7))));
303}
304
e6d428c1
VS
305struct glyph_replace *subst_rightjoin, *subst_leftjoin, *subst_medijoin;
306
307struct glyph_replace
308{
309 struct glyph_replace *next;
310 grub_uint32_t from, to;
311};
312
313/* TODO: sort glyph_replace and use binary search if necessary. */
314static void
315add_char (struct grub_font_info *font_info, FT_Face face,
a6ab5fb2 316 grub_uint32_t char_code, int nocut)
e6d428c1
VS
317{
318 FT_UInt glyph_idx;
319 struct glyph_replace *cur;
320
321 glyph_idx = FT_Get_Char_Index (face, char_code);
322 if (!glyph_idx)
323 return;
a6ab5fb2 324 add_glyph (font_info, glyph_idx, face, char_code, nocut);
e6d428c1
VS
325 for (cur = subst_rightjoin; cur; cur = cur->next)
326 if (cur->from == glyph_idx)
327 {
328 add_glyph (font_info, cur->to, face,
a6ab5fb2 329 char_code | GRUB_FONT_CODE_RIGHT_JOINED, nocut);
e6d428c1
VS
330 break;
331 }
3f11c713
VS
332 if (!cur && char_code >= GRUB_UNICODE_ARABIC_START
333 && char_code < GRUB_UNICODE_ARABIC_END)
334 {
335 int i;
336 for (i = 0; grub_unicode_arabic_shapes[i].code; i++)
337 if (grub_unicode_arabic_shapes[i].code == char_code
338 && grub_unicode_arabic_shapes[i].right_linked)
339 {
340 FT_UInt idx2;
341 idx2 = FT_Get_Char_Index (face, grub_unicode_arabic_shapes[i]
342 .right_linked);
343 if (idx2)
344 add_glyph (font_info, idx2, face,
a6ab5fb2 345 char_code | GRUB_FONT_CODE_RIGHT_JOINED, nocut);
3f11c713
VS
346 break;
347 }
348
349 }
350
e6d428c1
VS
351 for (cur = subst_leftjoin; cur; cur = cur->next)
352 if (cur->from == glyph_idx)
353 {
354 add_glyph (font_info, cur->to, face,
a6ab5fb2 355 char_code | GRUB_FONT_CODE_LEFT_JOINED, nocut);
e6d428c1
VS
356 break;
357 }
3f11c713
VS
358 if (!cur && char_code >= GRUB_UNICODE_ARABIC_START
359 && char_code < GRUB_UNICODE_ARABIC_END)
360 {
361 int i;
362 for (i = 0; grub_unicode_arabic_shapes[i].code; i++)
363 if (grub_unicode_arabic_shapes[i].code == char_code
364 && grub_unicode_arabic_shapes[i].left_linked)
365 {
366 FT_UInt idx2;
367 idx2 = FT_Get_Char_Index (face, grub_unicode_arabic_shapes[i]
368 .left_linked);
369 if (idx2)
370 add_glyph (font_info, idx2, face,
a6ab5fb2 371 char_code | GRUB_FONT_CODE_LEFT_JOINED, nocut);
3f11c713
VS
372 break;
373 }
374
375 }
e6d428c1
VS
376 for (cur = subst_medijoin; cur; cur = cur->next)
377 if (cur->from == glyph_idx)
378 {
379 add_glyph (font_info, cur->to, face,
380 char_code | GRUB_FONT_CODE_LEFT_JOINED
a6ab5fb2 381 | GRUB_FONT_CODE_RIGHT_JOINED, nocut);
e6d428c1
VS
382 break;
383 }
3f11c713
VS
384 if (!cur && char_code >= GRUB_UNICODE_ARABIC_START
385 && char_code < GRUB_UNICODE_ARABIC_END)
386 {
387 int i;
388 for (i = 0; grub_unicode_arabic_shapes[i].code; i++)
389 if (grub_unicode_arabic_shapes[i].code == char_code
390 && grub_unicode_arabic_shapes[i].both_linked)
391 {
392 FT_UInt idx2;
393 idx2 = FT_Get_Char_Index (face, grub_unicode_arabic_shapes[i]
394 .both_linked);
395 if (idx2)
396 add_glyph (font_info, idx2, face,
397 char_code | GRUB_FONT_CODE_LEFT_JOINED
a6ab5fb2 398 | GRUB_FONT_CODE_RIGHT_JOINED, nocut);
3f11c713
VS
399 break;
400 }
401
402 }
e6d428c1
VS
403}
404
405struct gsub_header
406{
407 grub_uint32_t version;
408 grub_uint16_t scripts_off;
409 grub_uint16_t features_off;
410 grub_uint16_t lookups_off;
411} __attribute__ ((packed));
412
413struct gsub_features
414{
415 grub_uint16_t count;
416 struct
417 {
418#define FEATURE_FINA 0x66696e61
419#define FEATURE_INIT 0x696e6974
420#define FEATURE_MEDI 0x6d656469
421#define FEATURE_AALT 0x61616c74
6d107fb2
VS
422#define FEATURE_LIGA 0x6c696761
423#define FEATURE_RLIG 0x726c6967
e6d428c1
VS
424 grub_uint32_t feature_tag;
425 grub_uint16_t offset;
426 } __attribute__ ((packed)) features[0];
427} __attribute__ ((packed));
428
429struct gsub_feature
430{
431 grub_uint16_t params;
432 grub_uint16_t lookupcount;
433 grub_uint16_t lookupindices[0];
434} __attribute__ ((packed));
435
436struct gsub_lookup_list
437{
438 grub_uint16_t count;
439 grub_uint16_t offsets[0];
440} __attribute__ ((packed));
441
442struct gsub_lookup
443{
444 grub_uint16_t type;
445 grub_uint16_t flag;
446 grub_uint16_t subtablecount;
447 grub_uint16_t subtables[0];
448} __attribute__ ((packed));
449
450struct gsub_substitution
451{
452 grub_uint16_t type;
453 grub_uint16_t coverage_off;
454 union
455 {
456 grub_int16_t delta;
457 struct
458 {
459 grub_int16_t count;
460 grub_uint16_t repl[0];
461 };
462 };
463} __attribute__ ((packed));
464
465struct gsub_coverage_list
466{
467 grub_uint16_t type;
468 grub_uint16_t count;
469 grub_uint16_t glyphs[0];
470} __attribute__ ((packed));
471
472struct gsub_coverage_ranges
473{
474 grub_uint16_t type;
475 grub_uint16_t count;
476 struct
477 {
478 grub_uint16_t start;
479 grub_uint16_t end;
480 grub_uint16_t start_index;
481 } __attribute__ ((packed)) ranges[0];
482} __attribute__ ((packed));
483
484#define GSUB_SINGLE_SUBSTITUTION 1
485
486#define GSUB_SUBSTITUTION_DELTA 1
487#define GSUB_SUBSTITUTION_MAP 2
488
489#define GSUB_COVERAGE_LIST 1
490#define GSUB_COVERAGE_RANGE 2
491
492#define GSUB_RTL_CHAR 1
493
494static void
495add_subst (grub_uint32_t from, grub_uint32_t to, struct glyph_replace **target)
496{
497 struct glyph_replace *new = xmalloc (sizeof (*new));
498 new->next = *target;
499 new->from = from;
500 new->to = to;
501 *target = new;
502}
503
504static void
505process_cursive (struct gsub_feature *feature,
506 struct gsub_lookup_list *lookups,
507 grub_uint32_t feattag)
508{
509 int j, k;
510 int i;
511 struct glyph_replace **target;
512 struct gsub_substitution *sub;
513
514 auto inline void subst (grub_uint32_t glyph);
515 void subst (grub_uint32_t glyph)
516 {
517 grub_uint16_t substtype;
518 substtype = grub_be_to_cpu16 (sub->type);
519
520 if (substtype == GSUB_SUBSTITUTION_DELTA)
521 add_subst (glyph, glyph + grub_be_to_cpu16 (sub->delta), target);
522 else if (i >= grub_be_to_cpu16 (sub->count))
10f0117b 523 printf (_("Out of range substitution (%d, %d)\n"), i,
e6d428c1
VS
524 grub_be_to_cpu16 (sub->count));
525 else
526 add_subst (glyph, grub_be_to_cpu16 (sub->repl[i++]), target);
527 }
528
529 for (j = 0; j < grub_be_to_cpu16 (feature->lookupcount); j++)
530 {
531 int lookup_index = grub_be_to_cpu16 (feature->lookupindices[j]);
532 struct gsub_lookup *lookup;
533 if (lookup_index >= grub_be_to_cpu16 (lookups->count))
534 {
10f0117b 535 printf (_("Out of range lookup: %d\n"), lookup_index);
e6d428c1
VS
536 continue;
537 }
538 lookup = (struct gsub_lookup *)
539 ((grub_uint8_t *) lookups
540 + grub_be_to_cpu16 (lookups->offsets[lookup_index]));
541 if (grub_be_to_cpu16 (lookup->type) != GSUB_SINGLE_SUBSTITUTION)
542 {
10f0117b 543 printf (_("Unsupported substitution type: %d\n"),
e6d428c1
VS
544 grub_be_to_cpu16 (lookup->type));
545 continue;
546 }
547 if (grub_be_to_cpu16 (lookup->flag) & ~GSUB_RTL_CHAR)
548 {
10f0117b 549 printf (_("Unsupported substitution flag: 0x%x\n"),
e6d428c1
VS
550 grub_be_to_cpu16 (lookup->flag));
551 }
552 switch (feattag)
553 {
554 case FEATURE_INIT:
555 if (grub_be_to_cpu16 (lookup->flag) & GSUB_RTL_CHAR)
556 target = &subst_leftjoin;
557 else
558 target = &subst_rightjoin;
559 break;
560 case FEATURE_FINA:
561 if (grub_be_to_cpu16 (lookup->flag) & GSUB_RTL_CHAR)
562 target = &subst_rightjoin;
563 else
564 target = &subst_leftjoin;
565 break;
566 case FEATURE_MEDI:
567 target = &subst_medijoin;
568 break;
569 }
570 for (k = 0; k < grub_be_to_cpu16 (lookup->subtablecount); k++)
571 {
572 sub = (struct gsub_substitution *)
573 ((grub_uint8_t *) lookup + grub_be_to_cpu16 (lookup->subtables[k]));
574 grub_uint16_t substtype;
575 substtype = grub_be_to_cpu16 (sub->type);
576 if (substtype != GSUB_SUBSTITUTION_MAP
577 && substtype != GSUB_SUBSTITUTION_DELTA)
578 {
10f0117b 579 printf (_("Unsupported substitution specification: %d\n"),
e6d428c1
VS
580 substtype);
581 continue;
582 }
583 void *coverage = (grub_uint8_t *) sub
584 + grub_be_to_cpu16 (sub->coverage_off);
585 grub_uint32_t covertype;
586 covertype = grub_be_to_cpu16 (*(grub_uint16_t * __attribute__ ((packed))) coverage);
587 i = 0;
588 if (covertype == GSUB_COVERAGE_LIST)
589 {
590 struct gsub_coverage_list *cover = coverage;
591 int l;
592 for (l = 0; l < grub_be_to_cpu16 (cover->count); l++)
593 subst (grub_be_to_cpu16 (cover->glyphs[l]));
594 }
595 else if (covertype == GSUB_COVERAGE_RANGE)
596 {
597 struct gsub_coverage_ranges *cover = coverage;
598 int l, m;
599 for (l = 0; l < grub_be_to_cpu16 (cover->count); l++)
600 for (m = grub_be_to_cpu16 (cover->ranges[l].start);
601 m <= grub_be_to_cpu16 (cover->ranges[l].end); m++)
602 subst (m);
603 }
604 else
10f0117b 605 printf (_("Unsupported coverage specification: %d\n"), covertype);
e6d428c1
VS
606 }
607 }
608}
609
e52db1f7 610void
a6ab5fb2 611add_font (struct grub_font_info *font_info, FT_Face face, int nocut)
e52db1f7 612{
e6d428c1
VS
613 struct gsub_header *gsub = NULL;
614 FT_ULong gsub_len = 0;
615
616 if (!FT_Load_Sfnt_Table (face, TTAG_GSUB, 0, NULL, &gsub_len))
617 {
618 gsub = xmalloc (gsub_len);
619 if (FT_Load_Sfnt_Table (face, TTAG_GSUB, 0, (void *) gsub, &gsub_len))
620 {
621 free (gsub);
622 gsub = NULL;
623 gsub_len = 0;
624 }
625 }
626 if (gsub)
627 {
628 struct gsub_features *features
629 = (struct gsub_features *) (((grub_uint8_t *) gsub)
630 + grub_be_to_cpu16 (gsub->features_off));
631 struct gsub_lookup_list *lookups
632 = (struct gsub_lookup_list *) (((grub_uint8_t *) gsub)
633 + grub_be_to_cpu16 (gsub->lookups_off));
634 int i;
635 int nfeatures = grub_be_to_cpu16 (features->count);
636 for (i = 0; i < nfeatures; i++)
637 {
638 struct gsub_feature *feature = (struct gsub_feature *)
639 ((grub_uint8_t *) features
640 + grub_be_to_cpu16 (features->features[i].offset));
641 grub_uint32_t feattag
642 = grub_be_to_cpu32 (features->features[i].feature_tag);
643 if (feature->params)
10f0117b 644 printf (_("WARNING: unsupported feature parameters: %x\n"),
e6d428c1
VS
645 grub_be_to_cpu16 (feature->params));
646 switch (feattag)
647 {
648 /* Used for retrieving all possible variants. Useless in grub. */
649 case FEATURE_AALT:
650 break;
651
6d107fb2
VS
652 /* FIXME: Add ligature support. */
653 case FEATURE_LIGA:
654 case FEATURE_RLIG:
655 break;
656
e6d428c1
VS
657 /* Cursive form variants. */
658 case FEATURE_FINA:
659 case FEATURE_INIT:
660 case FEATURE_MEDI:
661 process_cursive (feature, lookups, feattag);
662 break;
663
664 default:
665 {
666 char str[5];
667 int j;
668 memcpy (str, &features->features[i].feature_tag,
669 sizeof (features->features[i].feature_tag));
670 str[4] = 0;
671 for (j = 0; j < 4; j++)
672 if (!grub_isgraph (str[j]))
673 str[j] = '?';
10f0117b 674 printf (_("Unknown gsub feature 0x%x (%s)\n"), feattag, str);
e6d428c1
VS
675 }
676 }
677 }
678 }
679
e52db1f7 680 if (font_info->num_range)
681 {
682 int i;
683 grub_uint32_t j;
684
685 for (i = 0; i < font_info->num_range; i++)
686 for (j = font_info->ranges[i * 2]; j <= font_info->ranges[i * 2 + 1];
687 j++)
a6ab5fb2 688 add_char (font_info, face, j, nocut);
e52db1f7 689 }
690 else
691 {
692 grub_uint32_t char_code, glyph_index;
693
694 for (char_code = FT_Get_First_Char (face, &glyph_index);
695 glyph_index;
696 char_code = FT_Get_Next_Char (face, char_code, &glyph_index))
a6ab5fb2 697 add_char (font_info, face, char_code, nocut);
e52db1f7 698 }
699}
700
701void
702write_string_section (char *name, char *str, int* offset, FILE* file)
703{
704 grub_uint32_t leng, leng_be32;
705
706 leng = strlen (str) + 1;
707 leng_be32 = grub_cpu_to_be32 (leng);
708
709 grub_util_write_image (name, 4, file);
710 grub_util_write_image ((char *) &leng_be32, 4, file);
711 grub_util_write_image (str, leng, file);
712
713 *offset += 8 + leng;
714}
715
716void
717write_be16_section (char *name, grub_uint16_t data, int* offset, FILE* file)
718{
719 grub_uint32_t leng;
720
721 leng = grub_cpu_to_be32 (2);
722 data = grub_cpu_to_be16 (data);
723 grub_util_write_image (name, 4, file);
724 grub_util_write_image ((char *) &leng, 4, file);
725 grub_util_write_image ((char *) &data, 2, file);
726
727 *offset += 10;
728}
729
730void
731print_glyphs (struct grub_font_info *font_info)
732{
733 int num;
734 struct grub_glyph_info *glyph;
735 char line[512];
736
e6d428c1
VS
737 for (glyph = font_info->glyphs_sorted, num = 0; num < font_info->num_glyphs;
738 glyph++, num++)
e52db1f7 739 {
740 int x, y, xmax, xmin, ymax, ymin;
741 grub_uint8_t *bitmap, mask;
742
10f0117b
VS
743 printf (_("\nGlyph #%d, U+%04x\n"), num, glyph->char_code);
744 printf (_("Width %d, Height %d, X offset %d, Y offset %d, Device width %d\n"),
e52db1f7 745 glyph->width, glyph->height, glyph->x_ofs, glyph->y_ofs,
746 glyph->device_width);
747
748 xmax = glyph->x_ofs + glyph->width;
749 if (xmax < glyph->device_width)
750 xmax = glyph->device_width;
751
752 xmin = glyph->x_ofs;
753 if (xmin > 0)
754 xmin = 0;
755
756 ymax = glyph->y_ofs + glyph->height;
42841caa
VS
757 if (ymax < font_info->asce)
758 ymax = font_info->asce;
e52db1f7 759
760 ymin = glyph->y_ofs;
761 if (ymin > - font_info->desc)
762 ymin = - font_info->desc;
763
764 bitmap = glyph->bitmap;
765 mask = 0x80;
766 for (y = ymax - 1; y >= ymin; y--)
767 {
768 int line_pos;
769
770 line_pos = 0;
771 for (x = xmin; x < xmax; x++)
772 {
773 if ((x >= glyph->x_ofs) &&
774 (x < glyph->x_ofs + glyph->width) &&
775 (y >= glyph->y_ofs) &&
776 (y < glyph->y_ofs + glyph->height))
777 {
778 line[line_pos++] = (*bitmap & mask) ? '#' : '_';
779 mask >>= 1;
780 if (mask == 0)
781 {
782 mask = 0x80;
783 bitmap++;
784 }
785 }
786 else if ((x >= 0) &&
787 (x < glyph->device_width) &&
788 (y >= - font_info->desc) &&
42841caa 789 (y < font_info->asce))
e52db1f7 790 {
791 line[line_pos++] = ((x == 0) || (y == 0)) ? '+' : '.';
792 }
793 else
794 line[line_pos++] = '*';
795 }
796 line[line_pos] = 0;
797 printf ("%s\n", line);
798 }
799 }
800}
801
802void
26ba5c22 803write_font_ascii_bitmap (struct grub_font_info *font_info, char *output_file)
804{
805 FILE *file;
806 struct grub_glyph_info *glyph;
807 int num;
808
809 file = fopen (output_file, "wb");
810 if (! file)
10f0117b 811 grub_util_error (_("Can\'t write to file %s."), output_file);
26ba5c22 812
813 int correct_size;
e6d428c1
VS
814 for (glyph = font_info->glyphs_sorted, num = 0; num < font_info->num_glyphs;
815 glyph++, num++)
26ba5c22 816 {
817 correct_size = 1;
818 if (glyph->width != 8 || glyph->height != 16)
819 {
d1fb0f65 820 /* printf ("Width or height from glyph U+%04x not supported, skipping.\n", glyph->char_code); */
26ba5c22 821 correct_size = 0;
822 }
823 int row;
824 for (row = 0; row < glyph->height; row++)
825 {
826 if (correct_size)
827 fwrite (&glyph->bitmap[row], sizeof(glyph->bitmap[row]), 1, file);
828 else
829 fwrite (&correct_size, 1, 1, file);
830 }
831 }
832 fclose (file);
833}
834
6c363dfd
VS
835void
836write_font_width_spec (struct grub_font_info *font_info, char *output_file)
837{
838 FILE *file;
839 struct grub_glyph_info *glyph;
840 grub_uint8_t *out;
6c363dfd
VS
841
842 out = xmalloc (8192);
843 memset (out, 0, 8192);
844
845 file = fopen (output_file, "wb");
846 if (! file)
10f0117b 847 grub_util_error (_("Can\'t write to file %s."), output_file);
6c363dfd 848
e6d428c1
VS
849 for (glyph = font_info->glyphs_sorted;
850 glyph < font_info->glyphs_sorted + font_info->num_glyphs; glyph++)
6c363dfd
VS
851 if (glyph->width > 12)
852 out[glyph->char_code >> 3] |= (1 << (glyph->char_code & 7));
853
854 fwrite (out, 8192, 1, file);
855 fclose (file);
856 free (out);
857}
858
26ba5c22 859void
860write_font_pf2 (struct grub_font_info *font_info, char *output_file)
e52db1f7 861{
862 FILE *file;
f8f479db 863 grub_uint32_t leng;
e52db1f7 864 char style_name[20], *font_name;
e6d428c1
VS
865 int offset;
866 struct grub_glyph_info *cur;
e52db1f7 867
868 file = fopen (output_file, "wb");
869 if (! file)
10f0117b 870 grub_util_error (_("Can\'t write to file %s."), output_file);
e52db1f7 871
872 offset = 0;
873
874 leng = grub_cpu_to_be32 (4);
de0b7a4e 875 grub_util_write_image (FONT_FORMAT_SECTION_NAMES_FILE,
876 sizeof(FONT_FORMAT_SECTION_NAMES_FILE) - 1, file);
e52db1f7 877 grub_util_write_image ((char *) &leng, 4, file);
de0b7a4e 878 grub_util_write_image (FONT_FORMAT_PFF2_MAGIC, 4, file);
e52db1f7 879 offset += 12;
880
881 if (! font_info->name)
882 font_info->name = "Unknown";
883
884 if (font_info->flags & GRUB_FONT_FLAG_BOLD)
885 font_info->style |= FT_STYLE_FLAG_BOLD;
886
887 style_name[0] = 0;
888 if (font_info->style & FT_STYLE_FLAG_BOLD)
889 strcpy (style_name, " Bold");
890
891 if (font_info->style & FT_STYLE_FLAG_ITALIC)
892 strcat (style_name, " Italic");
893
894 if (! style_name[0])
895 strcpy (style_name, " Regular");
896
d6ceebf1
CW
897 font_name = xasprintf ("%s %s %d", font_info->name, &style_name[1],
898 font_info->size);
e52db1f7 899
de0b7a4e 900 write_string_section (FONT_FORMAT_SECTION_NAMES_FONT_NAME,
901 font_name, &offset, file);
902 write_string_section (FONT_FORMAT_SECTION_NAMES_FAMILY,
903 font_info->name, &offset, file);
904 write_string_section (FONT_FORMAT_SECTION_NAMES_WEIGHT,
e52db1f7 905 (font_info->style & FT_STYLE_FLAG_BOLD) ?
906 "bold" : "normal",
907 &offset, file);
de0b7a4e 908 write_string_section (FONT_FORMAT_SECTION_NAMES_SLAN,
e52db1f7 909 (font_info->style & FT_STYLE_FLAG_ITALIC) ?
910 "italic" : "normal",
911 &offset, file);
912
de0b7a4e 913 write_be16_section (FONT_FORMAT_SECTION_NAMES_POINT_SIZE,
914 font_info->size, &offset, file);
915 write_be16_section (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH,
916 font_info->max_width, &offset, file);
917 write_be16_section (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT,
918 font_info->max_height, &offset, file);
e52db1f7 919
920 if (! font_info->desc)
921 {
922 if (font_info->min_y >= 0)
923 font_info->desc = 1;
924 else
925 font_info->desc = - font_info->min_y;
926 }
927
42841caa
VS
928 if (! font_info->asce)
929 {
930 if (font_info->max_y <= 0)
931 font_info->asce = 1;
932 else
933 font_info->asce = font_info->max_y;
934 }
935
de0b7a4e 936 write_be16_section (FONT_FORMAT_SECTION_NAMES_ASCENT,
937 font_info->asce, &offset, file);
938 write_be16_section (FONT_FORMAT_SECTION_NAMES_DESCENT,
939 font_info->desc, &offset, file);
e52db1f7 940
941 if (font_verbosity > 0)
942 {
943 printf ("Font name: %s\n", font_name);
944 printf ("Max width: %d\n", font_info->max_width);
945 printf ("Max height: %d\n", font_info->max_height);
42841caa 946 printf ("Font ascent: %d\n", font_info->asce);
e52db1f7 947 printf ("Font descent: %d\n", font_info->desc);
948 }
949
e52db1f7 950 if (font_verbosity > 0)
e6d428c1 951 printf ("Number of glyph: %d\n", font_info->num_glyphs);
e52db1f7 952
e6d428c1 953 leng = grub_cpu_to_be32 (font_info->num_glyphs * 9);
de0b7a4e 954 grub_util_write_image (FONT_FORMAT_SECTION_NAMES_CHAR_INDEX,
955 sizeof(FONT_FORMAT_SECTION_NAMES_CHAR_INDEX) - 1,
956 file);
e52db1f7 957 grub_util_write_image ((char *) &leng, 4, file);
e6d428c1 958 offset += 8 + font_info->num_glyphs * 9 + 8;
e52db1f7 959
e6d428c1
VS
960 for (cur = font_info->glyphs_sorted;
961 cur < font_info->glyphs_sorted + font_info->num_glyphs; cur++)
e52db1f7 962 {
f8f479db
VS
963 grub_uint32_t data32;
964 grub_uint8_t data8;
965 data32 = grub_cpu_to_be32 (cur->char_code);
966 grub_util_write_image ((char *) &data32, 4, file);
967 data8 = 0;
968 grub_util_write_image ((char *) &data8, 1, file);
969 data32 = grub_cpu_to_be32 (offset);
970 grub_util_write_image ((char *) &data32, 4, file);
e52db1f7 971 offset += 10 + cur->bitmap_size;
972 }
973
974 leng = 0xffffffff;
de0b7a4e 975 grub_util_write_image (FONT_FORMAT_SECTION_NAMES_DATA,
976 sizeof(FONT_FORMAT_SECTION_NAMES_DATA) - 1, file);
e52db1f7 977 grub_util_write_image ((char *) &leng, 4, file);
978
e6d428c1
VS
979 for (cur = font_info->glyphs_sorted;
980 cur < font_info->glyphs_sorted + font_info->num_glyphs; cur++)
e52db1f7 981 {
f8f479db 982 grub_uint16_t data;
e52db1f7 983 data = grub_cpu_to_be16 (cur->width);
984 grub_util_write_image ((char *) &data, 2, file);
985 data = grub_cpu_to_be16 (cur->height);
986 grub_util_write_image ((char *) &data, 2, file);
987 data = grub_cpu_to_be16 (cur->x_ofs);
988 grub_util_write_image ((char *) &data, 2, file);
989 data = grub_cpu_to_be16 (cur->y_ofs);
990 grub_util_write_image ((char *) &data, 2, file);
991 data = grub_cpu_to_be16 (cur->device_width);
992 grub_util_write_image ((char *) &data, 2, file);
993 grub_util_write_image ((char *) &cur->bitmap[0], cur->bitmap_size, file);
994 }
995
e52db1f7 996 fclose (file);
997}
998
999int
1000main (int argc, char *argv[])
1001{
1002 struct grub_font_info font_info;
1003 FT_Library ft_lib;
1004 int font_index = 0;
1005 int font_size = 0;
1006 char *output_file = NULL;
26ba5c22 1007 enum file_formats file_format = PF2;
e52db1f7 1008
1009 memset (&font_info, 0, sizeof (font_info));
1010
8a4c07fd 1011 set_program_name (argv[0]);
2f1a3acf
YB
1012
1013 grub_util_init_nls ();
e52db1f7 1014
1015 /* Check for options. */
1016 while (1)
1017 {
1018 int c = getopt_long (argc, argv, "bao:n:i:s:d:r:hVv", options, 0);
1019
1020 if (c == -1)
1021 break;
1022 else
1023 switch (c)
1024 {
1025 case 'b':
1026 font_info.flags |= GRUB_FONT_FLAG_BOLD;
1027 break;
1028
1029 case 0x100:
1030 font_info.flags |= GRUB_FONT_FLAG_NOBITMAP;
1031 break;
1032
1033 case 0x101:
1034 font_info.flags |= GRUB_FONT_FLAG_NOHINTING;
1035 break;
1036
1037 case 'a':
1038 font_info.flags |= GRUB_FONT_FLAG_FORCEHINT;
1039 break;
1040
1041 case 'o':
1042 output_file = optarg;
1043 break;
1044
1045 case 'n':
1046 font_info.name = optarg;
1047 break;
1048
1049 case 'i':
1050 font_index = strtoul (optarg, NULL, 0);
1051 break;
1052
1053 case 's':
1054 font_size = strtoul (optarg, NULL, 0);
1055 break;
1056
1057 case 'r':
1058 {
1059 char *p = optarg;
1060
1061 while (1)
1062 {
1063 grub_uint32_t a, b;
1064
1065 a = strtoul (p, &p, 0);
1066 if (*p != '-')
10f0117b 1067 grub_util_error (_("invalid font range"));
e52db1f7 1068 b = strtoul (p + 1, &p, 0);
1069 if ((font_info.num_range & (GRUB_FONT_RANGE_BLOCK - 1)) == 0)
1070 font_info.ranges = xrealloc (font_info.ranges,
1071 (font_info.num_range +
1072 GRUB_FONT_RANGE_BLOCK) *
26ba5c22 1073 sizeof (grub_uint32_t) * 2);
e52db1f7 1074
1075 font_info.ranges[font_info.num_range * 2] = a;
1076 font_info.ranges[font_info.num_range * 2 + 1] = b;
1077 font_info.num_range++;
1078
1079 if (*p)
1080 {
1081 if (*p != ',')
10f0117b 1082 grub_util_error (_("invalid font range"));
e52db1f7 1083 else
1084 p++;
1085 }
1086 else
1087 break;
1088 }
1089 break;
1090 }
1091
1092 case 'd':
1093 font_info.desc = strtoul (optarg, NULL, 0);
1094 break;
1095
42841caa
VS
1096 case 'e':
1097 font_info.asce = strtoul (optarg, NULL, 0);
1098 break;
1099
e52db1f7 1100 case 'h':
1101 usage (0);
1102 break;
1103
1104 case 'V':
8a4c07fd 1105 printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION);
e52db1f7 1106 return 0;
1107
1108 case 'v':
1109 font_verbosity++;
1110 break;
1111
26ba5c22 1112 case 0x102:
1113 file_format = ASCII_BITMAPS;
1114 break;
1115
6c363dfd
VS
1116 case 0x103:
1117 file_format = WIDTH_SPEC;
1118 break;
1119
e52db1f7 1120 default:
1121 usage (1);
1122 break;
1123 }
1124 }
1125
26ba5c22 1126 if (file_format == ASCII_BITMAPS && font_info.num_range > 0)
1127 {
10f0117b 1128 grub_util_error (_("Option --ascii-bitmaps doesn't accept ranges (use ASCII)."));
26ba5c22 1129 return 1;
1130 }
1131
1132 else if (file_format == ASCII_BITMAPS)
1133 {
1134 font_info.ranges = xrealloc (font_info.ranges,
1135 GRUB_FONT_RANGE_BLOCK *
1136 sizeof (grub_uint32_t) * 2);
1137
1138 font_info.ranges[0] = (grub_uint32_t) 0x00;
1139 font_info.ranges[1] = (grub_uint32_t) 0x7f;
1140 font_info.num_range = 1;
1141 }
1142
e52db1f7 1143 if (! output_file)
10f0117b 1144 grub_util_error (_("no output file is specified"));
e52db1f7 1145
1146 if (FT_Init_FreeType (&ft_lib))
10f0117b 1147 grub_util_error (_("FT_Init_FreeType fails"));
e52db1f7 1148
1149 for (; optind < argc; optind++)
1150 {
1151 FT_Face ft_face;
1152 int size;
323a8e9c 1153 FT_Error err;
e52db1f7 1154
323a8e9c
VS
1155 err = FT_New_Face (ft_lib, argv[optind], font_index, &ft_face);
1156 if (err)
e52db1f7 1157 {
10f0117b
VS
1158 grub_printf (_("can't open file %s, index %d: error %d"),
1159 argv[optind], font_index, err);
323a8e9c
VS
1160 if (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs))
1161 printf (": %s\n", ft_errmsgs[err]);
1162 else
1163 printf ("\n");
1164
e52db1f7 1165 continue;
1166 }
1167
1168 if ((! font_info.name) && (ft_face->family_name))
1169 font_info.name = xstrdup (ft_face->family_name);
1170
1171 size = font_size;
1172 if (! size)
1173 {
1174 if ((ft_face->face_flags & FT_FACE_FLAG_SCALABLE) ||
1175 (! ft_face->num_fixed_sizes))
1176 size = GRUB_FONT_DEFAULT_SIZE;
1177 else
1178 size = ft_face->available_sizes[0].height;
1179 }
1180
1181 font_info.style = ft_face->style_flags;
1182 font_info.size = size;
1183
5cf86f4b 1184 if (FT_Set_Pixel_Sizes (ft_face, size, size))
10f0117b 1185 grub_util_error (_("can't set %dx%d font size"), size, size);
a6ab5fb2 1186 add_font (&font_info, ft_face, file_format != PF2);
e52db1f7 1187 FT_Done_Face (ft_face);
1188 }
1189
1190 FT_Done_FreeType (ft_lib);
1191
e6d428c1
VS
1192 {
1193 int counter[65537];
1194 struct grub_glyph_info *tmp, *cur;
1195 int i;
1196
1197 memset (counter, 0, sizeof (counter));
1198
1199 for (cur = font_info.glyphs_unsorted; cur; cur = cur->next)
1200 counter[(cur->char_code & 0xffff) + 1]++;
1201 for (i = 0; i < 0x10000; i++)
1202 counter[i+1] += counter[i];
1203 tmp = xmalloc (font_info.num_glyphs
1204 * sizeof (tmp[0]));
1205 for (cur = font_info.glyphs_unsorted; cur; cur = cur->next)
1206 tmp[counter[(cur->char_code & 0xffff)]++] = *cur;
1207
1208 memset (counter, 0, sizeof (counter));
1209
1210 for (cur = tmp; cur < tmp + font_info.num_glyphs; cur++)
1211 counter[((cur->char_code & 0xffff0000) >> 16) + 1]++;
1212 for (i = 0; i < 0x10000; i++)
1213 counter[i+1] += counter[i];
1214 font_info.glyphs_sorted = xmalloc (font_info.num_glyphs
1215 * sizeof (font_info.glyphs_sorted[0]));
1216 for (cur = tmp; cur < tmp + font_info.num_glyphs; cur++)
1217 font_info.glyphs_sorted[counter[(cur->char_code & 0xffff0000) >> 16]++]
1218 = *cur;
1219 free (tmp);
1220 }
1221
6c363dfd
VS
1222 switch (file_format)
1223 {
1224 case PF2:
1225 write_font_pf2 (&font_info, output_file);
1226 break;
1227
1228 case ASCII_BITMAPS:
1229 write_font_ascii_bitmap (&font_info, output_file);
1230 break;
1231
1232 case WIDTH_SPEC:
1233 write_font_width_spec (&font_info, output_file);
1234 break;
1235 }
26ba5c22 1236
1237 if (font_verbosity > 1)
1238 print_glyphs (&font_info);
e52db1f7 1239
1240 return 0;
1241}