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