diff options
author | Jonathan Kew <jfkthame@googlemail.com> | 2006-09-29 15:15:10 +0000 |
---|---|---|
committer | Jonathan Kew <jfkthame@googlemail.com> | 2006-09-29 15:15:10 +0000 |
commit | 387cf3625583fb046baf756f72f188924f35cfe2 (patch) | |
tree | 6e09f2e03b9c590a9f14689dfdb4d77ed66e773d /Build/source/texk/xdvipdfmx/src/tt_cmap.c | |
parent | fe77ff4cdab25604b424a273c726920830f63abc (diff) |
adding xdvipdfmx sources
git-svn-id: svn://tug.org/texlive/trunk@2220 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/xdvipdfmx/src/tt_cmap.c')
-rw-r--r-- | Build/source/texk/xdvipdfmx/src/tt_cmap.c | 1906 |
1 files changed, 1906 insertions, 0 deletions
diff --git a/Build/source/texk/xdvipdfmx/src/tt_cmap.c b/Build/source/texk/xdvipdfmx/src/tt_cmap.c new file mode 100644 index 00000000000..1681dad8230 --- /dev/null +++ b/Build/source/texk/xdvipdfmx/src/tt_cmap.c @@ -0,0 +1,1906 @@ +/* $Header: /home/cvsroot/dvipdfmx/src/tt_cmap.c,v 1.24 2005/07/08 14:18:05 hirata Exp $ + + This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team <dvipdfmx@project.ktug.or.kr> + + 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. +*/ + +/* + * A large part of codes are brought from ttfdump-0.5.5. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "system.h" +#include "mem.h" +#include "error.h" + +#include "sfnt.h" + + +/* Sorry for placing this here. + * We need to rewrite TrueType font support code... + */ +#include "cmap.h" +#include "cmap_write.h" + +#include "tt_aux.h" +#include "tt_gsub.h" +#include "tt_post.h" + +#include "unicode.h" +#include "agl.h" +#include "pdfparse.h" +#include "pdfresource.h" +#include "otl_conf.h" + +#include "dpxfile.h" + +/* Hash */ +#include "dpxutil.h" + +#include "tt_cmap.h" + +#define VERBOSE_LEVEL_MIN 0 +static int verbose = 0; +void +otf_cmap_set_verbose (void) +{ + otl_gsub_set_verbose(); + verbose++; +} + +/* format 0: byte encoding table */ +struct cmap0 +{ + BYTE glyphIndexArray[256]; +}; + +static struct cmap0 * +read_cmap0 (sfnt *sfont, ULONG len) +{ + struct cmap0 *map; + int i; + + if (len < 256) + ERROR("invalid cmap subtable"); + + map = NEW(1, struct cmap0); + + for (i = 0; i < 256; i++) + map->glyphIndexArray[i] = sfnt_get_byte(sfont); + + return map; +} + +static void +release_cmap0(struct cmap0 *map) +{ + if (map) + RELEASE(map); +} + +static USHORT +lookup_cmap0 (struct cmap0 *map, USHORT cc) +{ + return ((cc > 255) ? 0 : map->glyphIndexArray[cc]); +} + +/* format 2: high-byte mapping through table */ +struct SubHeader +{ + USHORT firstCode; + USHORT entryCount; + SHORT idDelta; + USHORT idRangeOffset; +}; + +struct cmap2 +{ + USHORT subHeaderKeys[256]; + struct SubHeader *subHeaders; + USHORT *glyphIndexArray; +}; + +static struct cmap2 * +read_cmap2 (sfnt *sfont, ULONG len) +{ + struct cmap2 *map; + USHORT i, n; + + if (len < 512) + ERROR("invalid cmap subtable"); + + map = NEW(1, struct cmap2); + + for (i = 0; i < 256; i++) + map->subHeaderKeys[i] = sfnt_get_ushort(sfont); + + for (n = 0, i = 0; i < 256; i++) { + map->subHeaderKeys[i] /= 8; + if (n < map->subHeaderKeys[i]) + n = map->subHeaderKeys[i]; + } + n += 1; /* the number of subHeaders is one plus the max of subHeaderKeys */ + + map->subHeaders = NEW(n, struct SubHeader); + for (i = 0; i < n; i++) { + map->subHeaders[i].firstCode = sfnt_get_ushort(sfont); + map->subHeaders[i].entryCount = sfnt_get_ushort(sfont); + map->subHeaders[i].idDelta = sfnt_get_short(sfont); + map->subHeaders[i].idRangeOffset = sfnt_get_ushort(sfont); + + /* It makes things easier to let the offset starts from + * the beginning of glyphIndexArray. + */ + if (map->subHeaders[i].idRangeOffset != 0) + map->subHeaders[i].idRangeOffset -= (2 + (n - i - 1) * 8); + } + + /* Caculate the length of glyphIndexArray, this is ugly, + * there should be a better way to get this information. + */ + n = (USHORT) (len - 518 - n * 8) / 2; + + map->glyphIndexArray = NEW(n, USHORT); + for (i = 0; i < n; i++) + map->glyphIndexArray[i] = sfnt_get_ushort(sfont); + + return map; +} + +static void +release_cmap2 (struct cmap2 *map) +{ + if (map) { + if (map->subHeaders) + RELEASE(map->subHeaders); + if (map->glyphIndexArray) + RELEASE(map->glyphIndexArray); + RELEASE(map); + } +} + +static USHORT +lookup_cmap2 (struct cmap2 *map, USHORT cc) +{ + USHORT idx = 0; + SHORT idDelta; + USHORT firstCode, entryCount, idRangeOffset; + int hi, lo; + USHORT i; + + hi = (cc >> 8) & 0xff; + lo = cc & 0xff; + + /* select which subHeader to use */ + i = map->subHeaderKeys[hi]; + + firstCode = map->subHeaders[i].firstCode; + entryCount = map->subHeaders[i].entryCount; + idDelta = map->subHeaders[i].idDelta; + idRangeOffset = map->subHeaders[i].idRangeOffset / 2; + + if (lo >= firstCode && + lo < firstCode + entryCount) { + idRangeOffset += lo - firstCode; + idx = map->glyphIndexArray[idRangeOffset]; + if (idx != 0) + idx = (idx + idDelta) & 0xffff; + } + + return idx; +} + +/* + * format 4: segment mapping to delta values + * - Microsoft standard character to glyph index mapping table + */ +struct cmap4 +{ + USHORT segCountX2; + USHORT searchRange; + USHORT entrySelector; + USHORT rangeShift; + USHORT *endCount; + USHORT reservedPad; + USHORT *startCount; + USHORT *idDelta; + USHORT *idRangeOffset; + USHORT *glyphIndexArray; +}; + +static struct cmap4 * +read_cmap4(sfnt *sfont, ULONG len) +{ + struct cmap4 *map; + USHORT i, n, segCount; + + if (len < 8) + ERROR("invalid cmap subtable"); + + map = NEW(1, struct cmap4); + + map->segCountX2 = segCount = sfnt_get_ushort(sfont); + map->searchRange = sfnt_get_ushort(sfont); + map->entrySelector = sfnt_get_ushort(sfont); + map->rangeShift = sfnt_get_ushort(sfont); + + segCount /= 2; + + map->endCount = NEW(segCount, USHORT); + for (i = 0; i < segCount; i++) + map->endCount[i] = sfnt_get_ushort(sfont); + + map->reservedPad = sfnt_get_ushort(sfont); + + map->startCount = NEW(segCount, USHORT); + for (i = 0; i < segCount; i++) + map->startCount[i] = sfnt_get_ushort(sfont); + + map->idDelta = NEW(segCount, USHORT); + for (i = 0; i < segCount; i++) + map->idDelta[i] = sfnt_get_ushort(sfont); + + map->idRangeOffset = NEW(segCount, USHORT); + for (i = 0; i < segCount; i++) + map->idRangeOffset[i] = sfnt_get_ushort(sfont); + + n = (len - 16 - 8 * segCount) / 2; + if (n == 0) + map->glyphIndexArray = NULL; + else { + map->glyphIndexArray = NEW(n, USHORT); + for (i = 0; i < n; i++) + map->glyphIndexArray[i] = sfnt_get_ushort(sfont); + } + + return map; +} + +static void +release_cmap4 (struct cmap4 *map) +{ + if (map) { + if (map->endCount) RELEASE(map->endCount); + if (map->startCount) RELEASE(map->startCount); + if (map->idDelta) RELEASE(map->idDelta); + if (map->idRangeOffset) RELEASE(map->idRangeOffset); + if (map->glyphIndexArray) RELEASE(map->glyphIndexArray); + RELEASE(map); + } +} + +static USHORT +lookup_cmap4 (struct cmap4 *map, USHORT cc) +{ + USHORT gid = 0; + USHORT i, j, segCount; + + /* + * Segments are sorted in order of increasing endCode values. + * Last segment maps 0xffff to gid 0 (?) + */ + i = segCount = map->segCountX2 / 2; + while (i-- > 0 && cc <= map->endCount[i]) { + if (cc >= map->startCount[i]) { + if (map->idRangeOffset[i] == 0) { + gid = (cc + map->idDelta[i]) & 0xffff; + } else { + j = map->idRangeOffset[i] - (segCount - i) * 2; + j = (cc - map->startCount[i]) + (j / 2); + gid = map->glyphIndexArray[j]; + if (gid != 0) + gid = (gid + map->idDelta[i]) & 0xffff; + } + break; + } + } + + return gid; +} + +/* format 6: trimmed table mapping */ +struct cmap6 +{ + USHORT firstCode; + USHORT entryCount; + USHORT *glyphIndexArray; +}; + +static struct cmap6 * +read_cmap6 (sfnt *sfont, ULONG len) +{ + struct cmap6 *map; + USHORT i; + + if (len < 4) + ERROR("invalid cmap subtable"); + + map = NEW(1, struct cmap6); + map->firstCode = sfnt_get_ushort(sfont); + map->entryCount = sfnt_get_ushort(sfont); + map->glyphIndexArray = NEW(map->entryCount, USHORT); + + for (i = 0; i < map->entryCount; i++) + map->glyphIndexArray[i] = sfnt_get_ushort(sfont); + + return map; +} + +static void +release_cmap6 (struct cmap6 *map) +{ + if (map) { + if (map->glyphIndexArray) + RELEASE(map->glyphIndexArray); + RELEASE(map); + } +} + +static USHORT +lookup_cmap6 (struct cmap6 *map, USHORT cc) +{ + USHORT idx; + + idx = cc - map->firstCode; + if (idx < map->entryCount) + return map->glyphIndexArray[idx]; + else + return 0; + + return 0; +} + +/* Format 8 and 10 not supported... + * + * format 8: mixed 16-bit and 32-bit coverage + * format 10: trimmed array + */ + +/* + * format 12: segmented coverage + * + * startGlyphID is 32-bit long, however, GlyphID is still 16-bit long ! + */ + +struct charGroup +{ + ULONG startCharCode; + ULONG endCharCode; + ULONG startGlyphID; +}; + +struct cmap12 +{ + ULONG nGroups; + struct charGroup *groups; +}; + +/* ULONG length */ +static struct cmap12 * +read_cmap12 (sfnt *sfont, ULONG len) +{ + struct cmap12 *map; + ULONG i; + + if (len < 4) + ERROR("invalid cmap subtable"); + + map = NEW(1, struct cmap12); + map->nGroups = sfnt_get_ulong(sfont); + map->groups = NEW(map->nGroups, struct charGroup); + + for (i = 0; i < map->nGroups; i++) { + map->groups[i].startCharCode = sfnt_get_ulong(sfont); + map->groups[i].endCharCode = sfnt_get_ulong(sfont); + map->groups[i].startGlyphID = sfnt_get_ulong(sfont); + } + + return map; +} + +static void +release_cmap12 (struct cmap12 *map) +{ + if (map) { + if (map->groups) + RELEASE(map->groups); + RELEASE(map); + } +} + +static USHORT +lookup_cmap12 (struct cmap12 *map, ULONG cccc) +{ + USHORT gid = 0; + ULONG i; + + i = map->nGroups; + while (i-- >= 0 && + cccc <= map->groups[i].endCharCode) { + if (cccc >= map->groups[i].startCharCode) { + gid = (USHORT) ((cccc - + map->groups[i].startCharCode + + map->groups[i].startGlyphID) & 0xffff); + break; + } + } + + return gid; +} + +/* read cmap */ +tt_cmap * +tt_cmap_read (sfnt *sfont, USHORT platform, USHORT encoding) +{ + tt_cmap *cmap = NULL; + ULONG offset, length = 0; + USHORT version, p_id, e_id; + USHORT i, n_subtabs; + + ASSERT(sfont); + + offset = sfnt_locate_table(sfont, "cmap"); + version = sfnt_get_ushort(sfont); + n_subtabs = sfnt_get_ushort(sfont); + + for (i = 0; i < n_subtabs; i++) { + p_id = sfnt_get_ushort(sfont); + e_id = sfnt_get_ushort(sfont); + if (p_id != platform || e_id != encoding) + sfnt_get_ulong(sfont); + else { + offset += sfnt_get_ulong(sfont); + break; + } + } + + if (i == n_subtabs) + return NULL; + + cmap = NEW(1, tt_cmap); + cmap->map = NULL; + cmap->platform = platform; + cmap->encoding = encoding; + + sfnt_seek_set(sfont, offset); + cmap->format = sfnt_get_ushort(sfont); + /* Length and version (language) is ULONG for + * format 8, 10, 12 ! + */ + if (cmap->format <= 6) { + length = sfnt_get_ushort(sfont); + cmap->language = sfnt_get_ushort(sfont); /* language (Mac) */ + } else { + if (sfnt_get_ushort(sfont) != 0) { /* reverved - 0 */ + WARN("Unrecognized cmap subtable format."); + tt_cmap_release(cmap); + return NULL; + } else { + length = sfnt_get_ulong(sfont); + cmap->language = sfnt_get_ulong(sfont); + } + } + + switch(cmap->format) { + case 0: + cmap->map = read_cmap0(sfont, length); + break; + case 2: + cmap->map = read_cmap2(sfont, length); + break; + case 4: + cmap->map = read_cmap4(sfont, length); + break; + case 6: + cmap->map = read_cmap6(sfont, length); + break; + case 12: + /*WARN("UCS-4 TrueType cmap table...");*/ + cmap->map = read_cmap12(sfont, length); + break; + default: + WARN("Unrecognized TrueType cmap format."); + tt_cmap_release(cmap); + return NULL; + } + + if (!cmap->map) { + tt_cmap_release(cmap); + cmap = NULL; + } + + return cmap; +} + +void +tt_cmap_release (tt_cmap *cmap) +{ + + if (cmap) { + if (cmap->map) { + switch(cmap->format) { + case 0: + release_cmap0(cmap->map); + break; + case 2: + release_cmap2(cmap->map); + break; + case 4: + release_cmap4(cmap->map); + break; + case 6: + release_cmap6(cmap->map); + break; + case 12: + release_cmap12(cmap->map); + break; + default: + ERROR("Unrecognized TrueType cmap format."); + } + } + RELEASE(cmap); + } + + return; +} + + +USHORT +tt_cmap_lookup (tt_cmap *cmap, long cc) +{ + USHORT gid = 0; + + ASSERT(cmap); + + if (cc > 0xffffL && cmap->format < 12) { + WARN("Four bytes charcode not supported in TrueType cmap format 0...6."); + return 0; + } + + switch (cmap->format) { + case 0: + gid = lookup_cmap0(cmap->map, (USHORT) cc); + break; + case 2: + gid = lookup_cmap2(cmap->map, (USHORT) cc); + break; + case 4: + gid = lookup_cmap4(cmap->map, (USHORT) cc); + break; + case 6: + gid = lookup_cmap6(cmap->map, (USHORT) cc); + break; + case 12: + gid = lookup_cmap12(cmap->map, (ULONG) cc); + break; + default: + ERROR("Unrecognized TrueType cmap subtable format"); + break; + } + + return gid; +} + +/* Sorry for placing this here. + * We need to rewrite TrueType font support code... + */ + +#define WBUF_SIZE 1024 +static unsigned char wbuf[WBUF_SIZE]; + +static unsigned char srange_min[2] = {0x00, 0x00}; +static unsigned char srange_max[2] = {0xff, 0xff}; +static unsigned char lrange_min[4] = {0x00, 0x00, 0x00, 0x00}; +static unsigned char lrange_max[4] = {0x7f, 0xff, 0xff, 0xff}; + +static void +load_cmap4 (struct cmap4 *map, + unsigned char *GIDToCIDMap, CMap *cmap) +{ + USHORT c0, c1, gid, cid; + USHORT j, d, segCount; + USHORT ch; + long i; + + segCount = map->segCountX2 / 2; + for (i = segCount - 1; i >= 0 ; i--) { + c0 = map->startCount[i]; + c1 = map->endCount[i]; + d = map->idRangeOffset[i] / 2 - (segCount - i); + for (j = 0; j <= c1 - c0; j++) { + ch = c0 + j; + if (map->idRangeOffset[i] == 0) { + gid = (ch + map->idDelta[i]) & 0xffff; + } else { + gid = (map->glyphIndexArray[j+d] + + map->idDelta[i]) & 0xffff; + } + if (gid != 0 && gid != 0xffff) { + if (GIDToCIDMap) { + cid = ((GIDToCIDMap[2*gid] << 8)|GIDToCIDMap[2*gid+1]); + if (cid == 0) + WARN("GID %u does not have corresponding CID %u.", + gid, cid); + } else { + cid = gid; + } + wbuf[0] = 0; + wbuf[1] = 0; + wbuf[2] = (ch >> 8) & 0xff; + wbuf[3] = ch & 0xff; + CMap_add_cidchar(cmap, wbuf, 4, cid); + } + } + } + + return; +} + +static void +load_cmap12 (struct cmap12 *map, + unsigned char *GIDToCIDMap, CMap *cmap) +{ + ULONG i, ch; /* LONG ? */ + USHORT gid, cid; + + for (i = 0; i < map->nGroups; i++) { + for (ch = map->groups[i].startCharCode; + ch <= map->groups[i].endCharCode; + ch++) { + long d = ch - map->groups[i].startCharCode; + gid = (USHORT) ((map->groups[i].startGlyphID + d) & 0xffff); + if (GIDToCIDMap) { + cid = ((GIDToCIDMap[2*gid] << 8)|GIDToCIDMap[2*gid+1]); + if (cid == 0) + WARN("GID %u does not have corresponding CID %u.", gid, cid); + } else { + cid = gid; + } + wbuf[0] = (ch >> 24) & 0xff; + wbuf[1] = (ch >> 16) & 0xff; + wbuf[2] = (ch >> 8) & 0xff; + wbuf[3] = ch & 0xff; + CMap_add_cidchar(cmap, wbuf, 4, cid); + } + } + + return; +} + +/* OpenType CIDFont: + * + * We don't use GID for them. OpenType cmap table is for + * charcode to GID mapping rather than to-CID mapping. + */ +#include "cid.h" + +#include "tt_table.h" +#include "cff_types.h" +#include "cff_dict.h" +#include "cff.h" + +static int +handle_CIDFont (sfnt *sfont, + unsigned char **GIDToCIDMap, CIDSysInfo *csi) +{ + cff_font *cffont; + long offset, i; + card16 num_glyphs, gid; + cff_charsets *charset; + unsigned char *map; + struct tt_maxp_table *maxp; + + ASSERT(csi); + + offset = sfnt_find_table_pos(sfont, "CFF "); + if (offset == 0) { + csi->registry = NULL; + csi->ordering = NULL; + *GIDToCIDMap = NULL; + return 0; + } + + maxp = tt_read_maxp_table(sfont); + num_glyphs = (card16) maxp->numGlyphs; + RELEASE(maxp); + if (num_glyphs < 1) + ERROR("No glyph contained in this font..."); + + cffont = cff_open(sfont, offset, 0); + if (!cffont) + ERROR("Could not open CFF font..."); + + + if (!(cffont->flag & FONTTYPE_CIDFONT)) { + cff_close(cffont); + csi->registry = NULL; + csi->ordering = NULL; + *GIDToCIDMap = NULL; + return 0; + } + + if (!cff_dict_known(cffont->topdict, "ROS")) { + ERROR("No CIDSystemInfo???"); + } else { + card16 reg, ord; + + reg = (card16) cff_dict_get(cffont->topdict, "ROS", 0); + ord = (card16) cff_dict_get(cffont->topdict, "ROS", 1); + + csi->registry = cff_get_string(cffont, reg); + csi->ordering = cff_get_string(cffont, ord); + csi->supplement = (int) cff_dict_get(cffont->topdict, "ROS", 2); + } + + cff_read_charsets(cffont); + charset = cffont->charsets; + if (!charset) { + ERROR("No CFF charset data???"); + } + + map = NEW(num_glyphs * 2, unsigned char); + memset(map, 0, num_glyphs * 2); + switch (charset->format) { + case 0: + { + s_SID *cids; /* CID... */ + + cids = charset->data.glyphs; + for (gid = 1, i = 0; + i < charset->num_entries; i++) { + map[2*gid ] = (cids[i] >> 8) & 0xff; + map[2*gid+1] = cids[i] & 0xff; + gid++; + } + } + break; + case 1: + { + cff_range1 *ranges; + card16 cid, count; + + ranges = charset->data.range1; + for (gid = 1, i = 0; + i < charset->num_entries; i++) { + cid = ranges[i].first; + count = ranges[i].n_left + 1; /* card8 */ + while (count-- > 0 && + gid <= num_glyphs) { + map[2*gid ] = (cid >> 8) & 0xff; + map[2*gid + 1] = cid & 0xff; + gid++; + } + } + } + break; + case 2: + { + cff_range2 *ranges; + card16 cid, count; + + ranges = charset->data.range2; + if (charset->num_entries == 1 && + ranges[0].first == 1) { + /* "Complete" CIDFont */ + RELEASE(map); map = NULL; + } else { + /* Not trivial mapping */ + for (gid = 1, i = 0; + i < charset->num_entries; i++) { + cid = ranges[i].first; + count = ranges[i].n_left + 1; + while (count-- > 0 && + gid <= num_glyphs) { + map[gid] = (cid >> 8) & 0xff; + map[gid] = cid & 0xff; + gid++; + } + } + + } + } + break; + default: + RELEASE(map); map = NULL; + ERROR("Unknown CFF charset format...: %d", charset->format); + break; + } + cff_close(cffont); + + *GIDToCIDMap = map; + return 1; +} + +/* + * Substituted glyphs: + * + * Mapping information stored in cmap_add. + */ +#ifndef is_used_char2 +#define is_used_char2(b,c) (((b)[(c)/8]) & (1 << (7-((c)%8)))) +#endif + +static USHORT +handle_subst_glyphs (CMap *cmap, + CMap *cmap_add, const char *used_glyphs, + struct tt_post_table *post) +{ + USHORT count; + USHORT i, gid; + long ucv; + + for (count = 0, i = 0; i < 8192; i++) { + int j; + long len, inbytesleft, outbytesleft; + unsigned char *inbuf, *outbuf; + + if (used_glyphs[i] == 0) + continue; + + for (j = 0; j < 8; j++) { + gid = 8 * i + j; + + if (!is_used_char2(used_glyphs, gid)) + continue; + + if (!cmap_add && post) { + /* JK: try to look up Unicode values from the glyph name... + requires access to 'post' table */ +#define MAX_UNICODES 16 + long unicodes[MAX_UNICODES]; + int unicode_count = -1; + int k; + if (gid < post->numberOfGlyphs) { + unicode_count = agl_get_unicodes(post->glyphNamePtr[gid], unicodes, MAX_UNICODES); + } + if (unicode_count == -1) + WARN("No Unicode mapping available: GID=%u, name=%s", gid, + gid < post->numberOfGlyphs ? post->glyphNamePtr[gid] : "(none)"); + else { + /* the Unicode characters go into wbuf[2] and following, in UTF16BE */ + /* we rely on WBUF_SIZE being more than adequate for MAX_UNICODES */ + unsigned char* p = wbuf + 2; + len = 0; + for (k = 0; k < unicode_count; ++k) { + len += UC_sput_UTF16BE(unicodes[k], &p, wbuf+WBUF_SIZE); + } + CMap_add_bfchar(cmap, wbuf, 2, wbuf + 2, len); + } + } + else { + wbuf[0] = (gid >> 8) & 0xff; + wbuf[1] = gid & 0xff; + inbuf = wbuf; + inbytesleft = 2; + outbuf = inbuf + 2; + outbytesleft = WBUF_SIZE - 2; + CMap_decode(cmap_add, + (const unsigned char **) &inbuf , &inbytesleft, + &outbuf, &outbytesleft); + if (inbytesleft != 0) { + WARN("CMap conversion failed..."); + } else { + len = WBUF_SIZE - 2 - outbytesleft; + CMap_add_bfchar(cmap, wbuf, 2, wbuf + 2, len); + count++; + + if (verbose > VERBOSE_LEVEL_MIN) { + long _i; + + MESG("otf_cmap>> Additional ToUnicode mapping: <%04X> <", gid); + for (_i = 0; _i < len; _i++) { + MESG("%02X", wbuf[2 + _i]); + } + MESG(">\n"); + } + + } + } + + } + } + + return count; +} + +static pdf_obj * +create_ToUnicode_cmap4 (struct cmap4 *map, + const char *cmap_name, CMap *cmap_add, + const char *used_glyphs, + struct tt_post_table *post) +{ + pdf_obj *stream = NULL; + CMap *cmap; + USHORT c0, c1, gid, count, ch; + USHORT i, j, d, segCount; + char used_glyphs_copy[8192]; + + cmap = CMap_new(); + CMap_set_name (cmap, cmap_name); + CMap_set_wmode(cmap, 0); + CMap_set_type (cmap, CMAP_TYPE_TO_UNICODE); + CMap_set_CIDSysInfo(cmap, &CSI_UNICODE); + CMap_add_codespacerange(cmap, srange_min, srange_max, 2); + + memcpy(used_glyphs_copy, used_glyphs, 8192); + + segCount = map->segCountX2 / 2; + for (count = 0, i = 0; i < segCount; i++) { + c0 = map->startCount[i]; + c1 = map->endCount[i]; + d = map->idRangeOffset[i] / 2 - (segCount - i); + for (j = 0; j <= c1 - c0; j++) { + ch = c0 + j; + if (map->idRangeOffset[i] == 0) { + gid = (ch + map->idDelta[i]) & 0xffff; + } else { + gid = (map->glyphIndexArray[j+d] + + map->idDelta[i]) & 0xffff; + } + if (is_used_char2(used_glyphs_copy, gid)) { + count++; + + wbuf[0] = (gid >> 8) & 0xff; + wbuf[1] = (gid & 0xff); + + wbuf[2] = (ch >> 8) & 0xff; + wbuf[3] = ch & 0xff; + + CMap_add_bfchar(cmap, wbuf, 2, wbuf+2, 2); + + /* Avoid duplicate entry + * There are problem when two Unicode code is mapped to + * single glyph... + */ + used_glyphs_copy[gid/8] &= ~(1 << (7 - (gid % 8))); + count++; + } + } + } + + count += handle_subst_glyphs(cmap, cmap_add, used_glyphs_copy, post); + + if (count < 1) + stream = NULL; + else { + stream = CMap_create_stream(cmap, 0); + } + CMap_release(cmap); + + return stream; +} + + +static pdf_obj * +create_ToUnicode_cmap12 (struct cmap12 *map, + const char *cmap_name, CMap *cmap_add, + const char *used_glyphs, + struct tt_post_table *post) +{ + pdf_obj *stream = NULL; + CMap *cmap; + ULONG i, ch; + USHORT gid, count; + char used_glyphs_copy[8192]; + + cmap = CMap_new(); + CMap_set_name (cmap, cmap_name); + CMap_set_wmode(cmap, 0); + CMap_set_type (cmap, CMAP_TYPE_TO_UNICODE); + CMap_set_CIDSysInfo(cmap, &CSI_UNICODE); + CMap_add_codespacerange(cmap, srange_min, srange_max, 2); + + memcpy(used_glyphs_copy, used_glyphs, 8192); + for (count = 0, i = 0; i < map->nGroups; i++) { + for (ch = map->groups[i].startCharCode; + ch <= map->groups[i].endCharCode; ch++) { + unsigned char *p; + int len; + long d; + + p = wbuf + 2; + d = ch - map->groups[i].startCharCode; + gid = (USHORT) ((map->groups[i].startGlyphID + d) & 0xffff); + if (is_used_char2(used_glyphs_copy, gid)) { + count++; + wbuf[0] = (gid >> 8) & 0xff; + wbuf[1] = (gid & 0xff); + len = UC_sput_UTF16BE((long)ch, &p, wbuf+WBUF_SIZE); + + used_glyphs_copy[gid/8] &= ~(1 << (7 - (gid % 8))); + CMap_add_bfchar(cmap, wbuf, 2, wbuf+2, len); + } + } + } + + count += handle_subst_glyphs(cmap, cmap_add, used_glyphs_copy, post); + + if (count < 1) + stream = NULL; + else { + stream = CMap_create_stream(cmap, 0); + } + CMap_release(cmap); + + return stream; +} + +typedef struct { + short platform; + short encoding; +} cmap_plat_enc_rec; + +static cmap_plat_enc_rec cmap_plat_encs[] = { + { 3, 10 }, + { 0, 3 }, + { 0, 0 }, + { 3, 1 }, + { 0, 1 } +}; + +pdf_obj * +otf_create_ToUnicode_stream (const char *font_name, + int ttc_index, /* 0 for non-TTC */ + FT_Face face, + const char *used_glyphs) +{ + pdf_obj *cmap_ref = NULL; + long res_id; + pdf_obj *cmap_obj = NULL; + CMap *cmap_add; + int cmap_add_id; + tt_cmap *ttcmap; + char *cmap_name; + FILE *fp = NULL; + sfnt *sfont; + long offset = 0; + struct tt_post_table *ttpost = NULL; + int i; + + cmap_name = NEW(strlen(font_name)+strlen("-UTF16")+5, char); + sprintf(cmap_name, "%s,%03d-UTF16", font_name, ttc_index); + + res_id = pdf_findresource("CMap", cmap_name); + if (res_id >= 0) { + RELEASE(cmap_name); + cmap_ref = pdf_get_resource_reference(res_id); + return cmap_ref; + } + + if (verbose > VERBOSE_LEVEL_MIN) { + MESG("\n"); + MESG("otf_cmap>> Creating ToUnicode CMap for \"%s\"...\n", font_name); + } + +#ifdef XETEX + sfont = sfnt_open(face, -1); +#else + fp = DPXFOPEN(font_name, DPX_RES_TYPE_TTFONT); + if (!fp) { + fp = DPXFOPEN(font_name, DPX_RES_TYPE_OTFONT); + } + + if (!fp) { + RELEASE(cmap_name); + return NULL; + } + + sfont = sfnt_open(fp); +#endif + + if (!sfont) { + ERROR("Could not open TrueType font file \"%s\"", font_name); + } + + switch (sfont->type) { + case SFNT_TYPE_TTC: + offset = ttc_read_offset(sfont, ttc_index); + if (offset == 0) { + ERROR("Invalid TTC index"); + } + break; + default: + offset = 0; + break; + } + + if (sfnt_read_table_directory(sfont, offset) < 0) { + ERROR("Could not read TrueType table directory."); + } + + cmap_add_id = CMap_cache_find(cmap_name); + if (cmap_add_id < 0) { + cmap_add = NULL; + } else { + cmap_add = CMap_cache_get(cmap_add_id); + } + + ttpost = tt_read_post_table(sfont); + + CMap_set_silent(1); /* many warnings without this... */ + for (i = 0; i < sizeof(cmap_plat_encs) / sizeof(cmap_plat_enc_rec); ++i) { + ttcmap = tt_cmap_read(sfont, cmap_plat_encs[i].platform, cmap_plat_encs[i].encoding); + if (!ttcmap) + continue; + if (ttcmap->format == 4) { + cmap_obj = create_ToUnicode_cmap4(ttcmap->map, + cmap_name, cmap_add, used_glyphs, ttpost); + break; + } + if (ttcmap->format == 12) { + cmap_obj = create_ToUnicode_cmap12(ttcmap->map, + cmap_name, cmap_add, used_glyphs, ttpost); + break; + } + } + if (cmap_obj == NULL) + WARN("Unable to read TrueType Unicode cmap table."); + tt_cmap_release(ttcmap); + CMap_set_silent(0); + + if (ttpost != NULL) + tt_release_post_table(ttpost); + + if (cmap_obj) { + res_id = pdf_defineresource("CMap", cmap_name, + cmap_obj, PDF_RES_FLUSH_IMMEDIATE); + cmap_ref = pdf_get_resource_reference(res_id); + } else { + cmap_ref = NULL; + } + RELEASE(cmap_name); + + sfnt_close(sfont); + if (fp) + DPXFCLOSE(fp); + + return cmap_ref; +} + +/* Must be smaller than (WBUF_SIZE-2)/8 */ +#define MAX_UNICODES 16 + +struct gent +{ + USHORT gid; + long ucv; /* assigned PUA unicode */ + + int num_unicodes; + long unicodes[MAX_UNICODES]; +}; + +static void +create_cmaps (CMap *cmap, CMap *tounicode, + struct ht_table *unencoded, unsigned char *GIDToCIDMap) +{ + struct ht_iter iter; + + ASSERT(cmap && unencoded); + + if (ht_set_iter(unencoded, &iter) < 0) + return; + + CMap_set_silent(1); /* many warnings without this... */ + + do { + struct gent *glyph; + unsigned char *ucv; + int i, len; + unsigned char *p, *endptr; + CID cid; + + glyph = (struct gent *) ht_iter_getval(&iter); + ucv = (unsigned char *) ht_iter_getkey(&iter, &len); + + if (GIDToCIDMap) { + cid = ((GIDToCIDMap[2 * glyph->gid] << 8)|GIDToCIDMap[2 * glyph->gid + 1]); + if (cid == 0) + WARN("Glyph gid=%u does not have corresponding CID.", glyph->gid); + } else { + cid = glyph->gid; + } + + CMap_add_cidchar(cmap, ucv, 4, cid); + + if (tounicode) { + wbuf[0] = (cid >> 8) & 0xff; + wbuf[1] = cid & 0xff; + p = wbuf + 2; + endptr = wbuf + WBUF_SIZE; + len = 0; + for (i = 0; i < glyph->num_unicodes; i++) { + len += UC_sput_UTF16BE(glyph->unicodes[i], &p, endptr); + } + CMap_add_bfchar(tounicode, wbuf, 2, wbuf + 2, len); + } + } while (ht_iter_next(&iter) >= 0); + + CMap_set_silent(0); + + ht_clear_iter(&iter); +} + +static void +add_glyph (struct ht_table *unencoded, + USHORT gid, long ucv, int num_unicodes, long *unicodes) +{ + struct gent *glyph; + int i; + + ASSERT(unencoded); + + if (gid == 0 || num_unicodes < 1) { + return; + } + + wbuf[0] = (ucv >> 24) & 0xff; + wbuf[1] = (ucv >> 16) & 0xff; + wbuf[2] = (ucv >> 8) & 0xff; + wbuf[3] = ucv & 0xff; + + glyph = NEW(1, struct gent); + glyph->gid = gid; + glyph->num_unicodes = num_unicodes; + for (i = 0; + i < num_unicodes && i < MAX_UNICODES; i++) { + glyph->unicodes[i] = unicodes[i]; + } + + ht_append_table(unencoded, wbuf, 4, glyph); +} + +/* This seriously affects speed... */ +static struct gent * +find_glyph (struct ht_table *unencoded, long ucv) +{ + ASSERT(unencoded); + + wbuf[0] = (ucv >> 24) & 0xff; + wbuf[1] = (ucv >> 16) & 0xff; + wbuf[2] = (ucv >> 8) & 0xff; + wbuf[3] = ucv & 0xff; + + return (struct gent *) ht_lookup_table(unencoded, wbuf, 4); +} + +static void +handle_subst (pdf_obj *dst_obj, pdf_obj *src_obj, int flag, + otl_gsub *gsub_list, tt_cmap *ttcmap, + struct ht_table *unencoded) +{ + pdf_obj *tmp; + long i, j, src_size, dst_size; + long src, dst; + long src_start, src_end, dst_start, dst_end; + + src_size = pdf_array_length(src_obj); + dst_size = pdf_array_length(dst_obj); + + dst_start = dst_end = -1; dst = 0; + src_start = src_end = -1; src = 0; + for (i = 0, j = 0; + i < src_size && j < dst_size; i++) { + USHORT gid; + int rv; + struct gent *glyph; + + tmp = pdf_get_array(src_obj, i); + if (PDF_OBJ_ARRAYTYPE(tmp)) { + src_start = (long) pdf_number_value(pdf_get_array(tmp, 0)); + src_end = (long) pdf_number_value(pdf_get_array(tmp, 1)); + } else { + src_start = src_end = (long) pdf_number_value(tmp); + } + for (src = src_start; src <= src_end; src++) { + glyph = find_glyph(unencoded, src); + if (glyph) + gid = glyph->gid; + else { + gid = tt_cmap_lookup(ttcmap, src); + } + dst++; + if (dst > dst_end) { + tmp = pdf_get_array(dst_obj, j++); + if (PDF_OBJ_ARRAYTYPE(tmp)) { + dst_start = (long) pdf_number_value(pdf_get_array(tmp, 0)); + dst_end = (long) pdf_number_value(pdf_get_array(tmp, 1)); + } else { + dst_start = dst_end = (long) pdf_number_value(tmp); + } + dst = dst_start; + } + if (gid == 0) { + if (flag == 'r' || flag == 'p') { + if (src < 0x10000) { + WARN("Font does not have glyph for U+%04X.", src); + } else { + WARN("Font does not have glyph for U+%06X.", src); + } + } + if (flag == 'r') { + ERROR("Missing glyph found..."); + } + continue; + } + rv = otl_gsub_apply(gsub_list, &gid); + if (rv < 0) { + if (flag == 'p' || flag == 'r') { + if (src < 0x10000) { + WARN("No substituted glyph for U+%04X.", src); + } else { + WARN("No substituted glyph for U+%06X.", src); + } + } + if (flag == 'r') { + ERROR("Missing glyph found..."); + } + continue; + } + + if (glyph) { + glyph->gid = gid; + } else { + add_glyph(unencoded, gid, dst, 1, &src); + } + + if (verbose > VERBOSE_LEVEL_MIN) { + if (dst < 0x10000) { + MESG("otf_cmap>> Substituted glyph gid=%u assigned to U+%04X\n", + gid, dst); + } else { + MESG("otf_cmap>> Substituted glyph gid=%u assigned to U+%06X\n", + gid, dst); + } + } + + } + } + + if (dst < dst_end || src < src_end || + i < src_size || j < dst_size) { + WARN("Number of glyphs in left-side and right-side not equal..."); + WARN("Please check .otl file..."); + } +} + +static void +handle_assign (pdf_obj *dst, pdf_obj *src, int flag, + otl_gsub *gsub_list, tt_cmap *ttcmap, + struct ht_table *unencoded) +{ + long unicodes[MAX_UNICODES], ucv; + int i, n_unicodes, rv; + USHORT gid_in[MAX_UNICODES], lig; + + n_unicodes = pdf_array_length(src); /* FIXME */ + ucv = (long) pdf_number_value(pdf_get_array(dst, 0)); /* FIXME */ + if (!UC_is_valid(ucv)) { + if (flag == 'r' || flag == 'p') { + if (ucv < 0x10000) { + WARN("Invalid Unicode in: %04X", ucv); + } else { + WARN("Invalid Unicode in: %06X", ucv); + } + } + if (flag == 'r') { + ERROR("Invalid Unicode code specified.", ucv); + } + return; + } + + if (verbose > VERBOSE_LEVEL_MIN) { + MESG("otf_cmap>> Ligature component:"); + } + + for (i = 0; i < n_unicodes; i++) { + unicodes[i] = + (long) pdf_number_value(pdf_get_array(src, i)); + gid_in[i] = tt_cmap_lookup(ttcmap, unicodes[i]); + + if (verbose > VERBOSE_LEVEL_MIN) { + if (unicodes[i] < 0x10000) { + MESG(" U+%04X (gid=%u)", unicodes[i], gid_in[i]); + } else { + MESG(" U+%06X (gid=%u)", unicodes[i], gid_in[i]); + } + } + + if (gid_in[i] == 0) { + if (flag == 'r' || flag == 'p') { + if (unicodes[i] < 0x10000) { + WARN("Unicode char U+%04X not exist in font...", unicodes[i]); + } else { + WARN("Unicode char U+%06X not exist in font...", unicodes[i]); + } + } + if (flag == 'r') { + ERROR("Missing glyph found..."); + } + return; + } + + } + + if (verbose > VERBOSE_LEVEL_MIN) { + MESG("\n"); + } + + rv = otl_gsub_apply_lig(gsub_list, + gid_in, n_unicodes, &lig); + if (rv < 0) { + if (flag == 'p') + WARN("No ligature found..."); + else if (flag == 'r') + ERROR("No ligature found..."); + return; + } + + add_glyph(unencoded, lig, ucv, n_unicodes, unicodes); + + if (verbose > VERBOSE_LEVEL_MIN) { + if (ucv < 0x10000) { + MESG("otf_cmap>> Ligature glyph gid=%u assigned to U+%04X\n", lig, ucv); + } else { + MESG("otf_cmap>> Ligature glyph gid=%u assigned to U+%06X\n", lig, ucv); + } + } + + return; +} + +static int +load_base_CMap (const char *cmap_name, int wmode, + CIDSysInfo *csi, unsigned char *GIDToCIDMap, + tt_cmap *ttcmap) +{ + int cmap_id; + + cmap_id = CMap_cache_find(cmap_name); + if (cmap_id < 0) { + CMap *cmap; + + cmap = CMap_new(); + CMap_set_name (cmap, cmap_name); + CMap_set_type (cmap, CMAP_TYPE_CODE_TO_CID); + CMap_set_wmode(cmap, wmode); + CMap_add_codespacerange(cmap, lrange_min, lrange_max, 4); + + if (csi) { /* CID */ + CMap_set_CIDSysInfo(cmap, csi); + } else { + CMap_set_CIDSysInfo(cmap, &CSI_IDENTITY); + } + + if (ttcmap->format == 12) { + load_cmap12(ttcmap->map, GIDToCIDMap, cmap); + } else if (ttcmap->format == 4) { + load_cmap4(ttcmap->map, GIDToCIDMap, cmap); + } + + cmap_id = CMap_cache_add(cmap); + } + + return cmap_id; +} + +static void +load_gsub (pdf_obj *conf, otl_gsub *gsub_list, sfnt *sfont) +{ + pdf_obj *rule; + char *script, *language, *feature; + long i, size; + + rule = otl_conf_get_rule(conf); + if (!rule) + return; + + script = otl_conf_get_script (conf); + language = otl_conf_get_language(conf); + + size = pdf_array_length(rule); + for (i = 0; i < size; i += 2) { + pdf_obj *tmp, *commands; + int flag; + long j, num_comms; + + tmp = pdf_get_array(rule, i); + flag = (int) pdf_number_value(tmp); + + commands = pdf_get_array(rule, i+1); + num_comms = pdf_array_length(commands); + + /* (assign|substitute) tag dst src */ + for (j = 0 ; j < num_comms; j += 4) { + tmp = pdf_get_array(commands, 1); + if (PDF_OBJ_STRINGTYPE(tmp)) { + feature = pdf_string_value(tmp); + if (otl_gsub_add_feat(gsub_list, + script, language, feature, sfont) < 0) { + if (flag == 'p') + WARN("No OTL feature matches \"%s.%s.%s\" found.", + script, language, feature); + else if (flag == 'r') + ERROR("No OTL feature matches \"%s.%s.%s\" found.", + script, language, feature); + } + } + + } + } + +} + +static void +handle_gsub (pdf_obj *conf, + tt_cmap *ttcmap, otl_gsub *gsub_list, + struct ht_table *unencoded) +{ + pdf_obj *rule; + char *script, *language, *feature; + long i, size; + + if (!conf) + return; + + rule = otl_conf_get_rule(conf); + if (!rule) { + return; + } + + if (!PDF_OBJ_ARRAYTYPE(rule)) { + WARN("Not arraytype?"); + return; + } + script = otl_conf_get_script (conf); + language = otl_conf_get_language(conf); + + size = pdf_array_length(rule); + for (i = 0; i < size; i += 2) { + pdf_obj *tmp, *commands; + long j, num_comms; + int flag; + + tmp = pdf_get_array(rule, i); + flag = (int) pdf_number_value(tmp); + + commands = pdf_get_array (rule, i+1); + num_comms = pdf_array_length(commands); + + for (j = 0; j < num_comms; j += 4) { + pdf_obj *operator; + pdf_obj *src, *dst, *feat; + int rv; + + /* (assing|substitute) tag dst src */ + operator = pdf_get_array(commands, j); + + feat = pdf_get_array(commands, j+1); + if (PDF_OBJ_STRINGTYPE(feat)) + feature = pdf_string_value(feat); + else + feature = NULL; + + dst = pdf_get_array(commands, j+2); + src = pdf_get_array(commands, j+3); + + rv = otl_gsub_select(gsub_list, script, language, feature); + if (rv < 0) { + if (flag == 'p') { + WARN("No GSUB featre %s.%s.%s loaded...", + script, language, feature); + } else if (flag == 'r') { + ERROR("No GSUB featre %s.%s.%s loaded...", + script, language, feature); + } + } else { + + if (verbose > VERBOSE_LEVEL_MIN) { + MESG("otf_cmap>> %s:\n", pdf_name_value(operator)); + } + + if (!strcmp(pdf_name_value(operator), "assign")) { + handle_assign(dst, src, flag, + gsub_list, ttcmap, unencoded); + } else if (!strcmp(pdf_name_value(operator), "substitute")) { + handle_subst(dst, src, flag, + gsub_list, ttcmap, unencoded); + } + } + + } + + } + +} + +static void CDECL +hval_free (void *hval) +{ + RELEASE(hval); +} + +int +otf_load_Unicode_CMap (const char *map_name, int ttc_index, /* 0 for non-TTC font */ + const char *otl_tags, int wmode) +{ + int cmap_id = -1; + int tounicode_id = -1, is_cidfont = 0; + sfnt *sfont; + long offset = 0; + char *base_name = NULL, *cmap_name = NULL; + char *tounicode_name = NULL; + FILE *fp = NULL; + otl_gsub *gsub_list = NULL; + tt_cmap *ttcmap; + CMap *cmap, *base, *tounicode = NULL; + CIDSysInfo csi = {NULL, NULL, 0}; + unsigned char *GIDToCIDMap = NULL; + + if (!map_name) + return -1; + + if (ttc_index > 999 || ttc_index < 0) { + return -1; /* Sorry for this... */ + } + +fprintf(stderr, "otf_load_Unicode_CMap(%s, %d)\n", map_name, ttc_index); +#ifdef XETEX + sfont = NULL; /* FIXME */ +#else + fp = DPXFOPEN(map_name, DPX_RES_TYPE_TTFONT); + if (!fp) { + fp = DPXFOPEN(map_name, DPX_RES_TYPE_OTFONT); + } + if (!fp) + return -1; + + sfont = sfnt_open(fp, -1); +#endif + if (!sfont) { + ERROR("Could not open TrueType font file \"%s\"", map_name); + } + switch (sfont->type) { + case SFNT_TYPE_TTC: + offset = ttc_read_offset(sfont, ttc_index); + if (offset == 0) { + ERROR("Invalid TTC index"); + } + break; + case SFNT_TYPE_TRUETYPE: + case SFNT_TYPE_POSTSCRIPT: + offset = 0; + break; + default: + ERROR("Not a TrueType/TTC font?: %s", map_name); + break; + } + + if (sfnt_read_table_directory(sfont, offset) < 0) + ERROR("Could not read TrueType table directory."); + + base_name = NEW(strlen(map_name)+strlen("-UCS4-H")+5, char); + if (wmode) + sprintf(base_name, "%s,%03d-UCS4-V", map_name, ttc_index); + else { + sprintf(base_name, "%s,%03d-UCS4-H", map_name, ttc_index); + } + + if (otl_tags) { + cmap_name = NEW(strlen(map_name)+strlen(otl_tags)+strlen("-UCS4-H")+6, char); + if (wmode) + sprintf(cmap_name, "%s,%03d,%s-UCS4-V", map_name, ttc_index, otl_tags); + else + sprintf(cmap_name, "%s,%03d,%s-UCS4-H", map_name, ttc_index, otl_tags); + } else { + cmap_name = NEW(strlen(base_name)+1, char); + strcpy(cmap_name, base_name); + } + + if (sfont->type == SFNT_TYPE_POSTSCRIPT) { + is_cidfont = handle_CIDFont(sfont, &GIDToCIDMap, &csi); + } else { + is_cidfont = 0; + } + + if (is_cidfont) { + tounicode_name = NULL; + } else { + tounicode_name = NEW(strlen(map_name)+strlen("-UTF16")+5, char); + sprintf(tounicode_name, "%s,%03d-UTF16", map_name, ttc_index); + } + + if (verbose > VERBOSE_LEVEL_MIN) { + MESG("\n"); + MESG("otf_cmap>> Unicode charmap for font=\"%s\" layout=\"%s\"\n", + map_name, (otl_tags ? otl_tags : "none")); + } + + cmap_id = CMap_cache_find(cmap_name); + if (cmap_id >= 0) { + RELEASE(cmap_name); + RELEASE(base_name); + if (GIDToCIDMap) + RELEASE(GIDToCIDMap); + if (tounicode_name) + RELEASE(tounicode_name); + + sfnt_close(sfont); + DPXFCLOSE(fp); + + if (verbose > VERBOSE_LEVEL_MIN) + MESG("otf_cmap>> Found at cmap_id=%d.\n", cmap_id); + + return cmap_id; + } + + ttcmap = tt_cmap_read(sfont, 3, 10); + if (!ttcmap) { + ttcmap = tt_cmap_read(sfont, 3, 1); + } + if (!ttcmap) { + ERROR("Unable to read TrueType Unicode cmap table."); + } + cmap_id = load_base_CMap(base_name, wmode, + (is_cidfont ? &csi : NULL), + GIDToCIDMap, ttcmap); + if (cmap_id < 0) + ERROR("Failed to read TrueType cmap table."); + + if (!otl_tags) { + RELEASE(cmap_name); + RELEASE(base_name); + if (GIDToCIDMap) + RELEASE(GIDToCIDMap); + if (tounicode_name) + RELEASE(tounicode_name); + if (is_cidfont) { + if (csi.registry) + RELEASE(csi.registry); + if (csi.ordering) + RELEASE(csi.ordering); + } + tt_cmap_release(ttcmap); + sfnt_close(sfont); + DPXFCLOSE(fp); + + return cmap_id; + } + + base = CMap_cache_get(cmap_id); + + cmap = CMap_new(); + CMap_set_name (cmap, cmap_name); + CMap_set_type (cmap, CMAP_TYPE_CODE_TO_CID); + CMap_set_wmode(cmap, wmode); + /* CMap_add_codespacerange(cmap, lrange_min, lrange_max, 4); */ + CMap_set_usecmap(cmap, base); + CMap_add_cidchar(cmap, lrange_max, 4, 0); /* FIXME */ + + if (is_cidfont) { + CMap_set_CIDSysInfo(cmap, &csi); + if (csi.registry) + RELEASE(csi.registry); + if (csi.ordering) + RELEASE(csi.ordering); + } else { + CMap_set_CIDSysInfo(cmap, &CSI_IDENTITY); + } + + gsub_list = otl_gsub_new(); + + { + struct ht_table unencoded; + char *conf_name, *opt_tag; + pdf_obj *conf, *opt_conf; + + conf_name = NEW(strlen(otl_tags)+1, char); + memset (conf_name, 0, strlen(otl_tags)+1); + opt_tag = strchr(otl_tags, ':'); + if (opt_tag) { + opt_tag++; + strncpy(conf_name, otl_tags, + strlen(otl_tags) - strlen(opt_tag) - 1); + } else { + strcpy(conf_name, otl_tags); + } + + if (verbose > VERBOSE_LEVEL_MIN) { + MESG("otf_cmap>> Read layout config. \"%s\"\n", conf_name); + } + + conf = otl_find_conf(conf_name); + if (!conf) + ERROR("Layout file \"%s\" not found...", conf_name); + + load_gsub(conf, gsub_list, sfont); + if (opt_tag) { + if (verbose > VERBOSE_LEVEL_MIN) { + MESG("otf_cmap>> Layout option \"%s\" enabled\n", opt_tag); + } + opt_conf = otl_conf_find_opt(conf, opt_tag); + if (!opt_conf) + ERROR("There are no option \"%s\" in \"%s\".", + opt_tag, conf_name); + load_gsub(opt_conf, gsub_list, sfont); + } + + ht_init_table(&unencoded); + + handle_gsub(conf, ttcmap, gsub_list, &unencoded); + if (opt_tag) { + opt_conf = otl_conf_find_opt(conf, opt_tag); + if (!opt_conf) + ERROR("There are no option \"%s\" in \"%s\".", + opt_tag, conf_name); + handle_gsub(opt_conf, ttcmap, gsub_list, &unencoded); + } + if (is_cidfont) { + tounicode_id = -1; + tounicode = NULL; + } else { + tounicode_id = CMap_cache_find(tounicode_name); + if (tounicode_id >= 0) + tounicode = CMap_cache_get(tounicode_id); + else { + tounicode = CMap_new(); + CMap_set_name (tounicode, tounicode_name); + CMap_set_type (tounicode, CMAP_TYPE_TO_UNICODE); + CMap_set_wmode(tounicode, 0); + CMap_add_codespacerange(tounicode, srange_min, srange_max, 2); + CMap_set_CIDSysInfo(tounicode, &CSI_UNICODE); + /* FIXME */ + CMap_add_bfchar(tounicode, srange_min, 2, srange_max, 2); + } + } + create_cmaps(cmap, tounicode, &unencoded, GIDToCIDMap); + + ht_clear_table(&unencoded, hval_free); + RELEASE(conf_name); + } + + cmap_id = CMap_cache_add(cmap); + if (!is_cidfont && tounicode_id < 0) /* New */ + CMap_cache_add(tounicode); + + tt_cmap_release(ttcmap); + if (gsub_list) + otl_gsub_release(gsub_list); + + if (verbose > VERBOSE_LEVEL_MIN) { + MESG("otf_cmap>> Overwrite CMap \"%s\" by \"%s\" with usecmap\n", + base_name, cmap_name); + } + + if (GIDToCIDMap) + RELEASE(GIDToCIDMap); + if (base_name) + RELEASE(base_name); + if (cmap_name) + RELEASE(cmap_name); + if (tounicode_name) + RELEASE(tounicode_name); + + sfnt_close(sfont); + DPXFCLOSE(fp); + + return cmap_id; +} |