grub-mkfont.c 34 KB

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