static fz_error loadsimplefont(pdf_fontdesc **fontdescp, pdf_xref *xref, fz_obj *dict) { fz_error error; fz_obj *descriptor; fz_obj *encoding; fz_obj *widths; unsigned short *etable = nil; pdf_fontdesc *fontdesc; fz_bbox bbox; FT_Face face; FT_CharMap cmap; int kind; int symbolic; char *basefont; char *fontname; char *estrings[256]; char ebuffer[256][32]; int i, k, n; int fterr; basefont = fz_toname(fz_dictgets(dict, "BaseFont")); fontname = cleanfontname(basefont); /* Load font file */ fontdesc = pdf_newfontdesc(); pdf_logfont("load simple font (%d %d R) ptr=%p {\n", fz_tonum(dict), fz_togen(dict), fontdesc); pdf_logfont("basefont %s -> %s\n", basefont, fontname); descriptor = fz_dictgets(dict, "FontDescriptor"); if (descriptor) error = pdf_loadfontdescriptor(fontdesc, xref, descriptor, nil, basefont); else error = pdf_loadbuiltinfont(fontdesc, fontname); if (error) goto cleanup; face = fontdesc->font->ftface; kind = ftkind(face); pdf_logfont("ft name '%s' '%s'\n", face->family_name, face->style_name); bbox.x0 = (face->bbox.xMin * 1000) / face->units_per_EM; bbox.y0 = (face->bbox.yMin * 1000) / face->units_per_EM; bbox.x1 = (face->bbox.xMax * 1000) / face->units_per_EM; bbox.y1 = (face->bbox.yMax * 1000) / face->units_per_EM; pdf_logfont("ft bbox [%d %d %d %d]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1); if (bbox.x0 == bbox.x1) fz_setfontbbox(fontdesc->font, -1000, -1000, 2000, 2000); else fz_setfontbbox(fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* Encoding */ symbolic = fontdesc->flags & 4; if (face->num_charmaps > 0) cmap = face->charmaps[0]; else cmap = nil; 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_errorstring(fterr)); } else fz_warn("freetype could not find any cmaps"); etable = fz_malloc(sizeof(unsigned short) * 256); for (i = 0; i < 256; i++) { estrings[i] = nil; etable[i] = 0; } encoding = fz_dictgets(dict, "Encoding"); if (encoding) { if (fz_isname(encoding)) pdf_loadencoding(estrings, fz_toname(encoding)); if (fz_isdict(encoding)) { fz_obj *base, *diff, *item; base = fz_dictgets(encoding, "BaseEncoding"); if (fz_isname(base)) pdf_loadencoding(estrings, fz_toname(base)); else if (!fontdesc->isembedded && !symbolic) pdf_loadencoding(estrings, "StandardEncoding"); /* cf. http://bugs.ghostscript.com/show_bug.cgi?id=690615 and http://code.google.com/p/sumatrapdf/issues/detail?id=687 */ /* try to extract an encoding from the font or synthesize a likely one */ /* note: FT_Get_Name_Index fails for symbolic CFF fonts, so let them be encoded by index */ else if (!fontdesc->encoding && !ftloadt1encoding(face, estrings) && !(symbolic && !strcmp(FT_Get_X11_Font_Format(face), "CFF"))) pdf_loadencoding(estrings, "StandardEncoding"); diff = fz_dictgets(encoding, "Differences"); if (fz_isarray(diff)) { n = fz_arraylen(diff); k = 0; for (i = 0; i < n; i++) { item = fz_arrayget(diff, i); if (fz_isint(item)) k = fz_toint(item); if (fz_isname(item)) estrings[k++] = fz_toname(item); if (k < 0) k = 0; if (k > 255) k = 255; } } } } /* start with the builtin encoding */ for (i = 0; i < 256; i++) etable[i] = ftcharindex(face, i); /* encode by glyph name where we can */ if (kind == TYPE1) { pdf_logfont("encode type1/cff by strings\n"); 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_lookupagl(estrings[i]); char **aglnames = pdf_lookupaglnames(aglcode); while (*aglnames) { etable[i] = FT_Get_Name_Index(face, *aglnames); if (etable[i]) break; aglnames++; } } } } } /* encode by glyph name where we can */ if (kind == TRUETYPE) { /* Unicode cmap */ if (!symbolic && face->charmap && face->charmap->platform_id == 3) { pdf_logfont("encode truetype via unicode\n"); for (i = 0; i < 256; i++) { if (estrings[i]) { int aglcode = pdf_lookupagl(estrings[i]); if (!aglcode) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ftcharindex(face, aglcode); } } } /* MacRoman cmap */ else if (!symbolic && face->charmap && face->charmap->platform_id == 1) { pdf_logfont("encode truetype via macroman\n"); for (i = 0; i < 256; i++) { if (estrings[i]) { k = mrecode(estrings[i]); if (k <= 0) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ftcharindex(face, k); } } } /* Symbolic cmap */ else { pdf_logfont("encode truetype symbolic\n"); for (i = 0; i < 256; i++) { if (estrings[i]) { etable[i] = FT_Get_Name_Index(face, estrings[i]); if (etable[i] == 0) etable[i] = ftcharindex(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_errorstring(fterr)); if (ebuffer[i][0]) estrings[i] = ebuffer[i]; } else { estrings[i] = (char*) pdf_winansi[i]; /* discard const */ } } } /* Prevent encoding Differences from being overwritten by reloading them */ /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=115 */ if (fz_isdict(encoding)) { fz_obj *diff, *item; diff = fz_dictgets(encoding, "Differences"); if (fz_isarray(diff)) { n = fz_arraylen(diff); k = 0; for (i = 0; i < n; i++) { item = fz_arrayget(diff, i); if (fz_isint(item)) k = fz_toint(item); if (fz_isname(item)) estrings[k++] = fz_toname(item); if (k < 0) k = 0; if (k > 255) k = 255; } } } fontdesc->encoding = pdf_newidentitycmap(0, 1); fontdesc->ncidtogid = 256; fontdesc->cidtogid = etable; error = pdf_loadtounicode(fontdesc, xref, estrings, nil, fz_dictgets(dict, "ToUnicode")); if (error) goto cleanup; /* Widths */ pdf_setdefaulthmtx(fontdesc, fontdesc->missingwidth); widths = fz_dictgets(dict, "Widths"); if (widths) { int first, last; first = fz_toint(fz_dictgets(dict, "FirstChar")); last = fz_toint(fz_dictgets(dict, "LastChar")); if (first < 0 || last > 255 || first > last) first = last = 0; for (i = 0; i < last - first + 1; i++) { int wid = fz_toint(fz_arrayget(widths, i)); pdf_addhmtx(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_errorstring(fterr)); for (i = 0; i < 256; i++) { pdf_addhmtx(fontdesc, i, i, ftwidth(fontdesc, i)); } } pdf_endhmtx(fontdesc); pdf_logfont("}\n"); *fontdescp = fontdesc; return fz_okay; cleanup: if (etable != fontdesc->cidtogid) fz_free(etable); pdf_dropfont(fontdesc); return fz_rethrow(error, "cannot load simple font (%d %d R)", fz_tonum(dict), fz_togen(dict)); }
static fz_error loadcidfont(pdf_fontdesc **fontdescp, pdf_xref *xref, fz_obj *dict, fz_obj *encoding, fz_obj *tounicode) { fz_error error; fz_obj *widths; fz_obj *descriptor; pdf_fontdesc *fontdesc; FT_Face face; fz_bbox bbox; int kind; char collection[256]; char *basefont; int i, k, fterr; fz_obj *obj; int dw; /* Get font name and CID collection */ basefont = fz_toname(fz_dictgets(dict, "BaseFont")); { fz_obj *cidinfo; char tmpstr[64]; int tmplen; cidinfo = fz_dictgets(dict, "CIDSystemInfo"); if (!cidinfo) return fz_throw("cid font is missing info"); obj = fz_dictgets(cidinfo, "Registry"); tmplen = MIN(sizeof tmpstr - 1, fz_tostrlen(obj)); memcpy(tmpstr, fz_tostrbuf(obj), tmplen); tmpstr[tmplen] = '\0'; fz_strlcpy(collection, tmpstr, sizeof collection); fz_strlcat(collection, "-", sizeof collection); obj = fz_dictgets(cidinfo, "Ordering"); tmplen = MIN(sizeof tmpstr - 1, fz_tostrlen(obj)); memcpy(tmpstr, fz_tostrbuf(obj), tmplen); tmpstr[tmplen] = '\0'; fz_strlcat(collection, tmpstr, sizeof collection); } /* Load font file */ fontdesc = pdf_newfontdesc(); pdf_logfont("load cid font (%d %d R) ptr=%p {\n", fz_tonum(dict), fz_togen(dict), fontdesc); pdf_logfont("basefont %s\n", basefont); pdf_logfont("collection %s\n", collection); descriptor = fz_dictgets(dict, "FontDescriptor"); if (descriptor) error = pdf_loadfontdescriptor(fontdesc, xref, descriptor, collection, basefont); else error = fz_throw("syntaxerror: missing font descriptor"); if (error) goto cleanup; face = fontdesc->font->ftface; kind = ftkind(face); bbox.x0 = (face->bbox.xMin * 1000) / face->units_per_EM; bbox.y0 = (face->bbox.yMin * 1000) / face->units_per_EM; bbox.x1 = (face->bbox.xMax * 1000) / face->units_per_EM; bbox.y1 = (face->bbox.yMax * 1000) / face->units_per_EM; pdf_logfont("ft bbox [%d %d %d %d]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1); if (bbox.x0 == bbox.x1) fz_setfontbbox(fontdesc->font, -1000, -1000, 2000, 2000); else fz_setfontbbox(fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* Encoding */ error = fz_okay; if (fz_isname(encoding)) { pdf_logfont("encoding /%s\n", fz_toname(encoding)); if (!strcmp(fz_toname(encoding), "Identity-H")) fontdesc->encoding = pdf_newidentitycmap(0, 2); else if (!strcmp(fz_toname(encoding), "Identity-V")) fontdesc->encoding = pdf_newidentitycmap(1, 2); else error = pdf_loadsystemcmap(&fontdesc->encoding, fz_toname(encoding)); } else if (fz_isindirect(encoding)) { pdf_logfont("encoding %d %d R\n", fz_tonum(encoding), fz_togen(encoding)); error = pdf_loadembeddedcmap(&fontdesc->encoding, xref, encoding); } else { error = fz_throw("syntaxerror: font missing encoding"); } if (error) goto cleanup; pdf_setfontwmode(fontdesc, pdf_getwmode(fontdesc->encoding)); pdf_logfont("wmode %d\n", pdf_getwmode(fontdesc->encoding)); if (kind == TRUETYPE) { fz_obj *cidtogidmap; cidtogidmap = fz_dictgets(dict, "CIDToGIDMap"); if (fz_isindirect(cidtogidmap)) { fz_buffer *buf; pdf_logfont("cidtogidmap stream\n"); error = pdf_loadstream(&buf, xref, fz_tonum(cidtogidmap), fz_togen(cidtogidmap)); if (error) goto cleanup; fontdesc->ncidtogid = (buf->len) / 2; fontdesc->cidtogid = fz_malloc(fontdesc->ncidtogid * sizeof(unsigned short)); for (i = 0; i < fontdesc->ncidtogid; i++) fontdesc->cidtogid[i] = (buf->data[i * 2] << 8) + buf->data[i * 2 + 1]; fz_dropbuffer(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->ftsubstitute) { pdf_logfont("emulate ttf cidfont\n"); fterr = FT_Select_Charmap(face, ft_encoding_unicode); if (fterr) { error = fz_throw("fonterror: no unicode cmap when emulating CID font: %s", ft_errorstring(fterr)); goto cleanup; } if (!strcmp(collection, "Adobe-CNS1")) error = pdf_loadsystemcmap(&fontdesc->tottfcmap, "Adobe-CNS1-UCS2"); else if (!strcmp(collection, "Adobe-GB1")) error = pdf_loadsystemcmap(&fontdesc->tottfcmap, "Adobe-GB1-UCS2"); else if (!strcmp(collection, "Adobe-Japan1")) error = pdf_loadsystemcmap(&fontdesc->tottfcmap, "Adobe-Japan1-UCS2"); else if (!strcmp(collection, "Adobe-Japan2")) error = pdf_loadsystemcmap(&fontdesc->tottfcmap, "Adobe-Japan2-UCS2"); else if (!strcmp(collection, "Adobe-Korea1")) error = pdf_loadsystemcmap(&fontdesc->tottfcmap, "Adobe-Korea1-UCS2"); else error = fz_okay; if (error) { error = fz_rethrow(error, "cannot load system cmap %s", collection); goto cleanup; } } } error = pdf_loadtounicode(fontdesc, xref, nil, collection, tounicode); if (error) goto cleanup; /* Horizontal */ dw = 1000; obj = fz_dictgets(dict, "DW"); if (obj) dw = fz_toint(obj); pdf_setdefaulthmtx(fontdesc, dw); widths = fz_dictgets(dict, "W"); if (widths) { int c0, c1, w; for (i = 0; i < fz_arraylen(widths); ) { c0 = fz_toint(fz_arrayget(widths, i)); obj = fz_arrayget(widths, i + 1); if (fz_isarray(obj)) { for (k = 0; k < fz_arraylen(obj); k++) { w = fz_toint(fz_arrayget(obj, k)); pdf_addhmtx(fontdesc, c0 + k, c0 + k, w); } i += 2; } else { c1 = fz_toint(obj); w = fz_toint(fz_arrayget(widths, i + 2)); pdf_addhmtx(fontdesc, c0, c1, w); i += 3; } } } pdf_endhmtx(fontdesc); /* Vertical */ if (pdf_getwmode(fontdesc->encoding) == 1) { int dw2y = 880; int dw2w = -1000; obj = fz_dictgets(dict, "DW2"); if (obj) { dw2y = fz_toint(fz_arrayget(obj, 0)); dw2w = fz_toint(fz_arrayget(obj, 1)); } pdf_setdefaultvmtx(fontdesc, dw2y, dw2w); widths = fz_dictgets(dict, "W2"); if (widths) { int c0, c1, w, x, y; for (i = 0; i < fz_arraylen(widths); ) { c0 = fz_toint(fz_arrayget(widths, i)); obj = fz_arrayget(widths, i + 1); if (fz_isarray(obj)) { for (k = 0; k < fz_arraylen(obj); k += 3) { w = fz_toint(fz_arrayget(obj, k + 0)); x = fz_toint(fz_arrayget(obj, k + 1)); y = fz_toint(fz_arrayget(obj, k + 2)); pdf_addvmtx(fontdesc, c0 + k, c0 + k, x, y, w); } i += 2; } else { c1 = fz_toint(obj); w = fz_toint(fz_arrayget(widths, i + 2)); x = fz_toint(fz_arrayget(widths, i + 3)); y = fz_toint(fz_arrayget(widths, i + 4)); pdf_addvmtx(fontdesc, c0, c1, x, y, w); i += 5; } } } pdf_endvmtx(fontdesc); } pdf_logfont("}\n"); *fontdescp = fontdesc; return fz_okay; cleanup: pdf_dropfont(fontdesc); return fz_rethrow(error, "cannot load cid font (%d %d R)", fz_tonum(dict), fz_togen(dict)); }
static fz_error loadsimplefont(pdf_fontdesc **fontdescp, pdf_xref *xref, fz_obj *dict) { fz_error error; fz_obj *descriptor = nil; fz_obj *encoding = nil; fz_obj *widths = nil; unsigned short *etable = nil; pdf_fontdesc *fontdesc; fz_irect bbox; FT_Face face; FT_CharMap cmap; int kind; int symbolic; char *basefont; char *fontname; char *estrings[256]; char ebuffer[256][32]; int i, k, n; int fterr; basefont = fz_toname(fz_dictgets(dict, "BaseFont")); fontname = cleanfontname(basefont); /* * Load font file */ fontdesc = pdf_newfontdesc(); if (!fontdesc) return fz_rethrow(-1, "out of memory"); pdf_logfont("load simple font (%d %d R) ptr=%p {\n", fz_tonum(dict), fz_togen(dict), fontdesc); pdf_logfont("basefont0 %s\n", basefont); pdf_logfont("basefont1 %s\n", fontname); descriptor = fz_dictgets(dict, "FontDescriptor"); if (descriptor && basefont == fontname) error = pdf_loadfontdescriptor(fontdesc, xref, descriptor, nil); else error = pdf_loadbuiltinfont(fontdesc, fontname); if (error) goto cleanup; face = fontdesc->font->ftface; kind = ftkind(face); pdf_logfont("ft name '%s' '%s'\n", face->family_name, face->style_name); bbox.x0 = (face->bbox.xMin * 1000) / face->units_per_EM; bbox.y0 = (face->bbox.yMin * 1000) / face->units_per_EM; bbox.x1 = (face->bbox.xMax * 1000) / face->units_per_EM; bbox.y1 = (face->bbox.yMax * 1000) / face->units_per_EM; pdf_logfont("ft bbox [%d %d %d %d]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1); if (bbox.x0 == bbox.x1) fz_setfontbbox(fontdesc->font, -1000, -1000, 2000, 2000); else fz_setfontbbox(fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* * Encoding */ symbolic = fontdesc->flags & 4; if (face->num_charmaps > 0) cmap = face->charmaps[0]; else cmap = nil; 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_errorstring(fterr)); } else fz_warn("freetype could not find any cmaps"); etable = fz_malloc(sizeof(unsigned short) * 256); if (!etable) goto cleanup; for (i = 0; i < 256; i++) { estrings[i] = nil; etable[i] = 0; } encoding = fz_dictgets(dict, "Encoding"); if (encoding && !(kind == TRUETYPE && symbolic)) { if (fz_isname(encoding)) pdf_loadencoding(estrings, fz_toname(encoding)); if (fz_isdict(encoding)) { fz_obj *base, *diff, *item; base = fz_dictgets(encoding, "BaseEncoding"); if (fz_isname(base)) pdf_loadencoding(estrings, fz_toname(base)); else if (!fontdesc->isembedded) pdf_loadencoding(estrings, "StandardEncoding"); diff = fz_dictgets(encoding, "Differences"); if (fz_isarray(diff)) { n = fz_arraylen(diff); k = 0; for (i = 0; i < n; i++) { item = fz_arrayget(diff, i); if (fz_isint(item)) k = fz_toint(item); if (fz_isname(item)) estrings[k++] = fz_toname(item); if (k < 0) k = 0; if (k > 255) k = 255; } } } if (kind == TYPE1) { pdf_logfont("encode type1/cff by strings\n"); for (i = 0; i < 256; i++) if (estrings[i]) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ftcharindex(face, i); } if (kind == TRUETYPE) { /* Unicode cmap */ if (face->charmap && face->charmap->platform_id == 3) { pdf_logfont("encode truetype via unicode\n"); for (i = 0; i < 256; i++) if (estrings[i]) { int aglbuf[256]; int aglnum; aglnum = pdf_lookupagl(estrings[i], aglbuf, nelem(aglbuf)); if (aglnum != 1) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ftcharindex(face, aglbuf[0]); } else etable[i] = ftcharindex(face, i); } /* MacRoman cmap */ else if (face->charmap && face->charmap->platform_id == 1) { pdf_logfont("encode truetype via macroman\n"); for (i = 0; i < 256; i++) if (estrings[i]) { k = mrecode(estrings[i]); if (k <= 0) etable[i] = FT_Get_Name_Index(face, estrings[i]); else etable[i] = ftcharindex(face, k); } else etable[i] = ftcharindex(face, i); } /* Symbolic cmap */ else { pdf_logfont("encode truetype symbolic\n"); for (i = 0; i < 256; i++) { etable[i] = ftcharindex(face, i); fterr = FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32); if (fterr) { error = fz_throw("freetype get glyph name (gid %d): %s", etable[i], ft_errorstring(fterr)); goto cleanup; } if (ebuffer[i][0]) estrings[i] = ebuffer[i]; } } } } else { pdf_logfont("encode builtin\n"); for (i = 0; i < 256; i++) { etable[i] = ftcharindex(face, i); if (etable[i] == 0) continue; if (FT_HAS_GLYPH_NAMES(face)) { fterr = FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32); if (fterr) { error = fz_throw("freetype get glyph name (gid %d): %s", etable[i], ft_errorstring(fterr)); goto cleanup; } if (ebuffer[i][0]) estrings[i] = ebuffer[i]; } } } error = pdf_newidentitycmap(&fontdesc->encoding, 0, 1); if (error) goto cleanup; fontdesc->ncidtogid = 256; fontdesc->cidtogid = etable; error = pdf_loadtounicode(fontdesc, xref, estrings, nil, fz_dictgets(dict, "ToUnicode")); if (error) goto cleanup; /* * Widths */ pdf_setdefaulthmtx(fontdesc, fontdesc->missingwidth); widths = fz_dictgets(dict, "Widths"); if (widths) { int first, last; first = fz_toint(fz_dictgets(dict, "FirstChar")); last = fz_toint(fz_dictgets(dict, "LastChar")); if (first < 0 || last > 255 || first > last) first = last = 0; for (i = 0; i < last - first + 1; i++) { int wid = fz_toint(fz_arrayget(widths, i)); error = pdf_addhmtx(fontdesc, i + first, i + first, wid); if (error) goto cleanup; } } else { fterr = FT_Set_Char_Size(face, 1000, 1000, 72, 72); if (fterr) fz_warn("freetype set character size: %s", ft_errorstring(fterr)); for (i = 0; i < 256; i++) { error = pdf_addhmtx(fontdesc, i, i, ftwidth(fontdesc, i)); if (error) goto cleanup; } } error = pdf_endhmtx(fontdesc); if (error) goto cleanup; pdf_logfont("}\n"); *fontdescp = fontdesc; return fz_okay; cleanup: fz_free(etable); fz_dropfont(fontdesc->font); fz_free(fontdesc); return fz_rethrow(error, "cannot load simple font"); }