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