summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvipdfm-x/cidtype2.c
diff options
context:
space:
mode:
authorPeter Breitenlohner <peb@mppmu.mpg.de>2013-07-08 13:41:49 +0000
committerPeter Breitenlohner <peb@mppmu.mpg.de>2013-07-08 13:41:49 +0000
commit09607811ee9f819abbeca6c1366f4c447ef68314 (patch)
treeab9240dfaa01c7eb4437d5f7523411d248c881b1 /Build/source/texk/dvipdfm-x/cidtype2.c
parentfffc4a898e030f526c17acd03f9e3d37aecb5a3f (diff)
dvipdfm-x: Continue merging dvipdfmx and xdvipdfmx
git-svn-id: svn://tug.org/texlive/trunk@31133 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/dvipdfm-x/cidtype2.c')
-rw-r--r--Build/source/texk/dvipdfm-x/cidtype2.c1123
1 files changed, 1123 insertions, 0 deletions
diff --git a/Build/source/texk/dvipdfm-x/cidtype2.c b/Build/source/texk/dvipdfm-x/cidtype2.c
new file mode 100644
index 00000000000..edea6e916ed
--- /dev/null
+++ b/Build/source/texk/dvipdfm-x/cidtype2.c
@@ -0,0 +1,1123 @@
+/*
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2002-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.
+*/
+
+/*
+ * TrueType glyf table is sorted by CID and no CIDToGIDMap is used here.
+ * GhostScript can't handle CIDToGIDMap correctly.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "system.h"
+#include "numbers.h"
+#include "mem.h"
+#include "error.h"
+#include "dpxfile.h"
+
+#include "pdfobj.h"
+/* pseudo unique tag */
+#include "pdffont.h"
+
+#ifndef PDF_NAME_LEN_MAX
+# define PDF_NAME_LEN_MAX 255
+#endif
+
+/* TrueType */
+#include "sfnt.h"
+#include "tt_aux.h"
+#include "tt_glyf.h"
+#include "tt_cmap.h"
+#include "tt_table.h"
+
+#include "tt_gsub.h"
+
+/* CID font */
+#include "cmap.h"
+#include "type0.h"
+#include "cid.h"
+#include "cid_p.h"
+#include "cidtype2.h"
+
+static int verbose = 0;
+static int opt_flags = 0;
+
+void
+CIDFont_type2_set_verbose (void)
+{
+ verbose++;
+}
+
+void
+CIDFont_type2_set_flags (long flags)
+{
+ opt_flags = flags;
+}
+
+/*
+ * PDF viewer applications use following tables (CIDFontType 2)
+ *
+ * head, hhea, loca, maxp, glyf, hmtx, fpgm, cvt_, prep
+ *
+ * - from PDF Ref. v.1.3, 2nd ed.
+ *
+ * The fpgm, cvt_, and prep tables appears only when TrueType instructions
+ * requires them. Those tables must be preserved if they exist.
+ * We use must_exist flag to indicate `preserve it if present'
+ * and to make sure not to cause an error when it does not exist.
+ *
+ * post and name table must exist in ordinary TrueType font file,
+ * but when a TrueType font is converted to CIDFontType 2 font, those tables
+ * are no longer required.
+ *
+ * The OS/2 table (required for TrueType font for Windows and OS/2) contains
+ * liscencing information, but PDF viewers seems not using them.
+ *
+ * The 'name' table added. See comments in ttf.c.
+ */
+
+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}, {NULL, 0}
+};
+
+static void
+validate_name (char *fontname, int len)
+{
+ int i, count;
+ char *p;
+ static const char *badstrlist[] = {
+ "-WIN-RKSJ-H",
+ "-WINP-RKSJ-H",
+ "-WING-RKSJ-H",
+ "-90pv-RKSJ-H",
+ NULL
+ };
+
+ for (count = 0, i = 0; i < len; i++) {
+ if (fontname[i] == 0) {
+ memmove(fontname + i, fontname + i + 1, len - i);
+ count++;
+ len--;
+ }
+ }
+ if (count > 0) {
+ WARN("Removed %d null character(s) from fontname --> %s",
+ count, fontname);
+ }
+ fontname[len] = '\0';
+
+ /* For some fonts that have bad PS name. ad hoc. remove me. */
+ for (i = 0; badstrlist[i] != NULL; i++) {
+ p = strstr(fontname, badstrlist[i]);
+ if (p && p > fontname) {
+ WARN("Removed string \"%s\" from fontname \"%s\".",
+ badstrlist[i], fontname);
+ p[0] = '\0';
+ len = (int) (p - fontname);
+ break;
+ }
+ }
+
+ if (len < 1) {
+ ERROR("No valid character found in fontname string.");
+ }
+}
+
+/*
+ * We will follow the convension for finding ToUnicode CMap described in PDF
+ * Reference 4th ed., page 432. The name of "ToCode" (not limited to Unicode
+ * here) CMap is obtained by concatenating the registry, ordering, and the
+ * name of encoding.
+ *
+ * UCSms-UCS4, UCSms-UCS2, UCS4 added...
+ */
+
+#define WIN_UCS_INDEX_MAX 1
+#define KNOWN_ENCODINGS_MAX 9
+static struct
+{
+ unsigned short platform;
+ unsigned short encoding;
+ const char *pdfnames[5];
+} known_encodings[] = {
+ {TT_WIN, TT_WIN_UCS4, {"UCSms-UCS4", "UCSms-UCS2", "UCS4", "UCS2", NULL}},
+ {TT_WIN, TT_WIN_UNICODE, {"UCSms-UCS4", "UCSms-UCS2", "UCS4", "UCS2", NULL}},
+ {TT_WIN, TT_WIN_SJIS, {"90ms-RKSJ", NULL}},
+ {TT_WIN, TT_WIN_RPC, {"GBK-EUC", NULL}},
+ {TT_WIN, TT_WIN_BIG5, {"ETen-B5", NULL}},
+ {TT_WIN, TT_WIN_WANSUNG, {"KSCms-UHC", NULL}},
+ {TT_MAC, TT_MAC_JAPANESE, {"90pv-RKSJ", NULL}},
+ {TT_MAC, TT_MAC_TRADITIONAL_CHINESE, {"B5pc", NULL}},
+ {TT_MAC, TT_MAC_SIMPLIFIED_CHINESE, {"GBpc-EUC", NULL}},
+ {TT_MAC, TT_MAC_KOREAN, {"KSCpc-EUC", NULL}},
+ {0, 0, {NULL}}
+};
+
+static CMap *
+find_tocode_cmap (const char *reg, const char *ord, int select)
+{
+ int cmap_id = -1, i;
+ char *cmap_name;
+ const char *append;
+
+ if (!reg || !ord ||
+ select < 0 || select > KNOWN_ENCODINGS_MAX)
+ ERROR("Character set unknown.");
+
+ if (!strcmp(ord, "UCS") &&
+ select <= WIN_UCS_INDEX_MAX)
+ return NULL;
+
+ for (i = 0; cmap_id < 0 && i < 5; i++) {
+ append = known_encodings[select].pdfnames[i];
+ if (!append)
+ break;
+ cmap_name = NEW(strlen(reg) + strlen(ord) + strlen(append) + 3, char);
+ sprintf(cmap_name, "%s-%s-%s", reg, ord, append);
+ cmap_id = CMap_cache_find(cmap_name);
+ RELEASE(cmap_name);
+ }
+ if (cmap_id < 0) {
+ WARN("Could not find CID-to-Code mapping for \"%s-%s\".", reg, ord);
+ WARN("I tried to load (one of) the following file(s):");
+ for (i = 0; i < 5; i++) {
+ append = known_encodings[select].pdfnames[i];
+ if (!append)
+ break;
+ MESG(" %s-%s-%s", reg, ord, append);
+ }
+ WARN("Please check if this file exists.");
+ ERROR("Cannot continue...");
+ }
+
+ return CMap_cache_get(cmap_id);
+}
+
+
+/*
+ * CIDFont glyph metrics:
+ * Mostly same as add_CID[HV]Metrics in cidtype0.c.
+ */
+#define PDFUNIT(v) ((double) (ROUND(1000.0*(v)/(g->emsize), 1)))
+
+static void
+add_TTCIDHMetrics (pdf_obj *fontdict, struct tt_glyphs *g,
+ char *used_chars, unsigned char *cidtogidmap, unsigned short last_cid)
+{
+ long cid, start = 0, prev = 0;
+ pdf_obj *w_array, *an_array = NULL;
+ double dw;
+ int empty = 1;
+
+ w_array = pdf_new_array();
+ if (g->dw != 0 && g->dw <= g->emsize) {
+ dw = PDFUNIT(g->dw);
+ } else {
+ dw = PDFUNIT(g->gd[0].advw);
+ }
+ for (cid = 0; cid <= last_cid; cid++) {
+ USHORT idx, gid;
+ double width;
+
+ if (!is_used_char2(used_chars, cid))
+ continue;
+ gid = (cidtogidmap) ? ((cidtogidmap[2*cid] << 8)|cidtogidmap[2*cid+1]) : cid;
+ idx = tt_get_index(g, gid);
+ if (cid != 0 && idx == 0)
+ continue;
+ width = PDFUNIT((g->gd)[idx].advw);
+ if (width == dw) {
+ if (an_array) {
+ pdf_add_array(w_array, pdf_new_number(start));
+ pdf_add_array(w_array, an_array);
+ an_array = NULL;
+ empty = 0;
+ }
+ } else {
+ if (cid != prev + 1) {
+ if (an_array) {
+ pdf_add_array(w_array, pdf_new_number(start));
+ pdf_add_array(w_array, an_array);
+ an_array = NULL;
+ empty = 0;
+ }
+ }
+ if (an_array == NULL) {
+ an_array = pdf_new_array();
+ start = cid;
+ }
+ pdf_add_array(an_array, pdf_new_number(width));
+ prev = cid;
+ }
+ }
+
+ if (an_array) {
+ pdf_add_array(w_array, pdf_new_number(start));
+ pdf_add_array(w_array, an_array);
+ empty = 0;
+ }
+
+ pdf_add_dict(fontdict,
+ pdf_new_name("DW"),
+ pdf_new_number(dw));
+ if (!empty) {
+ pdf_add_dict(fontdict,
+ pdf_new_name("W"),
+ pdf_ref_obj(w_array));
+ }
+ pdf_release_obj(w_array);
+
+ return;
+}
+
+static void
+add_TTCIDVMetrics (pdf_obj *fontdict, struct tt_glyphs *g,
+ char *used_chars, unsigned char *cidtogidmap, unsigned short last_cid)
+{
+ pdf_obj *w2_array, *an_array = NULL;
+ long cid;
+#if 0
+ long prev = 0, start = 0;
+#endif
+ double defaultVertOriginY, defaultAdvanceHeight;
+ int empty = 1;
+
+ defaultVertOriginY = PDFUNIT(g->default_advh - g->default_tsb);
+ defaultAdvanceHeight = PDFUNIT(g->default_advh);
+
+ w2_array = pdf_new_array();
+ for (cid = 0; cid <= last_cid; cid++) {
+ USHORT idx;
+#if 0
+ USHORT gid;
+#endif
+ double vertOriginX, vertOriginY, advanceHeight;
+
+ if (!is_used_char2(used_chars, cid))
+ continue;
+#if 0
+ gid = (cidtogidmap) ? ((cidtogidmap[2*cid] << 8)|cidtogidmap[2*cid+1]) : cid;
+#endif
+ idx = tt_get_index(g, (USHORT)cid);
+ if (cid != 0 && idx == 0)
+ continue;
+ advanceHeight = PDFUNIT(g->gd[idx].advh);
+ vertOriginX = PDFUNIT(0.5*(g->gd[idx].advw));
+ vertOriginY = PDFUNIT(g->gd[idx].tsb + g->gd[idx].ury);
+#if 0
+ /*
+ * c [w1_1y v_1x v_1y w1_2y v_2x v_2y ...]
+ * Not working... Why?
+ * Acrobat Reader:
+ * Wrong rendering, interpretation of position vector is wrong.
+ * Xpdf and gs: ignores W2?
+ */
+ if (vertOriginY == defaultVertOriginY &&
+ advanceHeight == defaultAdvanceHeight) {
+ if (an_array) {
+ pdf_add_array(w2_array, pdf_new_number(start));
+ pdf_add_array(w2_array, an_array);
+ an_array = NULL;
+ empty = 0;
+ }
+ } else {
+ if (cid != prev + 1 && an_array) {
+ pdf_add_array(w2_array, pdf_new_number(start));
+ pdf_add_array(w2_array, an_array);
+ an_array = NULL;
+ empty = 0;
+ }
+ if (an_array == NULL) {
+ an_array = pdf_new_array();
+ start = cid;
+ }
+ pdf_add_array(an_array, pdf_new_number(-advanceHeight));
+ pdf_add_array(an_array, pdf_new_number(vertOriginX));
+ pdf_add_array(an_array, pdf_new_number(vertOriginY));
+ prev = cid;
+ }
+#else
+ /*
+ * c_first c_last w1_y v_x v_y
+ * This form may hit Acrobat's implementation limit of array element size,
+ * 8192. AFPL GhostScript 8.11 stops with rangecheck error with this.
+ * Maybe GS's bug?
+ */
+ if (vertOriginY != defaultVertOriginY ||
+ advanceHeight != defaultAdvanceHeight) {
+ pdf_add_array(w2_array, pdf_new_number(cid));
+ pdf_add_array(w2_array, pdf_new_number(cid));
+ pdf_add_array(w2_array, pdf_new_number(-advanceHeight));
+ pdf_add_array(w2_array, pdf_new_number(vertOriginX));
+ pdf_add_array(w2_array, pdf_new_number(vertOriginY));
+ empty = 0;
+ }
+#endif
+ }
+
+#if 0
+ if (an_array) {
+ pdf_add_array(w2_array, pdf_new_number(start));
+ pdf_add_array(w2_array, an_array);
+ empty = 0;
+ }
+#endif
+
+ if (defaultVertOriginY != 880 || defaultAdvanceHeight != 1000) {
+ an_array = pdf_new_array();
+ pdf_add_array(an_array, pdf_new_number(defaultVertOriginY));
+ pdf_add_array(an_array, pdf_new_number(-defaultAdvanceHeight));
+ pdf_add_dict(fontdict, pdf_new_name ("DW2"), an_array);
+ }
+ if (!empty) {
+ pdf_add_dict(fontdict,
+ pdf_new_name("W2"),
+ pdf_ref_obj(w2_array));
+ }
+ pdf_release_obj(w2_array);
+
+ return;
+}
+
+/*
+ * The following routine fixes few problems caused by vendor specific
+ * Unicode mappings.
+ */
+
+#define FIX_CJK_UNIOCDE_SYMBOLS 1
+
+static unsigned short
+fix_CJK_symbols (unsigned short code)
+{
+ unsigned short alt_code;
+ static struct
+ {
+ unsigned short alt1;
+ unsigned short alt2;
+ } CJK_Uni_symbols[] = {
+ /*
+ * Microsoft/Apple Unicode mapping difference:
+ * They are taken from SJIS-Unicode mapping difference but nearly
+ * same thing might be applied to Chinese (e.g., Big5) too.
+ */
+ {0x2014, 0x2015}, /* EM DASH <-> HORIZONTAL BAR */
+ {0x2016, 0x2225}, /* DOUBLE VERTICAL LINE <-> PARALLEL TO */
+ {0x203E, 0xFFE3}, /* OVERLINE <-> FULLWIDTH MACRON */
+ {0x2026, 0x22EF}, /* HORIZONTAL ELLIPSIS <-> MIDLINE HORIZONTAL ELLIPSIS */
+ {0x2212, 0xFF0D}, /* MINUS SIGN <-> FULLWIDTH HYPHEN-MINUS */
+ {0x301C, 0xFF5E}, /* WAVE DASH <-> FULLWIDTH TILDE */
+ {0xFFE0, 0x00A2}, /* FULLWIDTH CENT SIGN <-> CENT SIGN */
+ {0xFFE1, 0x00A3}, /* FULLWIDTH POUND SIGN <-> POUND SIGN */
+ {0xFFE2, 0x00AC}, /* FULLWIDTH NOT SIGN <-> NOT SIGN */
+ {0xFFFF, 0xFFFF}, /* EOD */
+ };
+#define NUM_CJK_SYMBOLS (sizeof(CJK_Uni_symbols)/sizeof(CJK_Uni_symbols[0]))
+ int i;
+
+ alt_code = code;
+ for (i = 0; i < NUM_CJK_SYMBOLS; i++) {
+ if (CJK_Uni_symbols[i].alt1 == code) {
+ alt_code = CJK_Uni_symbols[i].alt2;
+ break;
+ } else if (CJK_Uni_symbols[i].alt2 == code) {
+ alt_code = CJK_Uni_symbols[i].alt1;
+ break;
+ }
+ }
+
+ return alt_code;
+}
+
+static long
+cid_to_code (CMap *cmap, CID cid)
+{
+ unsigned char inbuf[2], outbuf[32];
+ long inbytesleft = 2, outbytesleft = 32;
+ const unsigned char *p;
+ unsigned char *q;
+
+ if (!cmap)
+ return cid;
+
+ inbuf[0] = (cid >> 8) & 0xff;
+ inbuf[1] = cid & 0xff;
+ p = inbuf; q = outbuf;
+
+ CMap_decode_char(cmap, &p, &inbytesleft, &q, &outbytesleft);
+
+ if (inbytesleft != 0)
+ return 0;
+ else if (outbytesleft == 31)
+ return (long) outbuf[0];
+ else if (outbytesleft == 30)
+ return (long) (outbuf[0] << 8|outbuf[1]);
+ else if (outbytesleft == 28) { /* We assume the output encoding is UTF-16. */
+ CID hi, lo;
+ hi = outbuf[0] << 8|outbuf[1];
+ lo = outbuf[2] << 8|outbuf[3];
+ if (hi >= 0xd800 && hi <= 0xdbff && lo >= 0xdc00 && lo <= 0xdfff)
+ return (long) ((hi - 0xd800) * 0x400 + 0x10000 + lo - 0xdc00);
+ else
+ return (long) (hi << 16|lo);
+ }
+
+ return 0;
+}
+
+/* #define NO_GHOSTSCRIPT_BUG 1 */
+
+void
+CIDFont_type2_dofont (CIDFont *font)
+{
+ pdf_obj *fontfile;
+ sfnt *sfont;
+ char *h_used_chars, *v_used_chars, *used_chars;
+ struct tt_glyphs *glyphs;
+ CMap *cmap = NULL;
+ tt_cmap *ttcmap = NULL;
+ unsigned long offset = 0;
+ CID cid, last_cid;
+ unsigned char *cidtogidmap;
+ USHORT num_glyphs;
+ int i, glyph_ordering = 0, unicode_cmap = 0;
+ FILE *fp = NULL;
+
+ if (!font->indirect)
+ return;
+
+ pdf_add_dict(font->fontdict,
+ pdf_new_name("FontDescriptor"), pdf_ref_obj(font->descriptor));
+
+ if (CIDFont_is_BaseFont(font))
+ return;
+
+ /*
+ * CIDSystemInfo comes here since Supplement can be increased.
+ */
+ {
+ pdf_obj *tmp;
+
+ tmp = pdf_new_dict ();
+ pdf_add_dict(tmp,
+ pdf_new_name("Registry"),
+ pdf_new_string(font->csi->registry, strlen(font->csi->registry)));
+ pdf_add_dict(tmp,
+ pdf_new_name("Ordering"),
+ pdf_new_string(font->csi->ordering, strlen(font->csi->ordering)));
+ pdf_add_dict(tmp,
+ pdf_new_name("Supplement"),
+ pdf_new_number(font->csi->supplement));
+ pdf_add_dict(font->fontdict, pdf_new_name("CIDSystemInfo"), tmp);
+ }
+
+ /* Quick exit for non-embedded & fixed-pitch font. */
+ if (!CIDFont_get_embedding(font) &&
+ (opt_flags & CIDFONT_FORCE_FIXEDPITCH)) {
+ pdf_add_dict(font->fontdict,
+ pdf_new_name("DW"), pdf_new_number(1000.0));
+ return;
+ }
+
+#ifdef XETEX
+ sfont = sfnt_open(font->ft_face, SFNT_TYPE_TTC | SFNT_TYPE_TRUETYPE);
+#else
+ fp = DPXFOPEN(font->ident, DPX_RES_TYPE_TTFONT);
+ if (!fp) {
+ fp = DPXFOPEN(font->ident, DPX_RES_TYPE_DFONT);
+ if (!fp) ERROR("Could not open TTF/dfont file: %s", font->ident);
+ sfont = dfont_open(fp, font->options->index);
+ } else {
+ sfont = sfnt_open(fp);
+ }
+#endif
+
+ if (!sfont) {
+ ERROR("Could not open TTF file: %s", font->ident);
+ }
+
+ switch (sfont->type) {
+ case SFNT_TYPE_TTC:
+ offset = ttc_read_offset(sfont, font->options->index);
+ if (offset == 0)
+ ERROR("Invalid TTC index in %s.", font->ident);
+ break;
+ case SFNT_TYPE_TRUETYPE:
+#ifdef XETEX
+ /* disable the check here becuase sfnt_open() does not distinguish dfont
+ * from regular trutype */
+#else
+ if (font->options->index > 0)
+ ERROR("Found TrueType font file while expecting TTC file (%s).", font->ident);
+#endif
+ offset = 0;
+ break;
+ case SFNT_TYPE_DFONT:
+ offset = sfont->offset;
+ break;
+ default:
+ ERROR("Not a TrueType/TTC font (%s)?", font->ident);
+ break;
+ }
+
+ if (sfnt_read_table_directory(sfont, offset) < 0)
+ ERROR("Could not read TrueType table directory (%s).", font->ident);
+
+ /*
+ * Adobe-Identity means font's internal glyph ordering here.
+ */
+ if (!strcmp(font->csi->registry, "Adobe") &&
+ !strcmp(font->csi->ordering, "Identity")) {
+ glyph_ordering = 1;
+ } else {
+ glyph_ordering = 0;
+ }
+
+ /*
+ * Select TrueType cmap table, find ToCode CMap for each TrueType encodings.
+ */
+ if (glyph_ordering) {
+ ttcmap = NULL;
+ cmap = NULL;
+ } else {
+ /*
+ * This part contains a bug. It may choose SJIS encoding TrueType cmap
+ * table for Adobe-GB1.
+ */
+ for (i = 0; i <= KNOWN_ENCODINGS_MAX; i++) {
+ ttcmap = tt_cmap_read(sfont,
+ known_encodings[i].platform,
+ known_encodings[i].encoding);
+ if (ttcmap)
+ break;
+ }
+ if (!ttcmap) {
+ WARN("No usable TrueType cmap table found for font \"%s\".", font->ident);
+ WARN("CID character collection for this font is set to \"%s-%s\"",
+ font->csi->registry, font->csi->ordering);
+ ERROR("Cannot continue without this...");
+ } else if (i <= WIN_UCS_INDEX_MAX) {
+ unicode_cmap = 1;
+ } else {
+ unicode_cmap = 0;
+ }
+
+ /*
+ * NULL is returned if CMap is Identity CMap.
+ */
+ cmap = find_tocode_cmap(font->csi->registry,
+ font->csi->ordering, i);
+ }
+
+ glyphs = tt_build_init();
+
+ last_cid = 0;
+ num_glyphs = 1; /* .notdef */
+ used_chars = h_used_chars = v_used_chars = NULL;
+ {
+ Type0Font *parent;
+ int parent_id, c;
+
+ if ((parent_id = CIDFont_get_parent_id(font, 0)) >= 0) {
+ parent = Type0Font_cache_get(parent_id);
+ h_used_chars = Type0Font_get_usedchars(parent);
+ }
+ if ((parent_id = CIDFont_get_parent_id(font, 1)) >= 0) {
+ parent = Type0Font_cache_get(parent_id);
+ v_used_chars = Type0Font_get_usedchars(parent);
+ }
+ if (!h_used_chars && !v_used_chars)
+ ERROR("Unexpected error.");
+
+ /*
+ * Quick check of max CID.
+ */
+ c = 0;
+ for (i = 8191; i >= 0; i--) {
+ if (h_used_chars && h_used_chars[i] != 0) {
+ last_cid = i * 8 + 7;
+ c = h_used_chars[i];
+ break;
+ }
+ if (v_used_chars && v_used_chars[i] != 0) {
+ last_cid = i * 8 + 7;
+ c = v_used_chars[i];
+ break;
+ }
+ }
+ if (last_cid > 0) {
+ for (i = 0; i < 8; i++) {
+ if ((c >> i) & 1)
+ break;
+ last_cid--;
+ }
+ }
+ if (last_cid >= 0xFFFFu) {
+ ERROR("CID count > 65535");
+ }
+ }
+
+#ifndef NO_GHOSTSCRIPT_BUG
+ cidtogidmap = NULL;
+#else
+ cidtogidmap = NEW((last_cid + 1) * 2, unsigned char);
+ memset(cidtogidmap, 0, (last_cid + 1) * 2);
+#endif /* !NO_GHOSTSCRIPT_BUG */
+
+ /*
+ * Map CIDs to GIDs.
+ * Horizontal and vertical used_chars are merged.
+ */
+
+ /*
+ * Horizontal
+ */
+ if (h_used_chars) {
+ used_chars = h_used_chars;
+ for (cid = 1; cid <= last_cid; cid++) {
+ long code;
+ unsigned short gid;
+
+ if (!is_used_char2(h_used_chars, cid))
+ continue;
+
+ if (glyph_ordering) {
+ gid = cid;
+ code = cid;
+ } else {
+ code = cid_to_code(cmap, cid);
+ gid = tt_cmap_lookup(ttcmap, code);
+#ifdef FIX_CJK_UNIOCDE_SYMBOLS
+ if (gid == 0 && unicode_cmap) {
+ long alt_code;
+
+ alt_code = fix_CJK_symbols((unsigned short)code);
+ if (alt_code != code) {
+ gid = tt_cmap_lookup(ttcmap, alt_code);
+ if (gid != 0) {
+ WARN("Unicode char U+%04x replaced with U+%04x.",
+ code, alt_code);
+ }
+ }
+ }
+#endif /* FIX_CJK_UNIOCDE_SYMBOLS */
+ }
+
+ if (gid == 0) {
+ WARN("Glyph missing in font. (CID=%u, code=0x%04x)", cid, code);
+ }
+
+ /* TODO: duplicated glyph */
+#ifndef NO_GHOSTSCRIPT_BUG
+ gid = tt_add_glyph(glyphs, gid, cid);
+#else
+ gid = tt_add_glyph(glyphs, gid, num_glyphs);
+ cidtogidmap[2*cid ] = gid >> 8;
+ cidtogidmap[2*cid+1] = gid & 0xff;
+#endif /* !NO_GHOSTSCRIPT_BUG */
+
+ num_glyphs++;
+ }
+ }
+
+ /*
+ * Vertical
+ */
+ if (v_used_chars) {
+ otl_gsub *gsub_list = NULL;
+
+ /*
+ * Require `vrt2' or `vert'.
+ */
+ if (glyph_ordering) {
+ gsub_list = NULL;
+ } else {
+ gsub_list = otl_gsub_new();
+ if (otl_gsub_add_feat(gsub_list,
+ "*", "*", "vrt2", sfont) < 0) {
+ if (otl_gsub_add_feat(gsub_list,
+ "*", "*", "vert", sfont) < 0) {
+ WARN("GSUB feature vrt2/vert not found.");
+ otl_gsub_release(gsub_list);
+ gsub_list = NULL;
+ } else {
+ otl_gsub_select(gsub_list, "*", "*", "vert");
+ }
+ } else {
+ otl_gsub_select(gsub_list, "*", "*", "vrt2");
+ }
+ }
+
+ for (cid = 1; cid <= last_cid; cid++) {
+ long code;
+ unsigned short gid;
+
+ if (!is_used_char2(v_used_chars, cid))
+ continue;
+
+ /* There may be conflict of horizontal and vertical glyphs
+ * when font is used with /UCS. However, we simply ignore
+ * that...
+ */
+ if (h_used_chars && is_used_char2(h_used_chars, cid)) {
+ continue;
+ }
+
+ if (glyph_ordering) {
+ gid = cid;
+ code = cid;
+ } else {
+ code = cid_to_code(cmap, cid);
+ gid = tt_cmap_lookup(ttcmap, code);
+#ifdef FIX_CJK_UNIOCDE_SYMBOLS
+ if (gid == 0 && unicode_cmap) {
+ long alt_code;
+
+ alt_code = fix_CJK_symbols((unsigned short)code);
+ if (alt_code != code) {
+ gid = tt_cmap_lookup(ttcmap, alt_code);
+ if (gid != 0) {
+ WARN("Unicode char U+%04x replaced with U+%04x.",
+ code, alt_code);
+ }
+ }
+ }
+#endif /* FIX_CJK_UNIOCDE_SYMBOLS */
+ }
+ if (gid == 0) {
+ WARN("Glyph missing in font. (CID=%u, code=0x%04x)", cid, code);
+ } else if (gsub_list) {
+ otl_gsub_apply(gsub_list, &gid);
+ }
+
+#ifndef NO_GHOSTSCRIPT_BUG
+ gid = tt_add_glyph(glyphs, gid, cid);
+#else
+ gid = tt_add_glyph(glyphs, gid, num_glyphs);
+ cidtogidmap[2*cid ] = gid >> 8;
+ cidtogidmap[2*cid+1] = gid & 0xff;
+#endif /* !NO_GHOSTSCRIPT_BUG */
+
+ if (used_chars) /* merge vertical used_chars to horizontal */
+ add_to_used_chars2(used_chars, cid);
+
+ num_glyphs++;
+ }
+
+ if (gsub_list)
+ otl_gsub_release(gsub_list);
+
+ if (!used_chars) /* We have no horizontal. */
+ used_chars = v_used_chars;
+ }
+
+ if (!used_chars)
+ ERROR("Unexpected error.");
+
+ tt_cmap_release(ttcmap);
+
+ if (CIDFont_get_embedding(font)) {
+ if (tt_build_tables(sfont, glyphs) < 0)
+ ERROR("Could not created FontFile stream.");
+ if (verbose > 1)
+ MESG("[%u glyphs (Max CID: %u)]", glyphs->num_glyphs, last_cid);
+ } else {
+ if (tt_get_metrics(sfont, glyphs) < 0)
+ ERROR("Reading glyph metrics failed...");
+ }
+
+ /*
+ * DW, W, DW2, and W2
+ */
+ if (opt_flags & CIDFONT_FORCE_FIXEDPITCH) {
+ pdf_add_dict(font->fontdict,
+ pdf_new_name("DW"), pdf_new_number(1000.0));
+ } else {
+ add_TTCIDHMetrics(font->fontdict, glyphs, used_chars, cidtogidmap, last_cid);
+ if (v_used_chars)
+ add_TTCIDVMetrics(font->fontdict, glyphs, used_chars, cidtogidmap, last_cid);
+ }
+
+ tt_build_finish(glyphs);
+
+ /* Finish here if not embedded. */
+ if (!CIDFont_get_embedding(font)) {
+ if (cidtogidmap)
+ RELEASE(cidtogidmap);
+ sfnt_close(sfont);
+ if (fp)
+ DPXFCLOSE(fp);
+
+ return;
+ }
+
+ /* Create font file */
+ for (i = 0; required_table[i].name; i++) {
+ if (sfnt_require_table(sfont,
+ required_table[i].name,
+ required_table[i].must_exist) < 0) {
+ ERROR("Some required TrueType table (%s) does not exist.", required_table[i].name);
+ }
+ }
+
+ /*
+ * FontFile2
+ */
+ fontfile = sfnt_create_FontFile_stream(sfont);
+
+ sfnt_close(sfont);
+ if (fp)
+ DPXFCLOSE(fp);
+
+ if (!fontfile)
+ ERROR("Could not created FontFile stream for \"%s\".", font->ident);
+
+ if (verbose > 1) {
+ MESG("[%ld bytes]", pdf_stream_length(fontfile));
+ }
+
+ pdf_add_dict(font->descriptor,
+ pdf_new_name("FontFile2"),
+ pdf_ref_obj (fontfile));
+ pdf_release_obj(fontfile);
+
+ /*
+ * CIDSet
+ */
+ {
+ pdf_obj *cidset;
+
+ cidset = pdf_new_stream(STREAM_COMPRESS);
+ pdf_add_stream(cidset, used_chars, last_cid/8 + 1);
+ pdf_add_dict(font->descriptor,
+ pdf_new_name("CIDSet"),
+ pdf_ref_obj(cidset));
+ pdf_release_obj(cidset);
+ }
+
+ /*
+ * CIDToGIDMap
+ */
+ if (cidtogidmap) {
+ pdf_obj *c2gmstream;
+
+ c2gmstream = pdf_new_stream(STREAM_COMPRESS);
+ pdf_add_stream(c2gmstream, cidtogidmap, (last_cid + 1) * 2);
+ pdf_add_dict(font->fontdict,
+ pdf_new_name("CIDToGIDMap"),
+ pdf_ref_obj (c2gmstream));
+ pdf_release_obj(c2gmstream);
+ RELEASE(cidtogidmap);
+ }
+
+ return;
+}
+
+int
+CIDFont_type2_open (CIDFont *font, const char *name,
+ CIDSysInfo *cmap_csi, cid_opt *opt)
+{
+ char *fontname;
+ sfnt *sfont;
+ unsigned long offset = 0;
+ FILE *fp = NULL;
+
+ ASSERT(font && opt);
+
+#ifdef XETEX
+ sfont = sfnt_open(font->ft_face, SFNT_TYPE_TTC | SFNT_TYPE_TRUETYPE);
+ if (!sfont)
+ return -1;
+#else
+ fp = DPXFOPEN(name, DPX_RES_TYPE_TTFONT);
+ if (!fp) {
+ fp = DPXFOPEN(name, DPX_RES_TYPE_DFONT);
+ if (!fp) return -1;
+ sfont = dfont_open(fp, opt->index);
+ } else {
+ sfont = sfnt_open(fp);
+ }
+
+ if (!sfont) {
+ DPXFCLOSE(fp);
+ return -1;
+ }
+#endif
+
+ switch (sfont->type) {
+ case SFNT_TYPE_TTC:
+ offset = ttc_read_offset(sfont, opt->index);
+ break;
+ case SFNT_TYPE_TRUETYPE:
+#ifdef XETEX
+ /* disable the check here becuase sfnt_open() does not distinguish dfont
+ * from regular trutype */
+#else
+ if (opt->index > 0)
+ ERROR("Invalid TTC index (not TTC font): %s", name);
+#endif
+ offset = 0;
+ break;
+ case SFNT_TYPE_DFONT:
+ offset = sfont->offset;
+ break;
+ default:
+ sfnt_close(sfont);
+ if (fp)
+ DPXFCLOSE(fp);
+ return -1;
+ break;
+ }
+
+ if (sfnt_read_table_directory(sfont, offset) < 0) {
+ ERROR("Reading TrueType table directory failed.");
+ }
+
+ {
+ char *shortname;
+ long namelen;
+
+ /* MAC-ROMAN-EN-POSTSCRIPT or WIN-UNICODE-EN(US)-POSTSCRIPT */
+ shortname = NEW(PDF_NAME_LEN_MAX, char);
+ namelen = tt_get_ps_fontname(sfont, shortname, PDF_NAME_LEN_MAX);
+ if (namelen == 0) {
+ memset(shortname, 0, PDF_NAME_LEN_MAX);
+ strncpy(shortname, name, PDF_NAME_LEN_MAX);
+ namelen = strlen(shortname);
+ }
+ validate_name(shortname, namelen); /* for SJIS, UTF-16, ... string */
+ /*
+ * Strlen works, after validate_named string.
+ * Mangled name requires more 7 bytes.
+ * Style requires more 11 bytes.
+ */
+ fontname = NEW(strlen(shortname)+19, char);
+ strcpy(fontname, shortname);
+ RELEASE(shortname);
+ }
+
+ if (opt->embed && opt->style != FONT_STYLE_NONE) {
+ WARN("Embedding disabled due to style option for %s.", name);
+ opt->embed = 0;
+ }
+ switch (opt->style) {
+ case FONT_STYLE_BOLD:
+ strcat(fontname, ",Bold");
+ break;
+ case FONT_STYLE_ITALIC:
+ strcat(fontname, ",Italic");
+ break;
+ case FONT_STYLE_BOLDITALIC:
+ strcat(fontname, ",BoldItalic");
+ break;
+ }
+ /*
+ * CIDSystemInfo is determined from CMap or from map record option.
+ */
+ font->fontname = fontname;
+ font->subtype = CIDFONT_TYPE2;
+ font->csi = NEW(1, CIDSysInfo);
+ if (opt->csi) {
+ if (cmap_csi) {
+ if (strcmp(opt->csi->registry, cmap_csi->registry) ||
+ strcmp(opt->csi->ordering, cmap_csi->ordering)) {
+ WARN("CID character collection mismatched:\n");
+ MESG("\tFont: %s-%s-%d\n",
+ opt->csi->registry, opt->csi->ordering, opt->csi->supplement);
+ MESG("\tCMap: %s-%s-%d\n",
+ cmap_csi->registry, cmap_csi->ordering, cmap_csi->supplement);
+ ERROR("Incompatible CMap specified for this font.");
+ }
+ if (opt->csi->supplement < cmap_csi->supplement) {
+ WARN("Supplmement value in CIDSystemInfo increased.");
+ WARN("Some characters may not shown.");
+ opt->csi->supplement = cmap_csi->supplement;
+ }
+ }
+ font->csi->registry = NEW(strlen(opt->csi->registry)+1, char);
+ strcpy(font->csi->registry, opt->csi->registry);
+ font->csi->ordering = NEW(strlen(opt->csi->ordering)+1, char);
+ strcpy(font->csi->ordering, opt->csi->ordering);
+ font->csi->supplement = opt->csi->supplement;
+ } else if (cmap_csi) {
+ font->csi->registry = NEW(strlen(cmap_csi->registry)+1, char);
+ strcpy(font->csi->registry, cmap_csi->registry);
+ font->csi->ordering = NEW(strlen(cmap_csi->ordering)+1, char);
+ strcpy(font->csi->ordering, cmap_csi->ordering);
+ font->csi->supplement = cmap_csi->supplement;
+ } else { /* This means font's internal glyph ordering. */
+ font->csi->registry = NEW(strlen("Adobe")+1, char);
+ strcpy(font->csi->registry, "Adobe");
+ font->csi->ordering = NEW(strlen("Identity")+1, char);
+ strcpy(font->csi->ordering, "Identity");
+ font->csi->supplement = 0;
+ }
+
+ font->fontdict = pdf_new_dict();
+ pdf_add_dict(font->fontdict,
+ pdf_new_name("Type"),
+ pdf_new_name("Font"));
+ pdf_add_dict(font->fontdict,
+ pdf_new_name("Subtype"),
+ pdf_new_name("CIDFontType2"));
+
+ font->descriptor = tt_get_fontdesc(sfont, &(opt->embed), opt->stemv, 0, name);
+ if (!font->descriptor) {
+ ERROR("Could not obtain necessary font info.");
+ }
+
+ if (opt->embed) {
+ memmove(fontname + 7, fontname, strlen(fontname) + 1);
+ pdf_font_make_uniqueTag(fontname);
+ fontname[6] = '+';
+ }
+
+ pdf_add_dict(font->descriptor,
+ pdf_new_name("FontName"),
+ pdf_new_name(fontname));
+ pdf_add_dict(font->fontdict,
+ pdf_new_name("BaseFont"),
+ pdf_new_name(fontname));
+
+ sfnt_close(sfont);
+ if (fp)
+ DPXFCLOSE(fp);
+
+ /*
+ * Don't write fontdict here.
+ * /Supplement in /CIDSystemInfo may change.
+ */
+
+ return 0;
+}
+
+void
+CIDFont_type2_release (CIDFont *font)
+{
+ return;
+}