/* $Header: /home/cvsroot/dvipdfmx/src/cid.c,v 1.29 2005/07/30 11:44:18 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 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. */ /* * CID-keyed font support: * * See also, cidtype0, and cidtype2 */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include "system.h" #include "mem.h" #include "error.h" #include "dpxutil.h" #include "pdfobj.h" #include "cidtype0.h" #include "cidtype2.h" #include "cid_p.h" #include "cid.h" #define CIDFONT_DEBUG 3 #define CIDFONT_DEBUG_STR "CIDFont" #define PDF_CID_SUPPORT_MIN 2 #define PDF_CID_SUPPORT_MAX 6 /* * Unicode and PDF Standard Character Collections. * * Adobe-Identity is only for TrueType fonts and it means font's * internal glyph ordering. */ static struct { const char *registry; const char *ordering; /* Heighest Supplement values supported by PDF-1.0, 1.1, ... */ int supplement[16]; } CIDFont_stdcc_def[] = { {"Adobe", "UCS", {-1, -1, 0, 0, 0, 0, 0}}, {"Adobe", "GB1", {-1, -1, 0, 2, 4, 4, 4}}, {"Adobe", "CNS1", {-1, -1, 0, 0, 3, 4, 4}}, {"Adobe", "Japan1", {-1, -1, 2, 2, 4, 5, 6}}, {"Adobe", "Korea1", {-1, -1, 1, 1, 2, 2, 2}}, {"Adobe", "Identity", {-1, -1, 0, 0, 0, 0, 0}}, {NULL, NULL, {0,0,0,0,0,0,0}} }; #define UCS_CC 0 #define ACC_START 1 #define ACC_END 4 CIDSysInfo CSI_IDENTITY = { (char *) "Adobe", (char *) "Identity", 0 }; CIDSysInfo CSI_UNICODE = { (char *) "Adobe", (char *) "UCS", 0 }; /* * Optional supplement after alias name. */ static struct { const char *name; int index; } CIDFont_stdcc_alias[] = { {"AU", 0}, {"AG1", 1}, {"AC1", 2}, {"AJ1", 3}, {"AK1", 4}, {"AI", 5}, {"UCS", 0}, {"GB1", 1}, {"CNS1", 2}, {"Japan1", 3}, {"Korea1", 4}, {"Identity", 5}, {"U", 0}, {"G", 1}, {"C", 2}, {"J", 3}, {"K", 4}, {"I", 5}, {NULL, 0} }; static void release_opt (cid_opt *opt); static CIDSysInfo *get_cidsysinfo (const char *map_name, fontmap_opt *fmap_opt); static int __verbose = 0; static long cidoptflags = 0; void CIDFont_set_verbose (void) { CIDFont_type0_set_verbose(); CIDFont_type2_set_verbose(); __verbose++; } int CIDFont_require_version (void) { return PDF_CID_SUPPORT_MIN; } CIDFont * CIDFont_new (void) { CIDFont *font = NULL; font = NEW(1, struct CIDFont); font->name = NULL; font->fontname = NULL; font->ident = NULL; #ifdef XETEX font->ft_face = NULL; font->ft_to_gid = NULL; #endif /* * CIDFont */ font->subtype = -1; font->flags = FONT_FLAG_NONE; font->csi = NULL; font->options = NULL; (font->parent)[0] = -1; /* Horizontal */ (font->parent)[1] = -1; /* Vertical */ /* * PDF Font Resource */ font->indirect = NULL; font->fontdict = NULL; font->descriptor = NULL; return font; } /* It does write PDF objects. */ void CIDFont_flush (CIDFont *font) { if (font) { if (font->indirect) pdf_release_obj(font->indirect); font->indirect = NULL; if (font->fontdict) pdf_release_obj(font->fontdict); font->fontdict = NULL; if (font->descriptor) pdf_release_obj(font->descriptor); font->descriptor = NULL; } } void CIDFont_release (CIDFont *font) { if (font) { switch(font->subtype) { case CIDFONT_TYPE0: CIDFont_type0_release(font); break; case CIDFONT_TYPE2: CIDFont_type2_release(font); break; } if (font->indirect) ERROR("%s: Object not flushed.", CIDFONT_DEBUG_STR); if (font->fontdict) ERROR("%s: Object not flushed.", CIDFONT_DEBUG_STR); if (font->descriptor) ERROR("%s: Object not flushed.", CIDFONT_DEBUG_STR); if (font->fontname) RELEASE(font->fontname); if (font->name) RELEASE(font->name); if (font->ident) RELEASE(font->ident); if (font->csi) { if (font->csi->registry) RELEASE(font->csi->registry); if (font->csi->ordering) RELEASE(font->csi->ordering); RELEASE(font->csi); } if (font->options) release_opt(font->options); } } #ifdef XETEX unsigned short * CIDFont_get_ft_to_gid(CIDFont *font) { ASSERT(font); return font->ft_to_gid; } #endif char * CIDFont_get_fontname (CIDFont *font) { ASSERT(font); return font->fontname; } char * CIDFont_get_ident (CIDFont *font) { ASSERT(font); return font->ident; } int CIDFont_get_opt_index (CIDFont *font) { int opt_index; ASSERT(font); if (font->options) opt_index = font->options->index; else { opt_index = 0; } return opt_index; } #ifdef XETEX FT_Face CIDFont_get_ft_face(CIDFont *font) { ASSERT(font); return font->ft_face; } #endif int CIDFont_get_subtype (CIDFont *font) { ASSERT(font); return font->subtype; } int CIDFont_get_embedding (CIDFont *font) { ASSERT(font); return font->options->embed; } CIDSysInfo * CIDFont_get_CIDSysInfo (CIDFont *font) { ASSERT(font); return font->csi; } /* * Returns ID of parent Type0 font * wmode: 0 for horizontal, 1 for vertical */ int CIDFont_get_parent_id (CIDFont *font, int wmode) { ASSERT(font); if (wmode < 0 || wmode > 1) ERROR("%s: Invalid wmode value.", CIDFONT_DEBUG_STR); return (font->parent)[wmode]; } pdf_obj * CIDFont_get_resource (CIDFont *font) { ASSERT(font); if (!font->indirect) font->indirect = pdf_ref_obj(font->fontdict); return pdf_link_obj(font->indirect); } /* * Set parent Type0 font. */ void CIDFont_attach_parent (CIDFont *font, int parent_id, int wmode) { ASSERT(font); if (wmode < 0 || wmode > 1) ERROR("%s: Invalid wmode value.", CIDFONT_DEBUG_STR); if (font->parent[wmode] >= 0) WARN("%s: CIDFont already have a parent Type1 font.", CIDFONT_DEBUG_STR); font->parent[wmode] = parent_id; } int CIDFont_is_ACCFont (CIDFont *font) { int i; ASSERT(font); if (!font->csi) ERROR("%s: CIDSystemInfo undefined.", CIDFONT_DEBUG_STR); for (i = ACC_START; i <= ACC_END ; i++) { if (!strcmp(font->csi->registry, CIDFont_stdcc_def[i].registry) && !strcmp(font->csi->ordering, CIDFont_stdcc_def[i].ordering)) return 1; } return 0; } int CIDFont_is_UCSFont (CIDFont *font) { ASSERT(font); if (!strcmp(font->csi->ordering, "UCS") || !strcmp(font->csi->ordering, "UCS2")) return 1; return 0; } /* FIXME */ int CIDFont_get_flag (CIDFont *font, int mask) { ASSERT(font); return ((font->flags & mask) ? 1 : 0); } static void CIDFont_dofont (CIDFont *font) { if (!font || !font->indirect) return; if (__verbose) MESG(":%s", font->ident); if (__verbose > 1) { if (font->fontname) MESG("[%s]", font->fontname); } switch (font->subtype) { case CIDFONT_TYPE0: if(__verbose) MESG("[CIDFontType0]"); if (CIDFont_get_flag(font, CIDFONT_FLAG_TYPE1)) CIDFont_type0_t1dofont(font); else if (CIDFont_get_flag(font, CIDFONT_FLAG_TYPE1C)) CIDFont_type0_t1cdofont(font); else CIDFont_type0_dofont(font); break; case CIDFONT_TYPE2: if(__verbose) MESG("[CIDFontType2]"); CIDFont_type2_dofont(font); break; default: ERROR("%s: Unknown CIDFontType %d.", CIDFONT_DEBUG_STR, font->subtype); break; } } /* * */ int CIDFont_is_BaseFont (CIDFont *font) { ASSERT(font); return (font->flags & FONT_FLAG_BASEFONT) ? 1 : 0; } #include "pdfparse.h" #include "cid_basefont.h" static int CIDFont_base_open (CIDFont *font, const char *name, CIDSysInfo *cmap_csi, cid_opt *opt); static int CIDFont_base_open (CIDFont *font, const char *name, CIDSysInfo *cmap_csi, cid_opt *opt) { pdf_obj *fontdict, *descriptor; char *fontname = NULL; int idx; ASSERT(font); for (idx = 0; cid_basefont[idx].fontname != NULL; idx++) { if (!strcmp(name, cid_basefont[idx].fontname) || (strlen(name) == strlen(cid_basefont[idx].fontname) - strlen("-Acro") && !strncmp(name, cid_basefont[idx].fontname, strlen(cid_basefont[idx].fontname)-strlen("-Acro"))) ) break; } if (cid_basefont[idx].fontname == NULL) return -1; fontname = NEW(strlen(name)+12, char); memset(fontname, 0, strlen(name)+12); strcpy(fontname, name); 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; } { const char *start; const char *end; start = cid_basefont[idx].fontdict; end = start + strlen(start); fontdict = parse_pdf_dict((char **)&start, (char *)end); start = cid_basefont[idx].descriptor; end = start + strlen(start); descriptor = parse_pdf_dict((char **)&start, (char *)end); ASSERT(fontdict && descriptor); } font->fontname = fontname; font->flags |= FONT_FLAG_BASEFONT; { char *registry, *ordering; int supplement; pdf_obj *tmp; tmp = pdf_lookup_dict(fontdict, "CIDSystemInfo"); ASSERT( tmp && pdf_obj_typeof(tmp) == PDF_DICT ); registry = pdf_string_value(pdf_lookup_dict(tmp, "Registry")); ordering = pdf_string_value(pdf_lookup_dict(tmp, "Ordering")); supplement = pdf_number_value(pdf_lookup_dict(tmp, "Supplement")); if (cmap_csi) { /* NULL for accept any */ if (strcmp(registry, cmap_csi->registry) || strcmp(ordering, cmap_csi->ordering)) ERROR("Inconsistent CMap used for CID-keyed font %s.", cid_basefont[idx].fontname); else if (supplement < cmap_csi->supplement) { WARN("CMap has higher supplement number than CIDFont: %s", fontname); WARN("Some chracters may not be displayed or printed."); } } font->csi = NEW(1, CIDSysInfo); font->csi->registry = NEW(strlen(registry)+1, char); font->csi->ordering = NEW(strlen(ordering)+1, char); strcpy(font->csi->registry, registry); strcpy(font->csi->ordering, ordering); font->csi->supplement = supplement; } { pdf_obj *tmp; char *type; tmp = pdf_lookup_dict(fontdict, "Subtype"); ASSERT( tmp != NULL && pdf_obj_typeof(tmp) == PDF_NAME ); type = pdf_name_value(tmp); if (!strcmp(type, "CIDFontType0")) font->subtype = CIDFONT_TYPE0; else if (!strcmp(type, "CIDFontType2")) font->subtype = CIDFONT_TYPE2; else { ERROR("Unknown CIDFontType \"%s\"", type); } } if (cidoptflags & CIDFONT_FORCE_FIXEDPITCH) { if (pdf_lookup_dict(fontdict, "W")) { pdf_remove_dict(fontdict, "W"); } if (pdf_lookup_dict(fontdict, "W2")) { pdf_remove_dict(fontdict, "W2"); } } pdf_add_dict(fontdict, pdf_new_name("Type"), pdf_new_name("Font")); pdf_add_dict(fontdict, pdf_new_name("BaseFont"), pdf_new_name(fontname)); pdf_add_dict(descriptor, pdf_new_name("Type"), pdf_new_name("FontDescriptor")); pdf_add_dict(descriptor, pdf_new_name("FontName"), pdf_new_name(fontname)); font->fontdict = fontdict; font->descriptor = descriptor; opt->embed = 0; return 0; } #define CACHE_ALLOC_SIZE 16u struct FontCache { int num; int max; CIDFont **fonts; }; static struct FontCache *__cache = NULL; #define CHECK_ID(n) do {\ if (! __cache)\ ERROR("%s: CIDFont cache not initialized.", CIDFONT_DEBUG_STR);\ if ((n) < 0 || (n) >= __cache->num)\ ERROR("%s: Invalid ID %d", CIDFONT_DEBUG_STR, (n));\ } while (0) void CIDFont_cache_init (void) { if (__cache) ERROR("%s: Already initialized.", CIDFONT_DEBUG_STR); __cache = NEW(1, struct FontCache); __cache->max = CACHE_ALLOC_SIZE; __cache->fonts = NEW(__cache->max, struct CIDFont *); __cache->num = 0; } CIDFont * CIDFont_cache_get (int font_id) { CHECK_ID(font_id); return __cache->fonts[font_id]; } /* * cmap_csi is NULL if CMap is Identity. */ int CIDFont_cache_find (const char *map_name, CIDSysInfo *cmap_csi, fontmap_opt *fmap_opt) { int font_id = -1; CIDFont *font = NULL; cid_opt *opt = NULL; if (!__cache) CIDFont_cache_init(); opt = NEW(1, cid_opt); opt->style = fmap_opt->style; opt->index = fmap_opt->index; opt->embed = (fmap_opt->flags & FONTMAP_OPT_NOEMBED) ? 0 : 1; opt->name = NULL; opt->csi = get_cidsysinfo(map_name, fmap_opt); if (!opt->csi && cmap_csi) { /* * No CIDSystemInfo supplied explicitly. Copy from CMap's one if available. * It is not neccesary for CID-keyed fonts. But TrueType requires them. */ opt->csi = NEW(1, CIDSysInfo); opt->csi->registry = NEW(strlen(cmap_csi->registry)+1, char); strcpy(opt->csi->registry, cmap_csi->registry); opt->csi->ordering = NEW(strlen(cmap_csi->ordering)+1, char); strcpy(opt->csi->ordering, cmap_csi->ordering); opt->csi->supplement = cmap_csi->supplement; } /* * Here, we do not compare font->ident and map_name because of * implicit CIDSystemInfo supplied by CMap for TrueType. */ for (font_id = 0; font_id < __cache->num; font_id++) { font = __cache->fonts[font_id]; if (!strcmp(font->name, map_name) && font->options->style == opt->style && font->options->index == opt->index) { if (font->options->embed == opt->embed) { /* * Case 1: CSI not available (Identity CMap) * Font is TrueType --> continue * Font is CIDFont --> break * Case 2: CSI matched --> break */ if (!opt->csi) { if (font->subtype == CIDFONT_TYPE2) continue; else break; } else if (!strcmp(font->csi->registry, opt->csi->registry) && !strcmp(font->csi->ordering, opt->csi->ordering)) { if (font->subtype == CIDFONT_TYPE2) font->csi->supplement = MAX(opt->csi->supplement, font->csi->supplement); break; } } else if (CIDFont_is_BaseFont(font)) { opt->embed = 0; break; } } } if (font_id < __cache->num && cmap_csi) { if (strcmp(font->csi->registry, cmap_csi->registry) || strcmp(font->csi->ordering, cmap_csi->ordering)) ERROR("%s: Incompatible CMap for CIDFont \"%s\"", CIDFONT_DEBUG_STR, map_name); } if (font_id == __cache->num) { font = CIDFont_new(); #ifdef XETEX font->ft_face = fmap_opt->ft_face; #endif if (CIDFont_type0_open(font, map_name, cmap_csi, opt) < 0 && CIDFont_type2_open(font, map_name, cmap_csi, opt) < 0 && CIDFont_type0_t1open(font, map_name, cmap_csi, opt) < 0 && CIDFont_type0_t1copen(font, map_name, cmap_csi, opt) < 0 && CIDFont_base_open (font, map_name, cmap_csi, opt) < 0 ) { CIDFont_release(font); release_opt(opt); return -1; } else { if (__cache->num >= __cache->max) { __cache->max += CACHE_ALLOC_SIZE; __cache->fonts = RENEW(__cache->fonts, __cache->max, struct CIDFont *); } font->name = NEW(strlen(map_name)+1, char); strcpy(font->name, map_name); font->ident = NEW(strlen(map_name)+1, char); strcpy(font->ident, map_name); font->options = opt; __cache->fonts[font_id] = font; (__cache->num)++; } } else if (opt) { release_opt(opt); } return font_id; } void CIDFont_cache_close (void) { int font_id; if (__cache) { for (font_id = 0; font_id < __cache->num; font_id++) { CIDFont *font; font = __cache->fonts[font_id]; if (__verbose) MESG("(CID"); CIDFont_dofont (font); CIDFont_flush (font); CIDFont_release(font); RELEASE(font); if (__verbose) MESG(")"); } RELEASE(__cache->fonts); RELEASE(__cache); __cache = NULL; } } /******************************* OPTIONS *******************************/ /* * FORMAT: * * (:int:)?!?string(/string)?(,string)? */ static void release_opt (cid_opt *opt) { if (opt->csi) { if (opt->csi->registry) RELEASE(opt->csi->registry); if (opt->csi->ordering) RELEASE(opt->csi->ordering); RELEASE(opt->csi); } RELEASE(opt); } static CIDSysInfo * get_cidsysinfo (const char *map_name, fontmap_opt *fmap_opt) { CIDSysInfo *csi = NULL; int pdf_ver; int i, csi_idx = -1, n, m; pdf_ver = pdf_get_version(); if (!fmap_opt || !fmap_opt->charcoll) return NULL; /* First try alias for standard one. */ for (i = 0; CIDFont_stdcc_alias[i].name != NULL; i++) { n = strlen(CIDFont_stdcc_alias[i].name); if (!strncmp(fmap_opt->charcoll, CIDFont_stdcc_alias[i].name, n)) { csi_idx = CIDFont_stdcc_alias[i].index; csi = NEW(1, CIDSysInfo); csi->registry = NEW(strlen(CIDFont_stdcc_def[csi_idx].registry)+1, char); strcpy(csi->registry, CIDFont_stdcc_def[csi_idx].registry); csi->ordering = NEW(strlen(CIDFont_stdcc_def[csi_idx].ordering)+1, char); strcpy(csi->ordering, CIDFont_stdcc_def[csi_idx].ordering); if (strlen(fmap_opt->charcoll) > n) { csi->supplement = (int) strtoul(&(fmap_opt->charcoll[n]), NULL, 10); } else { /* Use heighest supported value for current output PDF version. */ csi->supplement = CIDFont_stdcc_def[csi_idx].supplement[pdf_ver]; } break; } } if (csi == NULL) { char *p, *q; p = (char *) fmap_opt->charcoll; csi = NEW(1, CIDSysInfo); /* Full REGISTRY-ORDERING-SUPPLEMENT */ p = strchr(fmap_opt->charcoll, '-'); if (!p || p[1] == '\0') ERROR("%s: String can't be converted to REGISTRY-ORDERING-SUPPLEMENT: %s", CIDFONT_DEBUG_STR, fmap_opt->charcoll); p++; q = strchr(p, '-'); if (!q || q[1] == '\0') ERROR("%s: String can't be converted to REGISTRY-ORDERING-SUPPLEMENT: %s", CIDFONT_DEBUG_STR, fmap_opt->charcoll); q++; if (!isdigit(q[0])) ERROR("%s: String can't be converted to REGISTRY-ORDERING-SUPPLEMENT: %s", CIDFONT_DEBUG_STR, fmap_opt->charcoll); n = strlen(fmap_opt->charcoll) - strlen(p) - 1; csi->registry = NEW(n+1, char); memcpy(csi->registry, fmap_opt->charcoll, n); csi->registry[n] = '\0'; m = strlen(p) - strlen(q) - 1; csi->ordering = NEW(m+1, char); memcpy(csi->ordering, p, m); csi->ordering[m] = '\0'; csi->supplement = (int) strtoul(q, NULL, 10); /* Check for standart character collections. */ for (i = 0; CIDFont_stdcc_def[i].ordering != NULL; i++) { if ((CIDFont_stdcc_def[i].registry && !strcmp(csi->registry, CIDFont_stdcc_def[i].registry)) && !strcmp(csi->ordering, CIDFont_stdcc_def[i].ordering)) { csi_idx = i; break; } } } if (csi && csi_idx >= 0) { if (csi->supplement > CIDFont_stdcc_def[csi_idx].supplement[pdf_ver] && (fmap_opt->flags & FONTMAP_OPT_NOEMBED)) { WARN("%s: Heighest supplement number supported in PDF-1.%d for %s-%s is %d.", CIDFONT_DEBUG_STR, pdf_ver, csi->registry, csi->ordering, CIDFont_stdcc_def[csi_idx].supplement[pdf_ver]); WARN("%s: Some character may not shown without embedded font (--> %s).", CIDFONT_DEBUG_STR, map_name); } } return csi; } void CIDFont_set_flags (long flags) { CIDFont_type0_set_flags(flags); CIDFont_type2_set_flags(flags); cidoptflags |= flags; }