1 /* Copyright (C) 2001-2006 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, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: zcid.c 9925 2009-08-02 23:16:26Z alexcher $ */
15 /* CMap and CID-keyed font services */
16 #include "ghost.h"
17 #include "ierrors.h"
18 #include "gxcid.h"
19 #include "icid.h"		/* for checking prototype */
20 #include "idict.h"
21 #include "idparam.h"
22 #include "store.h"
23 #include "oper.h"
24 #include "gserrors.h"
25 
26 /* Get the information from a CIDSystemInfo dictionary. */
27 int
cid_system_info_param(gs_cid_system_info_t * pcidsi,const ref * prcidsi)28 cid_system_info_param(gs_cid_system_info_t *pcidsi, const ref *prcidsi)
29 {
30     ref *pregistry;
31     ref *pordering;
32     int code;
33 
34     if (!r_has_type(prcidsi, t_dictionary))
35 	return_error(e_typecheck);
36     if (dict_find_string(prcidsi, "Registry", &pregistry) <= 0 ||
37 	dict_find_string(prcidsi, "Ordering", &pordering) <= 0
38 	)
39 	return_error(e_rangecheck);
40     check_read_type_only(*pregistry, t_string);
41     check_read_type_only(*pordering, t_string);
42     pcidsi->Registry.data = pregistry->value.const_bytes;
43     pcidsi->Registry.size = r_size(pregistry);
44     pcidsi->Ordering.data = pordering->value.const_bytes;
45     pcidsi->Ordering.size = r_size(pordering);
46     code = dict_int_param(prcidsi, "Supplement", 0, max_int, -1,
47 			  &pcidsi->Supplement);
48     return (code < 0 ? code : 0);
49 }
50 
51 /* Convert a CID into TT char code or to TT glyph index. */
52 static bool
TT_char_code_from_CID_no_subst(const gs_memory_t * mem,const ref * Decoding,const ref * TT_cmap,uint nCID,uint * c)53 TT_char_code_from_CID_no_subst(const gs_memory_t *mem,
54 			       const ref *Decoding, const ref *TT_cmap, uint nCID, uint *c)
55 {   ref *DecodingArray, char_code, char_code1, ih, *glyph_index;
56     bool found = false;
57     int i = nCID % 256, n;
58 
59     make_int(&ih, nCID / 256);
60     if (dict_find(Decoding, &ih, &DecodingArray) <= 0 ||
61 	    !r_has_type(DecodingArray, t_array) ||
62 	    array_get(mem, DecodingArray, i, &char_code) < 0)
63 	return false;
64     if (r_has_type(&char_code, t_integer))
65 	n = 1;
66     else if (r_has_type(&char_code, t_array)) {
67 	DecodingArray = &char_code;
68 	i = 0;
69 	n = r_size(DecodingArray);
70     } else
71 	return false; /* Must not happen. */
72     for (;n--; i++) {
73 	if (array_get(mem, DecodingArray, i, &char_code1) < 0 ||
74 	    !r_has_type(&char_code1, t_integer))
75 	    return false; /* Must not happen. */
76 	if (dict_find(TT_cmap, &char_code1, &glyph_index) >= 0 &&
77 		r_has_type(glyph_index, t_integer)) {
78 	    *c = glyph_index->value.intval;
79 	    found = true;
80 	    if (*c != 0)
81 		return true;
82 	}
83     }
84     return found;
85 }
86 
87 /* Convert a CID into a TT char code or into a TT glyph index, using SubstNWP. */
88 /* Returns 1 if a glyph presents, 0 if not, <0 if error. */
89 int
cid_to_TT_charcode(const gs_memory_t * mem,const ref * Decoding,const ref * TT_cmap,const ref * SubstNWP,uint nCID,uint * c,ref * src_type,ref * dst_type)90 cid_to_TT_charcode(const gs_memory_t *mem,
91 		   const ref *Decoding, const ref *TT_cmap, const ref *SubstNWP,
92                    uint nCID, uint *c, ref *src_type, ref *dst_type)
93 {
94     int SubstNWP_length = r_size(SubstNWP), i, code;
95 
96     if (TT_char_code_from_CID_no_subst(mem, Decoding, TT_cmap, nCID, c)) {
97 	make_null(src_type);
98 	/* Leaving dst_type uninitialized. */
99 	return 1;
100     }
101     for (i = 0; i < SubstNWP_length; i += 5) {
102         ref rb, re, rs;
103         int nb, ne, ns;
104 
105 	if ((code = array_get(mem, SubstNWP, i + 1, &rb)) < 0)
106 	    return code;
107         if ((code = array_get(mem, SubstNWP, i + 2, &re)) < 0)
108 	    return code;
109         if ((code = array_get(mem, SubstNWP, i + 3, &rs)) < 0)
110 	    return code;
111         nb = rb.value.intval;
112         ne = re.value.intval;
113         ns = rs.value.intval;
114         if (nCID >= nb && nCID <= ne)
115             if (TT_char_code_from_CID_no_subst(mem, Decoding, TT_cmap, ns + (nCID - nb), c)) {
116 		if ((code = array_get(mem, SubstNWP, i + 0, src_type)) < 0)
117 		    return code;
118 		if ((code = array_get(mem, SubstNWP, i + 4, dst_type)) < 0)
119 		    return code;
120                 return 1;
121 	    }
122         if (nCID >= ns && nCID <= ns + (ne - nb))
123             if (TT_char_code_from_CID_no_subst(mem, Decoding, TT_cmap, nb + (nCID - ns), c)) {
124 		if ((code = array_get(mem, SubstNWP, i + 0, dst_type)) < 0)
125 		    return code;
126 		if ((code = array_get(mem, SubstNWP, i + 4, src_type)) < 0)
127 		    return code;
128                 return 1;
129 	    }
130     }
131     *c = 0;
132     return 0;
133 }
134 
135 /* Set a CIDMap element. */
136 static int
set_CIDMap_element(const gs_memory_t * mem,ref * CIDMap,uint cid,uint glyph_index)137 set_CIDMap_element(const gs_memory_t *mem, ref *CIDMap, uint cid, uint glyph_index)
138 {   /* Assuming the CIDMap is already type-checked. */
139     /* Assuming GDBytes == 2. */
140     int offset = cid * 2;
141     int count = r_size(CIDMap), size, i;
142     ref s;
143     uchar *c;
144 
145     if (glyph_index >= 65536)
146 	return_error(e_rangecheck); /* Can't store with GDBytes == 2. */
147     for (i = 0; i < count; i++) {
148 	array_get(mem, CIDMap, i, &s);
149 	size = r_size(&s) & ~1;
150 	if (offset < size) {
151 	    c = s.value.bytes + offset;
152 	    c[0] = (uchar)(glyph_index >> 8);
153 	    c[1] = (uchar)(glyph_index & 255);
154 	    break;
155 	}
156 	offset -= size;
157     }
158     /* We ignore the substitution if it goes out the CIDMap range.
159        It must not happen, except for empty Decoding elements */
160     return 0;
161 }
162 
163 /* Create a CIDMap from a True Type cmap array, Decoding and SubstNWP. */
164 int
cid_fill_CIDMap(const gs_memory_t * mem,const ref * Decoding,const ref * TT_cmap,const ref * SubstNWP,int GDBytes,ref * CIDMap)165 cid_fill_CIDMap(const gs_memory_t *mem,
166 		const ref *Decoding, const ref *TT_cmap, const ref *SubstNWP, int GDBytes,
167                 ref *CIDMap)
168 {   int dict_enum;
169     ref el[2];
170     int count, i;
171 
172     if (GDBytes != 2)
173 	return_error(e_unregistered); /* Unimplemented. */
174     if (r_type(CIDMap) != t_array)
175 	return_error(e_unregistered); /* Unimplemented. It could be a single string. */
176     count = r_size(CIDMap);
177     /* Checking the CIDMap structure correctness : */
178     for (i = 0; i < count; i++) {
179 	ref s;
180 	int code = array_get(mem, CIDMap, i, &s);
181 
182 	if (code < 0)
183 	    return code;
184 	check_type(s, t_string); /* fixme : optimize with moving to TT_char_code_from_CID. */
185     }
186     /* Compute the CIDMap : */
187     dict_enum = dict_first(Decoding);
188     for (;;) {
189         int index, count, i;
190 
191 	if ((dict_enum = dict_next(Decoding, dict_enum, el)) == -1)
192 	    break;
193 	if (!r_has_type(&el[0], t_integer))
194 	    continue;
195 	if (!r_has_type(&el[1], t_array))
196 	    return_error(e_typecheck);
197 	index = el[0].value.intval;
198 	count = r_size(&el[1]);
199 	for (i = 0; i < count; i++) {
200 	    uint cid = index * 256 + i, glyph_index;
201 	    ref src_type, dst_type;
202 	    int code = cid_to_TT_charcode(mem, Decoding, TT_cmap, SubstNWP,
203                                 cid, &glyph_index, &src_type, &dst_type);
204 
205 	    if (code < 0)
206 		return code;
207 	    if (code > 0) {
208 	        code = set_CIDMap_element(mem, CIDMap, cid, glyph_index);
209 		if (code < 0)
210 		    return code;
211 	    }
212 	}
213     }
214     return 0;
215 }
216 
217 int
cid_fill_Identity_CIDMap(const gs_memory_t * mem,ref * CIDMap)218 cid_fill_Identity_CIDMap(const gs_memory_t *mem,
219                 ref *CIDMap)
220 {   int count, i;
221 
222     count = r_size(CIDMap);
223     if (count != 3)
224 	return_error(gs_error_rangecheck);
225 
226     /* Checking the CIDMap structure correctness : */
227     for (i = 0; i < count; i++) {
228 	ref s;
229 	int code = array_get(mem, CIDMap, i, &s);
230 
231 	if (code < 0)
232 	    return code;
233 	check_type(s, t_string); /* fixme : optimize with moving to TT_char_code_from_CID. */
234     }
235     for (i=0; i < 255*255; i++) {
236 	int code;
237 
238 	code = set_CIDMap_element(mem, CIDMap, i, i);
239 	if (code < 0)
240 	    return code;
241     }
242     return 0;
243 }
244