/src/ghostpdl/psi/zfont0.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2021 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 | | /* Composite font creation operator */ |
18 | | #include "ghost.h" |
19 | | #include "oper.h" |
20 | | #include "gsstruct.h" |
21 | | /* |
22 | | * The following lines used to say: |
23 | | * #include "gsmatrix.h" |
24 | | * #include "gxdevice.h" /. for gxfont.h ./ |
25 | | * Tony Li says the longer list is necessary to keep the GNU compiler |
26 | | * happy, but this is pretty hard to understand.... |
27 | | */ |
28 | | #include "gxfixed.h" |
29 | | #include "gxmatrix.h" |
30 | | #include "gzstate.h" /* must precede gxdevice */ |
31 | | #include "gxdevice.h" /* must precede gxfont */ |
32 | | #include "gxfcmap.h" |
33 | | #include "gxfont.h" |
34 | | #include "gxfont0.h" |
35 | | #include "bfont.h" |
36 | | #include "ialloc.h" |
37 | | #include "iddict.h" |
38 | | #include "idparam.h" |
39 | | #include "igstate.h" |
40 | | #include "iname.h" |
41 | | #include "store.h" |
42 | | |
43 | | /* Imported from zfcmap.c */ |
44 | | int ztype0_get_cmap(const gs_cmap_t ** ppcmap, const ref * pfdepvector, |
45 | | const ref * op, gs_memory_t *imem); |
46 | | |
47 | | /* Forward references */ |
48 | | static font_proc_define_font(ztype0_define_font); |
49 | | static font_proc_make_font(ztype0_make_font); |
50 | | static int ensure_char_entry(i_ctx_t *, os_ptr, const char *, byte *, int); |
51 | | |
52 | | /* <string|name> <font_dict> .buildfont0 <string|name> <font> */ |
53 | | /* Build a type 0 (composite) font. */ |
54 | | static int |
55 | | zbuildfont0(i_ctx_t *i_ctx_p) |
56 | 9 | { |
57 | 9 | os_ptr op = osp; |
58 | 9 | gs_type0_data data; |
59 | 9 | ref fdepvector; |
60 | 9 | ref *pprefenc; |
61 | 9 | gs_font_type0 *pfont; |
62 | 9 | font_data *pdata; |
63 | 9 | ref save_FID; |
64 | 9 | int i; |
65 | 9 | int code = 0; |
66 | | |
67 | 9 | check_type(*op, t_dictionary); |
68 | 1 | { |
69 | 1 | ref *pfmaptype; |
70 | 1 | ref *pfdepvector; |
71 | | |
72 | 1 | if (dict_find_string(op, "FMapType", &pfmaptype) <= 0 || |
73 | 1 | !r_has_type(pfmaptype, t_integer) || |
74 | 1 | pfmaptype->value.intval < (int)fmap_type_min || |
75 | 1 | pfmaptype->value.intval > (int)fmap_type_max || |
76 | 1 | dict_find_string(op, "FDepVector", &pfdepvector) <= 0 || |
77 | 1 | !r_is_array(pfdepvector) |
78 | 1 | ) |
79 | 1 | return_error(gs_error_invalidfont); |
80 | 0 | data.FMapType = (fmap_type) pfmaptype->value.intval; |
81 | | /* |
82 | | * Adding elements below could cause the font dictionary to be |
83 | | * resized, which would invalidate pfdepvector. |
84 | | */ |
85 | 0 | fdepvector = *pfdepvector; |
86 | 0 | } |
87 | | /* Check that every element of the FDepVector is a font. */ |
88 | 0 | data.fdep_size = r_size(&fdepvector); |
89 | 0 | for (i = 0; i < data.fdep_size; i++) { |
90 | 0 | ref fdep; |
91 | 0 | gs_font *psub; |
92 | |
|
93 | 0 | array_get(imemory, &fdepvector, i, &fdep); |
94 | 0 | if ((code = font_param(&fdep, &psub)) < 0) |
95 | 0 | return code; |
96 | | /* |
97 | | * Check the inheritance rules. Allowed configurations |
98 | | * (paths from root font) are defined by the regular |
99 | | * expression: |
100 | | * (shift | double_escape escape* | escape*) |
101 | | * non_modal* non_composite |
102 | | */ |
103 | 0 | if (psub->FontType == ft_composite) { |
104 | 0 | const gs_font_type0 *const psub0 = (const gs_font_type0 *)psub; |
105 | 0 | fmap_type fmt = psub0->data.FMapType; |
106 | |
|
107 | 0 | if (fmt == fmap_double_escape || |
108 | 0 | fmt == fmap_shift || |
109 | 0 | (fmt == fmap_escape && |
110 | 0 | !(data.FMapType == fmap_escape || |
111 | 0 | data.FMapType == fmap_double_escape)) |
112 | 0 | ) |
113 | 0 | return_error(gs_error_invalidfont); |
114 | 0 | } |
115 | 0 | } |
116 | 0 | switch (data.FMapType) { |
117 | 0 | case fmap_escape: |
118 | 0 | case fmap_double_escape: /* need EscChar */ |
119 | 0 | code = ensure_char_entry(i_ctx_p, op, "EscChar", &data.EscChar, 255); |
120 | 0 | break; |
121 | 0 | case fmap_shift: /* need ShiftIn & ShiftOut */ |
122 | 0 | code = ensure_char_entry(i_ctx_p, op, "ShiftIn", &data.ShiftIn, 15); |
123 | 0 | if (code >= 0) |
124 | 0 | code = ensure_char_entry(i_ctx_p, op, "ShiftOut", &data.ShiftOut, 14); |
125 | 0 | break; |
126 | 0 | case fmap_SubsVector: /* need SubsVector */ |
127 | 0 | { |
128 | 0 | ref *psubsvector; |
129 | 0 | uint svsize; |
130 | |
|
131 | 0 | if (dict_find_string(op, "SubsVector", &psubsvector) <= 0 || |
132 | 0 | !r_has_type(psubsvector, t_string) || |
133 | 0 | (svsize = r_size(psubsvector)) == 0 || |
134 | 0 | (data.subs_width = (int)*psubsvector->value.bytes + 1) > 4 || |
135 | 0 | (svsize - 1) % data.subs_width != 0 |
136 | 0 | ) |
137 | 0 | return_error(gs_error_invalidfont); |
138 | 0 | data.subs_size = (svsize - 1) / data.subs_width; |
139 | 0 | data.SubsVector.data = psubsvector->value.bytes + 1; |
140 | 0 | data.SubsVector.size = svsize - 1; |
141 | 0 | } break; |
142 | 0 | case fmap_CMap: /* need CMap */ |
143 | 0 | code = ztype0_get_cmap(&data.CMap, (const ref *)&fdepvector, |
144 | 0 | (const ref *)op, imemory); |
145 | 0 | break; |
146 | 0 | default: |
147 | 0 | ; |
148 | 0 | } |
149 | 0 | if (code < 0) |
150 | 0 | return code; |
151 | | /* |
152 | | * Save the old FID in case we have to back out. |
153 | | * build_gs_font will return an error if there is a FID entry |
154 | | * but it doesn't reference a valid font. |
155 | | */ |
156 | 0 | { |
157 | 0 | ref *pfid; |
158 | |
|
159 | 0 | if (dict_find_string(op, "FID", &pfid) <= 0) |
160 | 0 | make_null(&save_FID); |
161 | 0 | else |
162 | 0 | save_FID = *pfid; |
163 | 0 | } |
164 | 0 | { |
165 | 0 | build_proc_refs build; |
166 | |
|
167 | 0 | code = build_proc_name_refs(imemory, &build, |
168 | 0 | "%Type0BuildChar", "%Type0BuildGlyph"); |
169 | 0 | if (code < 0) |
170 | 0 | return code; |
171 | 0 | code = build_gs_font(i_ctx_p, op, (gs_font **) & pfont, |
172 | 0 | ft_composite, &st_gs_font_type0, &build, |
173 | 0 | bf_options_none); |
174 | 0 | } |
175 | 0 | if (code != 0) |
176 | 0 | return code; |
177 | | /* Fill in the rest of the basic font data. */ |
178 | 0 | pfont->procs.init_fstack = gs_type0_init_fstack; |
179 | 0 | pfont->procs.define_font = ztype0_define_font; |
180 | 0 | pfont->procs.make_font = ztype0_make_font; |
181 | 0 | pfont->procs.next_char_glyph = gs_type0_next_char_glyph; |
182 | 0 | pfont->procs.decode_glyph = gs_font_map_glyph_to_unicode; /* PDF needs. */ |
183 | 0 | if (dict_find_string(op, "PrefEnc", &pprefenc) <= 0) { |
184 | 0 | ref nul; |
185 | |
|
186 | 0 | make_null_new(&nul); |
187 | 0 | if ((code = idict_put_string(op, "PrefEnc", &nul)) < 0) |
188 | 0 | goto fail; |
189 | 0 | } |
190 | 0 | get_GlyphNames2Unicode(i_ctx_p, (gs_font *)pfont, op); |
191 | | /* Fill in the font data */ |
192 | 0 | pdata = pfont_data(pfont); |
193 | 0 | data.encoding_size = r_size(&pdata->Encoding); |
194 | | /* |
195 | | * Adobe interpreters apparently require that Encoding.size >= subs_size |
196 | | * +1 (not sure whether the +1 only applies if the sum of the range |
197 | | * sizes is less than the size of the code space). The gs library |
198 | | * doesn't require this -- it only gives an error if a show operation |
199 | | * actually would reference beyond the end of the Encoding -- so we |
200 | | * check this here rather than in the library. |
201 | | */ |
202 | 0 | if (data.FMapType == fmap_SubsVector) { |
203 | 0 | if (data.subs_size >= r_size(&pdata->Encoding)) { |
204 | 0 | code = gs_note_error(gs_error_rangecheck); |
205 | 0 | goto fail; |
206 | 0 | } |
207 | 0 | } |
208 | 0 | data.Encoding = |
209 | 0 | (uint *) ialloc_byte_array(data.encoding_size, sizeof(uint), |
210 | 0 | "buildfont0(Encoding)"); |
211 | 0 | if (data.Encoding == 0) { |
212 | 0 | code = gs_note_error(gs_error_VMerror); |
213 | 0 | goto fail; |
214 | 0 | } |
215 | | /* Fill in the encoding vector, checking to make sure that */ |
216 | | /* each element is an integer between 0 and fdep_size-1. */ |
217 | 0 | for (i = 0; i < data.encoding_size; i++) { |
218 | 0 | ref enc; |
219 | |
|
220 | 0 | array_get(imemory, &pdata->Encoding, i, &enc); |
221 | 0 | if (!r_has_type(&enc, t_integer)) { |
222 | 0 | code = gs_note_error(gs_error_typecheck); |
223 | 0 | goto fail; |
224 | 0 | } |
225 | 0 | if ((ulong) enc.value.intval >= data.fdep_size) { |
226 | 0 | code = gs_note_error(gs_error_rangecheck); |
227 | 0 | goto fail; |
228 | 0 | } |
229 | 0 | data.Encoding[i] = (uint) enc.value.intval; |
230 | 0 | } |
231 | 0 | data.FDepVector = |
232 | 0 | ialloc_struct_array(data.fdep_size, gs_font *, |
233 | 0 | &st_gs_font_ptr_element, |
234 | 0 | "buildfont0(FDepVector)"); |
235 | 0 | if (data.FDepVector == 0) { |
236 | 0 | code = gs_note_error(gs_error_VMerror); |
237 | 0 | goto fail; |
238 | 0 | } |
239 | 0 | for (i = 0; i < data.fdep_size; i++) { |
240 | 0 | ref fdep; |
241 | 0 | ref *pfid; |
242 | |
|
243 | 0 | array_get(pfont->memory, &fdepvector, i, &fdep); |
244 | | /* The lookup can't fail, because of the pre-check above. */ |
245 | 0 | dict_find_string(&fdep, "FID", &pfid); |
246 | 0 | if (!r_has_type(pfid, t_fontID)) |
247 | 0 | return gs_note_error(gs_error_typecheck); |
248 | | |
249 | 0 | data.FDepVector[i] = r_ptr(pfid, gs_font); |
250 | 0 | } |
251 | 0 | pfont->data = data; |
252 | 0 | code = define_gs_font(i_ctx_p, (gs_font *) pfont); |
253 | 0 | if (code >= 0) |
254 | 0 | return code; |
255 | 0 | fail: |
256 | | /* |
257 | | * Undo the insertion of the FID entry in the dictionary. Note that |
258 | | * some allocations (Encoding, FDepVector) are not undone. |
259 | | */ |
260 | 0 | if (r_has_type(&save_FID, t_null)) { |
261 | 0 | ref rnfid; |
262 | |
|
263 | 0 | name_enter_string(pfont->memory, "FID", &rnfid); |
264 | 0 | idict_undef(op, &rnfid); |
265 | 0 | } else |
266 | 0 | idict_put_string(op, "FID", &save_FID); |
267 | 0 | gs_free_object(pfont->memory, pfont, "buildfont0(font)"); |
268 | 0 | return code; |
269 | 0 | } |
270 | | /* If a newly defined or scaled composite font had to scale */ |
271 | | /* any composite sub-fonts, adjust the parent font's FDepVector. */ |
272 | | /* This is called only if gs_type0_define/make_font */ |
273 | | /* actually changed the FDepVector. */ |
274 | | static int |
275 | | ztype0_adjust_FDepVector(gs_font_type0 * pfont) |
276 | 0 | { |
277 | 0 | gs_memory_t *mem = pfont->memory; |
278 | | /* HACK: We know the font was allocated by the interpreter. */ |
279 | 0 | gs_ref_memory_t *imem = (gs_ref_memory_t *)mem; |
280 | 0 | gs_font **pdep = pfont->data.FDepVector; |
281 | 0 | ref newdep; |
282 | 0 | uint fdep_size = pfont->data.fdep_size; |
283 | 0 | ref *prdep; |
284 | 0 | uint i; |
285 | 0 | int code = gs_alloc_ref_array(imem, &newdep, a_readonly, fdep_size, |
286 | 0 | "ztype0_adjust_matrix"); |
287 | |
|
288 | 0 | if (code < 0) |
289 | 0 | return code; |
290 | 0 | for (prdep = newdep.value.refs, i = 0; i < fdep_size; i++, prdep++) { |
291 | 0 | const ref *pdict = pfont_dict(pdep[i]); |
292 | |
|
293 | 0 | ref_assign(prdep, pdict); |
294 | 0 | r_set_attrs(prdep, imemory_new_mask(imem)); |
295 | 0 | } |
296 | | /* |
297 | | * The FDepVector is an existing key in the parent's dictionary, |
298 | | * so it's safe to pass NULL as the dstack pointer to dict_put_string. |
299 | | */ |
300 | 0 | return dict_put_string(pfont_dict(pfont), "FDepVector", &newdep, NULL); |
301 | 0 | } |
302 | | static int |
303 | | ztype0_define_font(gs_font_dir * pdir, gs_font * pfont) |
304 | 0 | { |
305 | 0 | gs_font_type0 *const pfont0 = (gs_font_type0 *)pfont; |
306 | 0 | gs_font **pdep = pfont0->data.FDepVector; |
307 | 0 | int code = gs_type0_define_font(pdir, pfont); |
308 | |
|
309 | 0 | if (code < 0 || pfont0->data.FDepVector == pdep) |
310 | 0 | return code; |
311 | 0 | return ztype0_adjust_FDepVector(pfont0); |
312 | 0 | } |
313 | | static int |
314 | | ztype0_make_font(gs_font_dir * pdir, const gs_font * pfont, |
315 | | const gs_matrix * pmat, gs_font ** ppfont) |
316 | 0 | { |
317 | 0 | gs_font_type0 **const ppfont0 = (gs_font_type0 **)ppfont; |
318 | 0 | gs_font **pdep = (*ppfont0)->data.FDepVector; |
319 | 0 | int code; |
320 | |
|
321 | 0 | code = zdefault_make_font(pdir, pfont, pmat, ppfont); |
322 | 0 | if (code < 0) |
323 | 0 | return code; |
324 | 0 | code = gs_type0_make_font(pdir, pfont, pmat, ppfont); |
325 | 0 | if (code < 0) |
326 | 0 | return code; |
327 | 0 | if ((*ppfont0)->data.FDepVector == pdep) |
328 | 0 | return 0; |
329 | 0 | return ztype0_adjust_FDepVector(*ppfont0); |
330 | 0 | } |
331 | | |
332 | | /* ------ Internal routines ------ */ |
333 | | |
334 | | /* Find or add a character entry in a font dictionary. */ |
335 | | static int |
336 | | ensure_char_entry(i_ctx_t *i_ctx_p, os_ptr op, const char *kstr, |
337 | | byte * pvalue, int default_value) |
338 | 0 | { |
339 | 0 | ref *pentry; |
340 | |
|
341 | 0 | if (dict_find_string(op, kstr, &pentry) <= 0) { |
342 | 0 | ref ent; |
343 | |
|
344 | 0 | make_int(&ent, default_value); |
345 | 0 | *pvalue = (byte) default_value; |
346 | 0 | return idict_put_string(op, kstr, &ent); |
347 | 0 | } else { |
348 | 0 | check_int_leu_only(*pentry, 255); |
349 | 0 | *pvalue = (byte) pentry->value.intval; |
350 | 0 | return 0; |
351 | 0 | } |
352 | 0 | } |
353 | | |
354 | | /* ------ Initialization procedure ------ */ |
355 | | |
356 | | const op_def zfont0_op_defs[] = |
357 | | { |
358 | | {"2.buildfont0", zbuildfont0}, |
359 | | op_def_end(0) |
360 | | }; |