PageRenderTime 80ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/util/grub-mkfont.c

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