Subversion Repositories Kolibri OS

Rev

Rev 8429 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. #include "fitz.h"
  2. #include "mupdf.h"
  3.  
  4. #include <ft2build.h>
  5. #include FT_FREETYPE_H
  6. #include FT_XFREE86_H
  7.  
  8. static fz_error pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_xref *xref, fz_obj *dict, char *collection, char *basefont);
  9.  
  10. static char *base_font_names[14][7] =
  11. {
  12.         { "Courier", "CourierNew", "CourierNewPSMT", NULL },
  13.         { "Courier-Bold", "CourierNew,Bold", "Courier,Bold",
  14.                 "CourierNewPS-BoldMT", "CourierNew-Bold", NULL },
  15.         { "Courier-Oblique", "CourierNew,Italic", "Courier,Italic",
  16.                 "CourierNewPS-ItalicMT", "CourierNew-Italic", NULL },
  17.         { "Courier-BoldOblique", "CourierNew,BoldItalic", "Courier,BoldItalic",
  18.                 "CourierNewPS-BoldItalicMT", "CourierNew-BoldItalic", NULL },
  19.         { "Helvetica", "ArialMT", "Arial", NULL },
  20.         { "Helvetica-Bold", "Arial-BoldMT", "Arial,Bold", "Arial-Bold",
  21.                 "Helvetica,Bold", NULL },
  22.         { "Helvetica-Oblique", "Arial-ItalicMT", "Arial,Italic", "Arial-Italic",
  23.                 "Helvetica,Italic", "Helvetica-Italic", NULL },
  24.         { "Helvetica-BoldOblique", "Arial-BoldItalicMT",
  25.                 "Arial,BoldItalic", "Arial-BoldItalic",
  26.                 "Helvetica,BoldItalic", "Helvetica-BoldItalic", NULL },
  27.         { "Times-Roman", "TimesNewRomanPSMT", "TimesNewRoman",
  28.                 "TimesNewRomanPS", NULL },
  29.         { "Times-Bold", "TimesNewRomanPS-BoldMT", "TimesNewRoman,Bold",
  30.                 "TimesNewRomanPS-Bold", "TimesNewRoman-Bold", NULL },
  31.         { "Times-Italic", "TimesNewRomanPS-ItalicMT", "TimesNewRoman,Italic",
  32.                 "TimesNewRomanPS-Italic", "TimesNewRoman-Italic", NULL },
  33.         { "Times-BoldItalic", "TimesNewRomanPS-BoldItalicMT",
  34.                 "TimesNewRoman,BoldItalic", "TimesNewRomanPS-BoldItalic",
  35.                 "TimesNewRoman-BoldItalic", NULL },
  36.         { "Symbol", NULL },
  37.         { "ZapfDingbats", NULL }
  38. };
  39.  
  40. static int is_dynalab(char *name)
  41. {
  42.         if (strstr(name, "HuaTian"))
  43.                 return 1;
  44.         if (strstr(name, "MingLi"))
  45.                 return 1;
  46.         if ((strstr(name, "DF") == name) || strstr(name, "+DF"))
  47.                 return 1;
  48.         if ((strstr(name, "DLC") == name) || strstr(name, "+DLC"))
  49.                 return 1;
  50.         return 0;
  51. }
  52.  
  53. static int strcmp_ignore_space(char *a, char *b)
  54. {
  55.         while (1)
  56.         {
  57.                 while (*a == ' ')
  58.                         a++;
  59.                 while (*b == ' ')
  60.                         b++;
  61.                 if (*a != *b)
  62.                         return 1;
  63.                 if (*a == 0)
  64.                         return *a != *b;
  65.                 if (*b == 0)
  66.                         return *a != *b;
  67.                 a++;
  68.                 b++;
  69.         }
  70. }
  71.  
  72. static char *clean_font_name(char *fontname)
  73. {
  74.         int i, k;
  75.         for (i = 0; i < 14; i++)
  76.                 for (k = 0; base_font_names[i][k]; k++)
  77.                         if (!strcmp_ignore_space(base_font_names[i][k], fontname))
  78.                                 return base_font_names[i][0];
  79.         return fontname;
  80. }
  81.  
  82. /*
  83.  * FreeType and Rendering glue
  84.  */
  85.  
  86. enum { UNKNOWN, TYPE1, TRUETYPE };
  87.  
  88. static int ft_kind(FT_Face face)
  89. {
  90.         /// STUB ///
  91.         //const char *kind = FT_Get_X11_Font_Format(face);
  92.         const char *kind = "TrueType";
  93.        
  94.         if (!strcmp(kind, "TrueType"))
  95.                 return TRUETYPE;
  96.         if (!strcmp(kind, "Type 1"))
  97.                 return TYPE1;
  98.         if (!strcmp(kind, "CFF"))
  99.                 return TYPE1;
  100.         if (!strcmp(kind, "CID Type 1"))
  101.                 return TYPE1;
  102.         return UNKNOWN;
  103. }
  104.  
  105. static int ft_is_bold(FT_Face face)
  106. {
  107.         return face->style_flags & FT_STYLE_FLAG_BOLD;
  108. }
  109.  
  110. static int ft_is_italic(FT_Face face)
  111. {
  112.         return face->style_flags & FT_STYLE_FLAG_ITALIC;
  113. }
  114.  
  115. static int ft_char_index(FT_Face face, int cid)
  116. {
  117.         int gid = FT_Get_Char_Index(face, cid);
  118.         if (gid == 0)
  119.                 gid = FT_Get_Char_Index(face, 0xf000 + cid);
  120.  
  121.         /* some chinese fonts only ship the similarly looking 0x2026 */
  122.         if (gid == 0 && cid == 0x22ef)
  123.                 gid = FT_Get_Char_Index(face, 0x2026);
  124.  
  125.         return gid;
  126. }
  127.  
  128. static int ft_cid_to_gid(pdf_font_desc *fontdesc, int cid)
  129. {
  130.         if (fontdesc->to_ttf_cmap)
  131.         {
  132.                 cid = pdf_lookup_cmap(fontdesc->to_ttf_cmap, cid);
  133.                 return ft_char_index(fontdesc->font->ft_face, cid);
  134.         }
  135.  
  136.         if (fontdesc->cid_to_gid)
  137.                 return fontdesc->cid_to_gid[cid];
  138.  
  139.         return cid;
  140. }
  141.  
  142. int
  143. pdf_font_cid_to_gid(pdf_font_desc *fontdesc, int cid)
  144. {
  145.         if (fontdesc->font->ft_face)
  146.                 return ft_cid_to_gid(fontdesc, cid);
  147.         return cid;
  148. }
  149.  
  150. static int ft_width(pdf_font_desc *fontdesc, int cid)
  151. {
  152.         int gid = ft_cid_to_gid(fontdesc, cid);
  153.         int fterr = FT_Load_Glyph(fontdesc->font->ft_face, gid,
  154.                         FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM);
  155.         if (fterr)
  156.         {
  157.                 fz_warn("freetype load glyph (gid %d): %s", gid, ft_error_string(fterr));
  158.                 return 0;
  159.         }
  160.         return ((FT_Face)fontdesc->font->ft_face)->glyph->advance.x;
  161. }
  162.  
  163. static int lookup_mre_code(char *name)
  164. {
  165.         int i;
  166.         for (i = 0; i < 256; i++)
  167.                 if (pdf_mac_roman[i] && !strcmp(name, pdf_mac_roman[i]))
  168.                         return i;
  169.         return -1;
  170. }
  171.  
  172. /*
  173.  * Load font files.
  174.  */
  175.  
  176. static fz_error
  177. pdf_load_builtin_font(pdf_font_desc *fontdesc, char *fontname)
  178. {
  179.         fz_error error;
  180.         unsigned char *data;
  181.         unsigned int len;
  182.  
  183.         data = pdf_find_builtin_font(fontname, &len);
  184.         if (!data)
  185.                 return fz_throw("cannot find builtin font: '%s'", fontname);
  186.  
  187.         error = fz_new_font_from_memory(&fontdesc->font, data, len, 0);
  188.         if (error)
  189.                 return fz_rethrow(error, "cannot load freetype font from memory");
  190.  
  191.         if (!strcmp(fontname, "Symbol") || !strcmp(fontname, "ZapfDingbats"))
  192.                 fontdesc->flags |= PDF_FD_SYMBOLIC;
  193.  
  194.         return fz_okay;
  195. }
  196.  
  197. static fz_error
  198. pdf_load_substitute_font(pdf_font_desc *fontdesc, int mono, int serif, int bold, int italic)
  199. {
  200.         fz_error error;
  201.         unsigned char *data;
  202.         unsigned int len;
  203.  
  204.         data = pdf_find_substitute_font(mono, serif, bold, italic, &len);
  205.         if (!data)
  206.                 return fz_throw("cannot find substitute font");
  207.  
  208.         error = fz_new_font_from_memory(&fontdesc->font, data, len, 0);
  209.         if (error)
  210.                 return fz_rethrow(error, "cannot load freetype font from memory");
  211.  
  212.         fontdesc->font->ft_substitute = 1;
  213.         fontdesc->font->ft_bold = bold && !ft_is_bold(fontdesc->font->ft_face);
  214.         fontdesc->font->ft_italic = italic && !ft_is_italic(fontdesc->font->ft_face);
  215.         return fz_okay;
  216. }
  217.  
  218. static fz_error
  219. pdf_load_substitute_cjk_font(pdf_font_desc *fontdesc, int ros, int serif)
  220. {
  221.         fz_error error;
  222.         unsigned char *data;
  223.         unsigned int len;
  224.  
  225.         data = pdf_find_substitute_cjk_font(ros, serif, &len);
  226.         if (!data)
  227.                 return fz_throw("cannot find builtin CJK font");
  228.  
  229.         error = fz_new_font_from_memory(&fontdesc->font, data, len, 0);
  230.         if (error)
  231.                 return fz_rethrow(error, "cannot load builtin CJK font");
  232.  
  233.         fontdesc->font->ft_substitute = 1;
  234.         return fz_okay;
  235. }
  236.  
  237. static fz_error
  238. pdf_load_system_font(pdf_font_desc *fontdesc, char *fontname, char *collection)
  239. {
  240.         fz_error error;
  241.         int bold = 0;
  242.         int italic = 0;
  243.         int serif = 0;
  244.         int mono = 0;
  245.  
  246.         if (strstr(fontname, "Bold"))
  247.                 bold = 1;
  248.         if (strstr(fontname, "Italic"))
  249.                 italic = 1;
  250.         if (strstr(fontname, "Oblique"))
  251.                 italic = 1;
  252.  
  253.         if (fontdesc->flags & PDF_FD_FIXED_PITCH)
  254.                 mono = 1;
  255.         if (fontdesc->flags & PDF_FD_SERIF)
  256.                 serif = 1;
  257.         if (fontdesc->flags & PDF_FD_ITALIC)
  258.                 italic = 1;
  259.         if (fontdesc->flags & PDF_FD_FORCE_BOLD)
  260.                 bold = 1;
  261.  
  262.         if (collection)
  263.         {
  264.                 if (!strcmp(collection, "Adobe-CNS1"))
  265.                         return pdf_load_substitute_cjk_font(fontdesc, PDF_ROS_CNS, serif);
  266.                 else if (!strcmp(collection, "Adobe-GB1"))
  267.                         return pdf_load_substitute_cjk_font(fontdesc, PDF_ROS_GB, serif);
  268.                 else if (!strcmp(collection, "Adobe-Japan1"))
  269.                         return pdf_load_substitute_cjk_font(fontdesc, PDF_ROS_JAPAN, serif);
  270.                 else if (!strcmp(collection, "Adobe-Korea1"))
  271.                         return pdf_load_substitute_cjk_font(fontdesc, PDF_ROS_KOREA, serif);
  272.                 return fz_throw("unknown cid collection: %s", collection);
  273.         }
  274.  
  275.         error = pdf_load_substitute_font(fontdesc, mono, serif, bold, italic);
  276.         if (error)
  277.                 return fz_rethrow(error, "cannot load substitute font");
  278.  
  279.         return fz_okay;
  280. }
  281.  
  282. static fz_error
  283. pdf_load_embedded_font(pdf_font_desc *fontdesc, pdf_xref *xref, fz_obj *stmref)
  284. {
  285.         fz_error error;
  286.         fz_buffer *buf;
  287.  
  288.         error = pdf_load_stream(&buf, xref, fz_to_num(stmref), fz_to_gen(stmref));
  289.         if (error)
  290.                 return fz_rethrow(error, "cannot load font stream (%d %d R)", fz_to_num(stmref), fz_to_gen(stmref));
  291.  
  292.         error = fz_new_font_from_memory(&fontdesc->font, buf->data, buf->len, 0);
  293.         if (error)
  294.         {
  295.                 fz_drop_buffer(buf);
  296.                 return fz_rethrow(error, "cannot load embedded font (%d %d R)", fz_to_num(stmref), fz_to_gen(stmref));
  297.         }
  298.  
  299.         /* save the buffer so we can free it later */
  300.         fontdesc->font->ft_data = buf->data;
  301.         fontdesc->font->ft_size = buf->len;
  302.         fz_free(buf); /* only free the fz_buffer struct, not the contained data */
  303.  
  304.         fontdesc->is_embedded = 1;
  305.  
  306.         return fz_okay;
  307. }
  308.  
  309. /*
  310.  * Create and destroy
  311.  */
  312.  
  313. pdf_font_desc *
  314. pdf_keep_font(pdf_font_desc *fontdesc)
  315. {
  316.         fontdesc->refs ++;
  317.         return fontdesc;
  318. }
  319.  
  320. void
  321. pdf_drop_font(pdf_font_desc *fontdesc)
  322. {
  323.         if (fontdesc && --fontdesc->refs == 0)
  324.         {
  325.                 if (fontdesc->font)
  326.                         fz_drop_font(fontdesc->font);
  327.                 if (fontdesc->encoding)
  328.                         pdf_drop_cmap(fontdesc->encoding);
  329.                 if (fontdesc->to_ttf_cmap)
  330.                         pdf_drop_cmap(fontdesc->to_ttf_cmap);
  331.                 if (fontdesc->to_unicode)
  332.                         pdf_drop_cmap(fontdesc->to_unicode);
  333.                 fz_free(fontdesc->cid_to_gid);
  334.                 fz_free(fontdesc->cid_to_ucs);
  335.                 fz_free(fontdesc->hmtx);
  336.                 fz_free(fontdesc->vmtx);
  337.                 fz_free(fontdesc);
  338.         }
  339. }
  340.  
  341. pdf_font_desc *
  342. pdf_new_font_desc(void)
  343. {
  344.         pdf_font_desc *fontdesc;
  345.  
  346.         fontdesc = fz_malloc(sizeof(pdf_font_desc));
  347.         fontdesc->refs = 1;
  348.  
  349.         fontdesc->font = NULL;
  350.  
  351.         fontdesc->flags = 0;
  352.         fontdesc->italic_angle = 0;
  353.         fontdesc->ascent = 0;
  354.         fontdesc->descent = 0;
  355.         fontdesc->cap_height = 0;
  356.         fontdesc->x_height = 0;
  357.         fontdesc->missing_width = 0;
  358.  
  359.         fontdesc->encoding = NULL;
  360.         fontdesc->to_ttf_cmap = NULL;
  361.         fontdesc->cid_to_gid_len = 0;
  362.         fontdesc->cid_to_gid = NULL;
  363.  
  364.         fontdesc->to_unicode = NULL;
  365.         fontdesc->cid_to_ucs_len = 0;
  366.         fontdesc->cid_to_ucs = NULL;
  367.  
  368.         fontdesc->wmode = 0;
  369.  
  370.         fontdesc->hmtx_cap = 0;
  371.         fontdesc->vmtx_cap = 0;
  372.         fontdesc->hmtx_len = 0;
  373.         fontdesc->vmtx_len = 0;
  374.         fontdesc->hmtx = NULL;
  375.         fontdesc->vmtx = NULL;
  376.  
  377.         fontdesc->dhmtx.lo = 0x0000;
  378.         fontdesc->dhmtx.hi = 0xFFFF;
  379.         fontdesc->dhmtx.w = 1000;
  380.  
  381.         fontdesc->dvmtx.lo = 0x0000;
  382.         fontdesc->dvmtx.hi = 0xFFFF;
  383.         fontdesc->dvmtx.x = 0;
  384.         fontdesc->dvmtx.y = 880;
  385.         fontdesc->dvmtx.w = -1000;
  386.  
  387.         fontdesc->is_embedded = 0;
  388.  
  389.         return fontdesc;
  390. }
  391.  
  392. /*
  393.  * Simple fonts (Type1 and TrueType)
  394.  */
  395.  
  396. static fz_error
  397. pdf_load_simple_font(pdf_font_desc **fontdescp, pdf_xref *xref, fz_obj *dict)
  398. {
  399.         fz_error error;
  400.         fz_obj *descriptor;
  401.         fz_obj *encoding;
  402.         fz_obj *widths;
  403.         unsigned short *etable = NULL;
  404.         pdf_font_desc *fontdesc;
  405.         FT_Face face;
  406.         FT_CharMap cmap;
  407.         int symbolic;
  408.         int kind;
  409.  
  410.         char *basefont;
  411.         char *fontname;
  412.         char *estrings[256];
  413.         char ebuffer[256][32];
  414.         int i, k, n;
  415.         int fterr;
  416.  
  417.         basefont = fz_to_name(fz_dict_gets(dict, "BaseFont"));
  418.         fontname = clean_font_name(basefont);
  419.  
  420.         /* Load font file */
  421.  
  422.         fontdesc = pdf_new_font_desc();
  423.  
  424.         descriptor = fz_dict_gets(dict, "FontDescriptor");
  425.         if (descriptor)
  426.                 error = pdf_load_font_descriptor(fontdesc, xref, descriptor, NULL, basefont);
  427.         else
  428.                 error = pdf_load_builtin_font(fontdesc, fontname);
  429.         if (error)
  430.                 goto cleanup;
  431.  
  432.         /* Some chinese documents mistakenly consider WinAnsiEncoding to be codepage 936 */
  433.         if (!*fontdesc->font->name &&
  434.                 !fz_dict_gets(dict, "ToUnicode") &&
  435.                 !strcmp(fz_to_name(fz_dict_gets(dict, "Encoding")), "WinAnsiEncoding") &&
  436.                 fz_to_int(fz_dict_gets(descriptor, "Flags")) == 4)
  437.         {
  438.                 /* note: without the comma, pdf_load_font_descriptor would prefer /FontName over /BaseFont */
  439.                 char *cp936fonts[] = {
  440.                         "\xCB\xCE\xCC\xE5", "SimSun,Regular",
  441.                         "\xBA\xDA\xCC\xE5", "SimHei,Regular",
  442.                         "\xBF\xAC\xCC\xE5_GB2312", "SimKai,Regular",
  443.                         "\xB7\xC2\xCB\xCE_GB2312", "SimFang,Regular",
  444.                         "\xC1\xA5\xCA\xE9", "SimLi,Regular",
  445.                         NULL
  446.                 };
  447.                 for (i = 0; cp936fonts[i]; i += 2)
  448.                         if (!strcmp(basefont, cp936fonts[i]))
  449.                                 break;
  450.                 if (cp936fonts[i])
  451.                 {
  452.                         fz_warn("workaround for S22PDF lying about chinese font encodings");
  453.                         pdf_drop_font(fontdesc);
  454.                         fontdesc = pdf_new_font_desc();
  455.                         error = pdf_load_font_descriptor(fontdesc, xref, descriptor, "Adobe-GB1", cp936fonts[i+1]);
  456.                         error |= pdf_load_system_cmap(&fontdesc->encoding, "GBK-EUC-H");
  457.                         error |= pdf_load_system_cmap(&fontdesc->to_unicode, "Adobe-GB1-UCS2");
  458.                         error |= pdf_load_system_cmap(&fontdesc->to_ttf_cmap, "Adobe-GB1-UCS2");
  459.                         if (error)
  460.                                 return fz_rethrow(error, "cannot load font");
  461.  
  462.                         face = fontdesc->font->ft_face;
  463.                         kind = ft_kind(face);
  464.                         goto skip_encoding;
  465.                 }
  466.         }
  467.  
  468.         face = fontdesc->font->ft_face;
  469.         kind = ft_kind(face);
  470.  
  471.         /* Encoding */
  472.  
  473.         symbolic = fontdesc->flags & 4;
  474.  
  475.         if (face->num_charmaps > 0)
  476.                 cmap = face->charmaps[0];
  477.         else
  478.                 cmap = NULL;
  479.  
  480.         for (i = 0; i < face->num_charmaps; i++)
  481.         {
  482.                 FT_CharMap test = face->charmaps[i];
  483.  
  484.                 if (kind == TYPE1)
  485.                 {
  486.                         if (test->platform_id == 7)
  487.                                 cmap = test;
  488.                 }
  489.  
  490.                 if (kind == TRUETYPE)
  491.                 {
  492.                         if (test->platform_id == 1 && test->encoding_id == 0)
  493.                                 cmap = test;
  494.                         if (test->platform_id == 3 && test->encoding_id == 1)
  495.                                 cmap = test;
  496.                 }
  497.         }
  498.  
  499.         if (cmap)
  500.         {
  501.                 fterr = FT_Set_Charmap(face, cmap);
  502.                 if (fterr)
  503.                         fz_warn("freetype could not set cmap: %s", ft_error_string(fterr));
  504.         }
  505.         else
  506.                 fz_warn("freetype could not find any cmaps");
  507.  
  508.         etable = fz_calloc(256, sizeof(unsigned short));
  509.         for (i = 0; i < 256; i++)
  510.         {
  511.                 estrings[i] = NULL;
  512.                 etable[i] = 0;
  513.         }
  514.  
  515.         encoding = fz_dict_gets(dict, "Encoding");
  516.         if (encoding)
  517.         {
  518.                 if (fz_is_name(encoding))
  519.                         pdf_load_encoding(estrings, fz_to_name(encoding));
  520.  
  521.                 if (fz_is_dict(encoding))
  522.                 {
  523.                         fz_obj *base, *diff, *item;
  524.  
  525.                         base = fz_dict_gets(encoding, "BaseEncoding");
  526.                         if (fz_is_name(base))
  527.                                 pdf_load_encoding(estrings, fz_to_name(base));
  528.                         else if (!fontdesc->is_embedded && !symbolic)
  529.                                 pdf_load_encoding(estrings, "StandardEncoding");
  530.  
  531.                         diff = fz_dict_gets(encoding, "Differences");
  532.                         if (fz_is_array(diff))
  533.                         {
  534.                                 n = fz_array_len(diff);
  535.                                 k = 0;
  536.                                 for (i = 0; i < n; i++)
  537.                                 {
  538.                                         item = fz_array_get(diff, i);
  539.                                         if (fz_is_int(item))
  540.                                                 k = fz_to_int(item);
  541.                                         if (fz_is_name(item))
  542.                                                 estrings[k++] = fz_to_name(item);
  543.                                         if (k < 0) k = 0;
  544.                                         if (k > 255) k = 255;
  545.                                 }
  546.                         }
  547.                 }
  548.         }
  549.  
  550.         /* start with the builtin encoding */
  551.         for (i = 0; i < 256; i++)
  552.                 etable[i] = ft_char_index(face, i);
  553.  
  554.         /* encode by glyph name where we can */
  555.         if (kind == TYPE1)
  556.         {
  557.                 for (i = 0; i < 256; i++)
  558.                 {
  559.                         if (estrings[i])
  560.                         {
  561.                                 etable[i] = FT_Get_Name_Index(face, estrings[i]);
  562.                                 if (etable[i] == 0)
  563.                                 {
  564.                                         int aglcode = pdf_lookup_agl(estrings[i]);
  565.                                         const char **dupnames = pdf_lookup_agl_duplicates(aglcode);
  566.                                         while (*dupnames)
  567.                                         {
  568.                                                 etable[i] = FT_Get_Name_Index(face, (char*)*dupnames);
  569.                                                 if (etable[i])
  570.                                                         break;
  571.                                                 dupnames++;
  572.                                         }
  573.                                 }
  574.                         }
  575.                 }
  576.         }
  577.  
  578.         /* encode by glyph name where we can */
  579.         if (kind == TRUETYPE)
  580.         {
  581.                 /* Unicode cmap */
  582.                 if (!symbolic && face->charmap && face->charmap->platform_id == 3)
  583.                 {
  584.                         for (i = 0; i < 256; i++)
  585.                         {
  586.                                 if (estrings[i])
  587.                                 {
  588.                                         int aglcode = pdf_lookup_agl(estrings[i]);
  589.                                         if (!aglcode)
  590.                                                 etable[i] = FT_Get_Name_Index(face, estrings[i]);
  591.                                         else
  592.                                                 etable[i] = ft_char_index(face, aglcode);
  593.                                 }
  594.                         }
  595.                 }
  596.  
  597.                 /* MacRoman cmap */
  598.                 else if (!symbolic && face->charmap && face->charmap->platform_id == 1)
  599.                 {
  600.                         for (i = 0; i < 256; i++)
  601.                         {
  602.                                 if (estrings[i])
  603.                                 {
  604.                                         k = lookup_mre_code(estrings[i]);
  605.                                         if (k <= 0)
  606.                                                 etable[i] = FT_Get_Name_Index(face, estrings[i]);
  607.                                         else
  608.                                                 etable[i] = ft_char_index(face, k);
  609.                                 }
  610.                         }
  611.                 }
  612.  
  613.                 /* Symbolic cmap */
  614.                 else
  615.                 {
  616.                         for (i = 0; i < 256; i++)
  617.                         {
  618.                                 if (estrings[i])
  619.                                 {
  620.                                         etable[i] = FT_Get_Name_Index(face, estrings[i]);
  621.                                         if (etable[i] == 0)
  622.                                                 etable[i] = ft_char_index(face, i);
  623.                                 }
  624.                         }
  625.                 }
  626.         }
  627.  
  628.         /* try to reverse the glyph names from the builtin encoding */
  629.         for (i = 0; i < 256; i++)
  630.         {
  631.                 if (etable[i] && !estrings[i])
  632.                 {
  633.                         if (FT_HAS_GLYPH_NAMES(face))
  634.                         {
  635.                                 fterr = FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32);
  636.                                 if (fterr)
  637.                                         fz_warn("freetype get glyph name (gid %d): %s", etable[i], ft_error_string(fterr));
  638.                                 if (ebuffer[i][0])
  639.                                         estrings[i] = ebuffer[i];
  640.                         }
  641.                         else
  642.                         {
  643.                                 estrings[i] = (char*) pdf_win_ansi[i]; /* discard const */
  644.                         }
  645.                 }
  646.         }
  647.  
  648.         fontdesc->encoding = pdf_new_identity_cmap(0, 1);
  649.         fontdesc->cid_to_gid_len = 256;
  650.         fontdesc->cid_to_gid = etable;
  651.  
  652.         error = pdf_load_to_unicode(fontdesc, xref, estrings, NULL, fz_dict_gets(dict, "ToUnicode"));
  653.         if (error)
  654.                 fz_catch(error, "cannot load to_unicode");
  655.  
  656. skip_encoding:
  657.  
  658.         /* Widths */
  659.  
  660.         pdf_set_default_hmtx(fontdesc, fontdesc->missing_width);
  661.  
  662.         widths = fz_dict_gets(dict, "Widths");
  663.         if (widths)
  664.         {
  665.                 int first, last;
  666.  
  667.                 first = fz_to_int(fz_dict_gets(dict, "FirstChar"));
  668.                 last = fz_to_int(fz_dict_gets(dict, "LastChar"));
  669.  
  670.                 if (first < 0 || last > 255 || first > last)
  671.                         first = last = 0;
  672.  
  673.                 for (i = 0; i < last - first + 1; i++)
  674.                 {
  675.                         int wid = fz_to_int(fz_array_get(widths, i));
  676.                         pdf_add_hmtx(fontdesc, i + first, i + first, wid);
  677.                 }
  678.         }
  679.         else
  680.         {
  681.                 fterr = FT_Set_Char_Size(face, 1000, 1000, 72, 72);
  682.                 if (fterr)
  683.                         fz_warn("freetype set character size: %s", ft_error_string(fterr));
  684.                 for (i = 0; i < 256; i++)
  685.                 {
  686.                         pdf_add_hmtx(fontdesc, i, i, ft_width(fontdesc, i));
  687.                 }
  688.         }
  689.  
  690.         pdf_end_hmtx(fontdesc);
  691.  
  692.         *fontdescp = fontdesc;
  693.         return fz_okay;
  694.  
  695. cleanup:
  696.         if (etable != fontdesc->cid_to_gid)
  697.                 fz_free(etable);
  698.         pdf_drop_font(fontdesc);
  699.         return fz_rethrow(error, "cannot load simple font (%d %d R)", fz_to_num(dict), fz_to_gen(dict));
  700. }
  701.  
  702. /*
  703.  * CID Fonts
  704.  */
  705.  
  706. static fz_error
  707. load_cid_font(pdf_font_desc **fontdescp, pdf_xref *xref, fz_obj *dict, fz_obj *encoding, fz_obj *to_unicode)
  708. {
  709.         fz_error error;
  710.         fz_obj *widths;
  711.         fz_obj *descriptor;
  712.         pdf_font_desc *fontdesc;
  713.         FT_Face face;
  714.         int kind;
  715.         char collection[256];
  716.         char *basefont;
  717.         int i, k, fterr;
  718.         fz_obj *obj;
  719.         int dw;
  720.  
  721.         /* Get font name and CID collection */
  722.  
  723.         basefont = fz_to_name(fz_dict_gets(dict, "BaseFont"));
  724.  
  725.         {
  726.                 fz_obj *cidinfo;
  727.                 char tmpstr[64];
  728.                 int tmplen;
  729.  
  730.                 cidinfo = fz_dict_gets(dict, "CIDSystemInfo");
  731.                 if (!cidinfo)
  732.                         return fz_throw("cid font is missing info");
  733.  
  734.                 obj = fz_dict_gets(cidinfo, "Registry");
  735.                 tmplen = MIN(sizeof tmpstr - 1, fz_to_str_len(obj));
  736.                 memcpy(tmpstr, fz_to_str_buf(obj), tmplen);
  737.                 tmpstr[tmplen] = '\0';
  738.                 fz_strlcpy(collection, tmpstr, sizeof collection);
  739.  
  740.                 fz_strlcat(collection, "-", sizeof collection);
  741.  
  742.                 obj = fz_dict_gets(cidinfo, "Ordering");
  743.                 tmplen = MIN(sizeof tmpstr - 1, fz_to_str_len(obj));
  744.                 memcpy(tmpstr, fz_to_str_buf(obj), tmplen);
  745.                 tmpstr[tmplen] = '\0';
  746.                 fz_strlcat(collection, tmpstr, sizeof collection);
  747.         }
  748.  
  749.         /* Load font file */
  750.  
  751.         fontdesc = pdf_new_font_desc();
  752.  
  753.         descriptor = fz_dict_gets(dict, "FontDescriptor");
  754.         if (descriptor)
  755.                 error = pdf_load_font_descriptor(fontdesc, xref, descriptor, collection, basefont);
  756.         else
  757.                 error = fz_throw("syntaxerror: missing font descriptor");
  758.         if (error)
  759.                 goto cleanup;
  760.  
  761.         face = fontdesc->font->ft_face;
  762.         kind = ft_kind(face);
  763.  
  764.         /* Encoding */
  765.  
  766.         error = fz_okay;
  767.         if (fz_is_name(encoding))
  768.         {
  769.                 if (!strcmp(fz_to_name(encoding), "Identity-H"))
  770.                         fontdesc->encoding = pdf_new_identity_cmap(0, 2);
  771.                 else if (!strcmp(fz_to_name(encoding), "Identity-V"))
  772.                         fontdesc->encoding = pdf_new_identity_cmap(1, 2);
  773.                 else
  774.                         error = pdf_load_system_cmap(&fontdesc->encoding, fz_to_name(encoding));
  775.         }
  776.         else if (fz_is_indirect(encoding))
  777.         {
  778.                 error = pdf_load_embedded_cmap(&fontdesc->encoding, xref, encoding);
  779.         }
  780.         else
  781.         {
  782.                 error = fz_throw("syntaxerror: font missing encoding");
  783.         }
  784.         if (error)
  785.                 goto cleanup;
  786.  
  787.         pdf_set_font_wmode(fontdesc, pdf_get_wmode(fontdesc->encoding));
  788.  
  789.         if (kind == TRUETYPE)
  790.         {
  791.                 fz_obj *cidtogidmap;
  792.  
  793.                 cidtogidmap = fz_dict_gets(dict, "CIDToGIDMap");
  794.                 if (fz_is_indirect(cidtogidmap))
  795.                 {
  796.                         fz_buffer *buf;
  797.  
  798.                         error = pdf_load_stream(&buf, xref, fz_to_num(cidtogidmap), fz_to_gen(cidtogidmap));
  799.                         if (error)
  800.                                 goto cleanup;
  801.  
  802.                         fontdesc->cid_to_gid_len = (buf->len) / 2;
  803.                         fontdesc->cid_to_gid = fz_calloc(fontdesc->cid_to_gid_len, sizeof(unsigned short));
  804.                         for (i = 0; i < fontdesc->cid_to_gid_len; i++)
  805.                                 fontdesc->cid_to_gid[i] = (buf->data[i * 2] << 8) + buf->data[i * 2 + 1];
  806.  
  807.                         fz_drop_buffer(buf);
  808.                 }
  809.  
  810.                 /* if truetype font is external, cidtogidmap should not be identity */
  811.                 /* so we map from cid to unicode and then map that through the (3 1) */
  812.                 /* unicode cmap to get a glyph id */
  813.                 else if (fontdesc->font->ft_substitute)
  814.                 {
  815.                         fterr = FT_Select_Charmap(face, ft_encoding_unicode);
  816.                         if (fterr)
  817.                         {
  818.                                 error = fz_throw("fonterror: no unicode cmap when emulating CID font: %s", ft_error_string(fterr));
  819.                                 goto cleanup;
  820.                         }
  821.  
  822.                         if (!strcmp(collection, "Adobe-CNS1"))
  823.                                 error = pdf_load_system_cmap(&fontdesc->to_ttf_cmap, "Adobe-CNS1-UCS2");
  824.                         else if (!strcmp(collection, "Adobe-GB1"))
  825.                                 error = pdf_load_system_cmap(&fontdesc->to_ttf_cmap, "Adobe-GB1-UCS2");
  826.                         else if (!strcmp(collection, "Adobe-Japan1"))
  827.                                 error = pdf_load_system_cmap(&fontdesc->to_ttf_cmap, "Adobe-Japan1-UCS2");
  828.                         else if (!strcmp(collection, "Adobe-Japan2"))
  829.                                 error = pdf_load_system_cmap(&fontdesc->to_ttf_cmap, "Adobe-Japan2-UCS2");
  830.                         else if (!strcmp(collection, "Adobe-Korea1"))
  831.                                 error = pdf_load_system_cmap(&fontdesc->to_ttf_cmap, "Adobe-Korea1-UCS2");
  832.                         else
  833.                                 error = fz_okay;
  834.  
  835.                         if (error)
  836.                         {
  837.                                 error = fz_rethrow(error, "cannot load system cmap %s", collection);
  838.                                 goto cleanup;
  839.                         }
  840.                 }
  841.         }
  842.  
  843.         error = pdf_load_to_unicode(fontdesc, xref, NULL, collection, to_unicode);
  844.         if (error)
  845.                 fz_catch(error, "cannot load to_unicode");
  846.  
  847.         /* Horizontal */
  848.  
  849.         dw = 1000;
  850.         obj = fz_dict_gets(dict, "DW");
  851.         if (obj)
  852.                 dw = fz_to_int(obj);
  853.         pdf_set_default_hmtx(fontdesc, dw);
  854.  
  855.         widths = fz_dict_gets(dict, "W");
  856.         if (widths)
  857.         {
  858.                 int c0, c1, w;
  859.  
  860.                 for (i = 0; i < fz_array_len(widths); )
  861.                 {
  862.                         c0 = fz_to_int(fz_array_get(widths, i));
  863.                         obj = fz_array_get(widths, i + 1);
  864.                         if (fz_is_array(obj))
  865.                         {
  866.                                 for (k = 0; k < fz_array_len(obj); k++)
  867.                                 {
  868.                                         w = fz_to_int(fz_array_get(obj, k));
  869.                                         pdf_add_hmtx(fontdesc, c0 + k, c0 + k, w);
  870.                                 }
  871.                                 i += 2;
  872.                         }
  873.                         else
  874.                         {
  875.                                 c1 = fz_to_int(obj);
  876.                                 w = fz_to_int(fz_array_get(widths, i + 2));
  877.                                 pdf_add_hmtx(fontdesc, c0, c1, w);
  878.                                 i += 3;
  879.                         }
  880.                 }
  881.         }
  882.  
  883.         pdf_end_hmtx(fontdesc);
  884.  
  885.         /* Vertical */
  886.  
  887.         if (pdf_get_wmode(fontdesc->encoding) == 1)
  888.         {
  889.                 int dw2y = 880;
  890.                 int dw2w = -1000;
  891.  
  892.                 obj = fz_dict_gets(dict, "DW2");
  893.                 if (obj)
  894.                 {
  895.                         dw2y = fz_to_int(fz_array_get(obj, 0));
  896.                         dw2w = fz_to_int(fz_array_get(obj, 1));
  897.                 }
  898.  
  899.                 pdf_set_default_vmtx(fontdesc, dw2y, dw2w);
  900.  
  901.                 widths = fz_dict_gets(dict, "W2");
  902.                 if (widths)
  903.                 {
  904.                         int c0, c1, w, x, y;
  905.  
  906.                         for (i = 0; i < fz_array_len(widths); )
  907.                         {
  908.                                 c0 = fz_to_int(fz_array_get(widths, i));
  909.                                 obj = fz_array_get(widths, i + 1);
  910.                                 if (fz_is_array(obj))
  911.                                 {
  912.                                         for (k = 0; k * 3 < fz_array_len(obj); k ++)
  913.                                         {
  914.                                                 w = fz_to_int(fz_array_get(obj, k * 3 + 0));
  915.                                                 x = fz_to_int(fz_array_get(obj, k * 3 + 1));
  916.                                                 y = fz_to_int(fz_array_get(obj, k * 3 + 2));
  917.                                                 pdf_add_vmtx(fontdesc, c0 + k, c0 + k, x, y, w);
  918.                                         }
  919.                                         i += 2;
  920.                                 }
  921.                                 else
  922.                                 {
  923.                                         c1 = fz_to_int(obj);
  924.                                         w = fz_to_int(fz_array_get(widths, i + 2));
  925.                                         x = fz_to_int(fz_array_get(widths, i + 3));
  926.                                         y = fz_to_int(fz_array_get(widths, i + 4));
  927.                                         pdf_add_vmtx(fontdesc, c0, c1, x, y, w);
  928.                                         i += 5;
  929.                                 }
  930.                         }
  931.                 }
  932.  
  933.                 pdf_end_vmtx(fontdesc);
  934.         }
  935.  
  936.         *fontdescp = fontdesc;
  937.         return fz_okay;
  938.  
  939. cleanup:
  940.         pdf_drop_font(fontdesc);
  941.         return fz_rethrow(error, "cannot load cid font (%d %d R)", fz_to_num(dict), fz_to_gen(dict));
  942. }
  943.  
  944. static fz_error
  945. pdf_load_type0_font(pdf_font_desc **fontdescp, pdf_xref *xref, fz_obj *dict)
  946. {
  947.         fz_error error;
  948.         fz_obj *dfonts;
  949.         fz_obj *dfont;
  950.         fz_obj *subtype;
  951.         fz_obj *encoding;
  952.         fz_obj *to_unicode;
  953.  
  954.         dfonts = fz_dict_gets(dict, "DescendantFonts");
  955.         if (!dfonts)
  956.                 return fz_throw("cid font is missing descendant fonts");
  957.  
  958.         dfont = fz_array_get(dfonts, 0);
  959.  
  960.         subtype = fz_dict_gets(dfont, "Subtype");
  961.         encoding = fz_dict_gets(dict, "Encoding");
  962.         to_unicode = fz_dict_gets(dict, "ToUnicode");
  963.  
  964.         if (fz_is_name(subtype) && !strcmp(fz_to_name(subtype), "CIDFontType0"))
  965.                 error = load_cid_font(fontdescp, xref, dfont, encoding, to_unicode);
  966.         else if (fz_is_name(subtype) && !strcmp(fz_to_name(subtype), "CIDFontType2"))
  967.                 error = load_cid_font(fontdescp, xref, dfont, encoding, to_unicode);
  968.         else
  969.                 error = fz_throw("syntaxerror: unknown cid font type");
  970.         if (error)
  971.                 return fz_rethrow(error, "cannot load descendant font (%d %d R)", fz_to_num(dfont), fz_to_gen(dfont));
  972.  
  973.         return fz_okay;
  974. }
  975.  
  976. /*
  977.  * FontDescriptor
  978.  */
  979.  
  980. static fz_error
  981. pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_xref *xref, fz_obj *dict, char *collection, char *basefont)
  982. {
  983.         fz_error error;
  984.         fz_obj *obj1, *obj2, *obj3, *obj;
  985.         char *fontname;
  986.         char *origname;
  987.         FT_Face face;
  988.  
  989.         if (!strchr(basefont, ',') || strchr(basefont, '+'))
  990.                 origname = fz_to_name(fz_dict_gets(dict, "FontName"));
  991.         else
  992.                 origname = basefont;
  993.         fontname = clean_font_name(origname);
  994.  
  995.         fontdesc->flags = fz_to_int(fz_dict_gets(dict, "Flags"));
  996.         fontdesc->italic_angle = fz_to_real(fz_dict_gets(dict, "ItalicAngle"));
  997.         fontdesc->ascent = fz_to_real(fz_dict_gets(dict, "Ascent"));
  998.         fontdesc->descent = fz_to_real(fz_dict_gets(dict, "Descent"));
  999.         fontdesc->cap_height = fz_to_real(fz_dict_gets(dict, "CapHeight"));
  1000.         fontdesc->x_height = fz_to_real(fz_dict_gets(dict, "XHeight"));
  1001.         fontdesc->missing_width = fz_to_real(fz_dict_gets(dict, "MissingWidth"));
  1002.  
  1003.         obj1 = fz_dict_gets(dict, "FontFile");
  1004.         obj2 = fz_dict_gets(dict, "FontFile2");
  1005.         obj3 = fz_dict_gets(dict, "FontFile3");
  1006.         obj = obj1 ? obj1 : obj2 ? obj2 : obj3;
  1007.  
  1008.         if (fz_is_indirect(obj))
  1009.         {
  1010.                 error = pdf_load_embedded_font(fontdesc, xref, obj);
  1011.                 if (error)
  1012.                 {
  1013.                         fz_catch(error, "ignored error when loading embedded font, attempting to load system font");
  1014.                         if (origname != fontname)
  1015.                                 error = pdf_load_builtin_font(fontdesc, fontname);
  1016.                         else
  1017.                                 error = pdf_load_system_font(fontdesc, fontname, collection);
  1018.                         if (error)
  1019.                                 return fz_rethrow(error, "cannot load font descriptor (%d %d R)", fz_to_num(dict), fz_to_gen(dict));
  1020.                 }
  1021.         }
  1022.         else
  1023.         {
  1024.                 if (origname != fontname)
  1025.                         error = pdf_load_builtin_font(fontdesc, fontname);
  1026.                 else
  1027.                         error = pdf_load_system_font(fontdesc, fontname, collection);
  1028.                 if (error)
  1029.                         return fz_rethrow(error, "cannot load font descriptor (%d %d R)", fz_to_num(dict), fz_to_gen(dict));
  1030.         }
  1031.  
  1032.         fz_strlcpy(fontdesc->font->name, fontname, sizeof fontdesc->font->name);
  1033.  
  1034.         /* Check for DynaLab fonts that must use hinting */
  1035.         face = fontdesc->font->ft_face;
  1036.         if (ft_kind(face) == TRUETYPE)
  1037.         {
  1038.                 if (FT_IS_TRICKY(face) || is_dynalab(fontdesc->font->name))
  1039.                         fontdesc->font->ft_hint = 1;
  1040.         }
  1041.  
  1042.         return fz_okay;
  1043.  
  1044. }
  1045.  
  1046. static void
  1047. pdf_make_width_table(pdf_font_desc *fontdesc)
  1048. {
  1049.         fz_font *font = fontdesc->font;
  1050.         int i, k, cid, gid;
  1051.  
  1052.         font->width_count = 0;
  1053.         for (i = 0; i < fontdesc->hmtx_len; i++)
  1054.         {
  1055.                 for (k = fontdesc->hmtx[i].lo; k <= fontdesc->hmtx[i].hi; k++)
  1056.                 {
  1057.                         cid = pdf_lookup_cmap(fontdesc->encoding, k);
  1058.                         gid = pdf_font_cid_to_gid(fontdesc, cid);
  1059.                         if (gid > font->width_count)
  1060.                                 font->width_count = gid;
  1061.                 }
  1062.         }
  1063.         font->width_count ++;
  1064.  
  1065.         font->width_table = fz_calloc(font->width_count, sizeof(int));
  1066.         memset(font->width_table, 0, sizeof(int) * font->width_count);
  1067.  
  1068.         for (i = 0; i < fontdesc->hmtx_len; i++)
  1069.         {
  1070.                 for (k = fontdesc->hmtx[i].lo; k <= fontdesc->hmtx[i].hi; k++)
  1071.                 {
  1072.                         cid = pdf_lookup_cmap(fontdesc->encoding, k);
  1073.                         gid = pdf_font_cid_to_gid(fontdesc, cid);
  1074.                         if (gid >= 0 && gid < font->width_count)
  1075.                                 font->width_table[gid] = fontdesc->hmtx[i].w;
  1076.                 }
  1077.         }
  1078. }
  1079.  
  1080. fz_error
  1081. pdf_load_font(pdf_font_desc **fontdescp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict)
  1082. {
  1083.         fz_error error;
  1084.         char *subtype;
  1085.         fz_obj *dfonts;
  1086.         fz_obj *charprocs;
  1087.  
  1088.         if ((*fontdescp = pdf_find_item(xref->store, pdf_drop_font, dict)))
  1089.         {
  1090.                 pdf_keep_font(*fontdescp);
  1091.                 return fz_okay;
  1092.         }
  1093.  
  1094.         subtype = fz_to_name(fz_dict_gets(dict, "Subtype"));
  1095.         dfonts = fz_dict_gets(dict, "DescendantFonts");
  1096.         charprocs = fz_dict_gets(dict, "CharProcs");
  1097.  
  1098.         if (subtype && !strcmp(subtype, "Type0"))
  1099.                 error = pdf_load_type0_font(fontdescp, xref, dict);
  1100.         else if (subtype && !strcmp(subtype, "Type1"))
  1101.                 error = pdf_load_simple_font(fontdescp, xref, dict);
  1102.         else if (subtype && !strcmp(subtype, "MMType1"))
  1103.                 error = pdf_load_simple_font(fontdescp, xref, dict);
  1104.         else if (subtype && !strcmp(subtype, "TrueType"))
  1105.                 error = pdf_load_simple_font(fontdescp, xref, dict);
  1106.         else if (subtype && !strcmp(subtype, "Type3"))
  1107.                 error = pdf_load_type3_font(fontdescp, xref, rdb, dict);
  1108.         else if (charprocs)
  1109.         {
  1110.                 fz_warn("unknown font format, guessing type3.");
  1111.                 error = pdf_load_type3_font(fontdescp, xref, rdb, dict);
  1112.         }
  1113.         else if (dfonts)
  1114.         {
  1115.                 fz_warn("unknown font format, guessing type0.");
  1116.                 error = pdf_load_type0_font(fontdescp, xref, dict);
  1117.         }
  1118.         else
  1119.         {
  1120.                 fz_warn("unknown font format, guessing type1 or truetype.");
  1121.                 error = pdf_load_simple_font(fontdescp, xref, dict);
  1122.         }
  1123.         if (error)
  1124.                 return fz_rethrow(error, "cannot load font (%d %d R)", fz_to_num(dict), fz_to_gen(dict));
  1125.  
  1126.         /* Save the widths to stretch non-CJK substitute fonts */
  1127.         if ((*fontdescp)->font->ft_substitute && !(*fontdescp)->to_ttf_cmap)
  1128.                 pdf_make_width_table(*fontdescp);
  1129.  
  1130.         pdf_store_item(xref->store, pdf_keep_font, pdf_drop_font, dict, *fontdescp);
  1131.  
  1132.         return fz_okay;
  1133. }
  1134.  
  1135. void
  1136. pdf_debug_font(pdf_font_desc *fontdesc)
  1137. {
  1138.         int i;
  1139.  
  1140.         printf("fontdesc {\n");
  1141.  
  1142.         if (fontdesc->font->ft_face)
  1143.                 printf("\tfreetype font\n");
  1144.         if (fontdesc->font->t3procs)
  1145.                 printf("\ttype3 font\n");
  1146.  
  1147.         printf("\twmode %d\n", fontdesc->wmode);
  1148.         printf("\tDW %d\n", fontdesc->dhmtx.w);
  1149.  
  1150.         printf("\tW {\n");
  1151.         for (i = 0; i < fontdesc->hmtx_len; i++)
  1152.                 printf("\t\t<%04x> <%04x> %d\n",
  1153.                         fontdesc->hmtx[i].lo, fontdesc->hmtx[i].hi, fontdesc->hmtx[i].w);
  1154.         printf("\t}\n");
  1155.  
  1156.         if (fontdesc->wmode)
  1157.         {
  1158.                 printf("\tDW2 [%d %d]\n", fontdesc->dvmtx.y, fontdesc->dvmtx.w);
  1159.                 printf("\tW2 {\n");
  1160.                 for (i = 0; i < fontdesc->vmtx_len; i++)
  1161.                         printf("\t\t<%04x> <%04x> %d %d %d\n", fontdesc->vmtx[i].lo, fontdesc->vmtx[i].hi,
  1162.                                 fontdesc->vmtx[i].x, fontdesc->vmtx[i].y, fontdesc->vmtx[i].w);
  1163.                 printf("\t}\n");
  1164.         }
  1165. }
  1166.