diff options
author | Peter Breitenlohner <peb@mppmu.mpg.de> | 2013-07-22 09:10:19 +0000 |
---|---|---|
committer | Peter Breitenlohner <peb@mppmu.mpg.de> | 2013-07-22 09:10:19 +0000 |
commit | 9390cbb84a9dca0d3d20e02765cc92902b06ec14 (patch) | |
tree | 5688e78de0248b85cda933213a1aaa01e550b460 /Build/source/texk/dvipdfm-x/type1.c | |
parent | ccb5ed485c606f3475f6412c5f41f9c6dbd4484a (diff) |
dvipdfm-x: Continue merging dvipdfmx and xdvipdfmx
git-svn-id: svn://tug.org/texlive/trunk@31262 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/dvipdfm-x/type1.c')
-rw-r--r-- | Build/source/texk/dvipdfm-x/type1.c | 810 |
1 files changed, 810 insertions, 0 deletions
diff --git a/Build/source/texk/dvipdfm-x/type1.c b/Build/source/texk/dvipdfm-x/type1.c new file mode 100644 index 00000000000..67627c8c4bc --- /dev/null +++ b/Build/source/texk/dvipdfm-x/type1.c @@ -0,0 +1,810 @@ +/* + + This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2008-2012 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + the dvipdfmx project team. + + Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu> + + 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 <string.h> +#include <math.h> + +#include "system.h" +#include "mem.h" +#include "error.h" + +#include "dpxfile.h" + +#include "numbers.h" + +#include "pdfobj.h" +#include "pdffont.h" + +#include "pdfencoding.h" +#include "unicode.h" + +#include "dpxutil.h" + +#include "pst_obj.h" +#include "pst.h" + +#include "cff_limits.h" +#include "cff_types.h" +#include "cff_dict.h" +#include "cff.h" + +#include "t1_load.h" +#include "t1_char.h" + +#include "type1.h" + +#include "tfm.h" + +#define FONT_FLAG_FIXEDPITCH (1 << 0) /* Fixed-width font */ +#define FONT_FLAG_SERIF (1 << 1) /* Serif font */ +#define FONT_FLAG_SYMBOLIC (1 << 2) /* Symbolic font */ +#define FONT_FLAG_SCRIPT (1 << 3) /* Script font */ +#define FONT_FLAG_STANDARD (1 << 5) /* Adobe Standard Character Set */ +#define FONT_FLAG_ITALIC (1 << 6) /* Italic */ +#define FONT_FLAG_ALLCAP (1 << 16) /* All-cap font */ +#define FONT_FLAG_SMALLCAP (1 << 17) /* Small-cap font */ +#define FONT_FLAG_FORCEBOLD (1 << 18) /* Force bold at small text sizes */ + +static int +is_basefont (const char *name) +{ + static const char *basefonts[] = { + "Courier", "Courier-Bold", "Courier-Oblique", + "Courier-BoldOblique", "Helvetica", "Helvetica-Bold", + "Helvetica-Oblique", "Helvetica-BoldOblique", "Symbol", + "Times-Roman", "Times-Bold", "Times-Italic", + "Times-BoldItalic", "ZapfDingbats" + }; + int i; + + for (i = 0; i < 14; i++) { + if (!strcmp(name, basefonts[i])) + return 1; + } + + return 0; +} + +int +pdf_font_open_type1 (pdf_font *font) +{ + char *ident; + FILE *fp; + char fontname[PDF_NAME_LEN_MAX+1]; + + ASSERT(font); + + ident = pdf_font_get_ident(font); + + if (is_basefont(ident)) { + pdf_font_set_fontname(font, ident); + pdf_font_set_subtype (font, PDF_FONT_FONTTYPE_TYPE1); + pdf_font_set_flags (font, + (PDF_FONT_FLAG_NOEMBED|PDF_FONT_FLAG_BASEFONT)); + } else { + fp = DPXFOPEN(ident, DPX_RES_TYPE_T1FONT); + if (!fp) + return -1; + + memset(fontname, 0, PDF_NAME_LEN_MAX+1); + if (!is_pfb(fp) || t1_get_fontname(fp, fontname) < 0) { + ERROR("Failed to read Type 1 font \"%s\".", ident); + } + DPXFCLOSE(fp); + + pdf_font_set_fontname(font, fontname); + pdf_font_set_subtype (font, PDF_FONT_FONTTYPE_TYPE1); + } + + return 0; +} + +static void +get_font_attr (pdf_font *font, cff_font *cffont) +{ + char *fontname; + pdf_obj *descriptor; + double capheight, ascent, descent; + double italicangle, stemv; + double defaultwidth, nominalwidth; + long flags = 0, gid, i; + static const char *L_c[] = { + "H", "P", "Pi", "Rho", NULL + }; + static const char *L_d[] = { + "p", "q", "mu", "eta", NULL + }; + static const char *L_a[] = { + "b", "h", "lambda", NULL + }; + t1_ginfo gm; + + defaultwidth = 500.0; + nominalwidth = 0.0; + + /* + * CapHeight, Ascent, and Descent is meaningfull only for Latin/Greek/Cyrillic. + * The BlueValues and OtherBlues also have those information. + */ + if (cff_dict_known(cffont->topdict, "FontBBox")) { + /* Default values */ + capheight = ascent = cff_dict_get(cffont->topdict, "FontBBox", 3); + descent = cff_dict_get(cffont->topdict, "FontBBox", 1); + } else { + capheight = 680.0; + ascent = 690.0; + descent = -190.0; + } + if (cff_dict_known(cffont->private[0], "StdVW")) { + stemv = cff_dict_get(cffont->private[0], "StdVW", 0); + } else { + /* + * We may use the following values for StemV: + * Thin - ExtraLight: <= 50 + * Light: 71 + * Regular(Normal): 88 + * Medium: 109 + * SemiBold(DemiBold): 135 + * Bold - Heavy: >= 166 + */ + stemv = 88.0; + } + if (cff_dict_known(cffont->topdict, "ItalicAngle")) { + italicangle = cff_dict_get(cffont->topdict, "ItalicAngle", 0); + if (italicangle != 0.0) + flags |= FONT_FLAG_ITALIC; + } else { + italicangle = 0.0; + } + + /* + * Use "space", "H", "p", and "b" for various values. + * Those characters should not "seac". (no accent) + */ + gid = cff_glyph_lookup(cffont, "space"); + if (gid >= 0 && gid < cffont->cstrings->count) { + t1char_get_metrics(cffont->cstrings->data + cffont->cstrings->offset[gid] - 1, + cffont->cstrings->offset[gid+1] - cffont->cstrings->offset[gid], + cffont->subrs[0], &gm); + defaultwidth = gm.wx; + } + + for (i = 0; L_c[i] != NULL; i++) { + gid = cff_glyph_lookup(cffont, L_c[i]); + if (gid >= 0 && gid < cffont->cstrings->count) { + t1char_get_metrics(cffont->cstrings->data + cffont->cstrings->offset[gid] - 1, + cffont->cstrings->offset[gid+1] - cffont->cstrings->offset[gid], + cffont->subrs[0], &gm); + capheight = gm.bbox.ury; + break; + } + } + + for (i = 0; L_d[i] != NULL; i++) { + gid = cff_glyph_lookup(cffont, L_d[i]); + if (gid >= 0 && gid < cffont->cstrings->count) { + t1char_get_metrics(cffont->cstrings->data + cffont->cstrings->offset[gid] - 1, + cffont->cstrings->offset[gid+1] - cffont->cstrings->offset[gid], + cffont->subrs[0], &gm); + descent = gm.bbox.lly; + break; + } + } + + for (i = 0; L_a[i] != NULL; i++) { + gid = cff_glyph_lookup(cffont, L_a[i]); + if (gid >= 0 && gid < cffont->cstrings->count) { + t1char_get_metrics(cffont->cstrings->data + cffont->cstrings->offset[gid] - 1, + cffont->cstrings->offset[gid+1] - cffont->cstrings->offset[gid], + cffont->subrs[0], &gm); + ascent = gm.bbox.ury; + break; + } + } + + if (defaultwidth != 0.0) { + cff_dict_add(cffont->private[0], "defaultWidthX", 1); + cff_dict_set(cffont->private[0], "defaultWidthX", 0, defaultwidth); + } + if (nominalwidth != 0.0) { + cff_dict_add(cffont->private[0], "nominalWidthX", 1); + cff_dict_set(cffont->private[0], "nominalWidthX", 0, nominalwidth); + } + if (cff_dict_known(cffont->private[0], "ForceBold") && + cff_dict_get(cffont->private[0], "ForceBold", 0)) { + flags |= FONT_FLAG_FORCEBOLD; + } + if (cff_dict_known(cffont->private[0], "IsFixedPitch") && + cff_dict_get(cffont->private[0], "IsFixedPitch", 0)) { + flags |= FONT_FLAG_FIXEDPITCH; + } + + fontname = pdf_font_get_fontname (font); + descriptor = pdf_font_get_descriptor(font); + + if (fontname && !strstr(fontname, "Sans")) { + flags |= FONT_FLAG_SERIF; + } + if (fontname && strstr(fontname, "Caps")) { + flags |= FONT_FLAG_SMALLCAP; + } + flags |= FONT_FLAG_SYMBOLIC; /* FIXME */ + + pdf_add_dict(descriptor, + pdf_new_name("CapHeight"), pdf_new_number(capheight)); + pdf_add_dict(descriptor, + pdf_new_name("Ascent"), pdf_new_number(ascent)); + pdf_add_dict(descriptor, + pdf_new_name("Descent"), pdf_new_number(descent)); + pdf_add_dict(descriptor, + pdf_new_name("ItalicAngle"), pdf_new_number(italicangle)); + pdf_add_dict(descriptor, + pdf_new_name("StemV"), pdf_new_number(stemv)); + pdf_add_dict(descriptor, + pdf_new_name("Flags"), pdf_new_number(flags)); +} + +static void +add_metrics (pdf_font *font, cff_font *cffont, char **enc_vec, double *widths, long num_glyphs) +{ + pdf_obj *fontdict, *descriptor; + pdf_obj *tmp_array; + int code, firstchar, lastchar; + double val; + int i, tfm_id; + char *usedchars; + double scaling; + + fontdict = pdf_font_get_resource (font); + descriptor = pdf_font_get_descriptor(font); + usedchars = pdf_font_get_usedchars (font); + + /* + * The original FontBBox of the font is preserved, instead + * of replacing it with tight bounding box calculated from + * charstrings, to prevent Acrobat 4 from greeking text as + * much as possible. + */ + if (!cff_dict_known(cffont->topdict, "FontBBox")) { + ERROR("No FontBBox?"); + } + + /* The widhts array in the font dictionary must be given relative + * to the default scaling of 1000:1, not relative to the scaling + * given by the font matrix. + */ + if (cff_dict_known(cffont->topdict, "FontMatrix")) + scaling = 1000*cff_dict_get(cffont->topdict, "FontMatrix", 0); + else + scaling = 1; + + tmp_array = pdf_new_array(); + for (i = 0; i < 4; i++) { + val = cff_dict_get(cffont->topdict, "FontBBox", i); + pdf_add_array(tmp_array, pdf_new_number(ROUND(val, 1.0))); + } + pdf_add_dict(descriptor, pdf_new_name("FontBBox"), tmp_array); + + tmp_array = pdf_new_array(); + if (num_glyphs <= 1) { /* This must be an error. */ + firstchar = lastchar = 0; + pdf_add_array(tmp_array, pdf_new_number(0.0)); + } else { + 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(tmp_array); + 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 = scaling * widths[cff_glyph_lookup(cffont, enc_vec[code])]; + else + width = 1000. * tfm_get_width(tfm_id, code); + pdf_add_array(tmp_array, + pdf_new_number(ROUND(width, 0.1))); + } else { + pdf_add_array(tmp_array, pdf_new_number(0.0)); + } + } + } + + if (pdf_array_length(tmp_array) > 0) { + pdf_add_dict(fontdict, + pdf_new_name("Widths"), pdf_ref_obj(tmp_array)); + } + pdf_release_obj(tmp_array); + + 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 long +write_fontfile (pdf_font *font, cff_font *cffont, long num_glyphs) +{ + pdf_obj *descriptor; + pdf_obj *fontfile, *stream_dict; + cff_index *topdict; + long private_size, stream_data_len, charstring_len; + long topdict_offset, offset; +#define WBUF_SIZE 1024 + card8 *stream_data_ptr, wbuf[WBUF_SIZE]; + + descriptor = pdf_font_get_descriptor(font); + + topdict = cff_new_index(1); + /* + * Force existence of Encoding. + */ + if (!cff_dict_known(cffont->topdict, "CharStrings")) + cff_dict_add(cffont->topdict, "CharStrings", 1); + if (!cff_dict_known(cffont->topdict, "charset")) + cff_dict_add(cffont->topdict, "charset", 1); + if (!cff_dict_known(cffont->topdict, "Encoding")) + cff_dict_add(cffont->topdict, "Encoding", 1); + private_size = cff_dict_pack((cffont->private)[0], wbuf, WBUF_SIZE); +#ifdef XETEX + if (private_size > 0 && !cff_dict_known(cffont->topdict, "Private")) +#else + /* Private dict is required (but may have size 0) */ + if (!cff_dict_known(cffont->topdict, "Private")) +#endif + cff_dict_add(cffont->topdict, "Private", 2); + topdict->offset[1] = cff_dict_pack(cffont->topdict, wbuf, WBUF_SIZE) + 1; + + /* + * Estimate total size of fontfile. + */ + charstring_len = cff_index_size(cffont->cstrings); + + stream_data_len = 4; /* header size */ + stream_data_len += cff_index_size(cffont->name); + stream_data_len += cff_index_size(topdict); + stream_data_len += cff_index_size(cffont->string); + stream_data_len += cff_index_size(cffont->gsubr); + /* We are using format 1 for Encoding and format 0 for charset. + * TODO: Should implement cff_xxx_size(). + */ + stream_data_len += 2 + (cffont->encoding->num_entries)*2 + 1 + (cffont->encoding->num_supps)*3; + stream_data_len += 1 + (cffont->charsets->num_entries)*2; + stream_data_len += charstring_len; + stream_data_len += private_size; + + /* + * Now we create FontFile data. + */ + stream_data_ptr = NEW(stream_data_len, card8); + /* + * Data Layout order as described in CFF spec., sec 2 "Data Layout". + */ + offset = 0; + /* Header */ + offset += cff_put_header(cffont, + stream_data_ptr + offset, stream_data_len - offset); + /* Name */ + offset += cff_pack_index(cffont->name, + stream_data_ptr + offset, stream_data_len - offset); + /* Top DICT */ + topdict_offset = offset; + offset += cff_index_size(topdict); + /* Strings */ + offset += cff_pack_index(cffont->string, + stream_data_ptr + offset, stream_data_len - offset); + /* Global Subrs */ + offset += cff_pack_index(cffont->gsubr, + stream_data_ptr + offset, stream_data_len - offset); + /* Encoding */ + /* TODO: don't write Encoding entry if the font is always used + * with PDF Encoding information. Applies to type1c.c as well. + */ + cff_dict_set(cffont->topdict, "Encoding", 0, offset); + offset += cff_pack_encoding(cffont, + stream_data_ptr + offset, stream_data_len - offset); + /* charset */ + cff_dict_set(cffont->topdict, "charset", 0, offset); + offset += cff_pack_charsets(cffont, + stream_data_ptr + offset, stream_data_len - offset); + /* CharStrings */ + cff_dict_set(cffont->topdict, "CharStrings", 0, offset); + offset += cff_pack_index(cffont->cstrings, + stream_data_ptr + offset, charstring_len); + /* Private */ + if ((cffont->private)[0] && private_size > 0) { + private_size = cff_dict_pack(cffont->private[0], + stream_data_ptr + offset, private_size); + cff_dict_set(cffont->topdict, "Private", 1, offset); + cff_dict_set(cffont->topdict, "Private", 0, private_size); + } + offset += private_size; + + /* Finally Top DICT */ + topdict->data = NEW(topdict->offset[1] - 1, card8); + cff_dict_pack (cffont->topdict, topdict->data, topdict->offset[1] - 1); + cff_pack_index(topdict, + stream_data_ptr + topdict_offset, cff_index_size(topdict)); + cff_release_index(topdict); + + /* Copyright and Trademark Notice ommited. */ + + /* Flush Font File */ + fontfile = pdf_new_stream(STREAM_COMPRESS); + stream_dict = pdf_stream_dict(fontfile); + pdf_add_dict(descriptor, + pdf_new_name("FontFile3"), pdf_ref_obj (fontfile)); + pdf_add_dict(stream_dict, + pdf_new_name("Subtype"), pdf_new_name("Type1C")); + pdf_add_stream (fontfile, (void *) stream_data_ptr, offset); + pdf_release_obj(fontfile); + + RELEASE(stream_data_ptr); + + return offset; +} + + +int +pdf_font_load_type1 (pdf_font *font) +{ + pdf_obj *fontdict; + int encoding_id; + char *usedchars, *ident; + char *fontname, *uniqueTag; + char *fullname; /* With pseudo unique tag */ + cff_font *cffont; + cff_charsets *charset; + char **enc_vec; + double defaultwidth, nominalwidth; + double *widths; + card16 *GIDMap, num_glyphs = 0; + FILE *fp; + long offset; + int code, verbose; + + ASSERT(font); + + if (!pdf_font_is_in_use(font)) { + return 0; + } + + verbose = pdf_font_get_verbose(); + + encoding_id = pdf_font_get_encoding (font); + fontdict = pdf_font_get_resource (font); + + pdf_font_get_descriptor(font); + usedchars = pdf_font_get_usedchars (font); + ident = pdf_font_get_ident (font); + fontname = pdf_font_get_fontname (font); + uniqueTag = pdf_font_get_uniqueTag (font); + if (!usedchars || !ident || !fontname) { + ERROR("Type1: Unexpected error."); + } + + fp = DPXFOPEN(ident, DPX_RES_TYPE_T1FONT); + if (!fp) { + ERROR("Type1: Could not open Type1 font: %s", ident); + } + + GIDMap = NULL; + num_glyphs = 0; + + if (encoding_id >= 0) { + enc_vec = NULL; + } else { + enc_vec = NEW(256, char *); + for (code = 0; code <= 0xff; code++) { + enc_vec[code] = NULL; + } + } + + cffont = t1_load_font(enc_vec, 0, fp); + if (!cffont) { + ERROR("Could not load Type 1 font: %s", ident); + } + DPXFCLOSE(fp); + + fullname = NEW(strlen(fontname) + 8, char); + sprintf(fullname, "%6s+%s", uniqueTag, fontname); + + /* + * Encoding related things. + */ + if (encoding_id >= 0) { + enc_vec = pdf_encoding_get_encoding(encoding_id); + } else { + pdf_obj *tounicode; + + /* + * Create enc_vec and ToUnicode CMap for built-in encoding. + */ + if (!pdf_lookup_dict(fontdict, "ToUnicode")) { + tounicode = pdf_create_ToUnicode_CMap(fullname, + enc_vec, usedchars); + if (tounicode) { + pdf_add_dict(fontdict, + pdf_new_name("ToUnicode"), + pdf_ref_obj (tounicode)); + pdf_release_obj(tounicode); + } + } + } + + cff_set_name(cffont, fullname); + RELEASE(fullname); + + /* defaultWidthX, CapHeight, etc. */ + get_font_attr(font, cffont); + if (cff_dict_known(cffont->private[0], "defaultWidthX")) { + defaultwidth = cff_dict_get(cffont->private[0], "defaultWidthX", 0); + } else { + defaultwidth = 0.0; + } + if (cff_dict_known(cffont->private[0], "nominalWidthX")) { + nominalwidth = cff_dict_get(cffont->private[0], "nominalWidthX", 0); + } else { + nominalwidth = 0.0; + } + + /* Create CFF encoding, charset, sort glyphs */ +#define MAX_GLYPHS 1024 + GIDMap = NEW(MAX_GLYPHS, card16); + { + int prev, duplicate; + long gid; + char *glyph; + s_SID sid; + + cffont->encoding = NEW(1, cff_encoding); + cffont->encoding->format = 1; + cffont->encoding->num_entries = 0; + cffont->encoding->data.range1 = NEW(256, cff_range1); + cffont->encoding->num_supps = 0; + cffont->encoding->supp = NEW(256, cff_map); + + charset = NEW(1, cff_charsets); + charset->format = 0; + charset->num_entries = 0; + charset->data.glyphs = NEW(MAX_GLYPHS, s_SID); + + gid = cff_glyph_lookup(cffont, ".notdef"); + if (gid < 0) + ERROR("Type 1 font with no \".notdef\" glyph???"); + GIDMap[0] = (card16) gid; + if (verbose > 2) + MESG("[glyphs:/.notdef"); + num_glyphs = 1; + for (prev = -2, code = 0; code <= 0xff; code++) { + glyph = enc_vec[code]; + + if (!usedchars[code]) + continue; + if (glyph && !strcmp(glyph, ".notdef")) { + WARN("Character mapped to .notdef used in font: %s", + fontname); + usedchars[code] = 0; + continue; + } + + gid = cff_glyph_lookup(cffont, glyph); + if (gid < 1 || gid >= cffont->cstrings->count) { + WARN("Glyph \"%s\" missing in font \"%s\".", glyph, fontname); + usedchars[code] = 0; + continue; + } + + for (duplicate = 0; duplicate < code; duplicate++) { + if (usedchars[duplicate] && + enc_vec[duplicate] && !strcmp(enc_vec[duplicate], glyph)) + break; + } + + sid = cff_add_string(cffont, glyph, 1); /* FIXME */ + if (duplicate < code) { /* found duplicates */ + cffont->encoding->supp[cffont->encoding->num_supps].code = duplicate; + cffont->encoding->supp[cffont->encoding->num_supps].glyph = sid; + cffont->encoding->num_supps += 1; + } else { + GIDMap[num_glyphs] = (card16) gid; + charset->data.glyphs[charset->num_entries] = sid; + charset->num_entries += 1; + if (code != prev + 1) { + cffont->encoding->num_entries += 1; + cffont->encoding->data.range1[cffont->encoding->num_entries-1].first = code; + cffont->encoding->data.range1[cffont->encoding->num_entries-1].n_left = 0; + } else { + cffont->encoding->data.range1[cffont->encoding->num_entries-1].n_left += 1; + } + prev = code; + num_glyphs++; + + if (verbose > 2) { + MESG("/%s", glyph); + } + + } + } + if (cffont->encoding->num_supps > 0) { + cffont->encoding->format |= 0x80; + } else { + RELEASE(cffont->encoding->supp); /* FIXME */ + cffont->encoding->supp = NULL; + } + } + + widths = NEW(cffont->cstrings->count, double); + /* + * No more string will be added. + * The Type 1 seac operator may add another glyph but the glyph name of + * those glyphs are contained in standard string. The String Index will + * not be modified after here. + * BUT: We cannot update the String Index yet because then we wouldn't be + * able to find the GIDs of the base and accent characters (unless they + * have been used already). + */ + + { + cff_index *cstring; + t1_ginfo gm; + card16 gid, gid_orig; + long dstlen_max, srclen; + card8 *srcptr, *dstptr; + + offset = dstlen_max = 0L; + cstring = cff_new_index(cffont->cstrings->count); + cstring->data = NULL; + cstring->offset[0] = 1; + + /* The num_glyphs increases if "seac" operators are used. */ + for (gid = 0; gid < num_glyphs; gid++) { + if (offset + CS_STR_LEN_MAX >= dstlen_max) { + dstlen_max += CS_STR_LEN_MAX * 2; + cstring->data = RENEW(cstring->data, dstlen_max, card8); + } + gid_orig = GIDMap[gid]; + + dstptr = cstring->data + cstring->offset[gid] - 1; + srcptr = cffont->cstrings->data + cffont->cstrings->offset[gid_orig] - 1; + srclen = cffont->cstrings->offset[gid_orig + 1] - cffont->cstrings->offset[gid_orig]; + + offset += t1char_convert_charstring(dstptr, CS_STR_LEN_MAX, + srcptr, srclen, + cffont->subrs[0], defaultwidth, nominalwidth, &gm); + cstring->offset[gid + 1] = offset + 1; + if (gm.use_seac) { + long bchar_gid, achar_gid, i; + const char *bchar_name, *achar_name; + + /* + * NOTE: + * 1. seac.achar and seac.bchar must be contained in the CFF standard string. + * 2. Those characters need not to be encoded. + * 3. num_glyphs == charsets->num_entries + 1. + */ + achar_name = t1_get_standard_glyph(gm.seac.achar); + achar_gid = cff_glyph_lookup(cffont, achar_name); + bchar_name = t1_get_standard_glyph(gm.seac.bchar); + bchar_gid = cff_glyph_lookup(cffont, bchar_name); + if (achar_gid < 0) { + WARN("Accent char \"%s\" not found. Invalid use of \"seac\" operator.", + achar_name); + continue; + } + if (bchar_gid < 0) { + WARN("Base char \"%s\" not found. Invalid use of \"seac\" operator.", + bchar_name); + continue; + } + + for (i = 0; i < num_glyphs; i++) { + if (GIDMap[i] == achar_gid) + break; + } + if (i == num_glyphs) { + if (verbose > 2) + MESG("/%s", achar_name); + GIDMap[num_glyphs++] = achar_gid; + charset->data.glyphs[charset->num_entries] = cff_get_seac_sid(cffont, achar_name); + charset->num_entries += 1; + } + + for (i = 0; i < num_glyphs; i++) { + if (GIDMap[i] == bchar_gid) + break; + } + if (i == num_glyphs) { + if (verbose > 2) + MESG("/%s", bchar_name); + GIDMap[num_glyphs++] = bchar_gid; + charset->data.glyphs[charset->num_entries] = cff_get_seac_sid(cffont, bchar_name); + charset->num_entries += 1; + } + } + widths[gid] = gm.wx; + } + cstring->count = num_glyphs; + + cff_release_index(cffont->subrs[0]); + cffont->subrs[0] = NULL; + RELEASE(cffont->subrs); + cffont->subrs = NULL; + + cff_release_index(cffont->cstrings); + cffont->cstrings = cstring; + + cff_release_charsets(cffont->charsets); + cffont->charsets = charset; + } + if (verbose > 2) + MESG("]"); + + /* Now we can update the String Index */ + cff_dict_update (cffont->topdict, cffont); + cff_dict_update (cffont->private[0], cffont); + cff_update_string(cffont); + + add_metrics(font, cffont, enc_vec, widths, num_glyphs); + + offset = write_fontfile(font, cffont, num_glyphs); + if (verbose > 1) + MESG("[%u glyphs][%ld bytes]", num_glyphs, offset); + + cff_close(cffont); + + /* Cleanup */ + if (encoding_id < 0 && enc_vec) { + for (code = 0; code < 256; code++) { + if (enc_vec[code]) + RELEASE(enc_vec[code]); + enc_vec[code] = NULL; + } + RELEASE(enc_vec); + } + if (widths) + RELEASE(widths); + if (GIDMap) + RELEASE(GIDMap); + + /* + * Maybe writing Charset is recommended for subsetted font. + */ + + return 0; +} |