/src/ghostpdl/psi/zcharout.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 | | /* Common code for outline (Type 1 / 4 / 42) fonts */ |
18 | | #include "memory_.h" |
19 | | #include "ghost.h" |
20 | | #include "oper.h" |
21 | | #include "gscrypt1.h" |
22 | | #include "gstext.h" |
23 | | #include "gxdevice.h" /* for gxfont.h */ |
24 | | #include "gxfont.h" |
25 | | #include "gxfont1.h" |
26 | | #include "dstack.h" /* only for systemdict */ |
27 | | #include "estack.h" |
28 | | #include "ichar.h" |
29 | | #include "icharout.h" |
30 | | #include "idict.h" |
31 | | #include "ifont.h" |
32 | | #include "igstate.h" |
33 | | #include "iname.h" |
34 | | #include "store.h" |
35 | | |
36 | | /* |
37 | | * Execute an outline defined by a PostScript procedure. |
38 | | * The top elements of the stack are: |
39 | | * <font> <code|name> <name> <outline_id> |
40 | | */ |
41 | | int |
42 | | zchar_exec_char_proc(i_ctx_t *i_ctx_p) |
43 | 0 | { |
44 | 0 | os_ptr op = osp; |
45 | | /* |
46 | | * The definition is a PostScript procedure. Execute |
47 | | * <code|name> proc |
48 | | * within a systemdict begin/end and a font begin/end. |
49 | | */ |
50 | 0 | es_ptr ep; |
51 | |
|
52 | 0 | check_estack(5); |
53 | 0 | ep = esp += 5; |
54 | 0 | make_op_estack(ep - 4, zend); |
55 | 0 | make_op_estack(ep - 3, zend); |
56 | 0 | ref_assign(ep - 2, op); |
57 | 0 | make_op_estack(ep - 1, zbegin); |
58 | 0 | make_op_estack(ep, zbegin); |
59 | 0 | ref_assign(op - 1, systemdict); |
60 | 0 | { |
61 | 0 | ref rfont; |
62 | |
|
63 | 0 | ref_assign(&rfont, op - 3); |
64 | 0 | ref_assign(op - 3, op - 2); |
65 | 0 | ref_assign(op - 2, &rfont); |
66 | 0 | } |
67 | 0 | pop(1); |
68 | 0 | return o_push_estack; |
69 | 0 | } |
70 | | |
71 | | /* |
72 | | * Get the metrics for a character from the Metrics dictionary of a base |
73 | | * font. If present, store the l.s.b. in psbw[0,1] and the width in |
74 | | * psbw[2,3]. |
75 | | */ |
76 | | int /*metrics_present*/ |
77 | | zchar_get_metrics(const gs_font_base * pbfont, const ref * pcnref, |
78 | | double psbw[4]) |
79 | 5.21M | { |
80 | 5.21M | const ref *pfdict = &pfont_data(gs_font_parent(pbfont))->dict; |
81 | 5.21M | ref *pmdict; |
82 | | |
83 | 5.21M | if (dict_find_string(pfdict, "Metrics", &pmdict) > 0) { |
84 | 0 | ref *pmvalue; |
85 | |
|
86 | 0 | check_type_only(*pmdict, t_dictionary); |
87 | 0 | check_dict_read(*pmdict); |
88 | 0 | if (dict_find(pmdict, pcnref, &pmvalue) > 0) { |
89 | 0 | if (num_params(pmvalue, 1, psbw + 2) >= 0) { /* <wx> only */ |
90 | 0 | psbw[3] = 0; |
91 | 0 | return metricsWidthOnly; |
92 | 0 | } else { |
93 | 0 | int code; |
94 | |
|
95 | 0 | check_read_type_only(*pmvalue, t_array); |
96 | 0 | switch (r_size(pmvalue)) { |
97 | 0 | case 2: /* [<sbx> <wx>] */ |
98 | 0 | code = num_params(pmvalue->value.refs + 1, |
99 | 0 | 2, psbw); |
100 | 0 | psbw[2] = psbw[1]; |
101 | 0 | psbw[1] = psbw[3] = 0; |
102 | 0 | break; |
103 | 0 | case 4: /* [<sbx> <sby> <wx> <wy>] */ |
104 | 0 | code = num_params(pmvalue->value.refs + 3, |
105 | 0 | 4, psbw); |
106 | 0 | break; |
107 | 0 | default: |
108 | 0 | return_error(gs_error_rangecheck); |
109 | 0 | } |
110 | 0 | if (code < 0) |
111 | 0 | return code; |
112 | 0 | return metricsSideBearingAndWidth; |
113 | 0 | } |
114 | 0 | } |
115 | 0 | } |
116 | 5.21M | return metricsNone; |
117 | 5.21M | } |
118 | | |
119 | | /* Get the vertical metrics for a character from Metrics2, if present. */ |
120 | | int |
121 | | zchar_get_metrics2(const gs_font_base * pbfont, const ref * pcnref, |
122 | | double pwv[4]) |
123 | 1.50M | { |
124 | 1.50M | const ref *pfdict = &pfont_data(gs_font_parent(pbfont))->dict; |
125 | 1.50M | ref *pmdict; |
126 | | |
127 | 1.50M | if (dict_find_string(pfdict, "Metrics2", &pmdict) > 0) { |
128 | 0 | ref *pmvalue; |
129 | |
|
130 | 0 | check_type_only(*pmdict, t_dictionary); |
131 | 0 | check_dict_read(*pmdict); |
132 | 0 | if (dict_find(pmdict, pcnref, &pmvalue) > 0) { |
133 | 0 | check_read_type_only(*pmvalue, t_array); |
134 | 0 | if (r_size(pmvalue) == 4) { |
135 | 0 | int code = num_params(pmvalue->value.refs + 3, 4, pwv); |
136 | |
|
137 | 0 | return (code < 0 ? code : metricsSideBearingAndWidth); |
138 | 0 | } |
139 | 0 | } |
140 | 0 | } |
141 | 1.50M | return metricsNone; |
142 | 1.50M | } |
143 | | |
144 | | /* |
145 | | * Get CDevProc. |
146 | | */ |
147 | | bool |
148 | | zchar_get_CDevProc(const gs_font_base * pbfont, ref **ppcdevproc) |
149 | 4.95M | { |
150 | 4.95M | const ref *pfdict = &pfont_data(gs_font_parent(pbfont))->dict; |
151 | | |
152 | 4.95M | return dict_find_string(pfdict, "CDevProc", ppcdevproc) > 0; |
153 | 4.95M | } |
154 | | |
155 | | /* |
156 | | * Consult Metrics2 and CDevProc, and call setcachedevice[2]. Return |
157 | | * o_push_estack if we had to call a CDevProc, or if we are skipping the |
158 | | * rendering process (only getting the metrics). |
159 | | * Returns exec_cont - a function, which must be called by caller after this function. |
160 | | */ |
161 | | int |
162 | | zchar_set_cache(i_ctx_t *i_ctx_p, const gs_font_base * pbfont, |
163 | | const ref * pcnref, const double psb[2], |
164 | | const double pwidth[2], const gs_rect * pbbox, |
165 | | op_proc_t cont, op_proc_t *exec_cont, |
166 | | const double Metrics2_sbw_default[4]) |
167 | 1.50M | { |
168 | 1.50M | os_ptr op = osp; |
169 | 1.50M | ref *pcdevproc, *valueref; |
170 | 1.50M | int have_cdevproc; |
171 | 1.50M | ref rpop; |
172 | 1.50M | ref cid, *cidptr; |
173 | 1.50M | bool metrics2; |
174 | 1.50M | bool metrics2_use_default = false; |
175 | 1.50M | double w2[10]; |
176 | 1.50M | gs_text_enum_t *penum = op_show_find(i_ctx_p); |
177 | | |
178 | 1.50M | if (penum == NULL) |
179 | 0 | return_error(gs_error_invalidaccess); |
180 | | |
181 | 1.50M | w2[0] = pwidth[0], w2[1] = pwidth[1]; |
182 | | |
183 | | /* Adjust the bounding box for stroking if needed. */ |
184 | | |
185 | 1.50M | w2[2] = pbbox->p.x, w2[3] = pbbox->p.y; |
186 | 1.50M | w2[4] = pbbox->q.x, w2[5] = pbbox->q.y; |
187 | 1.50M | if (pbfont->PaintType != 0) { |
188 | 0 | double expand = max(1.415, gs_currentmiterlimit(igs)) * |
189 | 0 | gs_currentlinewidth(igs) / 2; |
190 | |
|
191 | 0 | w2[2] -= expand, w2[3] -= expand; |
192 | 0 | w2[4] += expand, w2[5] += expand; |
193 | 0 | } |
194 | | |
195 | | /* Check for Metrics2. */ |
196 | | |
197 | 1.50M | { |
198 | 1.50M | int code = zchar_get_metrics2(pbfont, pcnref, w2 + 6); |
199 | | |
200 | 1.50M | if (code < 0) |
201 | 0 | return code; |
202 | 1.50M | metrics2 = code > 0; |
203 | 1.50M | } |
204 | | |
205 | | /* |
206 | | * For FontType 9 and 11, if Metrics2 is missing, the caller provides |
207 | | * default Metrics2 values derived from the FontBBox. |
208 | | */ |
209 | 1.50M | if (!metrics2 && Metrics2_sbw_default != NULL) { |
210 | 0 | w2[6] = Metrics2_sbw_default[2]; |
211 | 0 | w2[7] = Metrics2_sbw_default[3]; |
212 | 0 | w2[8] = Metrics2_sbw_default[0]; |
213 | 0 | w2[9] = Metrics2_sbw_default[1]; |
214 | 0 | metrics2 = true; |
215 | 0 | metrics2_use_default = true; |
216 | 0 | } |
217 | | |
218 | | /* Check for CDevProc or "short-circuiting". */ |
219 | | |
220 | 1.50M | have_cdevproc = zchar_get_CDevProc(pbfont, &pcdevproc); |
221 | | |
222 | | /* Obscure test. The CDevProc is supposed to be called with the original CID but what we get passed |
223 | | * here is the TT GID. So the CDevProc won't do the right thing. We need to extract the CID from the |
224 | | * enumerator, and use that instead. |
225 | | */ |
226 | 1.50M | cidptr = (ref *)pcnref; |
227 | 1.50M | if (pbfont->FontType == ft_CID_TrueType && dict_find_string(&pfont_data(gs_font_parent(pbfont))->dict, "File", &valueref) > 0) { |
228 | 0 | if (pbfont->key_name.size != pbfont->font_name.size || |
229 | 0 | strncmp((const char *)pbfont->key_name.chars, (const char *)pbfont->font_name.chars, pbfont->key_name.size)) { |
230 | |
|
231 | 0 | if (penum->returned.current_glyph >= GS_MIN_CID_GLYPH) { |
232 | 0 | make_int(&cid, penum->returned.current_glyph - GS_MIN_CID_GLYPH); |
233 | 0 | } |
234 | 0 | else { |
235 | 0 | make_int(&cid, penum->returned.current_glyph); |
236 | 0 | } |
237 | 0 | cidptr = &cid; |
238 | 0 | } |
239 | 0 | } |
240 | 1.50M | if (have_cdevproc || zchar_show_width_only(penum)) { |
241 | 680 | int i; |
242 | 680 | op_proc_t zsetc; |
243 | 680 | int nparams; |
244 | | |
245 | 680 | if (have_cdevproc) { |
246 | 0 | check_proc_only(*pcdevproc); |
247 | 0 | zsetc = zsetcachedevice2; |
248 | | |
249 | | /* If we have cdevproc and the font type is CID type 0, |
250 | | we'll throw away Metrics2_sbw_default that is calculated |
251 | | from FontBBox. */ |
252 | 0 | if (!metrics2 |
253 | 0 | || (penum->current_font->FontType == ft_CID_encrypted |
254 | 0 | && metrics2_use_default)) { |
255 | 0 | w2[6] = w2[0], w2[7] = w2[1]; |
256 | 0 | w2[8] = w2[9] = 0; |
257 | 0 | } |
258 | 0 | nparams = 10; |
259 | 680 | } else { |
260 | 680 | make_oper(&rpop, 0, zpop); |
261 | 680 | pcdevproc = &rpop; |
262 | 680 | if (metrics2) |
263 | 0 | zsetc = zsetcachedevice2, nparams = 10; |
264 | 680 | else |
265 | 680 | zsetc = zsetcachedevice, nparams = 6; |
266 | 680 | } |
267 | 680 | check_estack(3); |
268 | | /* Push the l.s.b. for .type1addpath if necessary. */ |
269 | 680 | if (psb != 0) { |
270 | 0 | push(nparams + 3); |
271 | 0 | make_real(op - (nparams + 2), psb[0]); |
272 | 0 | make_real(op - (nparams + 1), psb[1]); |
273 | 680 | } else { |
274 | 680 | push(nparams + 1); |
275 | 680 | } |
276 | 4.76k | for (i = 0; i < nparams; ++i) |
277 | 4.08k | make_real(op - nparams + i, w2[i]); |
278 | 680 | ref_assign(op, cidptr); |
279 | 680 | push_op_estack(cont); |
280 | 680 | push_op_estack(zsetc); |
281 | 680 | ++esp; |
282 | 680 | ref_assign(esp, pcdevproc); |
283 | 680 | return o_push_estack; |
284 | 1.50M | } { |
285 | 1.50M | int code = |
286 | 1.50M | (metrics2 ? gs_text_setcachedevice2(penum, w2) : |
287 | 1.50M | gs_text_setcachedevice(penum, w2)); |
288 | | |
289 | 1.50M | if (code < 0) |
290 | 0 | return code; |
291 | 1.50M | } |
292 | | |
293 | | /* No metrics modification, do the stroke or fill now. */ |
294 | | |
295 | | /* Push the l.s.b. for .type1addpath if necessary. */ |
296 | 1.50M | if (psb != 0) { |
297 | 0 | push(2); |
298 | 0 | make_real(op - 1, psb[0]); |
299 | 0 | make_real(op, psb[1]); |
300 | 0 | } |
301 | 1.50M | *exec_cont = cont; |
302 | 1.50M | return 0; |
303 | 1.50M | } |
304 | | |
305 | | /* |
306 | | * Get the CharString data corresponding to a glyph. Return typecheck |
307 | | * if it isn't a string. |
308 | | */ |
309 | | static bool charstring_is_notdef_proc(const gs_memory_t *mem, const ref *); |
310 | | static int charstring_make_notdef(gs_glyph_data_t *, gs_font *); |
311 | | int |
312 | | zchar_charstring_data(gs_font *font, const ref *pgref, gs_glyph_data_t *pgd) |
313 | 7.29M | { |
314 | 7.29M | ref *pcstr; |
315 | 7.29M | ref *cffcstr; |
316 | 7.29M | ref *pdr = pfont_dict(font); |
317 | | |
318 | 7.29M | if (dict_find(&pfont_data(font)->CharStrings, pgref, &pcstr) <= 0) |
319 | 0 | return_error(gs_error_undefined); |
320 | | |
321 | 7.29M | if (r_has_type(pcstr, t_integer) |
322 | 7.29M | && dict_find_string(pdr, "CFFCharStrings", &cffcstr) > 0) { |
323 | 0 | ref *pcstr2; |
324 | 0 | if (dict_find(cffcstr, pcstr, &pcstr2) <= 0) { |
325 | 0 | ref nd; |
326 | 0 | make_int(&nd, 0); |
327 | 0 | if (dict_find(cffcstr, &nd, &pcstr2) <= 0) { |
328 | 0 | return_error(gs_error_undefined); |
329 | 0 | } |
330 | 0 | } |
331 | 0 | pcstr = pcstr2; |
332 | 0 | } |
333 | | |
334 | 7.29M | if (!r_has_type(pcstr, t_string)) { |
335 | | /* |
336 | | * The ADOBEPS4 Windows driver replaces the .notdef entry of |
337 | | * otherwise normal Type 1 fonts with the procedure |
338 | | * {pop 0 0 setcharwidth} |
339 | | * To prevent this from making the font unembeddable in PDF files |
340 | | * (with our present font-writing code), we recognize this as a |
341 | | * special case and return a Type 1 CharString consisting of |
342 | | * 0 0 hsbw endchar |
343 | | */ |
344 | 0 | if (font->FontType == ft_encrypted && |
345 | 0 | charstring_is_notdef_proc(font->memory, pcstr) |
346 | 0 | ) |
347 | 0 | return charstring_make_notdef(pgd, font); |
348 | 0 | else { |
349 | | /* Bug #703779. It seems that other tools can modify type 1 fonts, using |
350 | | * a procedure in place of a CharString for the /.notdef. In this case the |
351 | | * culprit is "Polylogics DIAD White Pages Pagination". Doing this prevents |
352 | | * pdfwrite from being able to write the font. Obviously we cannot have a |
353 | | * PostScript procedure in a PDF file. Adobe Acrobat Distiller replaces |
354 | | * the procedure with a simple 'endchar' CharString, so we now do the |
355 | | * same. I've chosen to leave the specific ADOBEPS4 test above unchanged, rather |
356 | | * than roll it in here, because I can't find an example file for it and |
357 | | * can't be certain that 'pgref' will be a name in that case. |
358 | | */ |
359 | 0 | ref namestr; |
360 | |
|
361 | 0 | if (r_has_type(pgref, t_name)) { |
362 | 0 | name_string_ref(pgd->memory, pgref, &namestr); |
363 | 0 | if (r_size(&namestr) == 7 && !memcmp(namestr.value.bytes, ".notdef", 7)) |
364 | 0 | return charstring_make_notdef(pgd, font); |
365 | 0 | } |
366 | 0 | return_error(gs_error_typecheck); |
367 | 0 | } |
368 | 0 | } |
369 | 7.29M | gs_glyph_data_from_string(pgd, pcstr->value.const_bytes, r_size(pcstr), |
370 | 7.29M | NULL); |
371 | 7.29M | return 0; |
372 | 7.29M | } |
373 | | static bool |
374 | | charstring_is_notdef_proc(const gs_memory_t *mem, const ref *pcstr) |
375 | 0 | { |
376 | 0 | if (r_is_array(pcstr) && r_size(pcstr) == 4) { |
377 | 0 | ref elts[4]; |
378 | 0 | long i; |
379 | |
|
380 | 0 | for (i = 0; i < 4; ++i) |
381 | 0 | array_get(mem, pcstr, i, &elts[i]); |
382 | 0 | if (r_has_type(&elts[0], t_name) && |
383 | 0 | r_has_type(&elts[1], t_integer) && elts[1].value.intval == 0 && |
384 | 0 | r_has_type(&elts[2], t_integer) && elts[2].value.intval == 0 && |
385 | 0 | r_has_type(&elts[3], t_name) |
386 | 0 | ) { |
387 | 0 | ref nref; |
388 | |
|
389 | 0 | name_enter_string(mem, "pop", &nref); |
390 | 0 | if (name_eq(&elts[0], &nref)) { |
391 | 0 | name_enter_string(mem, "setcharwidth", &nref); |
392 | 0 | if (name_eq(&elts[3], &nref)) |
393 | 0 | return true; |
394 | 0 | } |
395 | 0 | } |
396 | 0 | } |
397 | 0 | return false; |
398 | 0 | } |
399 | | static int |
400 | | charstring_make_notdef(gs_glyph_data_t *pgd, gs_font *font) |
401 | 0 | { |
402 | 0 | gs_font_type1 *const pfont = (gs_font_type1 *)font; |
403 | 0 | static const byte char_data[4] = { |
404 | 0 | 139, /* 0 */ |
405 | 0 | 139, /* 0 */ |
406 | 0 | c1_hsbw, |
407 | 0 | cx_endchar |
408 | 0 | }; |
409 | 0 | uint len = max(pfont->data.lenIV, 0) + sizeof(char_data); |
410 | 0 | byte *chars = gs_alloc_string(font->memory, len, "charstring_make_notdef"); |
411 | |
|
412 | 0 | if (chars == 0) |
413 | 0 | return_error(gs_error_VMerror); |
414 | 0 | gs_glyph_data_from_string(pgd, chars, len, font); |
415 | 0 | if (pfont->data.lenIV < 0) |
416 | 0 | memcpy(chars, char_data, sizeof(char_data)); |
417 | 0 | else { |
418 | 0 | crypt_state state = crypt_charstring_seed; |
419 | |
|
420 | 0 | memcpy(chars + pfont->data.lenIV, char_data, sizeof(char_data)); |
421 | 0 | gs_type1_encrypt(chars, chars, len, &state); |
422 | 0 | } |
423 | 0 | return 0; |
424 | 0 | } |
425 | | |
426 | | /* |
427 | | * Enumerate the next glyph from a directory. This is essentially a |
428 | | * wrapper around dict_first/dict_next to implement the enumerate_glyph |
429 | | * font procedure. |
430 | | * |
431 | | * Note that *prdict will be null if the font is a subfont of a |
432 | | * CIDFontType 0 CIDFont. |
433 | | */ |
434 | | int |
435 | | zchar_enumerate_glyph(const gs_memory_t *mem, const ref *prdict, int *pindex, gs_glyph *pglyph) |
436 | 6.79M | { |
437 | 6.79M | int index = *pindex - 1; |
438 | 6.79M | ref elt[2]; |
439 | | |
440 | 6.79M | if (!r_has_type(prdict, t_dictionary)) |
441 | 0 | return 0; /* *pindex was 0, is still 0 */ |
442 | 6.79M | if (index < 0) |
443 | 8.48k | index = dict_first(prdict); |
444 | 6.79M | next: |
445 | 6.79M | index = dict_next(prdict, index, elt); |
446 | 6.79M | *pindex = index + 1; |
447 | 6.79M | if (index >= 0) { |
448 | 6.79M | switch (r_type(elt)) { |
449 | 0 | case t_integer: |
450 | 0 | *pglyph = GS_MIN_CID_GLYPH + elt[0].value.intval; |
451 | 0 | break; |
452 | 6.79M | case t_name: |
453 | 6.79M | *pglyph = name_index(mem, elt); |
454 | 6.79M | break; |
455 | 0 | default: /* can't handle it */ |
456 | 0 | goto next; |
457 | 6.79M | } |
458 | 6.79M | } |
459 | 6.79M | return 0; |
460 | 6.79M | } |