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