summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'base/gsfcid2.c')
-rw-r--r--base/gsfcid2.c320
1 files changed, 320 insertions, 0 deletions
diff --git a/base/gsfcid2.c b/base/gsfcid2.c
new file mode 100644
index 00000000..d81e100e
--- /dev/null
+++ b/base/gsfcid2.c
@@ -0,0 +1,320 @@
+/* Copyright (C) 2001-2019 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 the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+
+/* Create a CIDFontType 2 font from a Type 42 font. */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gsstruct.h"
+#include "gsutil.h"
+#include "gxfont.h"
+#include "gxfcid.h"
+#include "gxfcmap.h"
+#include "gxfont0c.h"
+
+/*
+ * Create a Type 2 CIDFont from a Type 42 font.
+ */
+static int
+identity_CIDMap_proc(gs_font_cid2 *pfont, gs_glyph glyph)
+{
+ ulong cid = glyph - GS_MIN_CID_GLYPH;
+
+ if (cid >= pfont->cidata.common.CIDCount)
+ return_error(gs_error_rangecheck);
+ return (int)cid;
+}
+int
+gs_font_cid2_from_type42(gs_font_cid2 **ppfcid, gs_font_type42 *pfont42,
+ int wmode, gs_memory_t *mem)
+{
+ gs_font_cid2 *pfcid =
+ gs_alloc_struct(mem, gs_font_cid2, &st_gs_font_cid2,
+ "gs_font_cid2_from_type42");
+
+ if (pfcid == 0)
+ return_error(gs_error_VMerror);
+
+ /* CIDFontType 2 is a subclass (extension) of FontType 42. */
+ memcpy(pfcid, pfont42, sizeof(*pfont42));
+ pfcid->memory = mem;
+ pfcid->next = pfcid->prev = 0; /* probably not necessary */
+ pfcid->is_resource = 0;
+ gs_font_notify_init((gs_font *)pfcid);
+ pfcid->id = gs_next_ids(mem, 1);
+ pfcid->base = (gs_font *)pfcid;
+ pfcid->FontType = ft_CID_TrueType;
+ /* Fill in the rest of the CIDFont data. */
+ cid_system_info_set_null(&pfcid->cidata.common.CIDSystemInfo);
+ pfcid->cidata.common.CIDCount = pfont42->data.numGlyphs;
+ pfcid->cidata.common.GDBytes = 2; /* not used */
+ pfcid->cidata.MetricsCount = 0;
+ pfcid->cidata.CIDMap_proc = identity_CIDMap_proc;
+ /* Since MetricsCount == 0, don't need orig_procs. */
+
+ *ppfcid = pfcid;
+ return 0;
+}
+
+#define U16(p) (((uint)((p)[0]) << 8) + (p)[1])
+#define U32(p) get_u32_msb(p)
+#define PUT16(p, v)\
+ BEGIN (p)[0] = (byte)((v) >> 8); (p)[1] = (byte)(v); END
+
+/*
+ * Define a subclass of gs_cmap_t that accesses the most common type of
+ * TrueType cmap (Platform 3, Encoding 1, Format 4) directly.
+ */
+typedef struct gs_cmap_tt_16bit_format4_s {
+ GS_CMAP_COMMON;
+ gs_font_type42 *font;
+ uint segCount2;
+ ulong endCount, startCount, idDelta, idRangeOffset, glyphIdArray;
+} gs_cmap_tt_16bit_format4_t;
+gs_public_st_suffix_add1(st_cmap_tt_16bit_format4, gs_cmap_tt_16bit_format4_t,
+ "gs_cmap_tt_16bit_format4_t",
+ cmap_tt_16bit_format4_enum_ptrs, cmap_tt_16bit_format4_reloc_ptrs,
+ st_cmap, font);
+
+static int
+tt_16bit_format4_decode_next(const gs_cmap_t * pcmap_in,
+ const gs_const_string * pstr,
+ uint * pindex, uint * pfidx,
+ gs_char * pchr, gs_glyph * pglyph)
+{
+ const gs_cmap_tt_16bit_format4_t *pcmap =
+ (const gs_cmap_tt_16bit_format4_t *)pcmap_in;
+ gs_font_type42 *pfont = pcmap->font;
+ byte ttdata[2];
+ int code;
+ uint chr, value = 0;
+ uint segment2;
+
+ if (pstr->size < *pindex + 2) {
+ *pglyph = GS_NO_GLYPH;
+ return (*pindex == pstr->size ? 2 : -1);
+ }
+ chr = U16(pstr->data + *pindex);
+ /* The table is sorted, but we use linear search for simplicity. */
+ for (segment2 = 0; segment2 < pcmap->segCount2; segment2 += 2) {
+ uint start, delta, roff;
+
+ READ_SFNTS(pfont, pcmap->endCount + segment2, 2, ttdata);
+ if (chr > U16(ttdata))
+ continue;
+ READ_SFNTS(pfont, pcmap->startCount + segment2, 2, ttdata);
+ start = U16(ttdata);
+ if (chr < start)
+ continue;
+ READ_SFNTS(pfont, pcmap->idDelta + segment2, 2, ttdata);
+ delta = U16(ttdata);
+ READ_SFNTS(pfont, pcmap->idRangeOffset + segment2, 2, ttdata);
+ roff = U16(ttdata);
+ if (roff) {
+ ulong gidoff = pcmap->idRangeOffset + segment2 + roff +
+ (chr - start) * 2;
+
+ READ_SFNTS(pfont, gidoff, 2, ttdata);
+ value = U16(ttdata);
+ if (value != 0)
+ value += delta;
+ } else
+ value = chr + delta;
+ break;
+ }
+ *pglyph = GS_MIN_CID_GLYPH + (value & 0xffff);
+ *pchr = chr;
+ *pindex += 2;
+ *pfidx = 0;
+ return 0;
+}
+static int
+tt_16bit_format4_next_range(gs_cmap_ranges_enum_t *penum)
+{
+ /* There is just a single 2-byte range. */
+ if (penum->index == 0) {
+ penum->range.first[0] = penum->range.first[1] = 0;
+ penum->range.last[0] = penum->range.last[1] = 0xff;
+ penum->range.size = 2;
+ penum->index = 1;
+ return 0;
+ }
+ return 1;
+}
+static const gs_cmap_ranges_enum_procs_t tt_16bit_format4_range_procs = {
+ tt_16bit_format4_next_range
+};
+static void
+tt_16bit_format4_enum_ranges(const gs_cmap_t *pcmap,
+ gs_cmap_ranges_enum_t *pre)
+{
+ gs_cmap_ranges_enum_setup(pre, pcmap, &tt_16bit_format4_range_procs);
+}
+static int
+tt_16bit_format4_next_lookup(gs_memory_t *mem, gs_cmap_lookups_enum_t *penum)
+{
+ penum->entry.value.data = 0L;
+ if (penum->index[0] == 0) {
+ penum->entry.key_size = 2;
+ penum->entry.key_is_range = true;
+ penum->entry.value_type = CODE_VALUE_CID;
+ penum->entry.value.size = 2;
+ penum->entry.font_index = 0;
+ penum->index[0] = 1;
+ return 0;
+ }
+ return 1;
+}
+static int
+tt_16bit_format4_next_entry(gs_cmap_lookups_enum_t *penum)
+{
+ /* index[1] is segment # << 17 + first code. */
+ uint segment2 = penum->index[1] >> 16;
+ uint next = penum->index[1] & 0xffff;
+ const gs_cmap_tt_16bit_format4_t *pcmap =
+ (const gs_cmap_tt_16bit_format4_t *)penum->cmap;
+ gs_font_type42 *pfont = pcmap->font;
+ byte ttdata[2];
+ int code;
+ uint start, end, delta, roff;
+ uint value;
+
+ top:
+ if (segment2 >= pcmap->segCount2)
+ return 1;
+ READ_SFNTS(pfont, pcmap->endCount + segment2, 2, ttdata);
+ end = U16(ttdata);
+ if (next > end) {
+ segment2 += 2;
+ goto top;
+ }
+ READ_SFNTS(pfont, pcmap->startCount + segment2, 2, ttdata);
+ start = U16(ttdata);
+ if (next < start)
+ next = start;
+ PUT16(penum->entry.key[0], next);
+ READ_SFNTS(pfont, pcmap->idDelta + segment2, 2, ttdata);
+ delta = U16(ttdata);
+ READ_SFNTS(pfont, pcmap->idRangeOffset + segment2, 2, ttdata);
+ roff = U16(ttdata);
+ if (roff) {
+ /* Non-zero offset, table lookup. */
+ ulong gidoff = pcmap->idRangeOffset + segment2 + roff;
+
+ READ_SFNTS(pfont, gidoff, 2, ttdata);
+ value = U16(ttdata);
+ if (value != 0)
+ value += delta;
+ ++next;
+ } else {
+ /* Zero offset, account for high-order byte changes. */
+ value = next + delta;
+ next = min(end, (next | 0xff)) + 1;
+ }
+ PUT16(penum->entry.key[1], next - 1);
+ PUT16(penum->temp_value, value);
+ penum->entry.value.data = penum->temp_value;
+ penum->entry.value.size = 2;
+ penum->index[1] = (segment2 << 16) + next;
+ return 0;
+}
+static const gs_cmap_lookups_enum_procs_t tt_16bit_format4_lookup_procs = {
+ tt_16bit_format4_next_lookup, tt_16bit_format4_next_entry
+};
+static void
+tt_16bit_format4_enum_lookups(const gs_cmap_t *pcmap, int which,
+ gs_cmap_lookups_enum_t *pre)
+{
+ gs_cmap_lookups_enum_setup(pre, pcmap,
+ (which ? &gs_cmap_no_lookups_procs :
+ &tt_16bit_format4_lookup_procs));
+}
+
+static const gs_cmap_procs_t tt_16bit_format4_procs = {
+ tt_16bit_format4_decode_next,
+ tt_16bit_format4_enum_ranges,
+ tt_16bit_format4_enum_lookups,
+ gs_cmap_compute_identity
+};
+
+/*
+ * Create a CMap from a TrueType Platform 3, Encoding 1, Format 4 cmap.
+ */
+int
+gs_cmap_from_type42_cmap(gs_cmap_t **ppcmap, gs_font_type42 *pfont,
+ int wmode, gs_memory_t *mem)
+{
+ ulong origin = pfont->data.cmap;
+ gs_cmap_tt_16bit_format4_t *pcmap;
+ int code;
+ byte ttdata[8];
+ ulong offset = origin;
+ uint segCount2;
+
+ if (origin == 0)
+ return_error(gs_error_invalidfont);
+
+ /*
+ * Find the desired cmap sub-table, if any.
+ */
+ {
+ uint cmap_count;
+ uint i;
+
+ READ_SFNTS(pfont, origin + 2, 2, ttdata);
+ cmap_count = U16(ttdata);
+ for (i = 0; i < cmap_count; ++i) {
+ READ_SFNTS(pfont, origin + 4 + i * 8, 8, ttdata);
+ if (U16(ttdata) != 3 || /* platform ID */
+ U16(ttdata + 2) != 1 /* encoding ID */
+ )
+ continue;
+ offset = origin + U32(ttdata + 4);
+ READ_SFNTS(pfont, offset, 2, ttdata);
+ if (U16(ttdata) != 4 /* format */)
+ continue;
+ break;
+ }
+ if (i >= cmap_count) /* not found */
+ return_error(gs_error_invalidfont);
+ READ_SFNTS(pfont, offset + 6, 2, ttdata);
+ segCount2 = U16(ttdata);
+ }
+
+ /* Allocate the CMap. */
+ {
+ static const gs_cid_system_info_t null_cidsi = {
+ { (const byte*) "none", 4 },
+ { (const byte*) "none", 4 },
+ 0
+ };
+ code = gs_cmap_alloc(ppcmap, &st_cmap_tt_16bit_format4, wmode,
+ (const byte *)"none", 4, &null_cidsi, 1,
+ &tt_16bit_format4_procs, mem);
+ if (code < 0)
+ return code;
+ }
+ pcmap = (gs_cmap_tt_16bit_format4_t *)*ppcmap;
+ pcmap->from_Unicode = true;
+ pcmap->font = pfont;
+ pcmap->segCount2 = segCount2;
+ pcmap->endCount = offset + 14;
+ pcmap->startCount = pcmap->endCount + segCount2 + 2;
+ pcmap->idDelta = pcmap->startCount + segCount2;
+ pcmap->idRangeOffset = pcmap->idDelta + segCount2;
+ pcmap->glyphIdArray = pcmap->idRangeOffset + segCount2;
+ return 0;
+}