1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* Create a CIDFontType 2 font from a Type 42 font. */
18 #include "memory_.h"
19 #include "gx.h"
20 #include "gserrors.h"
21 #include "gsstruct.h"
22 #include "gsutil.h"
23 #include "gxfont.h"
24 #include "gxfcid.h"
25 #include "gxfcmap.h"
26 #include "gxfont0c.h"
27
28 /*
29 * Create a Type 2 CIDFont from a Type 42 font.
30 */
31 static int
identity_CIDMap_proc(gs_font_cid2 * pfont,gs_glyph glyph)32 identity_CIDMap_proc(gs_font_cid2 *pfont, gs_glyph glyph)
33 {
34 ulong cid = glyph - GS_MIN_CID_GLYPH;
35
36 if (cid >= pfont->cidata.common.CIDCount)
37 return_error(gs_error_rangecheck);
38 return (int)cid;
39 }
40 int
gs_font_cid2_from_type42(gs_font_cid2 ** ppfcid,gs_font_type42 * pfont42,int wmode,gs_memory_t * mem)41 gs_font_cid2_from_type42(gs_font_cid2 **ppfcid, gs_font_type42 *pfont42,
42 int wmode, gs_memory_t *mem)
43 {
44 gs_font_cid2 *pfcid =
45 gs_alloc_struct(mem, gs_font_cid2, &st_gs_font_cid2,
46 "gs_font_cid2_from_type42");
47
48 if (pfcid == 0)
49 return_error(gs_error_VMerror);
50
51 /* CIDFontType 2 is a subclass (extension) of FontType 42. */
52 memcpy(pfcid, pfont42, sizeof(*pfont42));
53 pfcid->memory = mem;
54 pfcid->next = pfcid->prev = 0; /* probably not necessary */
55 pfcid->is_resource = 0;
56 gs_font_notify_init((gs_font *)pfcid);
57 pfcid->id = gs_next_ids(mem, 1);
58 pfcid->base = (gs_font *)pfcid;
59 pfcid->FontType = ft_CID_TrueType;
60 /* Fill in the rest of the CIDFont data. */
61 cid_system_info_set_null(&pfcid->cidata.common.CIDSystemInfo);
62 pfcid->cidata.common.CIDCount = pfont42->data.numGlyphs;
63 pfcid->cidata.common.GDBytes = 2; /* not used */
64 pfcid->cidata.MetricsCount = 0;
65 pfcid->cidata.CIDMap_proc = identity_CIDMap_proc;
66 /* Since MetricsCount == 0, don't need orig_procs. */
67
68 *ppfcid = pfcid;
69 return 0;
70 }
71
72 #define U16(p) (((uint)((p)[0]) << 8) + (p)[1])
73 #define U32(p) get_u32_msb(p)
74 #define PUT16(p, v)\
75 BEGIN (p)[0] = (byte)((v) >> 8); (p)[1] = (byte)(v); END
76
77 /*
78 * Define a subclass of gs_cmap_t that accesses the most common type of
79 * TrueType cmap (Platform 3, Encoding 1, Format 4) directly.
80 */
81 typedef struct gs_cmap_tt_16bit_format4_s {
82 GS_CMAP_COMMON;
83 gs_font_type42 *font;
84 uint segCount2;
85 ulong endCount, startCount, idDelta, idRangeOffset, glyphIdArray;
86 } gs_cmap_tt_16bit_format4_t;
87 gs_public_st_suffix_add1(st_cmap_tt_16bit_format4, gs_cmap_tt_16bit_format4_t,
88 "gs_cmap_tt_16bit_format4_t",
89 cmap_tt_16bit_format4_enum_ptrs, cmap_tt_16bit_format4_reloc_ptrs,
90 st_cmap, font);
91
92 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)93 tt_16bit_format4_decode_next(const gs_cmap_t * pcmap_in,
94 const gs_const_string * pstr,
95 uint * pindex, uint * pfidx,
96 gs_char * pchr, gs_glyph * pglyph)
97 {
98 const gs_cmap_tt_16bit_format4_t *pcmap =
99 (const gs_cmap_tt_16bit_format4_t *)pcmap_in;
100 gs_font_type42 *pfont = pcmap->font;
101 byte ttdata[2];
102 int code;
103 uint chr, value = 0;
104 uint segment2;
105
106 if (pstr->size < *pindex + 2) {
107 *pglyph = GS_NO_GLYPH;
108 return (*pindex == pstr->size ? 2 : -1);
109 }
110 chr = U16(pstr->data + *pindex);
111 /* The table is sorted, but we use linear search for simplicity. */
112 for (segment2 = 0; segment2 < pcmap->segCount2; segment2 += 2) {
113 uint start, delta, roff;
114
115 READ_SFNTS(pfont, pcmap->endCount + segment2, 2, ttdata);
116 if (chr > U16(ttdata))
117 continue;
118 READ_SFNTS(pfont, pcmap->startCount + segment2, 2, ttdata);
119 start = U16(ttdata);
120 if (chr < start)
121 continue;
122 READ_SFNTS(pfont, pcmap->idDelta + segment2, 2, ttdata);
123 delta = U16(ttdata);
124 READ_SFNTS(pfont, pcmap->idRangeOffset + segment2, 2, ttdata);
125 roff = U16(ttdata);
126 if (roff) {
127 ulong gidoff = pcmap->idRangeOffset + segment2 + roff +
128 (chr - start) * 2;
129
130 READ_SFNTS(pfont, gidoff, 2, ttdata);
131 value = U16(ttdata);
132 if (value != 0)
133 value += delta;
134 } else
135 value = chr + delta;
136 break;
137 }
138 *pglyph = GS_MIN_CID_GLYPH + (value & 0xffff);
139 *pchr = chr;
140 *pindex += 2;
141 *pfidx = 0;
142 return 0;
143 }
144 static int
tt_16bit_format4_next_range(gs_cmap_ranges_enum_t * penum)145 tt_16bit_format4_next_range(gs_cmap_ranges_enum_t *penum)
146 {
147 /* There is just a single 2-byte range. */
148 if (penum->index == 0) {
149 penum->range.first[0] = penum->range.first[1] = 0;
150 penum->range.last[0] = penum->range.last[1] = 0xff;
151 penum->range.size = 2;
152 penum->index = 1;
153 return 0;
154 }
155 return 1;
156 }
157 static const gs_cmap_ranges_enum_procs_t tt_16bit_format4_range_procs = {
158 tt_16bit_format4_next_range
159 };
160 static void
tt_16bit_format4_enum_ranges(const gs_cmap_t * pcmap,gs_cmap_ranges_enum_t * pre)161 tt_16bit_format4_enum_ranges(const gs_cmap_t *pcmap,
162 gs_cmap_ranges_enum_t *pre)
163 {
164 gs_cmap_ranges_enum_setup(pre, pcmap, &tt_16bit_format4_range_procs);
165 }
166 static int
tt_16bit_format4_next_lookup(gs_memory_t * mem,gs_cmap_lookups_enum_t * penum)167 tt_16bit_format4_next_lookup(gs_memory_t *mem, gs_cmap_lookups_enum_t *penum)
168 {
169 penum->entry.value.data = 0L;
170 if (penum->index[0] == 0) {
171 penum->entry.key_size = 2;
172 penum->entry.key_is_range = true;
173 penum->entry.value_type = CODE_VALUE_CID;
174 penum->entry.value.size = 2;
175 penum->entry.font_index = 0;
176 penum->index[0] = 1;
177 return 0;
178 }
179 return 1;
180 }
181 static int
tt_16bit_format4_next_entry(gs_cmap_lookups_enum_t * penum)182 tt_16bit_format4_next_entry(gs_cmap_lookups_enum_t *penum)
183 {
184 /* index[1] is segment # << 17 + first code. */
185 uint segment2 = penum->index[1] >> 16;
186 uint next = penum->index[1] & 0xffff;
187 const gs_cmap_tt_16bit_format4_t *pcmap =
188 (const gs_cmap_tt_16bit_format4_t *)penum->cmap;
189 gs_font_type42 *pfont = pcmap->font;
190 byte ttdata[2];
191 int code;
192 uint start, end, delta, roff;
193 uint value;
194
195 top:
196 if (segment2 >= pcmap->segCount2)
197 return 1;
198 READ_SFNTS(pfont, pcmap->endCount + segment2, 2, ttdata);
199 end = U16(ttdata);
200 if (next > end) {
201 segment2 += 2;
202 goto top;
203 }
204 READ_SFNTS(pfont, pcmap->startCount + segment2, 2, ttdata);
205 start = U16(ttdata);
206 if (next < start)
207 next = start;
208 PUT16(penum->entry.key[0], next);
209 READ_SFNTS(pfont, pcmap->idDelta + segment2, 2, ttdata);
210 delta = U16(ttdata);
211 READ_SFNTS(pfont, pcmap->idRangeOffset + segment2, 2, ttdata);
212 roff = U16(ttdata);
213 if (roff) {
214 /* Non-zero offset, table lookup. */
215 ulong gidoff = pcmap->idRangeOffset + segment2 + roff;
216
217 READ_SFNTS(pfont, gidoff, 2, ttdata);
218 value = U16(ttdata);
219 if (value != 0)
220 value += delta;
221 ++next;
222 } else {
223 /* Zero offset, account for high-order byte changes. */
224 value = next + delta;
225 next = min(end, (next | 0xff)) + 1;
226 }
227 PUT16(penum->entry.key[1], next - 1);
228 PUT16(penum->temp_value, value);
229 penum->entry.value.data = penum->temp_value;
230 penum->entry.value.size = 2;
231 penum->index[1] = (segment2 << 16) + next;
232 return 0;
233 }
234 static const gs_cmap_lookups_enum_procs_t tt_16bit_format4_lookup_procs = {
235 tt_16bit_format4_next_lookup, tt_16bit_format4_next_entry
236 };
237 static void
tt_16bit_format4_enum_lookups(const gs_cmap_t * pcmap,int which,gs_cmap_lookups_enum_t * pre)238 tt_16bit_format4_enum_lookups(const gs_cmap_t *pcmap, int which,
239 gs_cmap_lookups_enum_t *pre)
240 {
241 gs_cmap_lookups_enum_setup(pre, pcmap,
242 (which ? &gs_cmap_no_lookups_procs :
243 &tt_16bit_format4_lookup_procs));
244 }
245
246 static const gs_cmap_procs_t tt_16bit_format4_procs = {
247 tt_16bit_format4_decode_next,
248 tt_16bit_format4_enum_ranges,
249 tt_16bit_format4_enum_lookups,
250 gs_cmap_compute_identity
251 };
252
253 /*
254 * Create a CMap from a TrueType Platform 3, Encoding 1, Format 4 cmap.
255 */
256 int
gs_cmap_from_type42_cmap(gs_cmap_t ** ppcmap,gs_font_type42 * pfont,int wmode,gs_memory_t * mem)257 gs_cmap_from_type42_cmap(gs_cmap_t **ppcmap, gs_font_type42 *pfont,
258 int wmode, gs_memory_t *mem)
259 {
260 ulong origin = pfont->data.cmap;
261 gs_cmap_tt_16bit_format4_t *pcmap;
262 int code;
263 byte ttdata[8];
264 ulong offset = origin;
265 uint segCount2;
266
267 if (origin == 0)
268 return_error(gs_error_invalidfont);
269
270 /*
271 * Find the desired cmap sub-table, if any.
272 */
273 {
274 uint cmap_count;
275 uint i;
276
277 READ_SFNTS(pfont, origin + 2, 2, ttdata);
278 cmap_count = U16(ttdata);
279 for (i = 0; i < cmap_count; ++i) {
280 READ_SFNTS(pfont, origin + 4 + i * 8, 8, ttdata);
281 if (U16(ttdata) != 3 || /* platform ID */
282 U16(ttdata + 2) != 1 /* encoding ID */
283 )
284 continue;
285 offset = origin + U32(ttdata + 4);
286 READ_SFNTS(pfont, offset, 2, ttdata);
287 if (U16(ttdata) != 4 /* format */)
288 continue;
289 break;
290 }
291 if (i >= cmap_count) /* not found */
292 return_error(gs_error_invalidfont);
293 READ_SFNTS(pfont, offset + 6, 2, ttdata);
294 segCount2 = U16(ttdata);
295 }
296
297 /* Allocate the CMap. */
298 {
299 static const gs_cid_system_info_t null_cidsi = {
300 { (const byte*) "none", 4 },
301 { (const byte*) "none", 4 },
302 0
303 };
304 code = gs_cmap_alloc(ppcmap, &st_cmap_tt_16bit_format4, wmode,
305 (const byte *)"none", 4, &null_cidsi, 1,
306 &tt_16bit_format4_procs, mem);
307 if (code < 0)
308 return code;
309 }
310 pcmap = (gs_cmap_tt_16bit_format4_t *)*ppcmap;
311 pcmap->from_Unicode = true;
312 pcmap->font = pfont;
313 pcmap->segCount2 = segCount2;
314 pcmap->endCount = offset + 14;
315 pcmap->startCount = pcmap->endCount + segCount2 + 2;
316 pcmap->idDelta = pcmap->startCount + segCount2;
317 pcmap->idRangeOffset = pcmap->idDelta + segCount2;
318 pcmap->glyphIdArray = pcmap->idRangeOffset + segCount2;
319 return 0;
320 }
321