diff options
Diffstat (limited to 'Build/source/texk/dvipdfm-x/truetype.c')
-rw-r--r-- | Build/source/texk/dvipdfm-x/truetype.c | 1013 |
1 files changed, 1013 insertions, 0 deletions
diff --git a/Build/source/texk/dvipdfm-x/truetype.c b/Build/source/texk/dvipdfm-x/truetype.c new file mode 100644 index 00000000000..9e22c012557 --- /dev/null +++ b/Build/source/texk/dvipdfm-x/truetype.c @@ -0,0 +1,1013 @@ +/* + + This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2007-2012 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "system.h" + +#include "numbers.h" +#include "error.h" +#include "mem.h" + +#include "dpxfile.h" +#include "dpxutil.h" + +#include "pdfobj.h" +#include "pdfresource.h" +#include "pdffont.h" + +#include "pdfencoding.h" +#include "unicode.h" +#include "agl.h" + +/* TrueType */ +#include "sfnt.h" +#include "tt_cmap.h" +#include "tt_table.h" +#include "tt_glyf.h" +#include "tt_post.h" +#include "tt_gsub.h" +#include "tt_aux.h" + +#include "truetype.h" + +#include "tfm.h" + +/* Modifying this has no effect :P */ +#ifdef ENABLE_NOEMBED +# undef ENABLE_NOEMBED +#endif + +int +pdf_font_open_truetype (pdf_font *font) +{ + char *ident; + int index, encoding_id; + pdf_obj *fontdict, *descriptor; + sfnt *sfont; + int embedding = 1; /* Must be embedded. */ + FILE *fp = NULL; + int length, error = 0; + + ASSERT( font ); + + ident = pdf_font_get_ident(font); + index = pdf_font_get_index(font); + + ASSERT( ident ); + +#ifdef XETEX + sfont = sfnt_open(pdf_font_get_ft_face(font), SFNT_TYPE_TTC | SFNT_TYPE_TRUETYPE); + if (!sfont) + return -1; +#else + fp = DPXFOPEN(ident, DPX_RES_TYPE_TTFONT); + if (!fp) { + fp = DPXFOPEN(ident, DPX_RES_TYPE_DFONT); + if (!fp) return -1; + sfont = dfont_open(fp, index); + } else { + sfont = sfnt_open(fp); + } +#endif + + if (!sfont) { + WARN("Could not open TrueType font: %s", ident); + if (fp) + DPXFCLOSE(fp); + return -1; + } + + if (sfont->type == SFNT_TYPE_TTC) { + unsigned long offset; + offset = ttc_read_offset(sfont, index); + if (offset == 0) ERROR("Invalid TTC index in %s.", ident); + error = sfnt_read_table_directory(sfont, offset); + } else { + error = sfnt_read_table_directory(sfont, sfont->offset); + } + + if (error) { + sfnt_close(sfont); + if (fp) + DPXFCLOSE(fp); + return -1; /* Silently */ + } + + /* Reading fontdict before checking fonttype conflicts with PKFONT + * because pdf_font_get_resource() always makes a dictionary. + */ + encoding_id = pdf_font_get_encoding(font); + fontdict = pdf_font_get_resource(font); + descriptor = pdf_font_get_descriptor(font); +#ifdef ENABLE_NOEMBED + embedding = pdf_font_get_flag(font, PDF_FONT_FLAG_NOEMBED) ? 0 : 1; +#endif /* ENABLE_NOEMBED */ + + ASSERT( fontdict && descriptor ); + + { + char fontname[256]; + int n; + pdf_obj *tmp; + + memset(fontname, 0, 256); + length = tt_get_ps_fontname(sfont, fontname, 255); + if (length < 1) { + length = MIN(strlen(ident), 255); + strncpy(fontname, ident, length); + } + fontname[length] = '\0'; + for (n = 0; n < length; n++) { + if (fontname[n] == 0) { + memmove(fontname + n, fontname + n + 1, length - n - 1); + } + } + if (strlen(fontname) == 0) + ERROR("Can't find valid fontname for \"%s\".", ident); + pdf_font_set_fontname(font, fontname); + +#ifdef XETEX + tmp = tt_get_fontdesc(sfont, &embedding, -1, 1, fontname); +#else + tmp = tt_get_fontdesc(sfont, &embedding, -1, 1, NULL); +#endif + if (!tmp) { + ERROR("Could not obtain necessary font info."); + sfnt_close(sfont); + if (fp) + DPXFCLOSE(fp); + return -1; + } + ASSERT(pdf_obj_typeof(tmp) == PDF_DICT); + + pdf_merge_dict(descriptor, tmp); + pdf_release_obj(tmp); + } + + if (!embedding) { + if (encoding_id >= 0 && + !pdf_encoding_is_predefined(encoding_id)) { + ERROR("Custom encoding not allowed for non-embedded TrueType font."); + sfnt_close(sfont); + return -1; + } else { + /* There are basically no guarantee for font substitution + * can work with "symblic" fonts. At least all glyphs + * contained in the font must be identified; glyphs covers + * by this instance of font should contain glyphs only from + * Adobe Standard Latin Set. We allow non-embedded font + * only to predefined encodings for this reason. Note that + * "builtin" encoding means "MacRoman" here. + */ + pdf_obj *tmp; + long flags; + +#ifndef ENABLE_NOEMBED + ERROR("Font file=\"%s\" can't be embedded due to liscence restrictions.", ident); +#endif /* ENABLE_NOEMBED */ + pdf_font_set_flags(font, PDF_FONT_FLAG_NOEMBED); + tmp = pdf_lookup_dict(descriptor, "Flags"); + if (tmp && pdf_obj_typeof(tmp) == PDF_NUMBER) { + flags = (long) pdf_number_value(tmp); + flags &= (1 << 2); /* clear Symbolic */ + flags |= (1 << 5); /* set Nonsymbolic */ + pdf_add_dict(descriptor, pdf_new_name("Flags"), pdf_new_number(flags)); + } + } + } + + sfnt_close(sfont); + if (fp) + DPXFCLOSE(fp); + + pdf_add_dict(fontdict, + pdf_new_name("Type"), pdf_new_name("Font")); + pdf_add_dict(fontdict, + pdf_new_name("Subtype"), pdf_new_name("TrueType")); + + return 0; +} + +/* + * The 'name' table should be preserved since it contains copyright + * information, but it might cause problem when there are invalid + * table entries (wrongly encoded text which is often the case in + * CJK fonts). Acrobat does not use 'name' table. Unicode TrueType + * fonts may have 10K bytes 'name' table... + * + * We preserve the 'OS/2' table too, since it contains the license + * information. PDF applications should use this table to decide + * whether the font is embedded only for the purpose of preview & + * printing. Otherwise, we must encrypt the document. Acrobat does + * not use 'OS/2' table, though... + */ +static struct +{ + const char *name; + int must_exist; +} required_table[] = { + {"OS/2", 0}, {"head", 1}, {"hhea", 1}, {"loca", 1}, {"maxp", 1}, + {"name", 1}, {"glyf", 1}, {"hmtx", 1}, {"fpgm", 0}, {"cvt ", 0}, + {"prep", 0}, {"cmap", 1}, {NULL, 0} +}; + +static void +do_widths (pdf_font *font, double *widths) +{ + pdf_obj *fontdict; + pdf_obj *tmparray; + int code, firstchar, lastchar, tfm_id; + char *usedchars; + + fontdict = pdf_font_get_resource (font); + usedchars = pdf_font_get_usedchars (font); + + tmparray = pdf_new_array(); + for (firstchar = 255, lastchar = 0, code = 0; code < 256; code++) { + if (usedchars[code]) { + if (code < firstchar) firstchar = code; + if (code > lastchar) lastchar = code; + } + } + if (firstchar > lastchar) { + WARN("No glyphs actually used???"); + pdf_release_obj(tmparray); + return; + } + tfm_id = tfm_open(pdf_font_get_mapname(font), 0); + for (code = firstchar; code <= lastchar; code++) { + if (usedchars[code]) { + double width; + if (tfm_id < 0) /* tfm is not found */ + width = widths[code]; + else + width = 1000. * tfm_get_width(tfm_id, code); + pdf_add_array(tmparray, + pdf_new_number(ROUND(width, 0.1))); + } else { + pdf_add_array(tmparray, pdf_new_number(0.0)); + } + } + + if (pdf_array_length(tmparray) > 0) { + pdf_add_dict(fontdict, + pdf_new_name("Widths"), pdf_ref_obj(tmparray)); + } + pdf_release_obj(tmparray); + + pdf_add_dict(fontdict, + pdf_new_name("FirstChar"), pdf_new_number(firstchar)); + pdf_add_dict(fontdict, + pdf_new_name("LastChar"), pdf_new_number(lastchar)); + + return; +} + +static int verbose = 0; + +#define PDFUNIT(v) ((double) (ROUND(1000.0*(v)/(glyphs->emsize), 1))) + +/* + * There are several issues in TrueType font support in PDF. + * How PDF viewers select TrueType cmap table is not so clear. + * Most reliable way seem to reencode font and sort glyphs as + * charcode == gid and to use Mac-Roman format 0 subtable. + * It does not work with encodings that uses full 256 range since + * GID = 0 is reserved for .notdef, so GID = 256 is not accessible. + */ +static int +do_builtin_encoding (pdf_font *font, const char *usedchars, sfnt *sfont) +{ + struct tt_glyphs *glyphs; + char *cmap_table; + tt_cmap *ttcm; + USHORT gid, idx; + int code, count; + double widths[256]; + + ttcm = tt_cmap_read(sfont, TT_MAC, TT_MAC_ROMAN); + if (!ttcm) { + WARN("Could not read Mac-Roman TrueType cmap table..."); + return -1; + } + + cmap_table = NEW(274, char); + memset(cmap_table, 0, 274); + sfnt_put_ushort(cmap_table, 0); /* Version */ + sfnt_put_ushort(cmap_table+2, 1); /* Number of subtables */ + sfnt_put_ushort(cmap_table+4, TT_MAC); /* Platform ID */ + sfnt_put_ushort(cmap_table+6, TT_MAC_ROMAN); /* Encoding ID */ + sfnt_put_ulong (cmap_table+8, 12); /* Offset */ + sfnt_put_ushort(cmap_table+12, 0); /* Format */ + sfnt_put_ushort(cmap_table+14, 262); /* Length */ + sfnt_put_ushort(cmap_table+16, 0); /* Language */ + + glyphs = tt_build_init(); + + if (verbose > 2) + MESG("[glyphs:/.notdef"); + + count = 1; /* .notdef */ + for (code = 0; code < 256; code++) { + if (!usedchars[code]) + continue; + + if (verbose > 2) + MESG("/.c0x%02x", code); + + gid = tt_cmap_lookup(ttcm, code); + if (gid == 0) { + WARN("Glyph for character code=0x%02x missing in font font-file=\"%s\".", + code, pdf_font_get_ident(font)); + idx = 0; + } else { + idx = tt_find_glyph(glyphs, gid); + if (idx == 0) + idx = tt_add_glyph(glyphs, (USHORT)gid, (USHORT)count); /* count returned. */ + } + cmap_table[18+code] = idx & 0xff; /* bug here */ + count++; + } + tt_cmap_release(ttcm); + + if (verbose > 2) + MESG("]"); + + if (tt_build_tables(sfont, glyphs) < 0) { + WARN("Packing TrueType font into SFNT failed!"); + tt_build_finish(glyphs); + RELEASE(cmap_table); + return -1; + } + + for (code = 0; code < 256; code++) { + if (usedchars[code]) { + idx = tt_get_index(glyphs, (USHORT) cmap_table[18+code]); + widths[code] = PDFUNIT(glyphs->gd[idx].advw); + } else { + widths[code] = 0.0; + } + } + do_widths(font, widths); + + if (verbose > 1) + MESG("[%d glyphs]", glyphs->num_glyphs); + + tt_build_finish(glyphs); + + sfnt_set_table(sfont, "cmap", cmap_table, 274); + + return 0; +} + +/* Order of lookup should be + * post, unicode+otl + */ +struct glyph_mapper +{ + tt_cmap *codetogid; + otl_gsub *gsub; + sfnt *sfont; + struct tt_post_table *nametogid; +}; + + +/* WARNING: This modifies glyphname itself */ +static int +agl_decompose_glyphname (char *glyphname, char **nptrs, int size, char **suffix) +{ + char *q, *p = glyphname; + int n; + + q = strchr(p, '.'); /* chop every thing after *first* dot */ + if (!q) + *suffix = NULL; + else { + *q = '\0'; q++; + *suffix = q; + } + + nptrs[0] = p; + for (n = 1; p && *p; n++) { + p = strchr(p, '_'); + if (!p || p[1] == '\0') + break; + if (n >= size) + ERROR("Uh ah..."); /* _FIXME_ */ + *p = '\0'; p++; + nptrs[n] = p; + } + + return n; +} + +static int +select_gsub (const char *feat, struct glyph_mapper *gm) +{ + int idx, error = 0; + + if (!feat || *feat == 0 || !gm || !gm->gsub) + return -1; + + /* First treat as is */ + idx = otl_gsub_select(gm->gsub, "*", "*", feat); + if (idx >= 0) + return 0; + + if (verbose > 1) + MESG("\ntrutype>> Try loading OTL GSUB for \"*.*.%s\"...", feat); + error = otl_gsub_add_feat(gm->gsub, "*", "*", feat, gm->sfont); + if (!error) { + idx = otl_gsub_select(gm->gsub, "*", "*", feat); + return (idx >= 0 ? 0 : -1); + } + + return -1; +} + +static int findparanoiac (const char *glyph_name, USHORT *gid, struct glyph_mapper *gm); +static int resolve_glyph (const char *glyph_name, USHORT *gid, struct glyph_mapper *gm); + +/* Apply GSUB. This is a bit tricky... */ +static int +selectglyph (USHORT in, const char *suffix, struct glyph_mapper *gm, USHORT *out) +{ + char *s, *q, t[5]; + const char *r; + int n, error = 0; + + ASSERT(suffix && gm && out); + ASSERT(suffix && *suffix != 0); + + s = NEW(strlen(suffix) + 1, char); + strcpy(s, suffix); + + /* First try converting suffix to feature tag. + * agl.c currently only knows less ambiguos cases; + * e.g., 'sc', 'superior', etc. + */ + r = agl_suffix_to_otltag(s); + if (r) { /* We found feature tag for 'suffix'. */ + error = select_gsub(r, gm); /* no fallback for this */ + if (!error) + error = otl_gsub_apply(gm->gsub, &in); + } else { /* 'suffix' may represent feature tag. */ + /* Try loading GSUB only when length of 'suffix' is less + * than or equal to 4. tt_gsub give a warning otherwise. + */ + if (strlen(s) > 4) + error = -1; /* Uh */ + else if (strlen(s) == 4) + error = select_gsub(s, gm); + else { /* less than 4. pad ' '. */ + memset(t, ' ', 4); t[4] = '\0'; + memcpy(t, s, strlen(s)); + error = select_gsub(t, gm); + } + if (!error) /* 'suffix' represents feature tag. */ + error = otl_gsub_apply(gm->gsub, &in); + else { /* other case: alt1, nalt10... (alternates) */ + for (q = s + strlen(s) - 1; q > s && *q >= '0' && *q <= '9'; q--); + if (q == s) + error = -1; + else { /* starting at 1 */ + n = atoi(q + 1) - 1; q[1] = '\0'; + if (strlen(s) > 4) + error = -1; + else { /* This may be alternate substitution. */ + memset(t, ' ', 4); t[4] = '\0'; + memcpy(t, s, strlen(s)); + error = select_gsub(s, gm); + if (!error) + error = otl_gsub_apply_alt(gm->gsub, (USHORT)n, (USHORT *)&in); + } + } + } + } + RELEASE(s); + + *out = in; + return error; +} + + +/* Compose glyphs via ligature substitution. */ +static int +composeglyph (USHORT *glyphs, int n_glyphs, + const char *feat, struct glyph_mapper *gm, USHORT *gid) +{ + int error = 0; + char t[5] = {' ', ' ', ' ', ' ', 0}; + + ASSERT(glyphs && n_glyphs > 0 && gm && gid); + + if (!feat || feat[0] == '\0') /* meaning "Unknown" */ + error = select_gsub("(?lig|lig?|?cmp|cmp?|frac|afrc)", gm); + else { + if (strlen(feat) > 4) + error = -1; + else { + memcpy(t, feat, strlen(feat)); + error = select_gsub(t, gm); + } + } + + if (!error) + error = otl_gsub_apply_lig(gm->gsub, (USHORT *)glyphs, (USHORT)n_glyphs, + (USHORT *)gid); + + return error; +} + +/* This may be called by findparanoiac(). */ +static int +composeuchar (long *unicodes, int n_unicodes, + const char *feat, struct glyph_mapper *gm, USHORT *gid) +{ + USHORT *gids; + int i, error = 0; + + if (!gm->codetogid) + return -1; + + gids = NEW(n_unicodes, USHORT); + for (i = 0; + !error && i < n_unicodes; i++) { + gids[i] = tt_cmap_lookup(gm->codetogid, unicodes[i]); + error = (gids[i] == 0) ? -1 : 0; + } + + if (!error) + error = composeglyph(gids, n_unicodes, feat, gm, gid); + + RELEASE(gids); + + return error; +} + +/* Search 'post' table. */ +static int +findposttable (const char *glyph_name, USHORT *gid, struct glyph_mapper *gm) +{ + if (!gm->nametogid) + return -1; + + *gid = tt_lookup_post_table(gm->nametogid, glyph_name); +#if 0 + if (verbose > 1) + { + if (*gid > 0) + MESG("%s =post=> 0x%04X\n", glyph_name, *gid); + } +#endif + + return (*gid == 0 ? -1 : 0); +} + +/* This is wrong. We must care about '.'. */ +#define is_comp(n) (strchr((n), '_') != NULL) + +/* Glyph names are concatinated with '_'. */ +static int +findcomposite (const char *glyphname, USHORT *gid, struct glyph_mapper *gm) +{ + char *gname, *suffix = NULL; + USHORT gids[32]; + char *nptrs[32]; + int i, n_comp; + int error = 0; + + error = findposttable(glyphname, gid, gm); + if (!error) + return 0; + + gname = NEW(strlen(glyphname) + 1, char); + strcpy(gname, glyphname); + + memset(gids, 0, 32 * sizeof(USHORT)); + n_comp = agl_decompose_glyphname(gname, nptrs, 32, &suffix); + for (error = 0, i = 0; !error && i < n_comp; i++) { + error = resolve_glyph(nptrs[i], &gids[i], gm); + if (error) + WARN("Could not resolve glyph \"%s\" (%dth component of glyph \"%s\").", + nptrs[i], i, glyphname); + } + + if (!error) { + if (suffix && + (!strcmp(suffix, "liga") || !strcmp(suffix, "dlig") || + !strcmp(suffix, "hlig") || !strcmp(suffix, "frac") || + !strcmp(suffix, "ccmp") || !strcmp(suffix, "afrc") + ) + ) { + error = composeglyph(gids, n_comp, suffix, gm, gid); + } else { /* first try composing glyph */ + error = composeglyph(gids, n_comp, NULL, gm, gid); + if (!error && suffix) /* a_b_c.vert */ + error = selectglyph(*gid, suffix, gm, gid); + } + } + RELEASE(gname); + + return error; +} + +/* glyphname should not have suffix here */ +static int +findparanoiac (const char *glyphname, USHORT *gid, struct glyph_mapper *gm) +{ + agl_name *agln; + USHORT idx = 0U; + int error = 0; + + agln = agl_lookup_list(glyphname); + while (agln && idx == 0) { + if (agln->suffix) { + error = findparanoiac(agln->name, &idx, gm); + if (error) + return error; + + error = selectglyph(idx, agln->suffix, gm, &idx); + if (error) { + WARN("Variant \"%s\" for glyph \"%s\" might not be found.", + agln->suffix, agln->name); + WARN("Using glyph name without suffix instead..."); + error = 0; /* ignore */ + } + } else { + if (agln->n_components == 1) + idx = tt_cmap_lookup(gm->codetogid, agln->unicodes[0]); + else if (agln->n_components > 1) { + if (verbose >= 0) /* give warning */ + WARN("Glyph \"%s\" looks like a composite glyph...", + agln->name); + error = composeuchar(agln->unicodes, agln->n_components, NULL, gm, &idx); + if (verbose >= 0) { + if (error) + WARN("Not found..."); + else { + int _i, _n = 0; + char *_p, _buf[256]; + WARN(">> Composite glyph glyph-name=\"%s\" found at glyph-id=\"%u\".", + agln->name, idx); + for (_p = _buf, _i = 0; _i < agln->n_components && _n < 245; _i++) { + _p[_n++] = _i == 0 ? '<' : ' '; + if (agln->unicodes[_i] >= 0x10000) + _n += sprintf(_p+_n, "U+%06lX", agln->unicodes[_i]); + else + _n += sprintf(_p+_n, "U+%04lX", agln->unicodes[_i]); + _p[_n++] = _i == agln->n_components - 1 ? '>' : ','; + } + _p[_n++] = '\0'; + WARN(">> Input Unicode seq.=\"%s\" ==> glyph-id=\"%u\" in font-file=\"_please_try_-v_\".", _buf, idx); + } + } + } else ASSERT(0); /* Boooo */ + } + agln = agln->alternate; + } + + *gid = idx; + return (idx == 0 ? -1 : 0); +} + +static int +resolve_glyph (const char *glyphname, USHORT *gid, struct glyph_mapper *gm) +{ + int error = 0; + char *name, *suffix = NULL; + long ucv; + + ASSERT(glyphname); + + /* + * First we try glyph name to GID mapping using post table if post table + * is available. If post table is not available or glyph is not listed + * in the post table, then we try Unicode if Windows-Unicode TrueType + * cmap is available. + */ + error = findposttable(glyphname, gid, gm); + if (!error) + return 0; + + if (!gm->codetogid) + return -1; + + name = agl_chop_suffix(glyphname, &suffix); + if (!name) /* .notdef, .foo */ + error = -1; + else if (agl_name_is_unicode(name)) { + ucv = agl_name_convert_unicode(name); + *gid = tt_cmap_lookup(gm->codetogid, ucv); + error = (*gid == 0) ? -1 : 0; + } else { + error = findparanoiac(name, gid, gm); + } + if (!error && suffix) { + error = selectglyph(*gid, suffix, gm, gid); + if (error) { + WARN("Variant \"%s\" for glyph \"%s\" might not be found.", + suffix, name); + WARN("Using glyph name without suffix instead..."); + error = 0; /* ignore */ + } + } + if (suffix) + RELEASE(suffix); + if (name) + RELEASE(name); + + return error; +} + +/* Things are complicated. We still need to use PostScript + * glyph names. But OpenType fonts may not have PS name to + * glyph mapping. We use Unicode plus OTL GSUB for finding + * glyphs in this case. + */ +static int +setup_glyph_mapper (struct glyph_mapper *gm, sfnt *sfont) +{ + gm->sfont = sfont; + gm->nametogid = tt_read_post_table(sfont); + gm->codetogid = tt_cmap_read(sfont, TT_WIN, TT_WIN_UCS4); + if (!gm->codetogid) + gm->codetogid = tt_cmap_read(sfont, TT_WIN, TT_WIN_UNICODE); + + if (!gm->nametogid && !gm->codetogid) + return -1; + + gm->gsub = otl_gsub_new(); + + return 0; +} + +static void +clean_glyph_mapper (struct glyph_mapper *gm) +{ + if (gm->gsub) + otl_gsub_release(gm->gsub); + if (gm->codetogid) + tt_cmap_release (gm->codetogid); + if (gm->nametogid) + tt_release_post_table(gm->nametogid); + + gm->gsub = NULL; + gm->codetogid = NULL; + gm->nametogid = NULL; + gm->sfont = NULL; + + return; +} + +static int +do_custom_encoding (pdf_font *font, + char **encoding, const char *usedchars, sfnt *sfont) +{ + struct tt_glyphs *glyphs; + char *cmap_table; + int code, count; + double widths[256]; + struct glyph_mapper gm; + USHORT idx, gid; + int error = 0; + + ASSERT(font && encoding && usedchars && sfont); + + error = setup_glyph_mapper(&gm, sfont); + if (error) { + WARN("No post table nor Unicode cmap found in font: %s", + pdf_font_get_ident(font)); + WARN(">> I can't find glyphs without this!"); + return -1; + } + + cmap_table = NEW(274, char); + memset(cmap_table, 0, 274); + sfnt_put_ushort(cmap_table, 0); /* Version */ + sfnt_put_ushort(cmap_table+2, 1); /* Number of subtables */ + sfnt_put_ushort(cmap_table+4, TT_MAC); /* Platform ID */ + sfnt_put_ushort(cmap_table+6, TT_MAC_ROMAN); /* Encoding ID */ + sfnt_put_ulong (cmap_table+8, 12); /* Offset */ + sfnt_put_ushort(cmap_table+12, 0); /* Format */ + sfnt_put_ushort(cmap_table+14, 262); /* Length */ + sfnt_put_ushort(cmap_table+16, 0); /* Language */ + + glyphs = tt_build_init(); + + count = 1; /* +1 for .notdef */ + for (code = 0; code < 256; code++) { + if (!usedchars[code]) + continue; + + if (!encoding[code] || !strcmp(encoding[code], ".notdef")) { + WARN("Character code=\"0x%02X\" mapped to \".notdef\" glyph used in font font-file=\"%s\"", + code, pdf_font_get_ident(font)); + WARN(">> Maybe incorrect encoding specified?"); + idx = 0; + } else { + if (is_comp(encoding[code])) + error = findcomposite(encoding[code], &gid, &gm); + else + error = resolve_glyph(encoding[code], &gid, &gm); + + /* + * Older versions of gs had problem with glyphs (other than .notdef) + * mapped to gid = 0. + */ + if (error) { + WARN("Glyph \"%s\" not available in font \"%s\".", + encoding[code], pdf_font_get_ident(font)); + } else { + if (verbose > 1) + MESG("truetype>> Glyph glyph-name=\"%s\" found at glyph-id=\"%u\".\n", encoding[code], gid); + } + idx = tt_find_glyph(glyphs, gid); + if (idx == 0) { + idx = tt_add_glyph(glyphs, (USHORT)gid, (USHORT)count); /* count returned. */ + count++; + } + } + cmap_table[18 + code] = idx & 0xff; /* bug here */ + } + clean_glyph_mapper(&gm); + + if (tt_build_tables(sfont, glyphs) < 0) { + WARN("Packing TrueType font into SFNT file faild..."); /* _FIXME_: wrong message */ + tt_build_finish(glyphs); + RELEASE(cmap_table); + return -1; + } + + for (code = 0; code < 256; code++) { + if (usedchars[code]) { + idx = tt_get_index(glyphs, (USHORT) cmap_table[18+code]); + widths[code] = PDFUNIT(glyphs->gd[idx].advw); + } else { + widths[code] = 0.0; + } + } + do_widths(font, widths); + + if (verbose > 1) + MESG("[%d glyphs]", glyphs->num_glyphs); + + tt_build_finish(glyphs); + + sfnt_set_table(sfont, "cmap", cmap_table, 274); + + return 0; +} + +int +pdf_font_load_truetype (pdf_font *font) +{ + pdf_obj *descriptor = pdf_font_get_descriptor(font); + char *ident = pdf_font_get_ident(font); + int encoding_id = pdf_font_get_encoding(font); + char *usedchars = pdf_font_get_usedchars(font); +#ifdef ENABLE_NOEMBED + int embedding = pdf_font_get_flag(font, PDF_FONT_FLAG_NOEMBED) ? 0 : 1; +#endif /* ENABLE_NOEMBED */ + int index = pdf_font_get_index(font); + char **enc_vec; + pdf_obj *fontfile; + FILE *fp = NULL; + sfnt *sfont; + int i, error = 0; + + if (!pdf_font_is_in_use(font)) + return 0; + + verbose = pdf_font_get_verbose(); + +#ifdef XETEX + sfont = sfnt_open(pdf_font_get_ft_face(font), SFNT_TYPE_TTC | SFNT_TYPE_TRUETYPE); +#else + fp = DPXFOPEN(ident, DPX_RES_TYPE_TTFONT); + if (!fp) { + fp = DPXFOPEN(ident, DPX_RES_TYPE_DFONT); + if (!fp) ERROR("Unable to open TrueType/dfont font file: %s", ident); /* Should find *truetype* here */ + sfont = dfont_open(fp, index); + } else { + sfont = sfnt_open(fp); + } +#endif + + if (!sfont) { + ERROR("Unable to open TrueType/dfont file: %s", ident); + if (fp) + DPXFCLOSE(fp); + return -1; + } else if (sfont->type != SFNT_TYPE_TRUETYPE && + sfont->type != SFNT_TYPE_TTC && + sfont->type != SFNT_TYPE_DFONT) { + ERROR("Font \"%s\" not a TrueType/dfont font?", ident); + sfnt_close(sfont); + if (fp) + DPXFCLOSE(fp); + return -1; + } + + if (sfont->type == SFNT_TYPE_TTC) { + unsigned long offset; + offset = ttc_read_offset(sfont, index); + if (offset == 0) ERROR("Invalid TTC index in %s.", ident); + error = sfnt_read_table_directory(sfont, ttc_read_offset(sfont, offset)); + } else { + error = sfnt_read_table_directory(sfont, sfont->offset); + } + + if (error) { + ERROR("Reading SFND table dir failed for font-file=\"%s\"... Not a TrueType font?", ident); + sfnt_close(sfont); + if (fp) + DPXFCLOSE(fp); + return -1; + } + + /* + * Create new TrueType cmap table with MacRoman encoding. + */ + if (encoding_id < 0) + error = do_builtin_encoding(font, usedchars, sfont); + else { + enc_vec = pdf_encoding_get_encoding(encoding_id); + error = do_custom_encoding(font, enc_vec, usedchars, sfont); + } + if (error) { + ERROR("Error occured while creating font subfont for \"%s\"", ident); + sfnt_close(sfont); + if (fp) + DPXFCLOSE(fp); + return -1; + } + +#if ENABLE_NOEMBED + if (!embedding) { + sfnt_close(sfont); + if (fp) + DPXFCLOSE(fp); + return 0; + } +#endif /* ENABLE_NOEMBED */ + + /* + * TODO: post table? + */ + + for (i = 0; required_table[i].name != NULL; i++) { + if (sfnt_require_table(sfont, + required_table[i].name, + required_table[i].must_exist) < 0) { + ERROR("Required TrueType table \"%s\" does not exist in font: %s", + required_table[i].name, ident); + sfnt_close(sfont); + if (fp) + DPXFCLOSE(fp); + return -1; + } + } + + /* + * FontFile2 + */ + fontfile = sfnt_create_FontFile_stream(sfont); + if (!fontfile) + ERROR("Could not created FontFile stream for \"%s\".", ident); + + sfnt_close(sfont); + if (fp) + DPXFCLOSE(fp); + + if (verbose > 1) + MESG("[%ld bytes]", pdf_stream_length(fontfile)); + + pdf_add_dict(descriptor, + pdf_new_name("FontFile2"), pdf_ref_obj(fontfile)); /* XXX */ + pdf_release_obj(fontfile); + + return 0; +} |