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