summaryrefslogtreecommitdiff
path: root/gs/base/gxfcopy.c
diff options
context:
space:
mode:
Diffstat (limited to 'gs/base/gxfcopy.c')
-rw-r--r--gs/base/gxfcopy.c2424
1 files changed, 2424 insertions, 0 deletions
diff --git a/gs/base/gxfcopy.c b/gs/base/gxfcopy.c
new file mode 100644
index 000000000..630ff8906
--- /dev/null
+++ b/gs/base/gxfcopy.c
@@ -0,0 +1,2424 @@
+/* Copyright (C) 2001-2006 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied, modified
+ or distributed except as expressly authorized under the terms of that
+ license. Refer to licensing information at http://www.artifex.com/
+ or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
+ San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
+*/
+
+/* $Id$ */
+/* Font copying for high-level output */
+#include "memory_.h"
+#include "gx.h"
+#include <stdlib.h> /* for qsort */
+#include "gscencs.h"
+#include "gserrors.h"
+#include "gsline.h" /* for BuildChar */
+#include "gspaint.h" /* for BuildChar */
+#include "gspath.h" /* for gs_moveto in BuildChar */
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "gschar.h"
+#include "stream.h"
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "gxfont42.h"
+#include "gxchar.h"
+#include "gxfcid.h"
+#include "gxfcopy.h"
+#include "gxfcache.h" /* for gs_font_dir_s */
+#include "gxistate.h" /* for Type 1 glyph_outline */
+#include "gxtext.h" /* for BuildChar */
+#include "gxtype1.h" /* for Type 1 glyph_outline */
+#include "gzstate.h" /* for path for BuildChar */
+#include "gdevpsf.h"
+
+#define GLYPHS_SIZE_IS_PRIME 1 /* Old code = 0, new code = 1. */
+
+/* ================ Types and structures ================ */
+
+typedef struct gs_copied_glyph_s gs_copied_glyph_t;
+typedef struct gs_copied_font_data_s gs_copied_font_data_t;
+
+typedef struct gs_copied_font_procs_s {
+ int (*finish_copy_font)(gs_font *font, gs_font *copied);
+ int (*copy_glyph)(gs_font *font, gs_glyph glyph, gs_font *copied,
+ int options);
+ int (*add_encoding)(gs_font *copied, gs_char chr, gs_glyph glyph);
+ int (*named_glyph_slot)(gs_copied_font_data_t *cfdata, gs_glyph glyph,
+ gs_copied_glyph_t **pslot);
+ /* Font procedures */
+ font_proc_encode_char((*encode_char));
+ font_proc_glyph_info((*glyph_info));
+ font_proc_glyph_outline((*glyph_outline));
+} gs_copied_font_procs_t;
+
+/*
+ * We need to store the Subrs data for Type 1/2 and CIDFontType 0 fonts,
+ * and the GlobalSubrs data for all but Type 1.
+ */
+typedef struct gs_subr_info_s {
+ byte *data; /* Subr data */
+ int count;
+ uint *starts; /* [count+1] Subr[i] = data[starts[i]..starts[i+1]] */
+} gs_subr_info_t;
+
+/*
+ * The glyphs for copied fonts are stored explicitly in a table indexed by
+ * glyph number.
+ * For Type 1 fonts, the glyph numbers are parallel to the hashed name table.
+ * For TrueType fonts, the glyph number is the TrueType GID.
+ * For CIDFontType 0 fonts, the glyph number is the CID.
+ * For CIDFontType 2 fonts, the glyph number is the TrueType GID;
+ * a separate CIDMap array maps CIDs to GIDs.
+ */
+struct gs_copied_glyph_s {
+ gs_const_string gdata; /* vector data */
+#define HAS_DATA 1 /* entry is in use */
+ /* HAS_SBW* are only used for TT-based fonts */
+#define HAS_SBW0 2 /* has hmtx */
+#define HAS_SBW1 4 /* has vmtx */
+ byte used; /* non-zero iff this entry is in use */
+ /* (if not, gdata.{data,size} = 0) */
+ int order_index; /* Index for the ordered glyph set. */
+};
+/*
+ * We use a special GC descriptor to avoid large GC overhead.
+ */
+gs_private_st_composite(st_gs_copied_glyph_element, gs_copied_glyph_t,
+ "gs_copied_glyph_t[]", copied_glyph_element_enum_ptrs,
+ copied_glyph_element_reloc_ptrs);
+static ENUM_PTRS_WITH(copied_glyph_element_enum_ptrs, gs_copied_glyph_t *pcg)
+ if (index < size / (uint)sizeof(gs_copied_glyph_t))
+ return ENUM_CONST_STRING(&pcg[index].gdata);
+ return 0;
+ENUM_PTRS_END
+static RELOC_PTRS_WITH(copied_glyph_element_reloc_ptrs, gs_copied_glyph_t *pcg)
+{
+ uint count = size / (uint)sizeof(gs_copied_glyph_t);
+ gs_copied_glyph_t *p = pcg;
+
+ for (; count > 0; --count, ++p)
+ if (p->gdata.size > 0)
+ RELOC_CONST_STRING_VAR(p->gdata);
+}
+RELOC_PTRS_END
+
+/*
+ * Type 1 and TrueType fonts also have a 'names' table, parallel to the
+ * 'glyphs' table.
+ * For Type 1 fonts, this is a hash table; glyph numbers are assigned
+ * arbitrarily, according to the hashed placement of the names.
+ * For TrueType fonts, this is indexed by GID.
+ * The strings in this table are either those returned by the font's
+ * glyph_name procedure, which we assume are garbage-collected, or those
+ * associated with the known encodings, which we assume are immutable.
+ */
+typedef struct gs_copied_glyph_name_s {
+ gs_glyph glyph; /* key (for comparison and glyph_name only) */
+ gs_const_string str; /* glyph name */
+} gs_copied_glyph_name_t;
+/*
+ * We use the same special GC descriptor as above for 'names'.
+ */
+gs_private_st_composite(st_gs_copied_glyph_name_element,
+ gs_copied_glyph_name_t,
+ "gs_copied_glyph_name_t[]",
+ copied_glyph_name_enum_ptrs,
+ copied_glyph_name_reloc_ptrs);
+static ENUM_PTRS_WITH(copied_glyph_name_enum_ptrs, gs_copied_glyph_name_t *pcgn)
+ if (index < size / (uint)sizeof(gs_copied_glyph_name_t)) {
+ const gs_copied_glyph_name_t *const p = &pcgn[index];
+
+ return (p->str.size == 0 ||
+ gs_is_c_glyph_name(p->str.data, p->str.size) ?
+ ENUM_CONST_STRING2(0, 0) :
+ ENUM_CONST_STRING(&p->str));
+ }
+ return 0;
+ /* We should mark glyph name here, but we have no access to
+ the gs_font_dir instance. Will mark in gs_copied_font_data_enum_ptrs.
+ */
+ENUM_PTRS_END
+static RELOC_PTRS_WITH(copied_glyph_name_reloc_ptrs, gs_copied_glyph_name_t *pcgn)
+{
+ uint count = size / (uint)sizeof(gs_copied_glyph_name_t);
+ gs_copied_glyph_name_t *p = pcgn;
+
+ for (; count > 0; --count, ++p)
+ if (p->str.size > 0 && !gs_is_c_glyph_name(p->str.data, p->str.size))
+ RELOC_CONST_STRING_VAR(p->str);
+}
+RELOC_PTRS_END
+
+/*
+ * To accommodate glyphs with multiple names, there is an additional
+ * 'extra_names' table. Since this is rare, this table uses linear search.
+ */
+typedef struct gs_copied_glyph_extra_name_s gs_copied_glyph_extra_name_t;
+struct gs_copied_glyph_extra_name_s {
+ gs_copied_glyph_name_t name;
+ uint gid; /* index in glyphs table */
+ gs_copied_glyph_extra_name_t *next;
+};
+BASIC_PTRS(gs_copied_glyph_extra_name_ptrs) {
+ GC_STRING_ELT(gs_copied_glyph_extra_name_t, name.str),
+ GC_OBJ_ELT(gs_copied_glyph_extra_name_t, next)
+};
+gs_private_st_basic(st_gs_copied_glyph_extra_name,
+ gs_copied_glyph_extra_name_t,
+ "gs_copied_glyph_extra_name_t",
+ gs_copied_glyph_extra_name_ptrs,
+ gs_copied_glyph_extra_name_data);
+
+/*
+ * The client_data of copied fonts points to an instance of
+ * gs_copied_font_data_t.
+ */
+struct gs_copied_font_data_s {
+ gs_font_info_t info; /* from the original font, must be first */
+ const gs_copied_font_procs_t *procs;
+ gs_copied_glyph_t *glyphs; /* [glyphs_size] */
+ uint glyphs_size; /* (a power of 2 or a prime number for Type 1/2) */
+ uint num_glyphs; /* The number of glyphs copied. */
+ gs_glyph notdef; /* CID 0 or .notdef glyph */
+ /*
+ * We don't use a union for the rest of the data, because some of the
+ * cases overlap and it's just not worth the trouble.
+ */
+ gs_copied_glyph_name_t *names; /* (Type 1/2, TrueType) [glyphs_size] */
+ gs_copied_glyph_extra_name_t *extra_names; /* (TrueType) */
+ byte *data; /* (TrueType and CID fonts) copied data */
+ uint data_size; /* (TrueType and CID fonts) */
+ gs_glyph *Encoding; /* (Type 1/2 and Type 42) [256] */
+ ushort *CIDMap; /* (CIDFontType 2) [CIDCount] */
+ gs_subr_info_t subrs; /* (Type 1/2 and CIDFontType 0) */
+ gs_subr_info_t global_subrs; /* (Type 2 and CIDFontType 0) */
+ gs_font_cid0 *parent; /* (Type 1 subfont) => parent CIDFontType 0 */
+ gs_font_dir *dir;
+ bool ordered;
+};
+extern_st(st_gs_font_info);
+static
+ENUM_PTRS_WITH(gs_copied_font_data_enum_ptrs, gs_copied_font_data_t *cfdata)
+ if (index == 12) {
+ gs_copied_glyph_name_t *names = cfdata->names;
+ gs_copied_glyph_extra_name_t *en = cfdata->extra_names;
+ int i;
+
+ if (names != NULL)
+ for (i = 0; i < cfdata->glyphs_size; ++i)
+ if (names[i].glyph < gs_c_min_std_encoding_glyph)
+ cfdata->dir->ccache.mark_glyph(mem, names[i].glyph, NULL);
+ for (; en != NULL; en = en->next)
+ if (en->name.glyph < gs_c_min_std_encoding_glyph)
+ cfdata->dir->ccache.mark_glyph(mem, en->name.glyph, NULL);
+ }
+ return ENUM_USING(st_gs_font_info, &cfdata->info, sizeof(gs_font_info_t), index - 12);
+ ENUM_PTR3(0, gs_copied_font_data_t, glyphs, names, extra_names);
+ ENUM_PTR3(3, gs_copied_font_data_t, data, Encoding, CIDMap);
+ ENUM_PTR3(6, gs_copied_font_data_t, subrs.data, subrs.starts, global_subrs.data);
+ ENUM_PTR3(9, gs_copied_font_data_t, global_subrs.starts, parent, dir);
+ENUM_PTRS_END
+
+static RELOC_PTRS_WITH(gs_copied_font_data_reloc_ptrs, gs_copied_font_data_t *cfdata)
+{
+ RELOC_PTR3(gs_copied_font_data_t, glyphs, names, extra_names);
+ RELOC_PTR3(gs_copied_font_data_t, data, Encoding, CIDMap);
+ RELOC_PTR3(gs_copied_font_data_t, subrs.data, subrs.starts, global_subrs.data);
+ RELOC_PTR3(gs_copied_font_data_t, global_subrs.starts, parent, dir);
+ RELOC_USING(st_gs_font_info, &cfdata->info, sizeof(gs_font_info_t));
+}
+RELOC_PTRS_END
+
+gs_private_st_composite(st_gs_copied_font_data, gs_copied_font_data_t, "gs_copied_font_data_t",\
+ gs_copied_font_data_enum_ptrs, gs_copied_font_data_reloc_ptrs);
+
+static inline gs_copied_font_data_t *
+cf_data(const gs_font *font)
+{
+ return (gs_copied_font_data_t *)font->client_data;
+}
+
+/* ================ Procedures ================ */
+
+/* ---------------- Private utilities ---------------- */
+
+/* Copy a string. Return 0 or gs_error_VMerror. */
+static int
+copy_string(gs_memory_t *mem, gs_const_string *pstr, client_name_t cname)
+{
+ const byte *data = pstr->data;
+ uint size = pstr->size;
+ byte *str;
+
+ if (data == 0)
+ return 0; /* empty string */
+ str = gs_alloc_string(mem, size, cname);
+ pstr->data = str;
+ if (str == 0)
+ return_error(gs_error_VMerror);
+ memcpy(str, data, size);
+ return 0;
+}
+
+/* Free a copied string. */
+static void
+uncopy_string(gs_memory_t *mem, gs_const_string *pstr, client_name_t cname)
+{
+ if (pstr->data)
+ gs_free_const_string(mem, pstr->data, pstr->size, cname);
+}
+
+/*
+ * Allocate an Encoding for a Type 1 or Type 42 font.
+ */
+static int
+copied_Encoding_alloc(gs_font *copied)
+{
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+ gs_glyph *Encoding = (gs_glyph *)
+ gs_alloc_byte_array(copied->memory, 256, sizeof(*cfdata->Encoding),
+ "copy_font_type1(Encoding)");
+ int i;
+
+ if (Encoding == 0)
+ return_error(gs_error_VMerror);
+ for (i = 0; i < 256; ++i)
+ Encoding[i] = GS_NO_GLYPH;
+ cfdata->Encoding = Encoding;
+ return 0;
+}
+
+/*
+ * Allocate and set up data copied from a TrueType or CID font.
+ * stell(*s) + extra is the length of the data.
+ */
+static int
+copied_data_alloc(gs_font *copied, stream *s, uint extra, int code)
+{
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+ uint len = stell(s);
+ byte *fdata;
+
+ if (code < 0)
+ return code;
+ fdata = gs_alloc_bytes(copied->memory, len + extra, "copied_data_alloc");
+ if (fdata == 0)
+ return_error(gs_error_VMerror);
+ s_init(s, copied->memory);
+ swrite_string(s, fdata, len);
+ cfdata->data = fdata;
+ cfdata->data_size = len + extra;
+ return 0;
+}
+
+/*
+ * Copy Subrs or GSubrs from a font.
+ */
+static int
+copy_subrs(gs_font_type1 *pfont, bool global, gs_subr_info_t *psi,
+ gs_memory_t *mem)
+{
+ int i, code;
+ uint size;
+ gs_glyph_data_t gdata;
+ byte *data;
+ uint *starts;
+
+ gdata.memory = pfont->memory;
+ /* Scan the font to determine the size of the subrs. */
+ for (i = 0, size = 0;
+ (code = pfont->data.procs.subr_data(pfont, i, global, &gdata)) !=
+ gs_error_rangecheck;
+ ++i) {
+ if (code >= 0) {
+ size += gdata.bits.size;
+ gs_glyph_data_free(&gdata, "copy_subrs");
+ }
+ }
+ if (size == 0)
+ data = 0, starts = 0, i = 0;
+ else {
+ /* Allocate the copy. */
+ data = gs_alloc_bytes(mem, size, "copy_subrs(data)");
+ starts = (uint *)gs_alloc_byte_array(mem, i + 1, sizeof(*starts),
+ "copy_subrs(starts)");
+ if (data == 0 || starts == 0) {
+ gs_free_object(mem, starts, "copy_subrs(starts)");
+ gs_free_object(mem, data, "copy_subrs(data)");
+ return_error(gs_error_VMerror);
+ }
+
+ /* Copy the data. */
+ for (i = 0, size = 0;
+ (code = pfont->data.procs.subr_data(pfont, i, global, &gdata)) !=
+ gs_error_rangecheck;
+ ++i) {
+ starts[i] = size;
+ if (code >= 0) {
+ memcpy(data + size, gdata.bits.data, gdata.bits.size);
+ size += gdata.bits.size;
+ gs_glyph_data_free(&gdata, "copy_subrs");
+ }
+ }
+ starts[i] = size;
+ }
+
+ psi->data = data;
+ psi->starts = starts;
+ psi->count = i;
+ return 0;
+}
+
+/*
+ * Return a pointer to the definition of a copied glyph, accessed either by
+ * name or by glyph number. If the glyph is out of range, return
+ * gs_error_rangecheck; if the glyph is in range but undefined, store a
+ * pointer to the slot where it would be added, which will have gdata.data
+ * == 0, and return gs_error_undefined; if the glyph is defined, store the
+ * pointer and return 0.
+ */
+static int
+copied_glyph_slot(gs_copied_font_data_t *cfdata, gs_glyph glyph,
+ gs_copied_glyph_t **pslot)
+{
+ uint gsize = cfdata->glyphs_size;
+
+ *pslot = 0;
+ if (glyph >= GS_MIN_GLYPH_INDEX) {
+ /* CIDFontType 2 uses glyph indices for slots. */
+ if (glyph - GS_MIN_GLYPH_INDEX >= gsize)
+ return_error(gs_error_rangecheck);
+ *pslot = &cfdata->glyphs[glyph - GS_MIN_GLYPH_INDEX];
+ } else if (glyph >= GS_MIN_CID_GLYPH) {
+ /* CIDFontType 0 uses CIDS for slots. */
+ if (glyph - GS_MIN_CID_GLYPH >= gsize)
+ return_error(gs_error_rangecheck);
+ *pslot = &cfdata->glyphs[glyph - GS_MIN_CID_GLYPH];
+ } else if (cfdata->names == 0)
+ return_error(gs_error_rangecheck);
+ else {
+ int code = cfdata->procs->named_glyph_slot(cfdata, glyph, pslot);
+
+ if (code < 0)
+ return code;
+ }
+ if (!(*pslot)->used)
+ return_error(gs_error_undefined);
+ return 0;
+}
+static int
+named_glyph_slot_none(gs_copied_font_data_t *cfdata, gs_glyph glyph,
+ gs_copied_glyph_t **pslot)
+{
+ return_error(gs_error_rangecheck);
+}
+static int
+named_glyph_slot_hashed(gs_copied_font_data_t *cfdata, gs_glyph glyph,
+ gs_copied_glyph_t **pslot)
+{
+ uint gsize = cfdata->glyphs_size;
+ gs_copied_glyph_name_t *names = cfdata->names;
+ uint hash = (uint)glyph % gsize;
+ /*
+ * gsize is either a prime number or a power of 2.
+ * If it is prime, any positive reprobe below gsize guarantees that we
+ * will touch every slot.
+ * If it is a power of 2, any odd reprobe guarantees that we
+ * will touch every slot.
+ */
+ uint hash2 = ((uint)glyph / gsize * 2 + 1) % gsize;
+ uint tries = gsize;
+
+ while (names[hash].str.data != 0 && names[hash].glyph != glyph) {
+ hash = (hash + hash2) % gsize;
+ if (!tries)
+ return gs_error_undefined;
+ tries--;
+ }
+ *pslot = &cfdata->glyphs[hash];
+ return 0;
+}
+static int
+named_glyph_slot_linear(gs_copied_font_data_t *cfdata, gs_glyph glyph,
+ gs_copied_glyph_t **pslot)
+{
+ {
+ gs_copied_glyph_name_t *names = cfdata->names;
+ int i;
+
+ for (i = 0; i < cfdata->glyphs_size; ++i)
+ if (names[i].glyph == glyph) {
+ *pslot = &cfdata->glyphs[i];
+ return 0;
+ }
+ }
+ /* This might be a glyph with multiple names. Search extra_names. */
+ {
+ gs_copied_glyph_extra_name_t *extra_name = cfdata->extra_names;
+
+ for (; extra_name != 0; extra_name = extra_name->next)
+ if (extra_name->name.glyph == glyph) {
+ *pslot = &cfdata->glyphs[extra_name->gid];
+ return 0;
+ }
+ }
+ return_error(gs_error_rangecheck);
+}
+
+/*
+ * Add glyph data to the glyph table. This handles copying the vector
+ * data, detecting attempted redefinitions, and freeing temporary glyph
+ * data. The glyph must be an integer, an index in the glyph table.
+ * Return 1 if the glyph was already defined, 0 if newly added (or an
+ * error per options).
+ */
+static int
+copy_glyph_data(gs_font *font, gs_glyph glyph, gs_font *copied, int options,
+ gs_glyph_data_t *pgdata, const byte *prefix, int prefix_bytes)
+{
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+ uint size = pgdata->bits.size;
+ gs_copied_glyph_t *pcg = 0;
+ int code = copied_glyph_slot(cfdata, glyph, &pcg);
+
+ if (cfdata->ordered)
+ return_error(gs_error_unregistered); /* Must not happen. */
+ switch (code) {
+ case 0: /* already defined */
+ if ((options & COPY_GLYPH_NO_OLD) ||
+ pcg->gdata.size != prefix_bytes + size ||
+ memcmp(pcg->gdata.data, prefix, prefix_bytes) ||
+ memcmp(pcg->gdata.data + prefix_bytes,
+ pgdata->bits.data, size)
+ )
+ code = gs_note_error(gs_error_invalidaccess);
+ else
+ code = 1;
+ break;
+ case gs_error_undefined:
+ if (options & COPY_GLYPH_NO_NEW)
+ code = gs_note_error(gs_error_undefined);
+ else if (pcg == NULL)
+ code = gs_note_error(gs_error_undefined);
+ else {
+ uint str_size = prefix_bytes + size;
+ byte *str = gs_alloc_string(copied->memory, str_size,
+ "copy_glyph_data(data)");
+
+ if (str == 0)
+ code = gs_note_error(gs_error_VMerror);
+ else {
+ if (prefix_bytes)
+ memcpy(str, prefix, prefix_bytes);
+ memcpy(str + prefix_bytes, pgdata->bits.data, size);
+ pcg->gdata.data = str;
+ pcg->gdata.size = str_size;
+ pcg->used = HAS_DATA;
+ pcg->order_index = -1;
+ code = 0;
+ cfdata->num_glyphs++;
+ }
+ }
+ default:
+ break;
+ }
+ gs_glyph_data_free(pgdata, "copy_glyph_data");
+ return code;
+}
+
+/*
+ * Copy a glyph name into the names table.
+ */
+static int
+copy_glyph_name(gs_font *font, gs_glyph glyph, gs_font *copied,
+ gs_glyph copied_glyph)
+{
+ gs_glyph known_glyph;
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+ gs_copied_glyph_t *pcg;
+ int code = copied_glyph_slot(cfdata, copied_glyph, &pcg);
+ gs_copied_glyph_name_t *pcgn;
+ gs_const_string str;
+
+ if (cfdata->ordered)
+ return_error(gs_error_unregistered); /* Must not happen. */
+ if (code < 0 ||
+ (code = font->procs.glyph_name(font, glyph, &str)) < 0
+ )
+ return code;
+ /* Try to share a permanently allocated known glyph name. */
+ if ((known_glyph = gs_c_name_glyph(str.data, str.size)) != GS_NO_GLYPH)
+ gs_c_glyph_name(known_glyph, &str);
+ else if ((code = copy_string(copied->memory, &str, "copy_glyph_name")) < 0)
+ return code;
+ pcgn = cfdata->names + (pcg - cfdata->glyphs);
+ if (pcgn->glyph != GS_NO_GLYPH &&
+ (pcgn->str.size != str.size ||
+ memcmp(pcgn->str.data, str.data, str.size))
+ ) {
+ /* This is a glyph with multiple names. Add an extra_name entry. */
+ gs_copied_glyph_extra_name_t *extra_name =
+ gs_alloc_struct(copied->memory, gs_copied_glyph_extra_name_t,
+ &st_gs_copied_glyph_extra_name,
+ "copy_glyph_name(extra_name)");
+
+ if (extra_name == 0)
+ return_error(gs_error_VMerror);
+ extra_name->next = cfdata->extra_names;
+ extra_name->gid = pcg - cfdata->glyphs;
+ cfdata->extra_names = extra_name;
+ pcgn = &extra_name->name;
+ }
+ pcgn->glyph = glyph;
+ pcgn->str = str;
+ return 0;
+}
+
+/*
+ * Find the .notdef glyph in a font.
+ */
+static gs_glyph
+find_notdef(gs_font_base *font)
+{
+ int index = 0;
+ gs_glyph glyph;
+
+ while (font->procs.enumerate_glyph((gs_font *)font, &index,
+ GLYPH_SPACE_NAME, &glyph),
+ index != 0)
+ if (gs_font_glyph_is_notdef(font, glyph))
+ return glyph;
+ return GS_NO_GLYPH; /* best we can do */
+}
+
+/*
+ * Add an Encoding entry to a character-indexed font (Type 1/2/42).
+ */
+static int
+copied_char_add_encoding(gs_font *copied, gs_char chr, gs_glyph glyph)
+{
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+ gs_glyph *Encoding = cfdata->Encoding;
+ gs_copied_glyph_t *pslot;
+ int code;
+
+ if (cfdata->ordered)
+ return_error(gs_error_unregistered); /* Must not happen. */
+ if (Encoding == 0)
+ return_error(gs_error_invalidaccess);
+ if (chr >= 256 || glyph >= GS_MIN_CID_GLYPH)
+ return_error(gs_error_rangecheck);
+ code = copied_glyph_slot(cfdata, glyph, &pslot);
+ if (code < 0)
+ return code;
+ if (Encoding[chr] != glyph && Encoding[chr] != GS_NO_GLYPH)
+ return_error(gs_error_invalidaccess);
+ Encoding[chr] = glyph;
+ return 0;
+}
+
+/* Don't allow adding an Encoding entry. */
+static int
+copied_no_add_encoding(gs_font *copied, gs_char chr, gs_glyph glyph)
+{
+ return_error(gs_error_invalidaccess);
+}
+
+/* ---------------- Font procedures ---------------- */
+
+static int
+copied_font_info(gs_font *font, const gs_point *pscale, int members,
+ gs_font_info_t *info)
+{
+ if (pscale != 0)
+ return_error(gs_error_rangecheck);
+ *info = cf_data(font)->info;
+ return 0;
+}
+
+static gs_glyph
+copied_encode_char(gs_font *copied, gs_char chr, gs_glyph_space_t glyph_space)
+{
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+ const gs_glyph *Encoding = cfdata->Encoding;
+
+ if (chr >= 256 || Encoding == 0)
+ return GS_NO_GLYPH;
+ return Encoding[chr];
+}
+
+static int
+copied_enumerate_glyph(gs_font *font, int *pindex,
+ gs_glyph_space_t glyph_space, gs_glyph *pglyph)
+{
+ gs_copied_font_data_t *const cfdata = cf_data(font);
+
+ if (cfdata->ordered) {
+ if (*pindex >= cfdata->num_glyphs)
+ *pindex = 0;
+ else {
+ int i = cfdata->glyphs[*pindex].order_index;
+
+ *pglyph = cfdata->names[i].glyph;
+ ++(*pindex);
+ }
+ return 0;
+ }
+ for (; *pindex < cfdata->glyphs_size; ++*pindex)
+ if (cfdata->glyphs[*pindex].used) {
+ *pglyph =
+ (glyph_space == GLYPH_SPACE_NAME && cfdata->names != 0 ?
+ cfdata->names[*pindex].glyph :
+ /* CIDFontType 0 uses CIDS as slot indices; CIDFontType 2 uses GIDs. */
+ *pindex + (glyph_space == GLYPH_SPACE_NAME
+ ? GS_MIN_CID_GLYPH : GS_MIN_GLYPH_INDEX));
+ ++(*pindex);
+ return 0;
+ }
+ *pindex = 0;
+ return 0;
+}
+
+static int
+copied_glyph_name(gs_font *font, gs_glyph glyph, gs_const_string *pstr)
+{
+ gs_copied_font_data_t *const cfdata = cf_data(font);
+ gs_copied_glyph_t *pcg;
+
+ if (glyph >= GS_MIN_CID_GLYPH)
+ return_error(gs_error_rangecheck);
+ if (copied_glyph_slot(cfdata, glyph, &pcg) < 0)
+ return_error(gs_error_undefined);
+ *pstr = cfdata->names[pcg - cfdata->glyphs].str;
+ return 0;
+}
+
+static int
+copied_build_char(gs_show_enum *pte, gs_state *pgs, gs_font *font,
+ gs_char chr, gs_glyph glyph)
+{
+ int wmode = font->WMode;
+ int code;
+ gs_glyph_info_t info;
+ double wxy[6];
+ double sbw_stub[4]; /* Currently glyph_outline retrieves sbw only with type 1,2,9 fonts. */
+
+ if (glyph == GS_NO_GLYPH) {
+ glyph = font->procs.encode_char(font, chr, GLYPH_SPACE_INDEX);
+ if (glyph == GS_NO_GLYPH)
+ glyph = cf_data(font)->notdef;
+ }
+ /*
+ * Type 1/2 outlines don't require a current point, but TrueType
+ * outlines do. We might want to fix this someday....
+ */
+ if ((code = gs_moveto(pgs, 0.0, 0.0)) < 0 ||
+ (code = font->procs.glyph_info(font, glyph, NULL,
+ (GLYPH_INFO_WIDTH << wmode) |
+ GLYPH_INFO_BBOX |
+ GLYPH_INFO_OUTLINE_WIDTHS,
+ &info)) < 0
+ )
+ return code;
+ wxy[0] = info.width[wmode].x;
+ wxy[1] = info.width[wmode].y;
+ wxy[2] = info.bbox.p.x;
+ wxy[3] = info.bbox.p.y;
+ wxy[4] = info.bbox.q.x;
+ wxy[5] = info.bbox.q.y;
+ if ((code = gs_setcachedevice_double(pte, pte->pgs, wxy)) < 0 ||
+ (code = font->procs.glyph_outline(font, wmode, glyph, &ctm_only(pgs),
+ pgs->path, sbw_stub)) < 0
+ )
+ return code;
+ if (font->PaintType != 0) {
+ gs_setlinewidth(pgs, font->StrokeWidth);
+ return gs_stroke(pgs);
+ } else {
+ return gs_fill(pgs);
+ }
+}
+
+static inline bool
+compare_arrays(const float *v0, int l0, const float *v1, int l1)
+{
+ if (l0 != l1)
+ return false;
+ if (memcmp(v0, v1, l0 * sizeof(v0[0])))
+ return false;
+ return true;
+}
+
+#define compare_tables(a, b) compare_arrays(a.values, a.count, b.values, b.count)
+
+static int
+compare_glyphs(const gs_font *cfont, const gs_font *ofont, gs_glyph *glyphs,
+ int num_glyphs, int glyphs_step, int level)
+{
+ /*
+ * Checking widths because we can synthesize fonts from random fonts
+ * having same FontName and FontType.
+ * We must request width explicitely because Type 42 stores widths
+ * separately from outline data. We could skip it for Type 1, which doesn't.
+ * We don't care of Metrics, Metrics2 because copied font never has them.
+ */
+ int i, WMode = ofont->WMode;
+ int members = (GLYPH_INFO_WIDTH0 << WMode) | GLYPH_INFO_OUTLINE_WIDTHS | GLYPH_INFO_NUM_PIECES;
+ gs_matrix mat;
+ gs_copied_font_data_t *const cfdata = cf_data(cfont);
+ int num_new_glyphs = 0;
+
+ gs_make_identity(&mat);
+ for (i = 0; i < num_glyphs; i++) {
+ gs_glyph glyph = *(gs_glyph *)((byte *)glyphs + i * glyphs_step);
+ gs_glyph pieces0[40], *pieces = pieces0;
+ gs_glyph_info_t info0, info1;
+ int code0 = ofont->procs.glyph_info((gs_font *)ofont, glyph, &mat, members, &info0);
+ int code1 = cfont->procs.glyph_info((gs_font *)cfont, glyph, &mat, members, &info1);
+ int code2, code;
+
+ if (code0 == gs_error_undefined)
+ continue;
+ if (code1 == gs_error_undefined) {
+ num_new_glyphs++;
+ if (num_new_glyphs > cfdata->glyphs_size - cfdata->num_glyphs)
+ return 0;
+ continue;
+ }
+ if (code0 < 0)
+ return code0;
+ if (code1 < 0)
+ return code1;
+ if (info0.num_pieces != info1.num_pieces)
+ return 0;
+ if (info0.width[WMode].x != info1.width[WMode].x ||
+ info0.width[WMode].y != info1.width[WMode].y)
+ return 0;
+ if (WMode && (info0.v.x != info1.v.x || info0.v.y != info1.v.y))
+ return 0;
+ if (info0.num_pieces > 0) {
+ if(level > 5)
+ return_error(gs_error_rangecheck); /* abnormal glyph recursion */
+ if (info0.num_pieces > countof(pieces0) / 2) {
+ pieces = (gs_glyph *)gs_alloc_bytes(cfont->memory,
+ sizeof(glyphs) * info0.num_pieces * 2, "compare_glyphs");
+ if (pieces == 0)
+ return_error(gs_error_VMerror);
+ }
+ info0.pieces = pieces;
+ info1.pieces = pieces + info0.num_pieces;
+ code0 = ofont->procs.glyph_info((gs_font *)ofont, glyph, &mat,
+ GLYPH_INFO_PIECES, &info0);
+ code1 = cfont->procs.glyph_info((gs_font *)cfont, glyph, &mat,
+ GLYPH_INFO_PIECES, &info1);
+ if (code0 >= 0 && code1 >= 0) {
+ code2 = memcmp(info0.pieces, info1.pieces, info0.num_pieces * sizeof(*pieces));
+ if (!code2)
+ code = compare_glyphs(cfont, ofont, pieces, info0.num_pieces, glyphs_step, level + 1);
+ else
+ code = 0; /* Quiet compiler. */
+ } else
+ code2 = code = 0;
+ if (pieces != pieces0)
+ gs_free_object(cfont->memory, pieces, "compare_glyphs");
+ if (code0 == gs_error_undefined)
+ continue;
+ if (code1 == gs_error_undefined) {
+ num_new_glyphs++;
+ if (num_new_glyphs > cfdata->glyphs_size - cfdata->num_glyphs)
+ return 0;
+ continue;
+ }
+ if (code0 < 0)
+ return code0;
+ if (code1 < 0)
+ return code1;
+ if (code2 || code == 0) {
+ return 0;
+ }
+ } else {
+ gs_glyph_data_t gdata0, gdata1;
+
+ switch(cfont->FontType) {
+ case ft_encrypted:
+ case ft_encrypted2: {
+ gs_font_type1 *font0 = (gs_font_type1 *)cfont;
+ gs_font_type1 *font1 = (gs_font_type1 *)ofont;
+
+ gdata0.memory = font0->memory;
+ gdata1.memory = font1->memory;
+ code0 = font0->data.procs.glyph_data(font0, glyph, &gdata0);
+ code1 = font1->data.procs.glyph_data(font1, glyph, &gdata1);
+ break;
+ }
+ case ft_TrueType:
+ case ft_CID_TrueType: {
+ gs_font_type42 *font0 = (gs_font_type42 *)cfont;
+ gs_font_type42 *font1 = (gs_font_type42 *)ofont;
+ uint glyph_index0 = font0->data.get_glyph_index(font0, glyph);
+ uint glyph_index1 = font1->data.get_glyph_index(font1, glyph);
+
+ gdata0.memory = font0->memory;
+ gdata1.memory = font1->memory;
+ code0 = font0->data.get_outline(font0, glyph_index0, &gdata0);
+ code1 = font1->data.get_outline(font1, glyph_index1, &gdata1);
+ break;
+ }
+ case ft_CID_encrypted: {
+ gs_font_cid0 *font0 = (gs_font_cid0 *)cfont;
+ gs_font_cid0 *font1 = (gs_font_cid0 *)ofont;
+ int fidx0, fidx1;
+
+ gdata0.memory = font0->memory;
+ gdata1.memory = font1->memory;
+ code0 = font0->cidata.glyph_data((gs_font_base *)font0, glyph, &gdata0, &fidx0);
+ code1 = font1->cidata.glyph_data((gs_font_base *)font1, glyph, &gdata1, &fidx1);
+ break;
+ }
+ default:
+ return_error(gs_error_unregistered); /* unimplemented */
+ }
+ if (code0 < 0) {
+ if (code1 >= 0)
+ gs_glyph_data_free(&gdata1, "compare_glyphs");
+ return code0;
+ }
+ if (code1 < 0) {
+ if (code0 >= 0)
+ gs_glyph_data_free(&gdata0, "compare_glyphs");
+ return code1;
+ }
+ if (gdata0.bits.size != gdata1.bits.size)
+ return 0;
+ if (memcmp(gdata0.bits.data, gdata0.bits.data, gdata0.bits.size))
+ return 0;
+ gs_glyph_data_free(&gdata0, "compare_glyphs");
+ gs_glyph_data_free(&gdata1, "compare_glyphs");
+ }
+ }
+ return 1;
+}
+
+/* ---------------- Individual FontTypes ---------------- */
+
+/* ------ Type 1 ------ */
+
+static int
+copied_type1_glyph_data(gs_font_type1 * pfont, gs_glyph glyph,
+ gs_glyph_data_t *pgd)
+{
+ gs_copied_font_data_t *const cfdata = cf_data((gs_font *)pfont);
+ gs_copied_glyph_t *pslot;
+ int code = copied_glyph_slot(cfdata, glyph, &pslot);
+
+ if (code < 0)
+ return code;
+ gs_glyph_data_from_string(pgd, pslot->gdata.data, pslot->gdata.size,
+ NULL);
+ return 0;
+}
+
+static int
+copied_type1_subr_data(gs_font_type1 * pfont, int subr_num, bool global,
+ gs_glyph_data_t *pgd)
+{
+ gs_copied_font_data_t *const cfdata = cf_data((gs_font *)pfont);
+ const gs_subr_info_t *psi =
+ (global ? &cfdata->global_subrs : &cfdata->subrs);
+
+ if (subr_num < 0 || subr_num >= psi->count)
+ return_error(gs_error_rangecheck);
+ gs_glyph_data_from_string(pgd, psi->data + psi->starts[subr_num],
+ psi->starts[subr_num + 1] -
+ psi->starts[subr_num],
+ NULL);
+ return 0;
+}
+
+static int
+copied_type1_seac_data(gs_font_type1 * pfont, int ccode,
+ gs_glyph * pglyph, gs_const_string *gstr, gs_glyph_data_t *pgd)
+{
+ /*
+ * This can only be invoked if the components have already been
+ * copied to their proper positions, so it is simple.
+ */
+ gs_glyph glyph = gs_c_known_encode((gs_char)ccode, ENCODING_INDEX_STANDARD);
+ gs_glyph glyph1;
+ int code;
+
+ if (glyph == GS_NO_GLYPH)
+ return_error(gs_error_rangecheck);
+ code = gs_c_glyph_name(glyph, gstr);
+ if (code < 0)
+ return code;
+ code = pfont->dir->global_glyph_code(pfont->memory, gstr, &glyph1);
+ if (code < 0)
+ return code;
+ if (pglyph)
+ *pglyph = glyph1;
+ if (pgd)
+ return copied_type1_glyph_data(pfont, glyph1, pgd);
+ else
+ return 0;
+}
+
+static int
+copied_type1_push_values(void *callback_data, const fixed *values, int count)
+{
+ return_error(gs_error_unregistered);
+}
+
+static int
+copied_type1_pop_value(void *callback_data, fixed *value)
+{
+ return_error(gs_error_unregistered);
+}
+
+static int
+copy_font_type1(gs_font *font, gs_font *copied)
+{
+ gs_font_type1 *font1 = (gs_font_type1 *)font;
+ gs_font_type1 *copied1 = (gs_font_type1 *)copied;
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+ int code;
+
+ cfdata->notdef = find_notdef((gs_font_base *)font);
+ code = copied_Encoding_alloc(copied);
+ if (code < 0)
+ return code;
+ if ((code = copy_subrs(font1, false, &cfdata->subrs, copied->memory)) < 0 ||
+ (code = copy_subrs(font1, true, &cfdata->global_subrs, copied->memory)) < 0
+ ) {
+ gs_free_object(copied->memory, cfdata->Encoding,
+ "copy_font_type1(Encoding)");
+ return code;
+ }
+ /*
+ * We don't need real push/pop procedures, because we can't do anything
+ * useful with fonts that have non-standard OtherSubrs anyway.
+ */
+ copied1->data.procs.glyph_data = copied_type1_glyph_data;
+ copied1->data.procs.subr_data = copied_type1_subr_data;
+ copied1->data.procs.seac_data = copied_type1_seac_data;
+ copied1->data.procs.push_values = copied_type1_push_values;
+ copied1->data.procs.pop_value = copied_type1_pop_value;
+ copied1->data.proc_data = 0;
+ return 0;
+}
+
+static int
+copy_glyph_type1(gs_font *font, gs_glyph glyph, gs_font *copied, int options)
+{
+ gs_glyph_data_t gdata;
+ gs_font_type1 *font1 = (gs_font_type1 *)font;
+ int code;
+ int rcode;
+
+ gdata.memory = font->memory;
+ code = font1->data.procs.glyph_data(font1, glyph, &gdata);
+ if (code < 0)
+ return code;
+ code = copy_glyph_data(font, glyph, copied, options, &gdata, NULL, 0);
+ if (code < 0)
+ return code;
+ rcode = code;
+ if (code == 0)
+ code = copy_glyph_name(font, glyph, copied, glyph);
+ return (code < 0 ? code : rcode);
+}
+
+static int
+copied_type1_glyph_outline(gs_font *font, int WMode, gs_glyph glyph,
+ const gs_matrix *pmat, gx_path *ppath, double sbw[4])
+{ /*
+ * 'WMode' may be inherited from an upper font.
+ * We ignore in because Type 1,2 charstrings do not depend on it.
+ */
+
+ /*
+ * This code duplicates much of zcharstring_outline in zchar1.c.
+ * This is unfortunate, but we don't see a simple way to refactor the
+ * code to avoid it.
+ */
+ gs_glyph_data_t gdata;
+ gs_font_type1 *const pfont1 = (gs_font_type1 *)font;
+ int code;
+ const gs_glyph_data_t *pgd = &gdata;
+ gs_type1_state cis;
+ gs_imager_state gis;
+
+ gdata.memory = pfont1->memory;
+ code = pfont1->data.procs.glyph_data(pfont1, glyph, &gdata);
+ if (code < 0)
+ return code;
+ if (pgd->bits.size <= max(pfont1->data.lenIV, 0))
+ return_error(gs_error_invalidfont);
+ /* Initialize just enough of the imager state. */
+ if (pmat)
+ gs_matrix_fixed_from_matrix(&gis.ctm, pmat);
+ else {
+ gs_matrix imat;
+
+ gs_make_identity(&imat);
+ gs_matrix_fixed_from_matrix(&gis.ctm, &imat);
+ }
+ gis.flatness = 0;
+ code = gs_type1_interp_init(&cis, &gis, ppath, NULL, NULL, true, 0,
+ pfont1);
+ if (code < 0)
+ return code;
+ cis.no_grid_fitting = true;
+ /* Continue interpreting. */
+ for (;;) {
+ int value;
+
+ code = pfont1->data.interpret(&cis, pgd, &value);
+ switch (code) {
+ case 0: /* all done */
+ /* falls through */
+ default: /* code < 0, error */
+ return code;
+ case type1_result_callothersubr: /* unknown OtherSubr */
+ return_error(gs_error_rangecheck); /* can't handle it */
+ case type1_result_sbw: /* [h]sbw, just continue */
+ pgd = 0;
+ type1_cis_get_metrics(&cis, sbw);
+ }
+ }
+}
+
+static const gs_copied_font_procs_t copied_procs_type1 = {
+ copy_font_type1, copy_glyph_type1, copied_char_add_encoding,
+ named_glyph_slot_hashed,
+ copied_encode_char, gs_type1_glyph_info, copied_type1_glyph_outline
+};
+
+static bool
+same_type1_subrs(const gs_font_type1 *cfont, const gs_font_type1 *ofont,
+ bool global)
+{
+ gs_glyph_data_t gdata0, gdata1;
+ int i, code = 0;
+ bool exit = false;
+
+ gdata0.memory = cfont->memory;
+ gdata1.memory = ofont->memory;
+ /* Scan the font to determine the size of the subrs. */
+ for (i = 0; !exit; i++) {
+ int code0 = cfont->data.procs.subr_data((gs_font_type1 *)cfont,
+ i, global, &gdata0);
+ int code1 = ofont->data.procs.subr_data((gs_font_type1 *)ofont,
+ i, global, &gdata1);
+ bool missing0, missing1;
+
+ if (code0 == gs_error_rangecheck && code1 == gs_error_rangecheck)
+ return 1; /* Both arrays exceeded. */
+ /* Some fonts use null for skiping elements in subrs array.
+ This gives typecheck.
+ */
+ missing0 = (code0 == gs_error_rangecheck || code0 == gs_error_typecheck);
+ missing1 = (code1 == gs_error_rangecheck || code1 == gs_error_typecheck);
+ if (missing0 && missing1)
+ continue;
+ if (missing0 && !missing1)
+ return 0; /* The copy has insufficient subrs. */
+ if (missing1)
+ continue;
+ if (code0 < 0)
+ code = code0, exit = true;
+ else if (code1 < 0)
+ code = code1, exit = true;
+ else if (gdata0.bits.size != gdata1.bits.size)
+ exit = true;
+ else if (memcmp(gdata0.bits.data, gdata1.bits.data, gdata0.bits.size))
+ exit = true;
+ if (code0 > 0)
+ gs_glyph_data_free(&gdata0, "same_type1_subrs");
+ if (code1 > 0)
+ gs_glyph_data_free(&gdata1, "same_type1_subrs");
+ }
+ return code;
+}
+
+static bool
+same_type1_hinting(const gs_font_type1 *cfont, const gs_font_type1 *ofont)
+{
+ const gs_type1_data *d0 = &cfont->data, *d1 = &ofont->data;
+
+ if (d0->lenIV != d1->lenIV)
+ return false;
+ /*
+ if (d0->defaultWidthX != d1->defaultWidthX)
+ return false;
+ if (d0->nominalWidthX != d1->nominalWidthX)
+ return false;
+ */
+ if (d0->BlueFuzz != d1->BlueFuzz)
+ return false;
+ if (d0->BlueScale != d1->BlueScale)
+ return false;
+ if (d0->BlueShift != d1->BlueShift)
+ return false;
+ if (d0->ExpansionFactor != d1->ExpansionFactor)
+ return false;
+ if (d0->ForceBold != d1->ForceBold)
+ return false;
+ if (!compare_tables(d0->FamilyBlues, d1->FamilyBlues))
+ return false;
+ if (!compare_tables(d0->FamilyOtherBlues, d1->FamilyOtherBlues))
+ return false;
+ if (d0->LanguageGroup != d1->LanguageGroup)
+ return false;
+ if (!compare_tables(d0->OtherBlues, d1->OtherBlues))
+ return false;
+ if (d0->RndStemUp != d1->RndStemUp)
+ return false;
+ if (!compare_tables(d0->StdHW, d1->StdHW))
+ return false;
+ if (!compare_tables(d0->StemSnapH, d1->StemSnapH))
+ return false;
+ if (!compare_tables(d0->StemSnapV, d1->StemSnapV))
+ return false;
+ if (!compare_tables(d0->WeightVector, d1->WeightVector))
+ return false;
+ if (!same_type1_subrs(cfont, ofont, false))
+ return false;
+ if (!same_type1_subrs(cfont, ofont, true))
+ return false;
+ /*
+ * We ignore differences in OtherSubrs because pdfwrite
+ * must build without PS interpreter and therefore copied font
+ * have no storage for them.
+ */
+ return true;
+}
+
+/* ------ Type 42 ------ */
+
+static int
+copied_type42_string_proc(gs_font_type42 *font, ulong offset, uint len,
+ const byte **pstr)
+{
+ gs_copied_font_data_t *const cfdata = font->data.proc_data;
+
+ if (offset + len > cfdata->data_size)
+ return_error(gs_error_rangecheck);
+ *pstr = cfdata->data + offset;
+ return 0;
+}
+
+static int
+copied_type42_get_outline(gs_font_type42 *font, uint glyph_index,
+ gs_glyph_data_t *pgd)
+{
+ gs_copied_font_data_t *const cfdata = font->data.proc_data;
+ gs_copied_glyph_t *pcg;
+
+ if (glyph_index >= cfdata->glyphs_size)
+ return_error(gs_error_rangecheck);
+ pcg = &cfdata->glyphs[glyph_index];
+ if (!pcg->used)
+ gs_glyph_data_from_null(pgd);
+ else
+ gs_glyph_data_from_string(pgd, pcg->gdata.data, pcg->gdata.size, NULL);
+ return 0;
+}
+
+static int
+copied_type42_get_metrics(gs_font_type42 * pfont, uint glyph_index,
+ gs_type42_metrics_options_t options, float sbw[4])
+{
+ /* Check whether we have metrics for this (glyph,wmode) pair. */
+ gs_copied_font_data_t *const cfdata = pfont->data.proc_data;
+ gs_copied_glyph_t *pcg;
+ int wmode = gs_type42_metrics_options_wmode(options);
+
+ if (glyph_index >= cfdata->glyphs_size)
+ return_error(gs_error_rangecheck);
+ pcg = &cfdata->glyphs[glyph_index];
+ if (!(pcg->used & (HAS_SBW0 << wmode)))
+ return_error(gs_error_undefined);
+ return gs_type42_default_get_metrics(pfont, glyph_index, options, sbw);
+}
+
+static uint
+copied_type42_get_glyph_index(gs_font_type42 *font, gs_glyph glyph)
+{
+ gs_copied_font_data_t *const cfdata = cf_data((gs_font *)font);
+ gs_copied_glyph_t *pcg;
+ int code = copied_glyph_slot(cfdata, glyph, &pcg);
+
+ if (code < 0)
+ return GS_NO_GLYPH;
+ return pcg - cfdata->glyphs;
+}
+
+static int
+copy_font_type42(gs_font *font, gs_font *copied)
+{
+ gs_font_type42 *const font42 = (gs_font_type42 *)font;
+ gs_font_type42 *const copied42 = (gs_font_type42 *)copied;
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+ /*
+ * We "write" the font, aside from the glyphs, into an in-memory
+ * structure, and access it from there.
+ * We allocate room at the end of the copied data for fake hmtx/vmtx.
+ */
+ uint extra = font42->data.trueNumGlyphs * 8;
+ stream fs;
+ int code;
+
+ cfdata->notdef = find_notdef((gs_font_base *)font);
+ code = copied_Encoding_alloc(copied);
+ if (code < 0)
+ return code;
+ s_init(&fs, font->memory);
+ swrite_position_only(&fs);
+ code = (font->FontType == ft_TrueType ? psf_write_truetype_stripped(&fs, font42)
+ : psf_write_cid2_stripped(&fs, (gs_font_cid2 *)font42));
+ code = copied_data_alloc(copied, &fs, extra, code);
+ if (code < 0)
+ goto fail;
+ if (font->FontType == ft_TrueType)
+ psf_write_truetype_stripped(&fs, font42);
+ else
+ psf_write_cid2_stripped(&fs, (gs_font_cid2 *)font42);
+ copied42->data.string_proc = copied_type42_string_proc;
+ copied42->data.proc_data = cfdata;
+ code = gs_type42_font_init(copied42, 0);
+ if (code < 0)
+ goto fail2;
+ /* gs_type42_font_init overwrites font_info. */
+ copied->procs.font_info = copied_font_info;
+ /* gs_type42_font_init overwrites enumerate_glyph. */
+ copied42->procs.enumerate_glyph = copied_enumerate_glyph;
+ copied42->data.get_glyph_index = copied_type42_get_glyph_index;
+ copied42->data.get_outline = copied_type42_get_outline;
+ copied42->data.get_metrics = copied_type42_get_metrics;
+ copied42->data.metrics[0].numMetrics =
+ copied42->data.metrics[1].numMetrics =
+ extra / 8;
+ copied42->data.metrics[0].offset = cfdata->data_size - extra;
+ copied42->data.metrics[1].offset = cfdata->data_size - extra / 2;
+ copied42->data.metrics[0].length =
+ copied42->data.metrics[1].length =
+ extra / 2;
+ memset(cfdata->data + cfdata->data_size - extra, 0, extra);
+ copied42->data.numGlyphs = font42->data.numGlyphs;
+ copied42->data.trueNumGlyphs = font42->data.trueNumGlyphs;
+ return 0;
+ fail2:
+ gs_free_object(copied->memory, cfdata->data,
+ "copy_font_type42(data)");
+ fail:
+ gs_free_object(copied->memory, cfdata->Encoding,
+ "copy_font_type42(Encoding)");
+ return code;
+}
+
+static int
+copy_glyph_type42(gs_font *font, gs_glyph glyph, gs_font *copied, int options)
+{
+ gs_glyph_data_t gdata;
+ gs_font_type42 *font42 = (gs_font_type42 *)font;
+ gs_font_cid2 *fontCID2 = (gs_font_cid2 *)font;
+ gs_font_type42 *const copied42 = (gs_font_type42 *)copied;
+ uint gid = (options & COPY_GLYPH_BY_INDEX ? glyph - GS_MIN_GLYPH_INDEX :
+ font->FontType == ft_CID_TrueType
+ ? fontCID2->cidata.CIDMap_proc(fontCID2, glyph)
+ : font42->data.get_glyph_index(font42, glyph));
+ int code;
+ int rcode;
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+ gs_copied_glyph_t *pcg;
+ float sbw[4];
+ double factor = font42->data.unitsPerEm;
+ int i;
+
+ gdata.memory = font42->memory;
+ code = font42->data.get_outline(font42, gid, &gdata);
+ if (code < 0)
+ return code;
+ code = copy_glyph_data(font, gid + GS_MIN_GLYPH_INDEX, copied, options,
+ &gdata, NULL, 0);
+ if (code < 0)
+ return code;
+ rcode = code;
+ if (glyph < GS_MIN_CID_GLYPH)
+ code = copy_glyph_name(font, glyph, copied,
+ gid + GS_MIN_GLYPH_INDEX);
+ DISCARD(copied_glyph_slot(cfdata, gid + GS_MIN_GLYPH_INDEX, &pcg)); /* can't fail */
+ for (i = 0; i < 2; ++i) {
+ if (font42->data.get_metrics(font42, gid, i, sbw) >= 0) {
+ int sb = (int)(sbw[i] * factor + 0.5);
+ uint width = (uint)(sbw[2 + i] * factor + 0.5);
+ byte *pmetrics =
+ cfdata->data + copied42->data.metrics[i].offset + gid * 4;
+
+ pmetrics[0] = (byte)(width >> 8);
+ pmetrics[1] = (byte)width;
+ pmetrics[2] = (byte)(sb >> 8);
+ pmetrics[3] = (byte)sb;
+ pcg->used |= HAS_SBW0 << i;
+ }
+ factor = -factor; /* values are negated for WMode = 1 */
+ }
+ return (code < 0 ? code : rcode);
+}
+
+static gs_glyph
+copied_type42_encode_char(gs_font *copied, gs_char chr,
+ gs_glyph_space_t glyph_space)
+{
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+ const gs_glyph *Encoding = cfdata->Encoding;
+ gs_glyph glyph;
+
+ if (chr >= 256 || Encoding == 0)
+ return GS_NO_GLYPH;
+ glyph = Encoding[chr];
+ if (glyph_space == GLYPH_SPACE_INDEX) {
+ /* Search linearly for the glyph by name. */
+ gs_copied_glyph_t *pcg;
+ int code = named_glyph_slot_linear(cfdata, glyph, &pcg);
+
+ if (code < 0 || !pcg->used)
+ return GS_NO_GLYPH;
+ return GS_MIN_GLYPH_INDEX + (pcg - cfdata->glyphs);
+ }
+ return glyph;
+}
+
+
+static const gs_copied_font_procs_t copied_procs_type42 = {
+ copy_font_type42, copy_glyph_type42, copied_char_add_encoding,
+ named_glyph_slot_linear,
+ copied_type42_encode_char, gs_type42_glyph_info, gs_type42_glyph_outline
+};
+
+static inline int
+access_type42_data(gs_font_type42 *pfont, ulong base, ulong length,
+ const byte **vptr)
+{
+ return pfont->data.string_proc(pfont, base, length, vptr);
+}
+
+static inline uint
+U16(const byte *p)
+{
+ return ((uint)p[0] << 8) + p[1];
+}
+
+static int
+same_type42_hinting(gs_font_type42 *font0, gs_font_type42 *font1)
+{
+ gs_type42_data *d0 = &font0->data, *d1 = &font1->data;
+ gs_font_type42 *font[2];
+ uint pos[2][3];
+ uint len[2][3] = {{0,0,0}, {0,0,0}};
+ int i, j, code;
+
+ if (d0->unitsPerEm != d1->unitsPerEm)
+ return 0;
+ font[0] = font0;
+ font[1] = font1;
+ memset(pos, 0, sizeof(pos));
+ for (j = 0; j < 2; j++) {
+ const byte *OffsetTable;
+ uint numTables;
+
+ code = access_type42_data(font[j], 0, 12, &OffsetTable);
+ if (code < 0)
+ return code;
+ numTables = U16(OffsetTable + 4);
+ for (i = 0; i < numTables; ++i) {
+ const byte *tab;
+ ulong start;
+ uint length;
+
+ code = access_type42_data(font[j], 12 + i * 16, 16, &tab);
+ if (code < 0)
+ return code;
+ start = get_u32_msb(tab + 8);
+ length = get_u32_msb(tab + 12);
+ if (!memcmp("prep", tab, 4))
+ pos[j][0] = start, len[j][0] = length;
+ else if (!memcmp("cvt ", tab, 4))
+ pos[j][1] = start, len[j][1] = length;
+ else if (!memcmp("fpgm", tab, 4))
+ pos[j][2] = start, len[j][2] = length;
+ }
+ }
+ for (i = 0; i < 3; i++) {
+ if (len[0][i] != len[1][i])
+ return 0;
+ }
+ for (i = 0; i < 3; i++) {
+ if (len[0][i] != 0) {
+ const byte *data0, *data1;
+ ulong length = len[0][i], size0, size1, size;
+ ulong pos0 = pos[0][i], pos1 = pos[1][i];
+
+ while (length > 0) {
+ code = access_type42_data(font0, pos0, length, &data0);
+ if (code < 0)
+ return code;
+ size0 = (code == 0 ? length : code);
+ code = access_type42_data(font1, pos1, length, &data1);
+ if (code < 0)
+ return code;
+ size1 = (code == 0 ? length : code);
+ size = min(size0, size1);
+ if (memcmp(data0, data1, size))
+ return 0;
+ pos0 += size;
+ pos1 += size;
+ length -= size;
+ }
+ }
+ }
+ return 1;
+}
+
+/* ------ CIDFont shared ------ */
+
+static int
+copy_font_cid_common(gs_font *font, gs_font *copied, gs_font_cid_data *pcdata)
+{
+ return (copy_string(copied->memory, &pcdata->CIDSystemInfo.Registry,
+ "Registry") |
+ copy_string(copied->memory, &pcdata->CIDSystemInfo.Ordering,
+ "Ordering"));
+}
+
+/* ------ CIDFontType 0 ------ */
+
+static int
+copied_cid0_glyph_data(gs_font_base *font, gs_glyph glyph,
+ gs_glyph_data_t *pgd, int *pfidx)
+{
+ gs_font_cid0 *fcid0 = (gs_font_cid0 *)font;
+ gs_copied_font_data_t *const cfdata = cf_data((gs_font *)font);
+ gs_copied_glyph_t *pcg;
+ int code = copied_glyph_slot(cfdata, glyph, &pcg);
+ int fdbytes = fcid0->cidata.FDBytes;
+ int i;
+
+ if (pfidx)
+ *pfidx = 0;
+ if (code < 0) {
+ if (pgd)
+ gs_glyph_data_from_null(pgd);
+ return_error(gs_error_undefined);
+ }
+ if (pfidx)
+ for (i = 0; i < fdbytes; ++i)
+ *pfidx = (*pfidx << 8) + pcg->gdata.data[i];
+ if (pgd)
+ gs_glyph_data_from_string(pgd, pcg->gdata.data + fdbytes,
+ pcg->gdata.size - fdbytes, NULL);
+ return 0;
+}
+static int
+copied_sub_type1_glyph_data(gs_font_type1 * pfont, gs_glyph glyph,
+ gs_glyph_data_t *pgd)
+{
+ return
+ copied_cid0_glyph_data((gs_font_base *)cf_data((gs_font *)pfont)->parent,
+ glyph, pgd, NULL);
+}
+
+static int
+cid0_subfont(gs_font *copied, gs_glyph glyph, gs_font_type1 **pfont1)
+{
+ int fidx;
+ int code = copied_cid0_glyph_data((gs_font_base *)copied, glyph, NULL,
+ &fidx);
+
+ if (code >= 0) {
+ gs_font_cid0 *font0 = (gs_font_cid0 *)copied;
+
+ if (fidx >= font0->cidata.FDArray_size)
+ return_error(gs_error_unregistered); /* Must not happen. */
+ *pfont1 = font0->cidata.FDArray[fidx];
+ }
+ return code;
+}
+
+static int
+copied_cid0_glyph_info(gs_font *font, gs_glyph glyph, const gs_matrix *pmat,
+ int members, gs_glyph_info_t *info)
+{
+ gs_font_type1 *subfont1;
+ int code = cid0_subfont(font, glyph, &subfont1);
+
+ if (code < 0)
+ return code;
+ if (members & GLYPH_INFO_WIDTH1) {
+ /* Hack : There is no way to pass WMode from font to glyph_info,
+ * and usually CID font has no metrics for WMode 1.
+ * Therefore we use FontBBox as default size.
+ * Warning : this incompletely implements the request :
+ * other requested members are not retrieved.
+ */
+ gs_font_info_t finfo;
+ int code = subfont1->procs.font_info(font, NULL, FONT_INFO_BBOX, &finfo);
+
+ if (code < 0)
+ return code;
+ info->width[0].x = 0;
+ info->width[0].y = 0;
+ info->width[1].x = 0;
+ info->width[1].y = -finfo.BBox.q.x; /* Sic! */
+ info->v.x = finfo.BBox.q.x / 2;
+ info->v.y = finfo.BBox.q.y;
+ info->members = GLYPH_INFO_WIDTH1;
+ return 0;
+ }
+ return subfont1->procs.glyph_info((gs_font *)subfont1, glyph, pmat,
+ members, info);
+}
+
+static int
+copied_cid0_glyph_outline(gs_font *font, int WMode, gs_glyph glyph,
+ const gs_matrix *pmat, gx_path *ppath, double sbw[4])
+{
+ gs_font_type1 *subfont1;
+ int code = cid0_subfont(font, glyph, &subfont1);
+
+ if (code < 0)
+ return code;
+ return subfont1->procs.glyph_outline((gs_font *)subfont1, WMode, glyph, pmat,
+ ppath, sbw);
+}
+
+static int
+copy_font_cid0(gs_font *font, gs_font *copied)
+{
+ gs_font_cid0 *copied0 = (gs_font_cid0 *)copied;
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+ gs_font_type1 **FDArray =
+ gs_alloc_struct_array(copied->memory, copied0->cidata.FDArray_size,
+ gs_font_type1 *,
+ &st_gs_font_type1_ptr_element, "FDArray");
+ int i = 0, code;
+
+ if (FDArray == 0)
+ return_error(gs_error_VMerror);
+ code = copy_font_cid_common(font, copied, &copied0->cidata.common);
+ if (code < 0)
+ goto fail;
+ for (; i < copied0->cidata.FDArray_size; ++i) {
+ gs_font *subfont = (gs_font *)copied0->cidata.FDArray[i];
+ gs_font_type1 *subfont1 = (gs_font_type1 *)subfont;
+ gs_font *subcopy;
+ gs_font_type1 *subcopy1;
+ gs_copied_font_data_t *subdata;
+
+ if (i == 0) {
+ /* copy_subrs requires a Type 1 font, even for GSubrs. */
+ code = copy_subrs(subfont1, true, &cfdata->global_subrs,
+ copied->memory);
+ if (code < 0)
+ goto fail;
+ }
+ code = gs_copy_font(subfont, &subfont->FontMatrix, copied->memory, &subcopy);
+ if (code < 0)
+ goto fail;
+ subcopy1 = (gs_font_type1 *)subcopy;
+ subcopy1->data.parent = NULL;
+ subdata = cf_data(subcopy);
+ subdata->parent = copied0;
+ gs_free_object(copied->memory, subdata->Encoding,
+ "copy_font_cid0(Encoding)");
+ subdata->Encoding = 0;
+ /*
+ * Share the glyph data and global_subrs with the parent. This
+ * allows copied_type1_glyph_data in the subfont to do the right
+ * thing.
+ */
+ gs_free_object(copied->memory, subdata->names,
+ "copy_font_cid0(subfont names)");
+ gs_free_object(copied->memory, subdata->glyphs,
+ "copy_font_cid0(subfont glyphs)");
+ subcopy1->data.procs.glyph_data = copied_sub_type1_glyph_data;
+ subdata->glyphs = cfdata->glyphs;
+ subdata->glyphs_size = cfdata->glyphs_size;
+ subdata->names = 0;
+ subdata->global_subrs = cfdata->global_subrs;
+ FDArray[i] = subcopy1;
+ }
+ cfdata->notdef = GS_MIN_CID_GLYPH;
+ copied0->cidata.FDArray = FDArray;
+ copied0->cidata.FDBytes =
+ (copied0->cidata.FDArray_size <= 1 ? 0 :
+ copied0->cidata.FDArray_size <= 256 ? 1 : 2);
+ copied0->cidata.glyph_data = copied_cid0_glyph_data;
+ return 0;
+ fail:
+ while (--i >= 0)
+ gs_free_object(copied->memory, FDArray[i], "copy_font_cid0(subfont)");
+ gs_free_object(copied->memory, FDArray, "FDArray");
+ return code;
+}
+
+static int
+copy_glyph_cid0(gs_font *font, gs_glyph glyph, gs_font *copied, int options)
+{
+ gs_glyph_data_t gdata;
+ gs_font_cid0 *fcid0 = (gs_font_cid0 *)font;
+ gs_font_cid0 *copied0 = (gs_font_cid0 *)copied;
+ int fdbytes = copied0->cidata.FDBytes;
+ int fidx;
+ int code;
+ byte prefix[MAX_FDBytes];
+ int i;
+
+ gdata.memory = font->memory;
+ code = fcid0->cidata.glyph_data((gs_font_base *)font, glyph,
+ &gdata, &fidx);
+ if (code < 0)
+ return code;
+ for (i = fdbytes - 1; i >= 0; --i, fidx >>= 8)
+ prefix[i] = (byte)fidx;
+ if (fidx != 0)
+ return_error(gs_error_rangecheck);
+ return copy_glyph_data(font, glyph, copied, options, &gdata, prefix, fdbytes);
+}
+
+static const gs_copied_font_procs_t copied_procs_cid0 = {
+ copy_font_cid0, copy_glyph_cid0, copied_no_add_encoding,
+ named_glyph_slot_none,
+ gs_no_encode_char, copied_cid0_glyph_info, copied_cid0_glyph_outline
+};
+
+static int
+same_cid0_hinting(const gs_font_cid0 *cfont, const gs_font_cid0 *ofont)
+{
+ int i;
+
+ if (cfont->cidata.FDArray_size != ofont->cidata.FDArray_size)
+ return 0;
+
+ for (i = 0; i < cfont->cidata.FDArray_size; i++) {
+ gs_font_type1 *subfont0 = cfont->cidata.FDArray[i];
+ gs_font_type1 *subfont1 = ofont->cidata.FDArray[i];
+ if (!same_type1_hinting(subfont0, subfont1))
+ return 0;
+ }
+ return 1;
+}
+
+/* ------ CIDFontType 2 ------ */
+
+static int
+copied_cid2_CIDMap_proc(gs_font_cid2 *fcid2, gs_glyph glyph)
+{
+ uint cid = glyph - GS_MIN_CID_GLYPH;
+ gs_copied_font_data_t *const cfdata = cf_data((gs_font *)fcid2);
+ const ushort *CIDMap = cfdata->CIDMap;
+
+ if (glyph < GS_MIN_CID_GLYPH || cid >= fcid2->cidata.common.CIDCount)
+ return_error(gs_error_rangecheck);
+ if (CIDMap[cid] == 0xffff)
+ return -1;
+ return CIDMap[cid];
+}
+
+static uint
+copied_cid2_get_glyph_index(gs_font_type42 *font, gs_glyph glyph)
+{
+ int glyph_index = copied_cid2_CIDMap_proc((gs_font_cid2 *)font, glyph);
+
+ if (glyph_index < 0)
+ return GS_NO_GLYPH;
+ return glyph_index;
+}
+
+static int
+copy_font_cid2(gs_font *font, gs_font *copied)
+{
+ gs_font_cid2 *copied2 = (gs_font_cid2 *)copied;
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+ int code;
+ int CIDCount = copied2->cidata.common.CIDCount;
+ ushort *CIDMap = (ushort *)
+ gs_alloc_byte_array(copied->memory, CIDCount, sizeof(ushort),
+ "copy_font_cid2(CIDMap");
+
+ if (CIDMap == 0)
+ return_error(gs_error_VMerror);
+ code = copy_font_cid_common(font, copied, &copied2->cidata.common);
+ if (code < 0 ||
+ (code = copy_font_type42(font, copied)) < 0
+ ) {
+ gs_free_object(copied->memory, CIDMap, "copy_font_cid2(CIDMap");
+ return code;
+ }
+ cfdata->notdef = GS_MIN_CID_GLYPH;
+ memset(CIDMap, 0xff, CIDCount * sizeof(*CIDMap));
+ cfdata->CIDMap = CIDMap;
+ copied2->cidata.MetricsCount = 0;
+ copied2->cidata.CIDMap_proc = copied_cid2_CIDMap_proc;
+ {
+ gs_font_type42 *const copied42 = (gs_font_type42 *)copied;
+
+ copied42->data.get_glyph_index = copied_cid2_get_glyph_index;
+ }
+ return 0;
+}
+
+static int expand_CIDMap(gs_font_cid2 *copied2, uint CIDCount)
+{
+ ushort *CIDMap;
+ gs_copied_font_data_t *const cfdata = cf_data((gs_font *)copied2);
+
+ if (CIDCount <= copied2->cidata.common.CIDCount)
+ return 0;
+ CIDMap = (ushort *)
+ gs_alloc_byte_array(copied2->memory, CIDCount, sizeof(ushort),
+ "copy_font_cid2(CIDMap");
+ if (CIDMap == 0)
+ return_error(gs_error_VMerror);
+ memcpy(CIDMap, cfdata->CIDMap, copied2->cidata.common.CIDCount * sizeof(*CIDMap));
+ memset(CIDMap + copied2->cidata.common.CIDCount, 0xFF,
+ (CIDCount - copied2->cidata.common.CIDCount) * sizeof(*CIDMap));
+ cfdata->CIDMap = CIDMap;
+ copied2->cidata.common.CIDCount = CIDCount;
+ return 0;
+}
+
+static int
+copy_glyph_cid2(gs_font *font, gs_glyph glyph, gs_font *copied, int options)
+{
+ gs_font_cid2 *fcid2 = (gs_font_cid2 *)font;
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+ gs_font_cid2 *copied2 = (gs_font_cid2 *)copied;
+ int gid;
+ int code;
+
+ if (!(options & COPY_GLYPH_BY_INDEX)) {
+ uint cid = glyph - GS_MIN_CID_GLYPH;
+ int CIDCount;
+
+ code = expand_CIDMap(copied2, cid + 1);
+ if (code < 0)
+ return code;
+ CIDCount = copied2->cidata.common.CIDCount;
+ gid = fcid2->cidata.CIDMap_proc(fcid2, glyph);
+ if (gid < 0 || gid >= cfdata->glyphs_size)
+ return_error(gs_error_rangecheck);
+ if (cid > CIDCount)
+ return_error(gs_error_invalidaccess);
+ if (cfdata->CIDMap[cid] != 0xffff && cfdata->CIDMap[cid] != gid)
+ return_error(gs_error_invalidaccess);
+ code = copy_glyph_type42(font, glyph, copied, options);
+ if (code < 0)
+ return code;
+ cfdata->CIDMap[cid] = gid;
+ } else {
+ gid = glyph - GS_MIN_GLYPH_INDEX;
+ if (gid < 0 || gid >= cfdata->glyphs_size)
+ return_error(gs_error_rangecheck);
+ code = copy_glyph_type42(font, glyph, copied, options);
+ if (code < 0)
+ return code;
+ }
+ return code;
+}
+
+static const gs_copied_font_procs_t copied_procs_cid2 = {
+ copy_font_cid2, copy_glyph_cid2, copied_no_add_encoding,
+ named_glyph_slot_none,
+ gs_no_encode_char, gs_type42_glyph_info, gs_type42_glyph_outline
+};
+
+static int
+same_cid2_hinting(const gs_font_cid2 *cfont, const gs_font_cid2 *ofont)
+{
+ return same_type42_hinting((gs_font_type42 *)cfont, (gs_font_type42 *)ofont);
+}
+
+/* ---------------- Public ---------------- */
+
+/*
+ * Procedure vector for copied fonts.
+ */
+static font_proc_font_info(copied_font_info);
+static font_proc_enumerate_glyph(copied_enumerate_glyph);
+static const gs_font_procs copied_font_procs = {
+ 0, /* define_font, not supported */
+ 0, /* make_font, not supported */
+ copied_font_info,
+ gs_default_same_font,
+ 0, /* encode_char, varies by FontType */
+ 0, /* decode_char, not supported */
+ copied_enumerate_glyph,
+ 0, /* glyph_info, varies by FontType */
+ 0, /* glyph_outline, varies by FontType */
+ copied_glyph_name,
+ gs_default_init_fstack,
+ gs_default_next_char_glyph,
+ copied_build_char
+};
+
+#if GLYPHS_SIZE_IS_PRIME
+static const int some_primes[] = {
+ /* Arbitrary choosen prime numbers, being reasonable for a Type 1|2 font size.
+ We start with 257 to fit 256 glyphs and .notdef .
+ Smaller numbers aren't useful, because we don't know whether a font
+ will add more glyphs incrementally when we allocate its stable copy.
+ */
+ 257, 359, 521, 769, 1031, 2053,
+ 3079, 4099, 5101, 6101, 7109, 8209, 10007, 12007, 14009,
+ 16411, 20107, 26501, 32771, 48857, 65537};
+#endif
+
+/*
+ * Copy a font, aside from its glyphs.
+ */
+int
+gs_copy_font(gs_font *font, const gs_matrix *orig_matrix, gs_memory_t *mem, gs_font **pfont_new)
+{
+ gs_memory_type_ptr_t fstype = gs_object_type(font->memory, font);
+ uint fssize = gs_struct_type_size(fstype);
+ gs_font *copied = 0;
+ gs_copied_font_data_t *cfdata = 0;
+ gs_font_info_t info;
+ gs_copied_glyph_t *glyphs = 0;
+ uint glyphs_size;
+ gs_copied_glyph_name_t *names = 0;
+ bool have_names = false;
+ const gs_copied_font_procs_t *procs;
+ int code;
+
+ /*
+ * Check for a supported FontType, and compute the size of its
+ * copied glyph table.
+ */
+ switch (font->FontType) {
+ case ft_TrueType:
+ procs = &copied_procs_type42;
+ glyphs_size = ((gs_font_type42 *)font)->data.trueNumGlyphs;
+ have_names = true;
+ break;
+ case ft_encrypted:
+ case ft_encrypted2:
+ procs = &copied_procs_type1;
+ /* Count the glyphs. */
+ glyphs_size = 0;
+ {
+ int index = 0;
+ gs_glyph glyph;
+
+ while (font->procs.enumerate_glyph(font, &index, GLYPH_SPACE_NAME,
+ &glyph), index != 0)
+ ++glyphs_size;
+ }
+#if GLYPHS_SIZE_IS_PRIME
+ /*
+ * Make glyphs_size a prime number to ensure termination of the loop in
+ * named_glyphs_slot_hashed, q.v.
+ * Also reserve additional slots for the case of font merging and
+ * for possible font increments.
+ */
+ glyphs_size = glyphs_size * 3 / 2;
+ if (glyphs_size < 257)
+ glyphs_size = 257;
+ { int i;
+ for (i = 0; i < count_of(some_primes); i++)
+ if (glyphs_size <= some_primes[i])
+ break;
+ if (i >= count_of(some_primes))
+ return_error(gs_error_rangecheck);
+ glyphs_size = some_primes[i];
+ }
+#else
+ /*
+ * Make names_size a power of 2 to ensure termination of the loop in
+ * named_glyphs_slot_hashed, q.v.
+ */
+ glyphs_size = glyphs_size * 3 / 2;
+ while (glyphs_size & (glyphs_size - 1))
+ glyphs_size = (glyphs_size | (glyphs_size - 1)) + 1;
+ if (glyphs_size < 256) /* probably incremental font */
+ glyphs_size = 256;
+#endif
+ have_names = true;
+ break;
+ case ft_CID_encrypted:
+ procs = &copied_procs_cid0;
+ glyphs_size = ((gs_font_cid0 *)font)->cidata.common.CIDCount;
+ break;
+ case ft_CID_TrueType:
+ procs = &copied_procs_cid2;
+ /* Glyphs are indexed by GID, not by CID. */
+ glyphs_size = ((gs_font_cid2 *)font)->data.trueNumGlyphs;
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+
+ /* Get the font_info for copying. */
+
+ memset(&info, 0, sizeof(info));
+ info.Flags_requested = ~0;
+ code = font->procs.font_info(font, NULL, ~0, &info);
+ if (code < 0)
+ return code;
+
+ /* Allocate the generic copied information. */
+
+ glyphs = gs_alloc_struct_array(mem, glyphs_size, gs_copied_glyph_t,
+ &st_gs_copied_glyph_element,
+ "gs_copy_font(glyphs)");
+ if (have_names != 0)
+ names = gs_alloc_struct_array(mem, glyphs_size, gs_copied_glyph_name_t,
+ &st_gs_copied_glyph_name_element,
+ "gs_copy_font(names)");
+ copied = gs_alloc_struct(mem, gs_font, fstype,
+ "gs_copy_font(copied font)");
+ cfdata = gs_alloc_struct(mem, gs_copied_font_data_t,
+ &st_gs_copied_font_data,
+ "gs_copy_font(wrapper data)");
+ if (cfdata)
+ memset(cfdata, 0, sizeof(*cfdata));
+ if (glyphs == 0 || (names == 0 && have_names) || copied == 0 ||
+ cfdata == 0
+ ) {
+ code = gs_note_error(gs_error_VMerror);
+ goto fail;
+ }
+ cfdata->info = info;
+ cfdata->dir = font->dir;
+ if ((code = (copy_string(mem, &cfdata->info.Copyright,
+ "gs_copy_font(Copyright)") |
+ copy_string(mem, &cfdata->info.Notice,
+ "gs_copy_font(Notice)") |
+ copy_string(mem, &cfdata->info.FamilyName,
+ "gs_copy_font(FamilyName)") |
+ copy_string(mem, &cfdata->info.FullName,
+ "gs_copy_font(FullName)"))) < 0
+ )
+ goto fail;
+
+ /* Initialize the copied font. */
+
+ memcpy(copied, font, fssize);
+ copied->next = copied->prev = 0;
+ copied->memory = mem;
+ copied->is_resource = false;
+ gs_notify_init(&copied->notify_list, mem);
+ copied->base = copied;
+ copied->FontMatrix = *orig_matrix;
+ copied->client_data = cfdata;
+ copied->procs = copied_font_procs;
+ copied->procs.encode_char = procs->encode_char;
+ copied->procs.glyph_info = procs->glyph_info;
+ copied->procs.glyph_outline = procs->glyph_outline;
+ {
+ gs_font_base *bfont = (gs_font_base *)copied;
+
+ bfont->FAPI = 0;
+ bfont->FAPI_font_data = 0;
+ bfont->encoding_index = ENCODING_INDEX_UNKNOWN;
+ code = uid_copy(&bfont->UID, mem, "gs_copy_font(UID)");
+ if (code < 0)
+ goto fail;
+ }
+
+ cfdata->procs = procs;
+ memset(glyphs, 0, glyphs_size * sizeof(*glyphs));
+ cfdata->glyphs = glyphs;
+ cfdata->glyphs_size = glyphs_size;
+ cfdata->num_glyphs = 0;
+ cfdata->ordered = false;
+ if (names)
+ memset(names, 0, glyphs_size * sizeof(*names));
+ cfdata->names = names;
+ if (names != 0) {
+ uint i;
+
+ for (i = 0; i < glyphs_size; ++i)
+ names[i].glyph = GS_NO_GLYPH;
+ }
+
+ /* Do FontType-specific initialization. */
+
+ code = procs->finish_copy_font(font, copied);
+ if (code < 0)
+ goto fail;
+
+ *pfont_new = copied;
+ if (cfdata->notdef != GS_NO_GLYPH)
+ code = gs_copy_glyph(font, cfdata->notdef, copied);
+ return code;
+
+ fail:
+ /* Free storage and exit. */
+ if (cfdata) {
+ uncopy_string(mem, &cfdata->info.FullName,
+ "gs_copy_font(FullName)");
+ uncopy_string(mem, &cfdata->info.FamilyName,
+ "gs_copy_font(FamilyName)");
+ uncopy_string(mem, &cfdata->info.Notice,
+ "gs_copy_font(Notice)");
+ uncopy_string(mem, &cfdata->info.Copyright,
+ "gs_copy_font(Copyright)");
+ gs_free_object(mem, cfdata, "gs_copy_font(wrapper data)");
+ }
+ gs_free_object(mem, copied, "gs_copy_font(copied font)");
+ gs_free_object(mem, names, "gs_copy_font(names)");
+ gs_free_object(mem, glyphs, "gs_copy_font(glyphs)");
+ return code;
+}
+
+/*
+ * Copy a glyph, including any sub-glyphs.
+ */
+int
+gs_copy_glyph(gs_font *font, gs_glyph glyph, gs_font *copied)
+{
+ return gs_copy_glyph_options(font, glyph, copied, 0);
+}
+int
+gs_copy_glyph_options(gs_font *font, gs_glyph glyph, gs_font *copied,
+ int options)
+{
+ int code;
+#define MAX_GLYPH_PIECES 64 /* arbitrary, but 32 is too small - bug 687698. */
+ gs_glyph glyphs[MAX_GLYPH_PIECES];
+ uint count = 1, i;
+
+ if (copied->procs.font_info != copied_font_info)
+ return_error(gs_error_rangecheck);
+ code = cf_data(copied)->procs->copy_glyph(font, glyph, copied, options);
+ if (code != 0)
+ return code;
+ /* Copy any sub-glyphs. */
+ glyphs[0] = glyph;
+ code = psf_add_subset_pieces(glyphs, &count, MAX_GLYPH_PIECES, MAX_GLYPH_PIECES,
+ font);
+ if (code < 0)
+ return code;
+ if (count > MAX_GLYPH_PIECES)
+ return_error(gs_error_limitcheck);
+ for (i = 1; i < count; ++i) {
+ code = gs_copy_glyph_options(font, glyphs[i], copied,
+ (options & ~COPY_GLYPH_NO_OLD) | COPY_GLYPH_BY_INDEX);
+ if (code < 0)
+ return code;
+ }
+ /*
+ * Because 'seac' accesses the Encoding of the font as well as the
+ * glyphs, we have to copy the Encoding entries as well.
+ */
+ if (count == 1)
+ return 0;
+ switch (font->FontType) {
+ case ft_encrypted:
+ case ft_encrypted2:
+ break;
+ default:
+ return 0;
+ }
+#if 0 /* No need to add subglyphs to the Encoding because they always are
+ taken from StandardEncoding (See the Type 1 spec about 'seac').
+ Attempt to add them to the encoding can cause a conflict,
+ if the encoding specifies different glyphs for these char codes
+ (See the bug #687172). */
+ {
+ gs_copied_glyph_t *pcg;
+ gs_glyph_data_t gdata;
+ gs_char chars[2];
+
+ gdata.memory = font->memory;
+ /* Since we just copied the glyph, copied_glyph_slot can't fail. */
+ DISCARD(copied_glyph_slot(cf_data(copied), glyph, &pcg));
+ gs_glyph_data_from_string(&gdata, pcg->gdata.data, pcg->gdata.size,
+ NULL);
+ code = gs_type1_piece_codes((gs_font_type1 *)font, &gdata, chars);
+ if (code <= 0 || /* 0 is not possible here */
+ (code = gs_copied_font_add_encoding(copied, chars[0], glyphs[1])) < 0 ||
+ (code = gs_copied_font_add_encoding(copied, chars[1], glyphs[2])) < 0
+ )
+ return code;
+ }
+#endif
+ return 0;
+#undef MAX_GLYPH_PIECES
+}
+
+/*
+ * Add an Encoding entry to a copied font. The glyph need not already have
+ * been copied.
+ */
+int
+gs_copied_font_add_encoding(gs_font *copied, gs_char chr, gs_glyph glyph)
+{
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+
+ if (copied->procs.font_info != copied_font_info)
+ return_error(gs_error_rangecheck);
+ return cfdata->procs->add_encoding(copied, chr, glyph);
+}
+
+/*
+ * Copy all the glyphs and, if relevant, Encoding entries from a font. This
+ * is equivalent to copying the glyphs and Encoding entries individually,
+ * and returns errors under the same conditions.
+ */
+int
+gs_copy_font_complete(gs_font *font, gs_font *copied)
+{
+ int index, code = 0;
+ gs_glyph_space_t space = GLYPH_SPACE_NAME;
+ gs_glyph glyph;
+
+ /*
+ * For Type 1 fonts and CIDFonts, enumerating the glyphs using
+ * GLYPH_SPACE_NAME will cover all the glyphs. (The "names" of glyphs
+ * in CIDFonts are CIDs, but that is not a problem.) For Type 42 fonts,
+ * however, we have to copy by name once, so that we also copy the
+ * name-to-GID mapping (the CharStrings dictionary in PostScript), and
+ * then copy again by GID, to cover glyphs that don't have names.
+ */
+ for (;;) {
+ for (index = 0;
+ code >= 0 &&
+ (font->procs.enumerate_glyph(font, &index, space, &glyph),
+ index != 0);
+ ) {
+ if (font->FontType == ft_TrueType &&
+ glyph >= GS_MIN_CID_GLYPH && glyph < GS_MIN_GLYPH_INDEX)
+ return_error(gs_error_invalidfont); /* bug 688370. */
+ code = gs_copy_glyph(font, glyph, copied);
+ }
+ /* For Type 42 fonts, if we copied by name, now copy again by index. */
+ if (space == GLYPH_SPACE_NAME && font->FontType == ft_TrueType)
+ space = GLYPH_SPACE_INDEX;
+ else
+ break;
+ }
+ if (cf_data(copied)->Encoding != 0)
+ for (index = 0; code >= 0 && index < 256; ++index) {
+ glyph = font->procs.encode_char(font, (gs_char)index,
+ GLYPH_SPACE_NAME);
+ if (glyph != GS_NO_GLYPH) {
+ code = gs_copied_font_add_encoding(copied, (gs_char)index,
+ glyph);
+ if (code == gs_error_undefined) {
+ /* Skip Encoding entries, which point to undefiuned glyphs -
+ happens with 033-52-5873.pdf. */
+ code = 0;
+ }
+ if (code == gs_error_rangecheck) {
+ /* Skip Encoding entries, which point to undefiuned glyphs -
+ happens with 159.pdf. */
+ code = 0;
+ }
+ }
+ }
+ if (copied->FontType != ft_composite) {
+ gs_font_base *bfont = (gs_font_base *)font;
+ gs_font_base *bcopied = (gs_font_base *)copied;
+
+ bcopied->encoding_index = bfont->encoding_index;
+ bcopied->nearest_encoding_index = bfont->nearest_encoding_index;
+ }
+ return code;
+}
+
+/*
+ * Check whether specified glyphs can be copied from another font.
+ * It means that (1) fonts have same hinting parameters and
+ * (2) font subsets for the specified glyph set don't include different
+ * outlines or metrics. Possible returned values :
+ * 0 (incompatible), 1 (compatible), < 0 (error)
+ */
+int
+gs_copied_can_copy_glyphs(const gs_font *cfont, const gs_font *ofont,
+ gs_glyph *glyphs, int num_glyphs, int glyphs_step,
+ bool check_hinting)
+{
+ int code = 0;
+
+ if (cfont == ofont)
+ return 1;
+ if (cfont->FontType != ofont->FontType)
+ return 0;
+ if (cfont->WMode != ofont->WMode)
+ return 0;
+ if (cfont->font_name.size == 0 || ofont->font_name.size == 0) {
+ if (cfont->key_name.size != ofont->key_name.size ||
+ memcmp(cfont->key_name.chars, ofont->key_name.chars,
+ cfont->font_name.size))
+ return 0; /* Don't allow to merge random fonts. */
+ } else {
+ if (cfont->font_name.size != ofont->font_name.size ||
+ memcmp(cfont->font_name.chars, ofont->font_name.chars,
+ cfont->font_name.size))
+ return 0; /* Don't allow to merge random fonts. */
+ }
+ if (check_hinting) {
+ switch(cfont->FontType) {
+ case ft_encrypted:
+ case ft_encrypted2:
+ if (!same_type1_hinting((const gs_font_type1 *)cfont,
+ (const gs_font_type1 *)ofont))
+ return 0;
+ code = 1;
+ break;
+ case ft_TrueType:
+ code = same_type42_hinting((gs_font_type42 *)cfont,
+ (gs_font_type42 *)ofont);
+ break;
+ case ft_CID_encrypted:
+ if (!gs_is_CIDSystemInfo_compatible(
+ gs_font_cid_system_info(cfont),
+ gs_font_cid_system_info(ofont)))
+ return 0;
+ code = same_cid0_hinting((const gs_font_cid0 *)cfont,
+ (const gs_font_cid0 *)ofont);
+ break;
+ case ft_CID_TrueType:
+ if (!gs_is_CIDSystemInfo_compatible(
+ gs_font_cid_system_info(cfont),
+ gs_font_cid_system_info(ofont)))
+ return 0;
+ code = same_cid2_hinting((const gs_font_cid2 *)cfont,
+ (const gs_font_cid2 *)ofont);
+ break;
+ default:
+ return_error(gs_error_unregistered); /* Must not happen. */
+ }
+ if (code <= 0) /* an error or false */
+ return code;
+ }
+ return compare_glyphs(cfont, ofont, glyphs, num_glyphs, glyphs_step, 0);
+}
+
+/* Extension glyphs may be added to a font to resolve
+ glyph name conflicts while conwerting a PDF Widths into Metrics.
+ This function drops them before writing out an embedded font. */
+int
+copied_drop_extension_glyphs(gs_font *copied)
+{
+ /* Note : This function drops 'used' flags for some glyphs
+ and truncates glyph names. Can't use the font
+ for outlining|rasterization|width after applying it.
+ */
+ gs_copied_font_data_t *const cfdata = cf_data(copied);
+ uint gsize = cfdata->glyphs_size, i;
+ const int sl = strlen(gx_extendeg_glyph_name_separator);
+
+ for (i = 0; i < gsize; i++) {
+ gs_copied_glyph_t *pslot = &cfdata->glyphs[i];
+ gs_copied_glyph_name_t *name;
+ int l, j, k, i0;
+
+ if (!pslot->used)
+ continue;
+ name = &cfdata->names[i];
+ l = name->str.size - sl;
+
+ for (j = 0; j < l; j ++)
+ if (!memcmp(gx_extendeg_glyph_name_separator, name->str.data + j, sl))
+ break;
+ if (j >= l)
+ continue;
+ /* Found an extension name.
+ Find the corresponding non-extended one. */
+ i0 = i;
+ for (k = 0; k < gsize; k++)
+ if (cfdata->glyphs[k].used &&
+ cfdata->names[k].str.size == j &&
+ !memcmp(cfdata->names[k].str.data, name->str.data, j) &&
+ !bytes_compare(pslot->gdata.data, pslot->gdata.size,
+ cfdata->glyphs[k].gdata.data, cfdata->glyphs[k].gdata.size)) {
+ i0 = k;
+ break;
+ }
+ /* Truncate the extended glyph name. */
+ cfdata->names[i0].str.size = j;
+ /* Drop others with same prefix. */
+ for (k = 0; k < gsize; k++)
+ if (k != i0 && cfdata->glyphs[k].used &&
+ cfdata->names[k].str.size >= j + sl &&
+ !memcmp(cfdata->names[k].str.data, name->str.data, j) &&
+ !memcmp(gx_extendeg_glyph_name_separator, name + j, sl) &&
+ !bytes_compare(pslot->gdata.data, pslot->gdata.size,
+ cfdata->glyphs[k].gdata.data, cfdata->glyphs[k].gdata.size))
+ cfdata->glyphs[k].used = false;
+ }
+ return 0;
+}
+
+static int
+compare_glyph_names(const void *pg1, const void *pg2)
+{
+ const gs_copied_glyph_name_t * gn1 = *(const gs_copied_glyph_name_t **)pg1;
+ const gs_copied_glyph_name_t * gn2 = *(const gs_copied_glyph_name_t **)pg2;
+
+ return bytes_compare(gn1->str.data, gn1->str.size, gn2->str.data, gn2->str.size);
+}
+
+
+/* Order font data to avoid a serialization indeterminism. */
+static int
+order_font_data(gs_copied_font_data_t *cfdata, gs_memory_t *memory)
+{
+ int i, j = 0;
+
+ gs_copied_glyph_name_t **a = (gs_copied_glyph_name_t **)gs_alloc_byte_array(memory, cfdata->num_glyphs,
+ sizeof(gs_copied_glyph_name_t *), "order_font_data");
+ if (a == NULL)
+ return_error(gs_error_VMerror);
+ j = 0;
+ for (i = 0; i < cfdata->glyphs_size; i++) {
+ if (cfdata->glyphs[i].used) {
+ if (j >= cfdata->num_glyphs)
+ return_error(gs_error_unregistered); /* Must not happen */
+ a[j++] = &cfdata->names[i];
+ }
+ }
+ qsort(a, cfdata->num_glyphs, sizeof(*a), compare_glyph_names);
+ for (j--; j >= 0; j--)
+ cfdata->glyphs[j].order_index = a[j] - cfdata->names;
+ gs_free_object(memory, a, "order_font_data");
+ return 0;
+}
+
+/* Order font to avoid a serialization indeterminism. */
+int
+copied_order_font(gs_font *font)
+{
+
+ if (font->procs.enumerate_glyph != copied_enumerate_glyph)
+ return_error(gs_error_unregistered); /* Must not happen */
+ if (font->FontType != ft_encrypted && font->FontType != ft_encrypted2) {
+ /* Don't need to order, because it is ordered by CIDs or glyph indices. */
+ return 0;
+ }
+ { gs_copied_font_data_t * cfdata = cf_data(font);
+ cfdata->ordered = true;
+ return order_font_data(cfdata, font->memory);
+ }
+}
+
+/* Get .nmotdef glyph. */
+gs_glyph
+copied_get_notdef(const gs_font *font)
+{
+ gs_copied_font_data_t * cfdata = cf_data(font);
+
+ return cfdata->notdef;
+}