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