1 /* Copyright (C) 2001-2012 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.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, 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_private_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_cmap_lookups_enum_t * penum)167 tt_16bit_format4_next_lookup(gs_cmap_lookups_enum_t *penum)
168 {
169     if (penum->index[0] == 0) {
170         penum->entry.key_size = 2;
171         penum->entry.key_is_range = true;
172         penum->entry.value_type = CODE_VALUE_CID;
173         penum->entry.value.size = 2;
174         penum->entry.font_index = 0;
175         penum->index[0] = 1;
176         return 0;
177     }
178     return 1;
179 }
180 static int
tt_16bit_format4_next_entry(gs_cmap_lookups_enum_t * penum)181 tt_16bit_format4_next_entry(gs_cmap_lookups_enum_t *penum)
182 {
183     /* index[1] is segment # << 17 + first code. */
184     uint segment2 = penum->index[1] >> 16;
185     uint next = penum->index[1] & 0xffff;
186     const gs_cmap_tt_16bit_format4_t *pcmap =
187         (const gs_cmap_tt_16bit_format4_t *)penum->cmap;
188     gs_font_type42 *pfont = pcmap->font;
189     byte ttdata[2];
190     int code;
191     uint start, end, delta, roff;
192     uint value;
193 
194  top:
195     if (segment2 >= pcmap->segCount2)
196         return 1;
197     READ_SFNTS(pfont, pcmap->endCount + segment2, 2, ttdata);
198     end = U16(ttdata);
199     if (next > end) {
200         segment2 += 2;
201         goto top;
202     }
203     READ_SFNTS(pfont, pcmap->startCount + segment2, 2, ttdata);
204     start = U16(ttdata);
205     if (next < start)
206         next = start;
207     PUT16(penum->entry.key[0], next);
208     READ_SFNTS(pfont, pcmap->idDelta + segment2, 2, ttdata);
209     delta = U16(ttdata);
210     READ_SFNTS(pfont, pcmap->idRangeOffset + segment2, 2, ttdata);
211     roff = U16(ttdata);
212     if (roff) {
213         /* Non-zero offset, table lookup. */
214         ulong gidoff = pcmap->idRangeOffset + segment2 + roff;
215 
216         READ_SFNTS(pfont, gidoff, 2, ttdata);
217         value = U16(ttdata);
218         if (value != 0)
219             value += delta;
220         ++next;
221     } else {
222         /* Zero offset, account for high-order byte changes. */
223         value = next + delta;
224         next = min(end, (next | 0xff)) + 1;
225     }
226     PUT16(penum->entry.key[1], next - 1);
227     PUT16(penum->temp_value, value);
228     penum->entry.value.data = penum->temp_value;
229     penum->entry.value.size = 2;
230     penum->index[1] = (segment2 << 16) + next;
231     return 0;
232 }
233 static const gs_cmap_lookups_enum_procs_t tt_16bit_format4_lookup_procs = {
234     tt_16bit_format4_next_lookup, tt_16bit_format4_next_entry
235 };
236 static void
tt_16bit_format4_enum_lookups(const gs_cmap_t * pcmap,int which,gs_cmap_lookups_enum_t * pre)237 tt_16bit_format4_enum_lookups(const gs_cmap_t *pcmap, int which,
238                         gs_cmap_lookups_enum_t *pre)
239 {
240     gs_cmap_lookups_enum_setup(pre, pcmap,
241                                (which ? &gs_cmap_no_lookups_procs :
242                                 &tt_16bit_format4_lookup_procs));
243 }
244 
245 static const gs_cmap_procs_t tt_16bit_format4_procs = {
246     tt_16bit_format4_decode_next,
247     tt_16bit_format4_enum_ranges,
248     tt_16bit_format4_enum_lookups,
249     gs_cmap_compute_identity
250 };
251 
252 /*
253  * Create a CMap from a TrueType Platform 3, Encoding 1, Format 4 cmap.
254  */
255 int
gs_cmap_from_type42_cmap(gs_cmap_t ** ppcmap,gs_font_type42 * pfont,int wmode,gs_memory_t * mem)256 gs_cmap_from_type42_cmap(gs_cmap_t **ppcmap, gs_font_type42 *pfont,
257                          int wmode, gs_memory_t *mem)
258 {
259     ulong origin = pfont->data.cmap;
260     gs_cmap_tt_16bit_format4_t *pcmap;
261     int code;
262     byte ttdata[8];
263     ulong offset = origin;
264     uint segCount2;
265 
266     if (origin == 0)
267         return_error(gs_error_invalidfont);
268 
269     /*
270      * Find the desired cmap sub-table, if any.
271      */
272     {
273         uint cmap_count;
274         uint i;
275 
276         READ_SFNTS(pfont, origin + 2, 2, ttdata);
277         cmap_count = U16(ttdata);
278         for (i = 0; i < cmap_count; ++i) {
279             READ_SFNTS(pfont, origin + 4 + i * 8, 8, ttdata);
280             if (U16(ttdata) != 3 || /* platform ID */
281                 U16(ttdata + 2) != 1 /* encoding ID */
282                 )
283                 continue;
284             offset = origin + U32(ttdata + 4);
285             READ_SFNTS(pfont, offset, 2, ttdata);
286             if (U16(ttdata) != 4 /* format */)
287                 continue;
288             break;
289         }
290         if (i >= cmap_count)	/* not found */
291             return_error(gs_error_invalidfont);
292         READ_SFNTS(pfont, offset + 6, 2, ttdata);
293         segCount2 = U16(ttdata);
294     }
295 
296     /* Allocate the CMap. */
297     {
298         static const gs_cid_system_info_t null_cidsi = {
299             { (const byte*) "none", 4 },
300             { (const byte*) "none", 4 },
301             0
302         };
303         code = gs_cmap_alloc(ppcmap, &st_cmap_tt_16bit_format4, wmode,
304                              (const byte *)"none", 4, &null_cidsi, 1,
305                              &tt_16bit_format4_procs, mem);
306         if (code < 0)
307             return code;
308     }
309     pcmap = (gs_cmap_tt_16bit_format4_t *)*ppcmap;
310     pcmap->from_Unicode = true;
311     pcmap->font = pfont;
312     pcmap->segCount2 = segCount2;
313     pcmap->endCount = offset + 14;
314     pcmap->startCount = pcmap->endCount + segCount2 + 2;
315     pcmap->idDelta = pcmap->startCount + segCount2;
316     pcmap->idRangeOffset = pcmap->idDelta + segCount2;
317     pcmap->glyphIdArray = pcmap->idRangeOffset + segCount2;
318     return 0;
319 }
320