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