#include "fitz.h" #include "mupdf.h" #include #include FT_FREETYPE_H #include FT_XFREE86_H static fz_error pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_xref *xref, fz_obj *dict, char *collection, char *basefont); static char *base_font_names[14][7] = { { "Courier", "CourierNew", "CourierNewPSMT", NULL }, { "Courier-Bold", "CourierNew,Bold", "Courier,Bold", "CourierNewPS-BoldMT", "CourierNew-Bold", NULL }, { "Courier-Oblique", "CourierNew,Italic", "Courier,Italic", "CourierNewPS-ItalicMT", "CourierNew-Italic", NULL }, { "Courier-BoldOblique", "CourierNew,BoldItalic", "Courier,BoldItalic", "CourierNewPS-BoldItalicMT", "CourierNew-BoldItalic", NULL }, { "Helvetica", "ArialMT", "Arial", NULL }, { "Helvetica-Bold", "Arial-BoldMT", "Arial,Bold", "Arial-Bold", "Helvetica,Bold", NULL }, { "Helvetica-Oblique", "Arial-ItalicMT", "Arial,Italic", "Arial-Italic", "Helvetica,Italic", "Helvetica-Italic", NULL }, { "Helvetica-BoldOblique", "Arial-BoldItalicMT", "Arial,BoldItalic", "Arial-BoldItalic", "Helvetica,BoldItalic", "Helvetica-BoldItalic", NULL }, { "Times-Roman", "TimesNewRomanPSMT", "TimesNewRoman", "TimesNewRomanPS", NULL }, { "Times-Bold", "TimesNewRomanPS-BoldMT", "TimesNewRoman,Bold", "TimesNewRomanPS-Bold", "TimesNewRoman-Bold", NULL }, { "Times-Italic", "TimesNewRomanPS-ItalicMT", "TimesNewRoman,Italic", "TimesNewRomanPS-Italic", "TimesNewRoman-Italic", NULL }, { "Times-BoldItalic", "TimesNewRomanPS-BoldItalicMT", "TimesNewRoman,BoldItalic", "TimesNewRomanPS-BoldItalic", "TimesNewRoman-BoldItalic", NULL }, { "Symbol", NULL }, { "ZapfDingbats", NULL } }; static int is_dynalab(char *name) { if (strstr(name, "HuaTian")) return 1; if (strstr(name, "MingLi")) return 1; if ((strstr(name, "DF") == name) || strstr(name, "+DF")) return 1; if ((strstr(name, "DLC") == name) || strstr(name, "+DLC")) return 1; return 0; } static int strcmp_ignore_space(char *a, char *b) { while (1) { while (*a == ' ') a++; while (*b == ' ') b++; if (*a != *b) return 1; if (*a == 0) return *a != *b; if (*b == 0) return *a != *b; a++; b++; } } static char *clean_font_name(char *fontname) { int i, k; for (i = 0; i < 14; i++) for (k = 0; base_font_names[i][k]; k++) if (!strcmp_ignore_space(base_font_names[i][k], fontname)) return base_font_names[i][0]; return fontname; } /* * FreeType and Rendering glue */ enum { UNKNOWN, TYPE1, TRUETYPE }; static int ft_kind(FT_Face face) { /// STUB /// //const char *kind = FT_Get_X11_Font_Format(face); const char *kind = "TrueType"; if (!strcmp(kind, "TrueType")) return TRUETYPE; if (!strcmp(kind, "Type 1")) return TYPE1; if (!strcmp(kind, "CFF")) return TYPE1; if (!strcmp(kind, "CID Type 1")) return TYPE1; return UNKNOWN; } static int ft_is_bold(FT_Face face) { return face->style_flags & FT_STYLE_FLAG_BOLD; } static int ft_is_italic(FT_Face face) { return face->style_flags & FT_STYLE_FLAG_ITALIC; } static int ft_char_index(FT_Face face, int cid) { int gid = FT_Get_Char_Index(face, cid); if (gid == 0) gid = FT_Get_Char_Index(face, 0xf000 + cid); /* some chinese fonts only ship the similarly looking 0x2026 */ if (gid == 0 && cid == 0x22ef) gid = FT_Get_Char_Index(face, 0x2026); return gid; } static int ft_cid_to_gid(pdf_font_desc *fontdesc, int cid) { if (fontdesc->to_ttf_cmap) { cid = pdf_lookup_cmap(fontdesc->to_ttf_cmap, cid); return ft_char_index(fontdesc->font->ft_face, cid); } if (fontdesc->cid_to_gid) return fontdesc->cid_to_gid[cid]; return cid; } int pdf_font_cid_to_gid(pdf_font_desc *fontdesc, int cid) { if (fontdesc->font->ft_face) return ft_cid_to_gid(fontdesc, cid); return cid; } static int ft_width(pdf_font_desc *fontdesc, int cid) { int gid = ft_cid_to_gid(fontdesc, cid); int fterr = FT_Load_Glyph(fontdesc->font->ft_face, gid, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM); if (fterr) { fz_warn("freetype load glyph (gid %d): %s", gid, ft_error_string(fterr)); return 0; } return ((FT_Face)fontdesc->font->ft_face)->glyph->advance.x; } static int lookup_mre_code(char *name) { int i; for (i = 0; i < 256; i++) if (pdf_mac_roman[i] && !strcmp(name, pdf_mac_roman[i])) return i; return -1; } /* * Load font files. */ static fz_error pdf_load_builtin_font(pdf_font_desc *fontdesc, char *fontname) { fz_error error; unsigned char *data; unsigned int len; data = pdf_find_builtin_font(fontname, &len); if (!data) return fz_throw("cannot find builtin font: '%s'", fontname); error = fz_new_font_from_memory(&fontdesc->font, data, len, 0); if (error) return fz_rethrow(error, "cannot load freetype font from memory"); if (!strcmp(fontname, "Symbol") || !strcmp(fontname, "ZapfDingbats")) fontdesc->flags |= PDF_FD_SYMBOLIC; return fz_okay; } static fz_error pdf_load_substitute_font(pdf_font_desc *fontdesc, int mono, int serif, int bold, int italic) { fz_error error; unsigned char *data; unsigned int len; data = pdf_find_substitute_font(mono, serif, bold, italic, &len); if (!data) return fz_throw("cannot find substitute font"); error = fz_new_font_from_memory(&fontdesc->font, data, len, 0); if (error) return fz_rethrow(error, "cannot load freetype font from memory"); fontdesc->font->ft_substitute = 1; fontdesc->font->ft_bold = bold && !ft_is_bold(fontdesc->font->ft_face); fontdesc->font->ft_italic = italic && !ft_is_italic(fontdesc->font->ft_face); return fz_okay; } static fz_error pdf_load_substitute_cjk_font(pdf_font_desc *fontdesc, int ros, int serif) { fz_error error; unsigned char *data; unsigned int len; data = pdf_find_substitute_cjk_font(ros, serif, &len); if (!data) return fz_throw("cannot find builtin CJK font"); error = fz_new_font_from_memory(&fontdesc->font, data, len, 0); if (error) return fz_rethrow(error, "cannot load builtin CJK font"); fontdesc->font->ft_substitute = 1; return fz_okay; } static fz_error pdf_load_system_font(pdf_font_desc *fontdesc, char *fontname, char *collection) { fz_error error; int bold = 0; int italic = 0; int serif = 0; int mono = 0; if (strstr(fontname, "Bold")) bold = 1; if (strstr(fontname, "Italic")) italic = 1; if (strstr(fontname, "Oblique")) italic = 1; if (fontdesc->flags & PDF_FD_FIXED_PITCH) mono = 1; if (fontdesc->flags & PDF_FD_SERIF) serif = 1; if (fontdesc->flags & PDF_FD_ITALIC) italic = 1; if (fontdesc->flags & PDF_FD_FORCE_BOLD) bold = 1; if (collection) { if (!strcmp(collection, "Adobe-CNS1")) return pdf_load_substitute_cjk_font(fontdesc, PDF_ROS_CNS, serif); else if (!strcmp(collection, "Adobe-GB1")) return pdf_load_substitute_cjk_font(fontdesc, PDF_ROS_GB, serif); else if (!strcmp(collection, "Adobe-Japan1")) return pdf_load_substitute_cjk_font(fontdesc, PDF_ROS_JAPAN, serif); else if (!strcmp(collection, "Adobe-Korea1")) return pdf_load_substitute_cjk_font(fontdesc, PDF_ROS_KOREA, serif); return fz_throw("unknown cid collection: %s", collection); } error = pdf_load_substitute_font(fontdesc, mono, serif, bold, italic); if (error) return fz_rethrow(error, "cannot load substitute font"); return fz_okay; } static fz_error pdf_load_embedded_font(pdf_font_desc *fontdesc, pdf_xref *xref, fz_obj *stmref) { fz_error error; fz_buffer *buf; error = pdf_load_stream(&buf, xref, fz_to_num(stmref), fz_to_gen(stmref)); if (error) return fz_rethrow(error, "cannot load font stream (%d %d R)", fz_to_num(stmref), fz_to_gen(stmref)); error = fz_new_font_from_memory(&fontdesc->font, buf->data, buf->len, 0); if (error) { fz_drop_buffer(buf); return fz_rethrow(error, "cannot load embedded font (%d %d R)", fz_to_num(stmref), fz_to_gen(stmref)); } /* save the buffer so we can free it later */ fontdesc->font->ft_data = buf->data; fontdesc->font->ft_size = buf->len; fz_free(buf); /* only free the fz_buffer struct, not the contained data */ fontdesc->is_embedded = 1; return fz_okay; } /* * Create and destroy */ pdf_font_desc * pdf_keep_font(pdf_font_desc *fontdesc) { fontdesc->refs ++; return fontdesc; } void pdf_drop_font(pdf_font_desc *fontdesc) { if (fontdesc && --fontdesc->refs == 0) { if (fontdesc->font) fz_drop_font(fontdesc->font); if (fontdesc->encoding) pdf_drop_cmap(fontdesc->encoding); if (fontdesc->to_ttf_cmap) pdf_drop_cmap(fontdesc->to_ttf_cmap); if (fontdesc->to_unicode) pdf_drop_cmap(fontdesc->to_unicode); fz_free(fontdesc->cid_to_gid); fz_free(fontdesc->cid_to_ucs); fz_free(fontdesc->hmtx); fz_free(fontdesc->vmtx); fz_free(fontdesc); } } pdf_font_desc * pdf_new_font_desc(void) { pdf_font_desc *fontdesc; fontdesc = fz_malloc(sizeof(pdf_font_desc)); fontdesc->refs = 1; fontdesc->font = NULL; fontdesc->flags = 0; fontdesc->italic_angle = 0; fontdesc->ascent = 0; fontdesc->descent = 0; fontdesc->cap_height = 0; fontdesc->x_height = 0; fontdesc->missing_width = 0; fontdesc->encoding = NULL; fontdesc->to_ttf_cmap = NULL; fontdesc->cid_to_gid_len = 0; fontdesc->cid_to_gid = NULL; fontdesc->to_unicode = NULL; fontdesc->cid_to_ucs_len = 0; fontdesc->cid_to_ucs = NULL; fontdesc->wmode = 0; fontdesc->hmtx_cap = 0; fontdesc->vmtx_cap = 0; fontdesc->hmtx_len = 0; fontdesc->vmtx_len = 0; fontdesc->hmtx = NULL; fontdesc->vmtx = NULL; fontdesc->dhmtx.lo = 0x0000; fontdesc->dhmtx.hi = 0xFFFF; fontdesc->dhmtx.w = 1000; fontdesc->dvmtx.lo = 0x0000; fontdesc->dvmtx.hi = 0xFFFF; fontdesc->dvmtx.x = 0; fontdesc->dvmtx.y = 880; fontdesc->dvmtx.w = -1000; fontdesc->is_embedded = 0; return fontdesc; } /* * Simple fonts (Type1 and TrueType) */ static fz_error pdf_load_simple_font(pdf_font_desc **fontdescp, pdf_xref *xref, fz_obj *dict) { fz_error error; fz_obj *descriptor; fz_obj *encoding; fz_obj *widths; unsigned short *etable = NULL; pdf_font_desc *fontdesc; FT_Face face; FT_CharMap cmap; int symbolic; int kind; char *basefont; char *fontname; char *estrings[256]; char ebuffer[256][32]; int i, k, n; int fterr; basefont = fz_to_name(fz_dict_gets(dict, "BaseFont")); fontname = clean_font_name(basefont); /* Load font file */ fontdesc = pdf_new_font_desc(); descriptor = fz_dict_gets(dict, "FontDescriptor"); if (descriptor) error = pdf_load_font_descriptor(fontdesc, xref, descriptor, NULL, basefont); else error = pdf_load_builtin_font(fontdesc, fontname); if (error) goto cleanup; /* Some chinese documents mistakenly consider WinAnsiEncoding to be codepage 936 */ if (!*fontdesc->font->name && !fz_dict_gets(dict, "ToUnicode") && !strcmp(fz_to_name(fz_dict_gets(dict, "Encoding")), "WinAnsiEncoding") && fz_to_int(fz_dict_gets(descriptor, "Flags")) == 4) { /* note: without the comma, pdf_load_font_descriptor would prefer /FontName over /BaseFont */ char *cp936fonts[] = { "\xCB\xCE\xCC\xE5", "SimSun,Regular", "\xBA\xDA\xCC\xE5", "SimHei,Regular", "\xBF\xAC\xCC\xE5_GB2312", "SimKai,Regular", "\xB7\xC2\xCB\xCE_GB2312", "SimFang,Regular", "\xC1\xA5\xCA\xE9", "SimLi,Regular", NULL }; for (i = 0; cp936fonts[i]; i += 2) if (!strcmp(basefont, cp936fonts[i])) break; if (cp936fonts[i]) { fz_warn("workaround for S22PDF lying about chinese font encodings"); pdf_drop_font(fontdesc); fontdesc = pdf_new_font_desc(); error = pdf_load_font_descriptor(fontdesc, xref, descriptor, "Adobe-GB1", cp936fonts[i+1]); error |= pdf_load_system_cmap(&fontdesc->encoding, "GBK-EUC-H"); error |= pdf_load_system_cmap(&fontdesc->to_unicode, "Adobe-GB1-UCS2"); error |= pdf_load_system_cmap(&fontdesc->to_ttf_cmap, "Adobe-GB1-UCS2"); if (error) return fz_rethrow(error, "cannot load font"); face = fontdesc->font->ft_face; kind = ft_kind(face); goto skip_encoding; } } face = fontdesc->font->ft_face; kind = ft_kind(face); /* Encoding */ symbolic = fontdesc->flags & 4; if (face->num_charmaps > 0) cmap = face->charmaps[0]; else cmap = NULL; for (i = 0; i < face->num_charmaps; i++) { FT_CharMap test = face->charmaps[i]; if (kind == TYPE1) { if (test->platform_id == 7) cmap = test; } if (kind == TRUETYPE) { if (test->platform_id == 1 && test->encoding_id == 0) cmap = test; if (test->platform_id == 3 && test->encoding_id == 1) cmap = test; } } if (cmap) { fterr = FT_Set_Charmap(face, cmap); if (fterr) fz_warn("freetype could not set cmap: %s", ft_error_string(fterr)); } else fz_warn("freetype could not find any cmaps"); etable = fz_calloc(256, sizeof(unsigned short)); for (i = 0; i < 256; i++) { estrings[i] = NULL; etable[i] = 0; } encoding = fz_dict_gets(dict, "Encoding"); if (encoding) { if (fz_is_name(encoding)) pdf_load_encoding(estrings, fz_to_name(encoding)); if (fz_is_dict(encoding)) { fz_obj *base, *diff, *item; base = fz_dict_gets(encoding, "BaseEncoding"); if (fz_is_name(base)) pdf_load_encoding(estrings, fz_to_name(base)); else if (!fontdesc->is_embedded && !symbolic) pdf_load_encoding(estrings, "StandardEncoding"); diff = fz_dict_gets(encoding, "Differences"); if (fz_is_array(diff)) { n = fz_array_len(diff); k = 0; for (i = 0; i < n; i++) { item = fz_array_get(diff, i); if (fz_is_int(item)) k = fz_to_int(item); if (fz_is_name(item)) estrings[k++] = fz_to_name(item); if (k < 0) k = 0; if (k > 255) k = 255; } } } } /* start with the builtin encoding */ for (i = 0; i < 256; i++) etable[i] = ft_char_index(face, i); /* encode by glyph name where we can */ if (kind == TYPE1) { for (i = 0; i < 256; i++) { if (estrings[i]) { etable[i] = FT_Get_Name_Index(face, estrings[i]); if (etable[i] == 0) { int aglcode = pdf_lookup_agl(estrings[i]); const char **dupnames = pdf_lookup_agl_duplicates(aglcode); while (*dupnames) { etable[i] = FT_Get_Name_Index(face, (char*)*dupnames); if (etable[i]) break; dupnames++; } } } } } /* encode by glyph name where we can */ if (kind == TRUETYPE) { /* Unicode cmap */ if (!symbolic && face->charmap && face->charmap->platform_id == 3) { for (i = 0; i < 256; i++) { if (estrings[i]) { int aglcode = pdf_lookup_agl(estrings[i]); if (!aglcode) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ft_char_index(face, aglcode); } } } /* MacRoman cmap */ else if (!symbolic && face->charmap && face->charmap->platform_id == 1) { for (i = 0; i < 256; i++) { if (estrings[i]) { k = lookup_mre_code(estrings[i]); if (k <= 0) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ft_char_index(face, k); } } } /* Symbolic cmap */ else { for (i = 0; i < 256; i++) { if (estrings[i]) { etable[i] = FT_Get_Name_Index(face, estrings[i]); if (etable[i] == 0) etable[i] = ft_char_index(face, i); } } } } /* try to reverse the glyph names from the builtin encoding */ for (i = 0; i < 256; i++) { if (etable[i] && !estrings[i]) { if (FT_HAS_GLYPH_NAMES(face)) { fterr = FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32); if (fterr) fz_warn("freetype get glyph name (gid %d): %s", etable[i], ft_error_string(fterr)); if (ebuffer[i][0]) estrings[i] = ebuffer[i]; } else { estrings[i] = (char*) pdf_win_ansi[i]; /* discard const */ } } } fontdesc->encoding = pdf_new_identity_cmap(0, 1); fontdesc->cid_to_gid_len = 256; fontdesc->cid_to_gid = etable; error = pdf_load_to_unicode(fontdesc, xref, estrings, NULL, fz_dict_gets(dict, "ToUnicode")); if (error) fz_catch(error, "cannot load to_unicode"); skip_encoding: /* Widths */ pdf_set_default_hmtx(fontdesc, fontdesc->missing_width); widths = fz_dict_gets(dict, "Widths"); if (widths) { int first, last; first = fz_to_int(fz_dict_gets(dict, "FirstChar")); last = fz_to_int(fz_dict_gets(dict, "LastChar")); if (first < 0 || last > 255 || first > last) first = last = 0; for (i = 0; i < last - first + 1; i++) { int wid = fz_to_int(fz_array_get(widths, i)); pdf_add_hmtx(fontdesc, i + first, i + first, wid); } } else { fterr = FT_Set_Char_Size(face, 1000, 1000, 72, 72); if (fterr) fz_warn("freetype set character size: %s", ft_error_string(fterr)); for (i = 0; i < 256; i++) { pdf_add_hmtx(fontdesc, i, i, ft_width(fontdesc, i)); } } pdf_end_hmtx(fontdesc); *fontdescp = fontdesc; return fz_okay; cleanup: if (etable != fontdesc->cid_to_gid) fz_free(etable); pdf_drop_font(fontdesc); return fz_rethrow(error, "cannot load simple font (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); } /* * CID Fonts */ static fz_error load_cid_font(pdf_font_desc **fontdescp, pdf_xref *xref, fz_obj *dict, fz_obj *encoding, fz_obj *to_unicode) { fz_error error; fz_obj *widths; fz_obj *descriptor; pdf_font_desc *fontdesc; FT_Face face; int kind; char collection[256]; char *basefont; int i, k, fterr; fz_obj *obj; int dw; /* Get font name and CID collection */ basefont = fz_to_name(fz_dict_gets(dict, "BaseFont")); { fz_obj *cidinfo; char tmpstr[64]; int tmplen; cidinfo = fz_dict_gets(dict, "CIDSystemInfo"); if (!cidinfo) return fz_throw("cid font is missing info"); obj = fz_dict_gets(cidinfo, "Registry"); tmplen = MIN(sizeof tmpstr - 1, fz_to_str_len(obj)); memcpy(tmpstr, fz_to_str_buf(obj), tmplen); tmpstr[tmplen] = '\0'; fz_strlcpy(collection, tmpstr, sizeof collection); fz_strlcat(collection, "-", sizeof collection); obj = fz_dict_gets(cidinfo, "Ordering"); tmplen = MIN(sizeof tmpstr - 1, fz_to_str_len(obj)); memcpy(tmpstr, fz_to_str_buf(obj), tmplen); tmpstr[tmplen] = '\0'; fz_strlcat(collection, tmpstr, sizeof collection); } /* Load font file */ fontdesc = pdf_new_font_desc(); descriptor = fz_dict_gets(dict, "FontDescriptor"); if (descriptor) error = pdf_load_font_descriptor(fontdesc, xref, descriptor, collection, basefont); else error = fz_throw("syntaxerror: missing font descriptor"); if (error) goto cleanup; face = fontdesc->font->ft_face; kind = ft_kind(face); /* Encoding */ error = fz_okay; if (fz_is_name(encoding)) { if (!strcmp(fz_to_name(encoding), "Identity-H")) fontdesc->encoding = pdf_new_identity_cmap(0, 2); else if (!strcmp(fz_to_name(encoding), "Identity-V")) fontdesc->encoding = pdf_new_identity_cmap(1, 2); else error = pdf_load_system_cmap(&fontdesc->encoding, fz_to_name(encoding)); } else if (fz_is_indirect(encoding)) { error = pdf_load_embedded_cmap(&fontdesc->encoding, xref, encoding); } else { error = fz_throw("syntaxerror: font missing encoding"); } if (error) goto cleanup; pdf_set_font_wmode(fontdesc, pdf_get_wmode(fontdesc->encoding)); if (kind == TRUETYPE) { fz_obj *cidtogidmap; cidtogidmap = fz_dict_gets(dict, "CIDToGIDMap"); if (fz_is_indirect(cidtogidmap)) { fz_buffer *buf; error = pdf_load_stream(&buf, xref, fz_to_num(cidtogidmap), fz_to_gen(cidtogidmap)); if (error) goto cleanup; fontdesc->cid_to_gid_len = (buf->len) / 2; fontdesc->cid_to_gid = fz_calloc(fontdesc->cid_to_gid_len, sizeof(unsigned short)); for (i = 0; i < fontdesc->cid_to_gid_len; i++) fontdesc->cid_to_gid[i] = (buf->data[i * 2] << 8) + buf->data[i * 2 + 1]; fz_drop_buffer(buf); } /* if truetype font is external, cidtogidmap should not be identity */ /* so we map from cid to unicode and then map that through the (3 1) */ /* unicode cmap to get a glyph id */ else if (fontdesc->font->ft_substitute) { fterr = FT_Select_Charmap(face, ft_encoding_unicode); if (fterr) { error = fz_throw("fonterror: no unicode cmap when emulating CID font: %s", ft_error_string(fterr)); goto cleanup; } if (!strcmp(collection, "Adobe-CNS1")) error = pdf_load_system_cmap(&fontdesc->to_ttf_cmap, "Adobe-CNS1-UCS2"); else if (!strcmp(collection, "Adobe-GB1")) error = pdf_load_system_cmap(&fontdesc->to_ttf_cmap, "Adobe-GB1-UCS2"); else if (!strcmp(collection, "Adobe-Japan1")) error = pdf_load_system_cmap(&fontdesc->to_ttf_cmap, "Adobe-Japan1-UCS2"); else if (!strcmp(collection, "Adobe-Japan2")) error = pdf_load_system_cmap(&fontdesc->to_ttf_cmap, "Adobe-Japan2-UCS2"); else if (!strcmp(collection, "Adobe-Korea1")) error = pdf_load_system_cmap(&fontdesc->to_ttf_cmap, "Adobe-Korea1-UCS2"); else error = fz_okay; if (error) { error = fz_rethrow(error, "cannot load system cmap %s", collection); goto cleanup; } } } error = pdf_load_to_unicode(fontdesc, xref, NULL, collection, to_unicode); if (error) fz_catch(error, "cannot load to_unicode"); /* Horizontal */ dw = 1000; obj = fz_dict_gets(dict, "DW"); if (obj) dw = fz_to_int(obj); pdf_set_default_hmtx(fontdesc, dw); widths = fz_dict_gets(dict, "W"); if (widths) { int c0, c1, w; for (i = 0; i < fz_array_len(widths); ) { c0 = fz_to_int(fz_array_get(widths, i)); obj = fz_array_get(widths, i + 1); if (fz_is_array(obj)) { for (k = 0; k < fz_array_len(obj); k++) { w = fz_to_int(fz_array_get(obj, k)); pdf_add_hmtx(fontdesc, c0 + k, c0 + k, w); } i += 2; } else { c1 = fz_to_int(obj); w = fz_to_int(fz_array_get(widths, i + 2)); pdf_add_hmtx(fontdesc, c0, c1, w); i += 3; } } } pdf_end_hmtx(fontdesc); /* Vertical */ if (pdf_get_wmode(fontdesc->encoding) == 1) { int dw2y = 880; int dw2w = -1000; obj = fz_dict_gets(dict, "DW2"); if (obj) { dw2y = fz_to_int(fz_array_get(obj, 0)); dw2w = fz_to_int(fz_array_get(obj, 1)); } pdf_set_default_vmtx(fontdesc, dw2y, dw2w); widths = fz_dict_gets(dict, "W2"); if (widths) { int c0, c1, w, x, y; for (i = 0; i < fz_array_len(widths); ) { c0 = fz_to_int(fz_array_get(widths, i)); obj = fz_array_get(widths, i + 1); if (fz_is_array(obj)) { for (k = 0; k * 3 < fz_array_len(obj); k ++) { w = fz_to_int(fz_array_get(obj, k * 3 + 0)); x = fz_to_int(fz_array_get(obj, k * 3 + 1)); y = fz_to_int(fz_array_get(obj, k * 3 + 2)); pdf_add_vmtx(fontdesc, c0 + k, c0 + k, x, y, w); } i += 2; } else { c1 = fz_to_int(obj); w = fz_to_int(fz_array_get(widths, i + 2)); x = fz_to_int(fz_array_get(widths, i + 3)); y = fz_to_int(fz_array_get(widths, i + 4)); pdf_add_vmtx(fontdesc, c0, c1, x, y, w); i += 5; } } } pdf_end_vmtx(fontdesc); } *fontdescp = fontdesc; return fz_okay; cleanup: pdf_drop_font(fontdesc); return fz_rethrow(error, "cannot load cid font (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); } static fz_error pdf_load_type0_font(pdf_font_desc **fontdescp, pdf_xref *xref, fz_obj *dict) { fz_error error; fz_obj *dfonts; fz_obj *dfont; fz_obj *subtype; fz_obj *encoding; fz_obj *to_unicode; dfonts = fz_dict_gets(dict, "DescendantFonts"); if (!dfonts) return fz_throw("cid font is missing descendant fonts"); dfont = fz_array_get(dfonts, 0); subtype = fz_dict_gets(dfont, "Subtype"); encoding = fz_dict_gets(dict, "Encoding"); to_unicode = fz_dict_gets(dict, "ToUnicode"); if (fz_is_name(subtype) && !strcmp(fz_to_name(subtype), "CIDFontType0")) error = load_cid_font(fontdescp, xref, dfont, encoding, to_unicode); else if (fz_is_name(subtype) && !strcmp(fz_to_name(subtype), "CIDFontType2")) error = load_cid_font(fontdescp, xref, dfont, encoding, to_unicode); else error = fz_throw("syntaxerror: unknown cid font type"); if (error) return fz_rethrow(error, "cannot load descendant font (%d %d R)", fz_to_num(dfont), fz_to_gen(dfont)); return fz_okay; } /* * FontDescriptor */ static fz_error pdf_load_font_descriptor(pdf_font_desc *fontdesc, pdf_xref *xref, fz_obj *dict, char *collection, char *basefont) { fz_error error; fz_obj *obj1, *obj2, *obj3, *obj; char *fontname; char *origname; FT_Face face; if (!strchr(basefont, ',') || strchr(basefont, '+')) origname = fz_to_name(fz_dict_gets(dict, "FontName")); else origname = basefont; fontname = clean_font_name(origname); fontdesc->flags = fz_to_int(fz_dict_gets(dict, "Flags")); fontdesc->italic_angle = fz_to_real(fz_dict_gets(dict, "ItalicAngle")); fontdesc->ascent = fz_to_real(fz_dict_gets(dict, "Ascent")); fontdesc->descent = fz_to_real(fz_dict_gets(dict, "Descent")); fontdesc->cap_height = fz_to_real(fz_dict_gets(dict, "CapHeight")); fontdesc->x_height = fz_to_real(fz_dict_gets(dict, "XHeight")); fontdesc->missing_width = fz_to_real(fz_dict_gets(dict, "MissingWidth")); obj1 = fz_dict_gets(dict, "FontFile"); obj2 = fz_dict_gets(dict, "FontFile2"); obj3 = fz_dict_gets(dict, "FontFile3"); obj = obj1 ? obj1 : obj2 ? obj2 : obj3; if (fz_is_indirect(obj)) { error = pdf_load_embedded_font(fontdesc, xref, obj); if (error) { fz_catch(error, "ignored error when loading embedded font, attempting to load system font"); if (origname != fontname) error = pdf_load_builtin_font(fontdesc, fontname); else error = pdf_load_system_font(fontdesc, fontname, collection); if (error) return fz_rethrow(error, "cannot load font descriptor (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); } } else { if (origname != fontname) error = pdf_load_builtin_font(fontdesc, fontname); else error = pdf_load_system_font(fontdesc, fontname, collection); if (error) return fz_rethrow(error, "cannot load font descriptor (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); } fz_strlcpy(fontdesc->font->name, fontname, sizeof fontdesc->font->name); /* Check for DynaLab fonts that must use hinting */ face = fontdesc->font->ft_face; if (ft_kind(face) == TRUETYPE) { if (FT_IS_TRICKY(face) || is_dynalab(fontdesc->font->name)) fontdesc->font->ft_hint = 1; } return fz_okay; } static void pdf_make_width_table(pdf_font_desc *fontdesc) { fz_font *font = fontdesc->font; int i, k, cid, gid; font->width_count = 0; for (i = 0; i < fontdesc->hmtx_len; i++) { for (k = fontdesc->hmtx[i].lo; k <= fontdesc->hmtx[i].hi; k++) { cid = pdf_lookup_cmap(fontdesc->encoding, k); gid = pdf_font_cid_to_gid(fontdesc, cid); if (gid > font->width_count) font->width_count = gid; } } font->width_count ++; font->width_table = fz_calloc(font->width_count, sizeof(int)); memset(font->width_table, 0, sizeof(int) * font->width_count); for (i = 0; i < fontdesc->hmtx_len; i++) { for (k = fontdesc->hmtx[i].lo; k <= fontdesc->hmtx[i].hi; k++) { cid = pdf_lookup_cmap(fontdesc->encoding, k); gid = pdf_font_cid_to_gid(fontdesc, cid); if (gid >= 0 && gid < font->width_count) font->width_table[gid] = fontdesc->hmtx[i].w; } } } fz_error pdf_load_font(pdf_font_desc **fontdescp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict) { fz_error error; char *subtype; fz_obj *dfonts; fz_obj *charprocs; if ((*fontdescp = pdf_find_item(xref->store, pdf_drop_font, dict))) { pdf_keep_font(*fontdescp); return fz_okay; } subtype = fz_to_name(fz_dict_gets(dict, "Subtype")); dfonts = fz_dict_gets(dict, "DescendantFonts"); charprocs = fz_dict_gets(dict, "CharProcs"); if (subtype && !strcmp(subtype, "Type0")) error = pdf_load_type0_font(fontdescp, xref, dict); else if (subtype && !strcmp(subtype, "Type1")) error = pdf_load_simple_font(fontdescp, xref, dict); else if (subtype && !strcmp(subtype, "MMType1")) error = pdf_load_simple_font(fontdescp, xref, dict); else if (subtype && !strcmp(subtype, "TrueType")) error = pdf_load_simple_font(fontdescp, xref, dict); else if (subtype && !strcmp(subtype, "Type3")) error = pdf_load_type3_font(fontdescp, xref, rdb, dict); else if (charprocs) { fz_warn("unknown font format, guessing type3."); error = pdf_load_type3_font(fontdescp, xref, rdb, dict); } else if (dfonts) { fz_warn("unknown font format, guessing type0."); error = pdf_load_type0_font(fontdescp, xref, dict); } else { fz_warn("unknown font format, guessing type1 or truetype."); error = pdf_load_simple_font(fontdescp, xref, dict); } if (error) return fz_rethrow(error, "cannot load font (%d %d R)", fz_to_num(dict), fz_to_gen(dict)); /* Save the widths to stretch non-CJK substitute fonts */ if ((*fontdescp)->font->ft_substitute && !(*fontdescp)->to_ttf_cmap) pdf_make_width_table(*fontdescp); pdf_store_item(xref->store, pdf_keep_font, pdf_drop_font, dict, *fontdescp); return fz_okay; } void pdf_debug_font(pdf_font_desc *fontdesc) { int i; printf("fontdesc {\n"); if (fontdesc->font->ft_face) printf("\tfreetype font\n"); if (fontdesc->font->t3procs) printf("\ttype3 font\n"); printf("\twmode %d\n", fontdesc->wmode); printf("\tDW %d\n", fontdesc->dhmtx.w); printf("\tW {\n"); for (i = 0; i < fontdesc->hmtx_len; i++) printf("\t\t<%04x> <%04x> %d\n", fontdesc->hmtx[i].lo, fontdesc->hmtx[i].hi, fontdesc->hmtx[i].w); printf("\t}\n"); if (fontdesc->wmode) { printf("\tDW2 [%d %d]\n", fontdesc->dvmtx.y, fontdesc->dvmtx.w); printf("\tW2 {\n"); for (i = 0; i < fontdesc->vmtx_len; i++) printf("\t\t<%04x> <%04x> %d %d %d\n", fontdesc->vmtx[i].lo, fontdesc->vmtx[i].hi, fontdesc->vmtx[i].x, fontdesc->vmtx[i].y, fontdesc->vmtx[i].w); printf("\t}\n"); } }