Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / util / grub-mkfont.c
bloba0cab3a93f86277d4d1dd24f9690b486cb9f9990
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2009,2010 Free Software Foundation, Inc.
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.
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.
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/>.
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>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
34 #ifndef GRUB_BUILD
35 #define _GNU_SOURCE 1
36 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
37 #pragma GCC diagnostic ignored "-Wmissing-declarations"
38 #include <argp.h>
39 #pragma GCC diagnostic error "-Wmissing-prototypes"
40 #pragma GCC diagnostic error "-Wmissing-declarations"
41 #endif
42 #include <assert.h>
44 #include <errno.h>
46 #include <ft2build.h>
47 #include FT_FREETYPE_H
48 #include FT_TRUETYPE_TAGS_H
49 #include FT_TRUETYPE_TABLES_H
50 #include FT_SYNTHESIS_H
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
58 #ifndef GRUB_BUILD
59 #include "progname.h"
60 #endif
62 #ifdef GRUB_BUILD
63 #define grub_util_fopen fopen
64 #endif
66 #define GRUB_FONT_DEFAULT_SIZE 16
68 #define GRUB_FONT_RANGE_BLOCK 1024
70 struct grub_glyph_info
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;
80 grub_uint8_t *bitmap;
83 enum file_formats
85 PF2
88 enum
90 GRUB_FONT_FLAG_BOLD = 1,
91 GRUB_FONT_FLAG_NOBITMAP = 2,
92 GRUB_FONT_FLAG_NOHINTING = 4,
93 GRUB_FONT_FLAG_FORCEHINT = 8
96 struct grub_font_info
98 const char *name;
99 int style;
100 int desc;
101 int asce;
102 int size;
103 int max_width;
104 int max_height;
105 int min_y;
106 int max_y;
107 int flags;
108 int num_range;
109 grub_uint32_t *ranges;
110 struct grub_glyph_info *glyphs_unsorted;
111 struct grub_glyph_info *glyphs_sorted;
112 int num_glyphs;
115 static int font_verbosity;
117 static void
118 add_pixel (grub_uint8_t **data, int *mask, int not_blank)
120 if (*mask == 0)
122 (*data)++;
123 **data = 0;
124 *mask = 128;
127 if (not_blank)
128 **data |= *mask;
130 *mask >>= 1;
133 static void
134 add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face,
135 grub_uint32_t char_code, int nocut)
137 struct grub_glyph_info *glyph_info;
138 int width, height;
139 int cuttop, cutbottom, cutleft, cutright;
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;
144 FT_Error err;
146 if (font_info->flags & GRUB_FONT_FLAG_NOBITMAP)
147 flag |= FT_LOAD_NO_BITMAP;
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;
154 err = FT_Load_Glyph (face, glyph_idx, flag);
155 if (err)
157 printf (_("Freetype Error %d loading glyph 0x%x for U+0x%x%s"),
158 err, glyph_idx, char_code & GRUB_FONT_CODE_CHAR_MASK,
159 char_code & GRUB_FONT_CODE_RIGHT_JOINED
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. */
165 ? ((char_code & GRUB_FONT_CODE_LEFT_JOINED) ? _(" (medial)"):
166 _(" (leftmost)"))
167 : ((char_code & GRUB_FONT_CODE_LEFT_JOINED) ? _(" (rightmost)"):
168 ""));
170 if (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs))
171 printf (": %s\n", ft_errmsgs[err]);
172 else
173 printf ("\n");
174 return;
177 glyph = face->glyph;
179 if (font_info->flags & GRUB_FONT_FLAG_BOLD)
180 FT_GlyphSlot_Embolden (glyph);
182 if (glyph->next)
183 printf ("%x\n", char_code);
185 if (nocut)
186 cuttop = cutbottom = cutleft = cutright = 0;
187 else
189 for (cuttop = 0; cuttop < glyph->bitmap.rows; cuttop++)
191 for (j = 0; j < glyph->bitmap.width; j++)
192 if (glyph->bitmap.buffer[j / 8 + cuttop * glyph->bitmap.pitch]
193 & (1 << (7 - (j & 7))))
194 break;
195 if (j != glyph->bitmap.width)
196 break;
199 for (cutbottom = glyph->bitmap.rows - 1; cutbottom >= 0; cutbottom--)
201 for (j = 0; j < glyph->bitmap.width; j++)
202 if (glyph->bitmap.buffer[j / 8 + cutbottom * glyph->bitmap.pitch]
203 & (1 << (7 - (j & 7))))
204 break;
205 if (j != glyph->bitmap.width)
206 break;
208 cutbottom = glyph->bitmap.rows - 1 - cutbottom;
209 if (cutbottom + cuttop >= glyph->bitmap.rows)
210 cutbottom = 0;
212 for (cutleft = 0; cutleft < glyph->bitmap.width; cutleft++)
214 for (j = 0; j < glyph->bitmap.rows; j++)
215 if (glyph->bitmap.buffer[cutleft / 8 + j * glyph->bitmap.pitch]
216 & (1 << (7 - (cutleft & 7))))
217 break;
218 if (j != glyph->bitmap.rows)
219 break;
221 for (cutright = glyph->bitmap.width - 1; cutright >= 0; cutright--)
223 for (j = 0; j < glyph->bitmap.rows; j++)
224 if (glyph->bitmap.buffer[cutright / 8 + j * glyph->bitmap.pitch]
225 & (1 << (7 - (cutright & 7))))
226 break;
227 if (j != glyph->bitmap.rows)
228 break;
230 cutright = glyph->bitmap.width - 1 - cutright;
231 if (cutright + cutleft >= glyph->bitmap.width)
232 cutright = 0;
235 width = glyph->bitmap.width - cutleft - cutright;
236 height = glyph->bitmap.rows - cutbottom - cuttop;
238 bitmap_size = ((width * height + 7) / 8);
239 glyph_info = xmalloc (sizeof (struct grub_glyph_info));
240 glyph_info->bitmap = xmalloc (bitmap_size);
241 glyph_info->bitmap_size = bitmap_size;
243 glyph_info->next = font_info->glyphs_unsorted;
244 font_info->glyphs_unsorted = glyph_info;
245 font_info->num_glyphs++;
247 glyph_info->char_code = char_code;
248 glyph_info->width = width;
249 glyph_info->height = height;
250 glyph_info->x_ofs = glyph->bitmap_left + cutleft;
251 glyph_info->y_ofs = glyph->bitmap_top - height - cuttop;
252 glyph_info->device_width = glyph->metrics.horiAdvance / 64;
254 if (width > font_info->max_width)
255 font_info->max_width = width;
257 if (height > font_info->max_height)
258 font_info->max_height = height;
260 if (glyph_info->y_ofs < font_info->min_y && glyph_info->y_ofs > -font_info->size)
261 font_info->min_y = glyph_info->y_ofs;
263 if (glyph_info->y_ofs + height > font_info->max_y)
264 font_info->max_y = glyph_info->y_ofs + height;
266 mask = 0;
267 data = &glyph_info->bitmap[0] - 1;
268 for (j = cuttop; j < height + cuttop; j++)
269 for (i = cutleft; i < width + cutleft; i++)
270 add_pixel (&data, &mask,
271 glyph->bitmap.buffer[i / 8 + j * glyph->bitmap.pitch] &
272 (1 << (7 - (i & 7))));
275 struct glyph_replace *subst_rightjoin, *subst_leftjoin, *subst_medijoin;
277 struct glyph_replace
279 struct glyph_replace *next;
280 grub_uint32_t from, to;
283 /* TODO: sort glyph_replace and use binary search if necessary. */
284 static void
285 add_char (struct grub_font_info *font_info, FT_Face face,
286 grub_uint32_t char_code, int nocut)
288 FT_UInt glyph_idx;
289 struct glyph_replace *cur;
291 glyph_idx = FT_Get_Char_Index (face, char_code);
292 if (!glyph_idx)
293 return;
294 add_glyph (font_info, glyph_idx, face, char_code, nocut);
295 for (cur = subst_rightjoin; cur; cur = cur->next)
296 if (cur->from == glyph_idx)
298 add_glyph (font_info, cur->to, face,
299 char_code | GRUB_FONT_CODE_RIGHT_JOINED, nocut);
300 break;
302 if (!cur && char_code >= GRUB_UNICODE_ARABIC_START
303 && char_code < GRUB_UNICODE_ARABIC_END)
305 int i;
306 for (i = 0; grub_unicode_arabic_shapes[i].code; i++)
307 if (grub_unicode_arabic_shapes[i].code == char_code
308 && grub_unicode_arabic_shapes[i].right_linked)
310 FT_UInt idx2;
311 idx2 = FT_Get_Char_Index (face, grub_unicode_arabic_shapes[i]
312 .right_linked);
313 if (idx2)
314 add_glyph (font_info, idx2, face,
315 char_code | GRUB_FONT_CODE_RIGHT_JOINED, nocut);
316 break;
321 for (cur = subst_leftjoin; cur; cur = cur->next)
322 if (cur->from == glyph_idx)
324 add_glyph (font_info, cur->to, face,
325 char_code | GRUB_FONT_CODE_LEFT_JOINED, nocut);
326 break;
328 if (!cur && char_code >= GRUB_UNICODE_ARABIC_START
329 && char_code < GRUB_UNICODE_ARABIC_END)
331 int i;
332 for (i = 0; grub_unicode_arabic_shapes[i].code; i++)
333 if (grub_unicode_arabic_shapes[i].code == char_code
334 && grub_unicode_arabic_shapes[i].left_linked)
336 FT_UInt idx2;
337 idx2 = FT_Get_Char_Index (face, grub_unicode_arabic_shapes[i]
338 .left_linked);
339 if (idx2)
340 add_glyph (font_info, idx2, face,
341 char_code | GRUB_FONT_CODE_LEFT_JOINED, nocut);
342 break;
346 for (cur = subst_medijoin; cur; cur = cur->next)
347 if (cur->from == glyph_idx)
349 add_glyph (font_info, cur->to, face,
350 char_code | GRUB_FONT_CODE_LEFT_JOINED
351 | GRUB_FONT_CODE_RIGHT_JOINED, nocut);
352 break;
354 if (!cur && char_code >= GRUB_UNICODE_ARABIC_START
355 && char_code < GRUB_UNICODE_ARABIC_END)
357 int i;
358 for (i = 0; grub_unicode_arabic_shapes[i].code; i++)
359 if (grub_unicode_arabic_shapes[i].code == char_code
360 && grub_unicode_arabic_shapes[i].both_linked)
362 FT_UInt idx2;
363 idx2 = FT_Get_Char_Index (face, grub_unicode_arabic_shapes[i]
364 .both_linked);
365 if (idx2)
366 add_glyph (font_info, idx2, face,
367 char_code | GRUB_FONT_CODE_LEFT_JOINED
368 | GRUB_FONT_CODE_RIGHT_JOINED, nocut);
369 break;
375 struct gsub_header
377 grub_uint32_t version;
378 grub_uint16_t scripts_off;
379 grub_uint16_t features_off;
380 grub_uint16_t lookups_off;
381 } GRUB_PACKED;
383 struct gsub_features
385 grub_uint16_t count;
386 struct
388 #define FEATURE_FINA 0x66696e61
389 #define FEATURE_INIT 0x696e6974
390 #define FEATURE_MEDI 0x6d656469
391 #define FEATURE_AALT 0x61616c74
392 #define FEATURE_LIGA 0x6c696761
393 #define FEATURE_RLIG 0x726c6967
394 grub_uint32_t feature_tag;
395 grub_uint16_t offset;
396 } GRUB_PACKED features[0];
397 } GRUB_PACKED;
399 struct gsub_feature
401 grub_uint16_t params;
402 grub_uint16_t lookupcount;
403 grub_uint16_t lookupindices[0];
404 } GRUB_PACKED;
406 struct gsub_lookup_list
408 grub_uint16_t count;
409 grub_uint16_t offsets[0];
410 } GRUB_PACKED;
412 struct gsub_lookup
414 grub_uint16_t type;
415 grub_uint16_t flag;
416 grub_uint16_t subtablecount;
417 grub_uint16_t subtables[0];
418 } GRUB_PACKED;
420 struct gsub_substitution
422 grub_uint16_t type;
423 grub_uint16_t coverage_off;
424 union
426 grub_int16_t delta;
427 struct
429 grub_int16_t count;
430 grub_uint16_t repl[0];
433 } GRUB_PACKED;
435 struct gsub_coverage_list
437 grub_uint16_t type;
438 grub_uint16_t count;
439 grub_uint16_t glyphs[0];
440 } GRUB_PACKED;
442 struct gsub_coverage_ranges
444 grub_uint16_t type;
445 grub_uint16_t count;
446 struct
448 grub_uint16_t start;
449 grub_uint16_t end;
450 grub_uint16_t start_index;
451 } GRUB_PACKED ranges[0];
452 } GRUB_PACKED;
454 #define GSUB_SINGLE_SUBSTITUTION 1
456 #define GSUB_SUBSTITUTION_DELTA 1
457 #define GSUB_SUBSTITUTION_MAP 2
459 #define GSUB_COVERAGE_LIST 1
460 #define GSUB_COVERAGE_RANGE 2
462 #define GSUB_RTL_CHAR 1
464 static void
465 add_subst (grub_uint32_t from, grub_uint32_t to, struct glyph_replace **target)
467 struct glyph_replace *new = xmalloc (sizeof (*new));
468 new->next = *target;
469 new->from = from;
470 new->to = to;
471 *target = new;
474 static void
475 subst (const struct gsub_substitution *sub, grub_uint32_t glyph,
476 struct glyph_replace **target, int *i)
478 grub_uint16_t substtype;
479 substtype = grub_be_to_cpu16 (sub->type);
481 if (substtype == GSUB_SUBSTITUTION_DELTA)
482 add_subst (glyph, glyph + grub_be_to_cpu16 (sub->delta), target);
483 else if (*i >= grub_be_to_cpu16 (sub->count))
484 printf (_("Out of range substitution (%d, %d)\n"), *i,
485 grub_be_to_cpu16 (sub->count));
486 else
487 add_subst (glyph, grub_be_to_cpu16 (sub->repl[(*i)++]), target);
490 static void
491 process_cursive (struct gsub_feature *feature,
492 struct gsub_lookup_list *lookups,
493 grub_uint32_t feattag)
495 int j, k;
496 int i;
497 struct glyph_replace **target = NULL;
498 struct gsub_substitution *sub;
500 for (j = 0; j < grub_be_to_cpu16 (feature->lookupcount); j++)
502 int lookup_index = grub_be_to_cpu16 (feature->lookupindices[j]);
503 struct gsub_lookup *lookup;
504 if (lookup_index >= grub_be_to_cpu16 (lookups->count))
506 /* TRANSLATORS: "lookup" is taken directly from font specifications
507 which are formulated as "Under condition X replace LOOKUP with
508 SUBSTITUITION". "*/
509 printf (_("Out of range lookup: %d\n"), lookup_index);
510 continue;
512 lookup = (struct gsub_lookup *)
513 ((grub_uint8_t *) lookups
514 + grub_be_to_cpu16 (lookups->offsets[lookup_index]));
515 if (grub_be_to_cpu16 (lookup->type) != GSUB_SINGLE_SUBSTITUTION)
517 printf (_("Unsupported substitution type: %d\n"),
518 grub_be_to_cpu16 (lookup->type));
519 continue;
521 if (grub_be_to_cpu16 (lookup->flag) & ~GSUB_RTL_CHAR)
523 grub_util_info ("unsupported substitution flag: 0x%x",
524 grub_be_to_cpu16 (lookup->flag));
526 switch (feattag)
528 case FEATURE_INIT:
529 if (grub_be_to_cpu16 (lookup->flag) & GSUB_RTL_CHAR)
530 target = &subst_leftjoin;
531 else
532 target = &subst_rightjoin;
533 break;
534 case FEATURE_FINA:
535 if (grub_be_to_cpu16 (lookup->flag) & GSUB_RTL_CHAR)
536 target = &subst_rightjoin;
537 else
538 target = &subst_leftjoin;
539 break;
540 case FEATURE_MEDI:
541 target = &subst_medijoin;
542 break;
544 for (k = 0; k < grub_be_to_cpu16 (lookup->subtablecount); k++)
546 sub = (struct gsub_substitution *)
547 ((grub_uint8_t *) lookup + grub_be_to_cpu16 (lookup->subtables[k]));
548 grub_uint16_t substtype;
549 substtype = grub_be_to_cpu16 (sub->type);
550 if (substtype != GSUB_SUBSTITUTION_MAP
551 && substtype != GSUB_SUBSTITUTION_DELTA)
553 printf (_("Unsupported substitution specification: %d\n"),
554 substtype);
555 continue;
557 void *coverage = (grub_uint8_t *) sub
558 + grub_be_to_cpu16 (sub->coverage_off);
559 grub_uint32_t covertype;
560 covertype = grub_be_to_cpu16 (grub_get_unaligned16 (coverage));
561 i = 0;
562 if (covertype == GSUB_COVERAGE_LIST)
564 struct gsub_coverage_list *cover = coverage;
565 int l;
566 for (l = 0; l < grub_be_to_cpu16 (cover->count); l++)
567 subst (sub, grub_be_to_cpu16 (cover->glyphs[l]), target, &i);
569 else if (covertype == GSUB_COVERAGE_RANGE)
571 struct gsub_coverage_ranges *cover = coverage;
572 int l, m;
573 for (l = 0; l < grub_be_to_cpu16 (cover->count); l++)
574 for (m = grub_be_to_cpu16 (cover->ranges[l].start);
575 m <= grub_be_to_cpu16 (cover->ranges[l].end); m++)
576 subst (sub, m, target, &i);
578 else
579 /* TRANSLATORS: most font transformations apply only to
580 some glyphs. Those glyphs are described as "coverage".
581 There are 2 coverage specifications: list and range.
582 This warning is thrown when another coverage specification
583 is detected. */
584 fprintf (stderr,
585 _("Unsupported coverage specification: %d\n"), covertype);
590 static void
591 add_font (struct grub_font_info *font_info, FT_Face face, int nocut)
593 struct gsub_header *gsub = NULL;
594 FT_ULong gsub_len = 0;
596 if (!FT_Load_Sfnt_Table (face, TTAG_GSUB, 0, NULL, &gsub_len))
598 gsub = xmalloc (gsub_len);
599 if (FT_Load_Sfnt_Table (face, TTAG_GSUB, 0, (void *) gsub, &gsub_len))
601 free (gsub);
602 gsub = NULL;
603 gsub_len = 0;
606 if (gsub)
608 struct gsub_features *features
609 = (struct gsub_features *) (((grub_uint8_t *) gsub)
610 + grub_be_to_cpu16 (gsub->features_off));
611 struct gsub_lookup_list *lookups
612 = (struct gsub_lookup_list *) (((grub_uint8_t *) gsub)
613 + grub_be_to_cpu16 (gsub->lookups_off));
614 int i;
615 int nfeatures = grub_be_to_cpu16 (features->count);
616 for (i = 0; i < nfeatures; i++)
618 struct gsub_feature *feature = (struct gsub_feature *)
619 ((grub_uint8_t *) features
620 + grub_be_to_cpu16 (features->features[i].offset));
621 grub_uint32_t feattag
622 = grub_be_to_cpu32 (features->features[i].feature_tag);
623 if (feature->params)
624 fprintf (stderr,
625 _("WARNING: unsupported font feature parameters: %x\n"),
626 grub_be_to_cpu16 (feature->params));
627 switch (feattag)
629 /* Used for retrieving all possible variants. Useless in grub. */
630 case FEATURE_AALT:
631 break;
633 /* FIXME: Add ligature support. */
634 case FEATURE_LIGA:
635 case FEATURE_RLIG:
636 break;
638 /* Cursive form variants. */
639 case FEATURE_FINA:
640 case FEATURE_INIT:
641 case FEATURE_MEDI:
642 process_cursive (feature, lookups, feattag);
643 break;
645 default:
647 char str[5];
648 int j;
649 memcpy (str, &features->features[i].feature_tag,
650 sizeof (features->features[i].feature_tag));
651 str[4] = 0;
652 for (j = 0; j < 4; j++)
653 if (!grub_isgraph (str[j]))
654 str[j] = '?';
655 /* TRANSLATORS: It's gsub feature, not gsub font. */
656 grub_util_info ("Unknown gsub font feature 0x%x (%s)",
657 feattag, str);
663 if (font_info->num_range)
665 int i;
666 grub_uint32_t j;
668 for (i = 0; i < font_info->num_range; i++)
669 for (j = font_info->ranges[i * 2]; j <= font_info->ranges[i * 2 + 1];
670 j++)
671 add_char (font_info, face, j, nocut);
673 else
675 grub_uint32_t char_code, glyph_index;
677 for (char_code = FT_Get_First_Char (face, &glyph_index);
678 glyph_index;
679 char_code = FT_Get_Next_Char (face, char_code, &glyph_index))
680 add_char (font_info, face, char_code, nocut);
684 static void
685 write_string_section (const char *name, const char *str,
686 int *offset, FILE *file,
687 const char *filename)
689 grub_uint32_t leng, leng_be32;
691 leng = strlen (str) + 1;
692 leng_be32 = grub_cpu_to_be32 (leng);
694 grub_util_write_image (name, 4, file, filename);
695 grub_util_write_image ((char *) &leng_be32, 4, file, filename);
696 grub_util_write_image (str, leng, file, filename);
698 *offset += 8 + leng;
701 static void
702 write_be16_section (const char *name, grub_uint16_t data, int* offset,
703 FILE *file, const char *filename)
705 grub_uint32_t leng;
707 leng = grub_cpu_to_be32_compile_time (2);
708 data = grub_cpu_to_be16 (data);
709 grub_util_write_image (name, 4, file, filename);
710 grub_util_write_image ((char *) &leng, 4, file, filename);
711 grub_util_write_image ((char *) &data, 2, file, filename);
713 *offset += 10;
716 static void
717 print_glyphs (struct grub_font_info *font_info)
719 int num;
720 struct grub_glyph_info *glyph;
721 char line[512];
723 for (glyph = font_info->glyphs_sorted, num = 0; num < font_info->num_glyphs;
724 glyph++, num++)
726 int x, y, xmax, xmin, ymax, ymin;
727 grub_uint8_t *bitmap, mask;
729 printf ("\nGlyph #%d, U+%04x\n", num, glyph->char_code);
730 printf ("Width %d, Height %d, X offset %d, Y offset %d, Device width %d\n",
731 glyph->width, glyph->height, glyph->x_ofs, glyph->y_ofs,
732 glyph->device_width);
734 xmax = glyph->x_ofs + glyph->width;
735 if (xmax < glyph->device_width)
736 xmax = glyph->device_width;
738 xmin = glyph->x_ofs;
739 if (xmin > 0)
740 xmin = 0;
742 ymax = glyph->y_ofs + glyph->height;
743 if (ymax < font_info->asce)
744 ymax = font_info->asce;
746 ymin = glyph->y_ofs;
747 if (ymin > - font_info->desc)
748 ymin = - font_info->desc;
750 bitmap = glyph->bitmap;
751 mask = 0x80;
752 for (y = ymax - 1; y > ymin - 1; y--)
754 int line_pos;
756 line_pos = 0;
757 for (x = xmin; x < xmax; x++)
759 if ((x >= glyph->x_ofs) &&
760 (x < glyph->x_ofs + glyph->width) &&
761 (y >= glyph->y_ofs) &&
762 (y < glyph->y_ofs + glyph->height))
764 line[line_pos++] = (*bitmap & mask) ? '#' : '_';
765 mask >>= 1;
766 if (mask == 0)
768 mask = 0x80;
769 bitmap++;
772 else if ((x >= 0) &&
773 (x < glyph->device_width) &&
774 (y >= - font_info->desc) &&
775 (y < font_info->asce))
777 line[line_pos++] = ((x == 0) || (y == 0)) ? '+' : '.';
779 else
780 line[line_pos++] = '*';
782 line[line_pos] = 0;
783 printf ("%s\n", line);
788 static void
789 write_font_pf2 (struct grub_font_info *font_info, char *output_file)
791 FILE *file;
792 grub_uint32_t leng;
793 char style_name[20], *font_name, *ptr;
794 int offset;
795 struct grub_glyph_info *cur;
797 file = grub_util_fopen (output_file, "wb");
798 if (! file)
799 grub_util_error (_("cannot write to `%s': %s"), output_file,
800 strerror (errno));
802 offset = 0;
804 leng = grub_cpu_to_be32_compile_time (4);
805 grub_util_write_image (FONT_FORMAT_SECTION_NAMES_FILE,
806 sizeof(FONT_FORMAT_SECTION_NAMES_FILE) - 1, file,
807 output_file);
808 grub_util_write_image ((char *) &leng, 4, file, output_file);
809 grub_util_write_image (FONT_FORMAT_PFF2_MAGIC, 4, file, output_file);
810 offset += 12;
812 if (! font_info->name)
813 font_info->name = "Unknown";
815 if (font_info->flags & GRUB_FONT_FLAG_BOLD)
816 font_info->style |= FT_STYLE_FLAG_BOLD;
818 style_name[0] = 0;
819 if (font_info->style & FT_STYLE_FLAG_BOLD)
820 strcpy (style_name, " Bold");
822 if (font_info->style & FT_STYLE_FLAG_ITALIC)
823 strcat (style_name, " Italic");
825 if (! style_name[0])
826 strcpy (style_name, " Regular");
828 font_name = xmalloc (strlen (font_info->name) + strlen (&style_name[1])
829 + 3 + 20);
830 ptr = grub_stpcpy (font_name, font_info->name);
831 *ptr++ = ' ';
832 ptr = grub_stpcpy (ptr, &style_name[1]);
833 *ptr++ = ' ';
834 snprintf (ptr, 20, "%d", font_info->size);
836 write_string_section (FONT_FORMAT_SECTION_NAMES_FONT_NAME,
837 font_name, &offset, file, output_file);
838 write_string_section (FONT_FORMAT_SECTION_NAMES_FAMILY,
839 font_info->name, &offset, file, output_file);
840 write_string_section (FONT_FORMAT_SECTION_NAMES_WEIGHT,
841 (font_info->style & FT_STYLE_FLAG_BOLD) ?
842 "bold" : "normal",
843 &offset, file, output_file);
844 write_string_section (FONT_FORMAT_SECTION_NAMES_SLAN,
845 (font_info->style & FT_STYLE_FLAG_ITALIC) ?
846 "italic" : "normal",
847 &offset, file, output_file);
849 write_be16_section (FONT_FORMAT_SECTION_NAMES_POINT_SIZE,
850 font_info->size, &offset, file, output_file);
851 write_be16_section (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH,
852 font_info->max_width, &offset, file, output_file);
853 write_be16_section (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT,
854 font_info->max_height, &offset, file, output_file);
856 if (! font_info->desc)
858 if (font_info->min_y >= 0)
859 font_info->desc = 1;
860 else
861 font_info->desc = - font_info->min_y;
864 if (! font_info->asce)
866 if (font_info->max_y <= 0)
867 font_info->asce = 1;
868 else
869 font_info->asce = font_info->max_y;
872 write_be16_section (FONT_FORMAT_SECTION_NAMES_ASCENT,
873 font_info->asce, &offset, file, output_file);
874 write_be16_section (FONT_FORMAT_SECTION_NAMES_DESCENT,
875 font_info->desc, &offset, file, output_file);
877 if (font_verbosity > 0)
879 printf ("Font name: %s\n", font_name);
880 printf ("Max width: %d\n", font_info->max_width);
881 printf ("Max height: %d\n", font_info->max_height);
882 printf ("Font ascent: %d\n", font_info->asce);
883 printf ("Font descent: %d\n", font_info->desc);
886 if (font_verbosity > 0)
887 printf ("Number of glyph: %d\n", font_info->num_glyphs);
889 leng = grub_cpu_to_be32 (font_info->num_glyphs * 9);
890 grub_util_write_image (FONT_FORMAT_SECTION_NAMES_CHAR_INDEX,
891 sizeof(FONT_FORMAT_SECTION_NAMES_CHAR_INDEX) - 1,
892 file, output_file);
893 grub_util_write_image ((char *) &leng, 4, file, output_file);
894 offset += 8 + font_info->num_glyphs * 9 + 8;
896 for (cur = font_info->glyphs_sorted;
897 cur < font_info->glyphs_sorted + font_info->num_glyphs; cur++)
899 grub_uint32_t data32;
900 grub_uint8_t data8;
901 data32 = grub_cpu_to_be32 (cur->char_code);
902 grub_util_write_image ((char *) &data32, 4, file, output_file);
903 data8 = 0;
904 grub_util_write_image ((char *) &data8, 1, file, output_file);
905 data32 = grub_cpu_to_be32 (offset);
906 grub_util_write_image ((char *) &data32, 4, file, output_file);
907 offset += 10 + cur->bitmap_size;
910 leng = 0xffffffff;
911 grub_util_write_image (FONT_FORMAT_SECTION_NAMES_DATA,
912 sizeof(FONT_FORMAT_SECTION_NAMES_DATA) - 1,
913 file, output_file);
914 grub_util_write_image ((char *) &leng, 4, file, output_file);
916 for (cur = font_info->glyphs_sorted;
917 cur < font_info->glyphs_sorted + font_info->num_glyphs; cur++)
919 grub_uint16_t data;
920 data = grub_cpu_to_be16 (cur->width);
921 grub_util_write_image ((char *) &data, 2, file, output_file);
922 data = grub_cpu_to_be16 (cur->height);
923 grub_util_write_image ((char *) &data, 2, file, output_file);
924 data = grub_cpu_to_be16 (cur->x_ofs);
925 grub_util_write_image ((char *) &data, 2, file, output_file);
926 data = grub_cpu_to_be16 (cur->y_ofs);
927 grub_util_write_image ((char *) &data, 2, file, output_file);
928 data = grub_cpu_to_be16 (cur->device_width);
929 grub_util_write_image ((char *) &data, 2, file, output_file);
930 grub_util_write_image ((char *) &cur->bitmap[0], cur->bitmap_size,
931 file, output_file);
934 fclose (file);
937 #ifndef GRUB_BUILD
938 static struct argp_option options[] = {
939 {"output", 'o', N_("FILE"), 0, N_("save output in FILE [required]"), 0},
940 /* TRANSLATORS: bitmaps are images like e.g. in JPEG. */
941 {"index", 'i', N_("NUM"), 0,
942 /* TRANSLATORS: some font files may have multiple faces (fonts).
943 This option is used to chose among them, the first face being '0'.
944 Rarely used. */
945 N_("select face index"), 0},
946 {"range", 'r', N_("FROM-TO[,FROM-TO]"), 0,
947 /* TRANSLATORS: It refers to the range of characters in font. */
948 N_("set font range"), 0},
949 {"name", 'n', N_("NAME"), 0,
950 /* TRANSLATORS: "family name" for font is just a generic name without suffix
951 like "Bold". */
952 N_("set font family name"), 0},
953 {"size", 's', N_("SIZE"), 0, N_("set font size"), 0},
954 {"desc", 'd', N_("NUM"), 0, N_("set font descent"), 0},
955 {"asce", 'c', N_("NUM"), 0, N_("set font ascent"), 0},
956 {"bold", 'b', 0, 0, N_("convert to bold font"), 0},
957 {"force-autohint", 'a', 0, 0, N_("force autohint"), 0},
958 {"no-hinting", 0x101, 0, 0, N_("disable hinting"), 0},
959 {"no-bitmap", 0x100, 0, 0,
960 /* TRANSLATORS: some fonts contain bitmap rendering for
961 some sizes. This option forces rerendering even if
962 pre-rendered bitmap is available.
964 N_("ignore bitmap strikes when loading"), 0},
965 {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
966 { 0, 0, 0, 0, 0, 0 }
968 #define my_argp_parse argp_parse
969 #define MY_ARGP_KEY_ARG ARGP_KEY_ARG
970 #define my_error_t error_t
971 #define MY_ARGP_ERR_UNKNOWN ARGP_ERR_UNKNOWN
972 #define my_argp_state argp_state
974 #else
976 #define my_error_t int
977 #define MY_ARGP_ERR_UNKNOWN -1
978 #define MY_ARGP_KEY_ARG -1
979 #define my_argp_parse(a, argc, argv, b, c, st) my_argp_parse_real(argc, argv, st)
980 struct my_argp_state
982 void *input;
985 #endif
987 struct arguments
989 struct grub_font_info font_info;
990 size_t nfiles;
991 size_t files_max;
992 char **files;
993 char *output_file;
994 int font_index;
995 int font_size;
996 enum file_formats file_format;
999 #ifdef GRUB_BUILD
1001 static int
1002 has_argument (int v)
1004 return v =='o' || v == 'i' || v == 'r' || v == 'n' || v == 's'
1005 || v == 'd' || v == 'c';
1008 #endif
1010 static my_error_t
1011 argp_parser (int key, char *arg, struct my_argp_state *state)
1013 /* Get the input argument from argp_parse, which we
1014 know is a pointer to our arguments structure. */
1015 struct arguments *arguments = state->input;
1017 switch (key)
1019 case 'b':
1020 arguments->font_info.flags |= GRUB_FONT_FLAG_BOLD;
1021 break;
1023 case 0x100:
1024 arguments->font_info.flags |= GRUB_FONT_FLAG_NOBITMAP;
1025 break;
1027 case 0x101:
1028 arguments->font_info.flags |= GRUB_FONT_FLAG_NOHINTING;
1029 break;
1031 case 'a':
1032 arguments->font_info.flags |= GRUB_FONT_FLAG_FORCEHINT;
1033 break;
1035 case 'o':
1036 arguments->output_file = xstrdup (arg);
1037 break;
1039 case 'n':
1040 arguments->font_info.name = xstrdup (arg);
1041 break;
1043 case 'i':
1044 arguments->font_index = strtoul (arg, NULL, 0);
1045 break;
1047 case 's':
1048 arguments->font_size = strtoul (arg, NULL, 0);
1049 break;
1051 case 'r':
1053 char *p = arg;
1055 while (1)
1057 grub_uint32_t a, b;
1059 a = strtoul (p, &p, 0);
1060 if (*p != '-')
1061 /* TRANSLATORS: It refers to the range of characters in font. */
1062 grub_util_error ("%s", _("invalid font range"));
1063 b = strtoul (p + 1, &p, 0);
1064 if ((arguments->font_info.num_range
1065 & (GRUB_FONT_RANGE_BLOCK - 1)) == 0)
1066 arguments->font_info.ranges = xrealloc (arguments->font_info.ranges,
1067 (arguments->font_info.num_range +
1068 GRUB_FONT_RANGE_BLOCK) *
1069 sizeof (grub_uint32_t) * 2);
1071 arguments->font_info.ranges[arguments->font_info.num_range * 2] = a;
1072 arguments->font_info.ranges[arguments->font_info.num_range * 2 + 1] = b;
1073 arguments->font_info.num_range++;
1075 if (*p)
1077 if (*p != ',')
1078 grub_util_error ("%s", _("invalid font range"));
1079 p++;
1081 else
1082 break;
1084 break;
1087 case 'd':
1088 arguments->font_info.desc = strtoul (arg, NULL, 0);
1089 break;
1091 case 'c':
1092 arguments->font_info.asce = strtoul (arg, NULL, 0);
1093 break;
1095 case 'v':
1096 font_verbosity++;
1097 break;
1099 case MY_ARGP_KEY_ARG:
1100 assert (arguments->nfiles < arguments->files_max);
1101 arguments->files[arguments->nfiles++] = xstrdup(arg);
1102 break;
1104 default:
1105 return MY_ARGP_ERR_UNKNOWN;
1107 return 0;
1110 #ifdef GRUB_BUILD
1112 /* We don't require host platform to have argp. In the same time configuring
1113 gnulib for build would result in even worse mess. So we have our
1114 minimalistic argp replacement just enough for build system. Most
1115 argp features are omitted. */
1117 static int
1118 my_argp_parse_real (int argc, char **argv, void *st)
1120 int curar;
1121 struct my_argp_state p;
1123 p.input = st;
1125 for (curar = 1; curar < argc; )
1127 if (argv[curar][0] == '-')
1129 if (has_argument (argv[curar][1])
1130 && curar + 1 >= argc)
1131 return 1;
1132 if (has_argument (argv[curar][1]))
1134 if (argp_parser (argv[curar][1], argv[curar + 1], &p))
1135 return 1;
1136 curar += 2;
1137 continue;
1139 if (argp_parser (argv[curar][1], NULL, &p))
1140 return 1;
1141 curar++;
1142 continue;
1144 if (argp_parser (MY_ARGP_KEY_ARG, argv[curar], &p))
1145 return 1;
1146 curar++;
1148 return 0;
1150 #endif
1152 #ifndef GRUB_BUILD
1153 static struct argp argp = {
1154 options, argp_parser, N_("[OPTIONS] FONT_FILES"),
1155 N_("Convert common font file formats into PF2"),
1156 NULL, NULL, NULL
1158 #endif
1161 main (int argc, char *argv[])
1163 FT_Library ft_lib;
1164 struct arguments arguments;
1166 #ifndef GRUB_BUILD
1167 grub_util_host_init (&argc, &argv);
1168 #endif
1170 memset (&arguments, 0, sizeof (struct arguments));
1171 arguments.file_format = PF2;
1172 arguments.files_max = argc + 1;
1173 arguments.files = xmalloc ((arguments.files_max + 1)
1174 * sizeof (arguments.files[0]));
1175 memset (arguments.files, 0, (arguments.files_max + 1)
1176 * sizeof (arguments.files[0]));
1178 if (my_argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0)
1180 fprintf (stderr, "%s", _("Error in parsing command line arguments\n"));
1181 exit(1);
1184 if (! arguments.output_file)
1185 grub_util_error ("%s", _("output file must be specified"));
1187 if (FT_Init_FreeType (&ft_lib))
1188 grub_util_error ("%s", _("FT_Init_FreeType fails"));
1191 size_t i;
1192 for (i = 0; i < arguments.nfiles; i++)
1194 FT_Face ft_face;
1195 int size;
1196 FT_Error err;
1198 err = FT_New_Face (ft_lib, arguments.files[i],
1199 arguments.font_index, &ft_face);
1200 if (err)
1202 printf (_("can't open file %s, index %d: error %d"),
1203 arguments.files[i],
1204 arguments.font_index, err);
1205 if (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs))
1206 printf (": %s\n", ft_errmsgs[err]);
1207 else
1208 printf ("\n");
1210 continue;
1213 if ((! arguments.font_info.name) && (ft_face->family_name))
1214 arguments.font_info.name = xstrdup (ft_face->family_name);
1216 size = arguments.font_size;
1217 if (! size)
1219 if ((ft_face->face_flags & FT_FACE_FLAG_SCALABLE) ||
1220 (! ft_face->num_fixed_sizes))
1221 size = GRUB_FONT_DEFAULT_SIZE;
1222 else
1223 size = ft_face->available_sizes[0].height;
1226 arguments.font_info.style = ft_face->style_flags;
1227 arguments.font_info.size = size;
1229 err = FT_Set_Pixel_Sizes (ft_face, size, size);
1231 if (err)
1232 grub_util_error (_("can't set %dx%d font size: Freetype error %d: %s"),
1233 size, size, err,
1234 (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs))
1235 ? ft_errmsgs[err] : "");
1236 add_font (&arguments.font_info, ft_face, arguments.file_format != PF2);
1237 FT_Done_Face (ft_face);
1241 FT_Done_FreeType (ft_lib);
1244 int counter[65537];
1245 struct grub_glyph_info *tmp, *cur;
1246 int i;
1248 memset (counter, 0, sizeof (counter));
1250 for (cur = arguments.font_info.glyphs_unsorted; cur; cur = cur->next)
1251 counter[(cur->char_code & 0xffff) + 1]++;
1252 for (i = 0; i < 0x10000; i++)
1253 counter[i+1] += counter[i];
1254 tmp = xmalloc (arguments.font_info.num_glyphs
1255 * sizeof (tmp[0]));
1256 for (cur = arguments.font_info.glyphs_unsorted; cur; cur = cur->next)
1257 tmp[counter[(cur->char_code & 0xffff)]++] = *cur;
1259 memset (counter, 0, sizeof (counter));
1261 for (cur = tmp; cur < tmp + arguments.font_info.num_glyphs; cur++)
1262 counter[((cur->char_code & 0xffff0000) >> 16) + 1]++;
1263 for (i = 0; i < 0x10000; i++)
1264 counter[i+1] += counter[i];
1265 arguments.font_info.glyphs_sorted = xmalloc (arguments.font_info.num_glyphs
1266 * sizeof (arguments.font_info.glyphs_sorted[0]));
1267 for (cur = tmp; cur < tmp + arguments.font_info.num_glyphs; cur++)
1268 arguments.font_info.glyphs_sorted[counter[(cur->char_code & 0xffff0000)
1269 >> 16]++] = *cur;
1270 free (tmp);
1273 switch (arguments.file_format)
1275 case PF2:
1276 write_font_pf2 (&arguments.font_info, arguments.output_file);
1277 break;
1280 if (font_verbosity > 1)
1281 print_glyphs (&arguments.font_info);
1284 size_t i;
1285 for (i = 0; i < arguments.nfiles; i++)
1286 free (arguments.files[i]);
1289 return 0;