/src/ghostpdl/psi/zchar.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2022 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 | | /* Character operators */ |
18 | | #include "ghost.h" |
19 | | #include "oper.h" |
20 | | #include "gsstruct.h" |
21 | | #include "gstext.h" |
22 | | #include "gxarith.h" |
23 | | #include "gxfixed.h" |
24 | | #include "gxmatrix.h" /* for ifont.h */ |
25 | | #include "gxdevice.h" /* for gxfont.h */ |
26 | | #include "gxfont.h" |
27 | | #include "gxfont42.h" |
28 | | #include "gxfont0.h" |
29 | | #include "gzstate.h" |
30 | | #include "dstack.h" /* for stack depth */ |
31 | | #include "estack.h" |
32 | | #include "ialloc.h" |
33 | | #include "ichar.h" |
34 | | #include "ichar1.h" |
35 | | #include "idict.h" |
36 | | #include "ifont.h" |
37 | | #include "igstate.h" |
38 | | #include "ilevel.h" |
39 | | #include "iname.h" |
40 | | #include "ipacked.h" |
41 | | #include "store.h" |
42 | | #include "zchar42.h" |
43 | | |
44 | | /* Forward references */ |
45 | | static bool map_glyph_to_char(const gs_memory_t *mem, |
46 | | const ref *, const ref *, ref *); |
47 | | static int finish_show(i_ctx_t *); |
48 | | static int op_show_cleanup(i_ctx_t *); |
49 | | static int op_show_return_width(i_ctx_t *, uint, double *); |
50 | | |
51 | | static int zawidthshow(i_ctx_t *i_ctx_p); |
52 | | static int zwidthshow(i_ctx_t *i_ctx_p); |
53 | | |
54 | | |
55 | | /* <string> show - */ |
56 | | static int |
57 | | zshow(i_ctx_t *i_ctx_p) |
58 | 25.3k | { |
59 | 25.3k | es_ptr ep = esp; /* Save in case of error */ |
60 | 25.3k | os_ptr op = osp; |
61 | 25.3k | gs_text_enum_t *penum = NULL; |
62 | 25.3k | int code = op_show_setup(i_ctx_p, op); |
63 | | |
64 | 25.3k | if (code != 0 || |
65 | 25.3k | (code = gs_show_begin(igs, op->value.bytes, r_size(op), imemory_local, &penum)) < 0) |
66 | 45 | return code; |
67 | 25.2k | *(op_proc_t *)&penum->enum_client_data = zshow; |
68 | 25.2k | if ((code = op_show_finish_setup(i_ctx_p, penum, 1, finish_show)) < 0) { |
69 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
70 | | * we 'retry' the operation (eg having increased the operand stack). |
71 | | * We'll rely on gc to handle the enumerator. |
72 | | * Bug #700618. |
73 | | */ |
74 | 0 | esp = ep; |
75 | 0 | return code; |
76 | 0 | } |
77 | | |
78 | 25.2k | code = op_show_continue_pop(i_ctx_p, 1); |
79 | 25.2k | if (code < 0) { |
80 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
81 | | * we 'retry' the operation (eg having increased the operand stack). |
82 | | * We'll rely on gc to handle the enumerator. |
83 | | * Bug #700618. |
84 | | */ |
85 | 1 | esp = ep; |
86 | 1 | } |
87 | 25.2k | return code; |
88 | 25.2k | } |
89 | | |
90 | | /* <ax> <ay> <string> ashow - */ |
91 | | static int |
92 | | zashow(i_ctx_t *i_ctx_p) |
93 | 2.49k | { |
94 | 2.49k | es_ptr ep = esp; /* Save in case of error */ |
95 | 2.49k | os_ptr op = osp; |
96 | 2.49k | gs_text_enum_t *penum = NULL; |
97 | 2.49k | double axy[2]; |
98 | 2.49k | int code = num_params(op - 1, 2, axy); |
99 | | |
100 | 2.49k | if (code < 0 || |
101 | 2.49k | (code = op_show_setup(i_ctx_p, op)) != 0 || |
102 | 2.49k | (code = gs_ashow_begin(igs, axy[0], axy[1], op->value.bytes, r_size(op), imemory_local, &penum)) < 0) |
103 | 41 | return code; |
104 | 2.45k | *(op_proc_t *)&penum->enum_client_data = zashow; |
105 | 2.45k | if ((code = op_show_finish_setup(i_ctx_p, penum, 3, finish_show)) < 0) { |
106 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
107 | | * we 'retry' the operation (eg having increased the operand stack). |
108 | | * We'll rely on gc to handle the enumerator. |
109 | | * Bug #700618. |
110 | | */ |
111 | 0 | esp = ep; |
112 | 0 | return code; |
113 | 0 | } |
114 | 2.45k | code = op_show_continue_pop(i_ctx_p, 3); |
115 | 2.45k | if (code < 0) { |
116 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
117 | | * we 'retry' the operation (eg having increased the operand stack). |
118 | | * We'll rely on gc to handle the enumerator. |
119 | | * Bug #700618. |
120 | | */ |
121 | 0 | esp = ep; |
122 | 0 | } |
123 | 2.45k | return code; |
124 | 2.45k | } |
125 | | |
126 | | static int |
127 | | widthshow_aux(i_ctx_t *i_ctx_p, bool single_byte_space) |
128 | 22 | { |
129 | 22 | es_ptr ep = esp; /* Save in case of error */ |
130 | 22 | os_ptr op = osp; |
131 | 22 | gs_text_enum_t *penum = NULL; |
132 | 22 | double cxy[2]; |
133 | 22 | int code; |
134 | | |
135 | 22 | if ((code = op_show_setup(i_ctx_p, op)) != 0 ) |
136 | 16 | return code; |
137 | 6 | check_type(op[-1], t_integer); |
138 | 3 | if (gs_currentfont(igs)->FontType == ft_composite) { |
139 | 0 | if ((gs_char) (op[-1].value.intval) != op[-1].value.intval) |
140 | 0 | return_error(gs_error_rangecheck); |
141 | 3 | } else { |
142 | 3 | if (op[-1].value.intval < 0 || op[-1].value.intval > 255) |
143 | 2 | return_error(gs_error_rangecheck); /* per PLRM and CET 13-26 */ |
144 | 3 | } |
145 | 1 | if ((code = num_params(op - 2, 2, cxy)) < 0 ) |
146 | 1 | return code; |
147 | 0 | if ((code = gs_widthshow_begin(igs, cxy[0], cxy[1], |
148 | 0 | (gs_char) op[-1].value.intval, |
149 | 0 | op->value.bytes, r_size(op), |
150 | 0 | imemory_local, &penum)) < 0) { |
151 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
152 | | * we 'retry' the operation (eg having increased the operand stack). |
153 | | * We'll rely on gc to handle the enumerator. |
154 | | * Bug #700618. |
155 | | */ |
156 | 0 | esp = ep; |
157 | 0 | return code; |
158 | 0 | } |
159 | 0 | *(op_proc_t *)&penum->enum_client_data = zwidthshow; |
160 | |
|
161 | 0 | penum->single_byte_space = single_byte_space; |
162 | |
|
163 | 0 | if ((code = op_show_finish_setup(i_ctx_p, penum, 4, finish_show)) < 0) { |
164 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
165 | | * we 'retry' the operation (eg having increased the operand stack). |
166 | | * We'll rely on gc to handle the enumerator. |
167 | | * Bug #700618. |
168 | | */ |
169 | 0 | esp = ep; |
170 | 0 | return code; |
171 | 0 | } |
172 | | |
173 | 0 | code = op_show_continue_pop(i_ctx_p, 4); |
174 | 0 | if (code < 0) { |
175 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
176 | | * we 'retry' the operation (eg having increased the operand stack). |
177 | | * We'll rely on gc to handle the enumerator. |
178 | | * Bug #700618. |
179 | | */ |
180 | 0 | esp = ep; |
181 | 0 | } |
182 | 0 | return code; |
183 | 0 | } |
184 | | |
185 | | /* <cx> <cy> <char> <string> widthshow - */ |
186 | | static int |
187 | | zwidthshow(i_ctx_t *i_ctx_p) |
188 | 22 | { |
189 | 22 | return(widthshow_aux(i_ctx_p, false)); |
190 | 22 | } |
191 | | |
192 | | /* For PDF word spacing we need to identify strictly |
193 | | single byte character codes of the value 32, and |
194 | | this conflicts with Postscript's widthshow character |
195 | | code matching, where any character code, regardless of |
196 | | its length will match. For example, in widthshow, a |
197 | | character code of <0032> will match a parameter value |
198 | | of 32, but for PDF word spacing, <0032> will not match |
199 | | the space character, and won't have the word spacing |
200 | | applied, but <32> will. |
201 | | Hence, we have a couple of custom operators to cover |
202 | | the different requirements. |
203 | | */ |
204 | | /* <cx> <cy> <char> <string> .pdfwidthshow - */ |
205 | | static int |
206 | | zpdfwidthshow(i_ctx_t *i_ctx_p) |
207 | 0 | { |
208 | 0 | return(widthshow_aux(i_ctx_p, true)); |
209 | 0 | } |
210 | | |
211 | | static int |
212 | | awidthshow_aux(i_ctx_t *i_ctx_p, bool single_byte_space) |
213 | 23 | { |
214 | 23 | es_ptr ep = esp; /* Save in case of error */ |
215 | 23 | os_ptr op = osp; |
216 | 23 | gs_text_enum_t *penum = NULL; |
217 | 23 | double cxy[2], axy[2]; |
218 | 23 | int code; |
219 | | |
220 | 23 | if ((code = op_show_setup(i_ctx_p, op)) != 0 ) |
221 | 19 | return code; |
222 | 4 | if ((code = num_params(op - 1, 2, axy)) < 0 ) |
223 | 4 | return code; |
224 | 0 | check_type(op[-3], t_integer); |
225 | 0 | if (gs_currentfont(igs)->FontType == ft_composite) { |
226 | 0 | if ((gs_char) (op[-3].value.intval) != op[-3].value.intval) |
227 | 0 | return_error(gs_error_rangecheck); |
228 | 0 | } else { |
229 | 0 | if (op[-3].value.intval < 0 || op[-3].value.intval > 255) |
230 | 0 | return_error(gs_error_rangecheck); /* per PLRM and CET 13-02 */ |
231 | 0 | } |
232 | 0 | if ((code = num_params(op - 4, 2, cxy)) < 0 ) |
233 | 0 | return code; |
234 | 0 | if ((code = gs_awidthshow_begin(igs, cxy[0], cxy[1], |
235 | 0 | (gs_char) op[-3].value.intval, |
236 | 0 | axy[0], axy[1], |
237 | 0 | op->value.bytes, r_size(op), |
238 | 0 | imemory_local, &penum)) < 0) |
239 | 0 | return code; |
240 | 0 | *(op_proc_t *)&penum->enum_client_data = zawidthshow; |
241 | |
|
242 | 0 | penum->single_byte_space = single_byte_space; |
243 | |
|
244 | 0 | if ((code = op_show_finish_setup(i_ctx_p, penum, 6, finish_show)) < 0) { |
245 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
246 | | * we 'retry' the operation (eg having increased the operand stack). |
247 | | * We'll rely on gc to handle the enumerator. |
248 | | * Bug #700618. |
249 | | */ |
250 | 0 | esp = ep; |
251 | 0 | return code; |
252 | 0 | } |
253 | | |
254 | 0 | code = op_show_continue_pop(i_ctx_p, 6); |
255 | 0 | if (code < 0) { |
256 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
257 | | * we 'retry' the operation (eg having increased the operand stack). |
258 | | * We'll rely on gc to handle the enumerator. |
259 | | * Bug #700618. |
260 | | */ |
261 | 0 | esp = ep; |
262 | 0 | } |
263 | 0 | return code; |
264 | 0 | } |
265 | | |
266 | | /* <cx> <cy> <char> <ax> <ay> <string> awidthshow - */ |
267 | | static int |
268 | | zawidthshow(i_ctx_t *i_ctx_p) |
269 | 23 | { |
270 | 23 | return(awidthshow_aux(i_ctx_p, false)); |
271 | 23 | } |
272 | | |
273 | | /* <cx> <cy> <char> <ax> <ay> <string> .pdfawidthshow - */ |
274 | | static int |
275 | | zpdfawidthshow(i_ctx_t *i_ctx_p) |
276 | 0 | { |
277 | 0 | return(awidthshow_aux(i_ctx_p, true)); |
278 | 0 | } |
279 | | |
280 | | /* <proc> <string> kshow - */ |
281 | | static int |
282 | | zkshow(i_ctx_t *i_ctx_p) |
283 | 6 | { |
284 | 6 | es_ptr ep = esp; /* Save in case of error */ |
285 | 6 | os_ptr op = osp; |
286 | 6 | gs_text_enum_t *penum = NULL; |
287 | 6 | int code; |
288 | | |
289 | 6 | check_read_type(*op, t_string); |
290 | 6 | check_proc(op[-1]); |
291 | | /* |
292 | | * Per PLRM Section xx.x, kshow is illegal if the current font is a |
293 | | * composite font. The graphics library does not have this limitation, |
294 | | * so we check for it here. |
295 | | */ |
296 | 0 | if (gs_currentfont(igs)->FontType == ft_composite) |
297 | 0 | return_error(gs_error_invalidfont); |
298 | 0 | if ((code = op_show_setup(i_ctx_p, op)) != 0 || |
299 | 0 | (code = gs_kshow_begin(igs, op->value.bytes, r_size(op), |
300 | 0 | imemory_local, &penum)) < 0) |
301 | 0 | return code; |
302 | 0 | *(op_proc_t *)&penum->enum_client_data = zkshow; |
303 | 0 | if ((code = op_show_finish_setup(i_ctx_p, penum, 2, finish_show)) < 0) { |
304 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
305 | | * we 'retry' the operation (eg having increased the operand stack). |
306 | | * We'll rely on gc to handle the enumerator. |
307 | | * Bug #700618. |
308 | | */ |
309 | 0 | esp = ep; |
310 | 0 | return code; |
311 | 0 | } |
312 | 0 | sslot = op[-1]; /* save kerning proc */ |
313 | 0 | code = op_show_continue_pop(i_ctx_p, 2); |
314 | 0 | if (code < 0) { |
315 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
316 | | * we 'retry' the operation (eg having increased the operand stack). |
317 | | * We'll rely on gc to handle the enumerator. |
318 | | * Bug #700618. |
319 | | */ |
320 | 0 | esp = ep; |
321 | 0 | } |
322 | 0 | return code; |
323 | 0 | } |
324 | | |
325 | | /* Common finish procedure for all show operations. */ |
326 | | /* Doesn't have to do anything. */ |
327 | | static int |
328 | | finish_show(i_ctx_t *i_ctx_p) |
329 | 29.7k | { |
330 | 29.7k | return 0; |
331 | 29.7k | } |
332 | | |
333 | | /* Finishing procedure for stringwidth. */ |
334 | | /* Pushes the accumulated width. */ |
335 | | static int |
336 | | finish_stringwidth(i_ctx_t *i_ctx_p) |
337 | 408 | { |
338 | 408 | os_ptr op = osp; |
339 | 408 | gs_point width; |
340 | | |
341 | 408 | gs_text_total_width(senum, &width); |
342 | 408 | push(2); |
343 | 408 | make_real(op - 1, width.x); |
344 | 408 | make_real(op, width.y); |
345 | 408 | return 0; |
346 | 408 | } |
347 | | |
348 | | /* <string> stringwidth <wx> <wy> */ |
349 | | static int |
350 | | zstringwidth(i_ctx_t *i_ctx_p) |
351 | 422 | { |
352 | 422 | es_ptr ep = esp; /* Save in case of error */ |
353 | 422 | os_ptr op = osp; |
354 | 422 | gs_text_enum_t *penum = NULL; |
355 | 422 | int code = op_show_setup(i_ctx_p, op); |
356 | | |
357 | 422 | if (code != 0 || |
358 | 422 | (code = gs_stringwidth_begin(igs, op->value.bytes, r_size(op), |
359 | 410 | imemory, &penum)) < 0) |
360 | 14 | return code; |
361 | 408 | *(op_proc_t *)&penum->enum_client_data = zstringwidth; |
362 | 408 | if ((code = op_show_finish_setup(i_ctx_p, penum, 1, finish_stringwidth)) < 0) { |
363 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
364 | | * we 'retry' the operation (eg having increased the operand stack). |
365 | | * We'll rely on gc to handle the enumerator. |
366 | | * Bug #700618. |
367 | | */ |
368 | 0 | esp = ep; |
369 | 0 | return code; |
370 | 0 | } |
371 | 408 | code = op_show_continue_pop(i_ctx_p, 1); |
372 | 408 | if (code < 0) { |
373 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
374 | | * we 'retry' the operation (eg having increased the operand stack). |
375 | | * We'll rely on gc to handle the enumerator. |
376 | | * Bug #700618. |
377 | | */ |
378 | 0 | esp = ep; |
379 | 0 | } |
380 | 408 | return code; |
381 | 408 | } |
382 | | /* Common code for charpath and .charboxpath. */ |
383 | | static int |
384 | | zchar_path(i_ctx_t *i_ctx_p, op_proc_t proc, |
385 | | int (*begin)(gs_gstate *, const byte *, uint, |
386 | | bool, gs_memory_t *, gs_text_enum_t **)) |
387 | 2.06k | { |
388 | 2.06k | es_ptr ep = esp; /* Save in case of error */ |
389 | 2.06k | os_ptr op = osp; |
390 | 2.06k | gs_text_enum_t *penum = NULL; |
391 | 2.06k | int code; |
392 | | |
393 | 2.06k | check_type(*op, t_boolean); |
394 | 2.04k | code = op_show_setup(i_ctx_p, op - 1); |
395 | 2.04k | if (code != 0 || |
396 | 2.04k | (code = begin(igs, op[-1].value.bytes, r_size(op - 1), |
397 | 2.04k | op->value.boolval, imemory, &penum)) < 0) |
398 | 13 | return code; |
399 | 2.03k | *(op_proc_t *)&penum->enum_client_data = proc; |
400 | 2.03k | if ((code = op_show_finish_setup(i_ctx_p, penum, 2, finish_show)) < 0) { |
401 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
402 | | * we 'retry' the operation (eg having increased the operand stack). |
403 | | * We'll rely on gc to handle the enumerator. |
404 | | * Bug #700618. |
405 | | */ |
406 | 0 | esp = ep; |
407 | 0 | return code; |
408 | 0 | } |
409 | 2.03k | code = op_show_continue_pop(i_ctx_p, 2); |
410 | 2.03k | if (code < 0) { |
411 | | /* We must restore the exec stack pointer back to the point where we entered, in case |
412 | | * we 'retry' the operation (eg having increased the operand stack). |
413 | | * We'll rely on gc to handle the enumerator. |
414 | | * Bug #700618. |
415 | | */ |
416 | 0 | esp = ep; |
417 | 0 | } |
418 | 2.03k | return code; |
419 | 2.03k | } |
420 | | /* <string> <outline_bool> charpath - */ |
421 | | static int |
422 | | zcharpath(i_ctx_t *i_ctx_p) |
423 | 2.06k | { |
424 | 2.06k | return zchar_path(i_ctx_p, zcharpath, gs_charpath_begin); |
425 | 2.06k | } |
426 | | /* <string> <box_bool> .charboxpath - */ |
427 | | static int |
428 | | zcharboxpath(i_ctx_t *i_ctx_p) |
429 | 0 | { |
430 | 0 | return zchar_path(i_ctx_p, zcharboxpath, gs_charboxpath_begin); |
431 | 0 | } |
432 | | |
433 | | /* <wx> <wy> <llx> <lly> <urx> <ury> setcachedevice - */ |
434 | | int |
435 | | zsetcachedevice(i_ctx_t *i_ctx_p) |
436 | 1.43k | { |
437 | 1.43k | os_ptr op = osp; |
438 | 1.43k | double wbox[6]; |
439 | 1.43k | gs_text_enum_t *penum = op_show_find(i_ctx_p); |
440 | 1.43k | int code = num_params(op, 6, wbox); |
441 | | |
442 | 1.43k | if (penum == 0) |
443 | 14 | return_error(gs_error_undefined); |
444 | 1.41k | if (code < 0) |
445 | 1 | return code; |
446 | 1.41k | if (zchar_show_width_only(penum)) |
447 | 1.02k | return op_show_return_width(i_ctx_p, 6, &wbox[0]); |
448 | 395 | code = gs_text_setcachedevice(penum, wbox); |
449 | 395 | if (code < 0) |
450 | 0 | return code; |
451 | 395 | pop(6); |
452 | 395 | if (code == 1) |
453 | 395 | clear_pagedevice(istate); |
454 | 395 | return 0; |
455 | 395 | } |
456 | | |
457 | | /* <w0x> <w0y> <llx> <lly> <urx> <ury> <w1x> <w1y> <vx> <vy> setcachedevice2 - */ |
458 | | int |
459 | | zsetcachedevice2(i_ctx_t *i_ctx_p) |
460 | 18 | { |
461 | 18 | os_ptr op = osp; |
462 | 18 | double wbox[10]; |
463 | 18 | gs_text_enum_t *penum = op_show_find(i_ctx_p); |
464 | 18 | int code = num_params(op, 10, wbox); |
465 | | |
466 | 18 | if (penum == 0) |
467 | 18 | return_error(gs_error_undefined); |
468 | 0 | if (code < 0) |
469 | 0 | return code; |
470 | 0 | if (zchar_show_width_only(penum)) |
471 | 0 | return op_show_return_width(i_ctx_p, 10, |
472 | 0 | (gs_rootfont(igs)->WMode ? |
473 | 0 | &wbox[6] : &wbox[0])); |
474 | 0 | code = gs_text_setcachedevice2(penum, wbox); |
475 | 0 | if (code < 0) |
476 | 0 | return code; |
477 | 0 | pop(10); |
478 | 0 | if (code == 1) |
479 | 0 | clear_pagedevice(istate); |
480 | 0 | return 0; |
481 | 0 | } |
482 | | |
483 | | /* <wx> <wy> setcharwidth - */ |
484 | | static int |
485 | | zsetcharwidth(i_ctx_t *i_ctx_p) |
486 | 190k | { |
487 | 190k | os_ptr op = osp; |
488 | 190k | double width[2]; |
489 | 190k | gs_text_enum_t *penum = op_show_find(i_ctx_p); |
490 | 190k | int code = num_params(op, 2, width); |
491 | | |
492 | 190k | if (penum == 0) |
493 | 98 | return_error(gs_error_undefined); |
494 | 190k | if (code < 0) |
495 | 0 | return code; |
496 | 190k | if (zchar_show_width_only(penum)) |
497 | 0 | return op_show_return_width(i_ctx_p, 2, &width[0]); |
498 | 190k | code = gs_text_setcharwidth(penum, width); |
499 | 190k | if (code < 0) |
500 | 0 | return code; |
501 | 190k | pop(2); |
502 | 190k | return 0; |
503 | 190k | } |
504 | | |
505 | | /* <dict> .fontbbox <llx> <lly> <urx> <ury> -true- */ |
506 | | /* <dict> .fontbbox -false- */ |
507 | | static int |
508 | | zfontbbox(i_ctx_t *i_ctx_p) |
509 | 44.0k | { |
510 | 44.0k | os_ptr op = osp; |
511 | 44.0k | double bbox[4]; |
512 | 44.0k | int code; |
513 | | |
514 | 44.0k | check_type(*op, t_dictionary); |
515 | 44.0k | check_dict_read(*op); |
516 | 44.0k | code = font_bbox_param(imemory, op, bbox); |
517 | 44.0k | if (code < 0) |
518 | 0 | return code; |
519 | 44.0k | if (bbox[0] < bbox[2] && bbox[1] < bbox[3]) { |
520 | 44.0k | push(4); |
521 | 44.0k | make_reals(op - 4, bbox, 4); |
522 | 44.0k | make_true(op); |
523 | 44.0k | } else { /* No bbox, or an empty one. */ |
524 | 1 | make_false(op); |
525 | 1 | } |
526 | 44.0k | return 0; |
527 | 44.0k | } |
528 | | |
529 | | /* Export in_cachedevice flag for PDF interpreter, which, unlike |
530 | | * PS unterpreter, ignores color operations in the inappropriate context. |
531 | | */ |
532 | | /* - .incachedevice <bool> */ |
533 | | static int |
534 | | zincachedevice(i_ctx_t *i_ctx_p) |
535 | 6 | { |
536 | 6 | os_ptr op = osp; |
537 | | |
538 | 6 | push(1); |
539 | 6 | make_bool(op, !!igs->in_cachedevice); |
540 | 6 | return 0; |
541 | 6 | } |
542 | | |
543 | | /* ------ Initialization procedure ------ */ |
544 | | |
545 | | const op_def zchar_a_op_defs[] = |
546 | | { |
547 | | {"3ashow", zashow}, |
548 | | {"6awidthshow", zawidthshow}, |
549 | | {"2charpath", zcharpath}, |
550 | | {"2.charboxpath", zcharboxpath}, |
551 | | {"2kshow", zkshow}, |
552 | | {"6setcachedevice", zsetcachedevice}, |
553 | | {":setcachedevice2", zsetcachedevice2}, |
554 | | {"2setcharwidth", zsetcharwidth}, |
555 | | {"1show", zshow}, |
556 | | {"1stringwidth", zstringwidth}, |
557 | | {"4widthshow", zwidthshow}, |
558 | | /* Extensions */ |
559 | | {"1.fontbbox", zfontbbox}, |
560 | | {"6.pdfawidthshow", zpdfawidthshow}, |
561 | | {"4.pdfwidthshow", zpdfwidthshow}, |
562 | | |
563 | | /* Internal operators */ |
564 | | {"0%finish_show", finish_show}, |
565 | | op_def_end(0) |
566 | | }; |
567 | | |
568 | | const op_def zchar_b_op_defs[] = |
569 | | { |
570 | | {"0%finish_stringwidth", finish_stringwidth}, |
571 | | {"0%op_show_continue", op_show_continue}, |
572 | | {"0.incachedevice", zincachedevice}, |
573 | | op_def_end(0) |
574 | | }; |
575 | | |
576 | | /* ------ Subroutines ------ */ |
577 | | |
578 | | /* Most of these are exported for zchar2.c. */ |
579 | | |
580 | | /* Convert a glyph to a ref. */ |
581 | | void |
582 | | glyph_ref(const gs_memory_t *mem, gs_glyph glyph, ref * gref) |
583 | 5.38M | { |
584 | 5.38M | if (glyph < GS_MIN_CID_GLYPH) |
585 | 5.38M | name_index_ref(mem, glyph, gref); |
586 | 0 | else |
587 | 5.38M | make_int(gref, glyph - GS_MIN_CID_GLYPH); |
588 | 5.38M | } |
589 | | |
590 | | /* Prepare to set up for a text operator. */ |
591 | | /* Don't change any state yet. */ |
592 | | int |
593 | | op_show_setup(i_ctx_t *i_ctx_p, os_ptr op) |
594 | 30.3k | { |
595 | 30.3k | check_read_type(*op, t_string); |
596 | 30.2k | return op_show_enum_setup(i_ctx_p); |
597 | 30.3k | } |
598 | | int |
599 | | op_show_enum_setup(i_ctx_t *i_ctx_p) |
600 | 30.2k | { |
601 | 30.2k | check_estack(snumpush + 2); |
602 | 30.2k | return 0; |
603 | 30.2k | } |
604 | | |
605 | | /* Finish setting up a text operator. */ |
606 | | int |
607 | | op_show_finish_setup(i_ctx_t *i_ctx_p, gs_text_enum_t * penum, int npop, |
608 | | op_proc_t endproc /* end procedure */ ) |
609 | 30.1k | { |
610 | 30.1k | gs_text_enum_t *osenum = op_show_find(i_ctx_p); |
611 | 30.1k | es_ptr ep = esp + snumpush; |
612 | 30.1k | gs_glyph glyph; |
613 | | |
614 | 30.1k | if (gs_currentcpsimode(igs->memory)) { |
615 | | /* CET 14-03.PS page 2 emits rangecheck before rendering a character. |
616 | | Early check the text to font compatibility |
617 | | with decomposing the text into characters.*/ |
618 | 0 | int code = gs_text_count_chars(igs, gs_get_text_params(penum), imemory); |
619 | |
|
620 | 0 | if (code < 0) |
621 | 0 | return code; |
622 | 0 | } |
623 | | /* |
624 | | * If we are in the procedure of a cshow for a CID font and this is |
625 | | * a show operator, do something special, per the Red Book. |
626 | | */ |
627 | 30.1k | if (osenum && |
628 | 30.1k | SHOW_IS_ALL_OF(osenum, |
629 | 30.1k | TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_INTERVENE) && |
630 | 30.1k | SHOW_IS_ALL_OF(penum, TEXT_FROM_STRING | TEXT_RETURN_WIDTH) && |
631 | 30.1k | (glyph = gs_text_current_glyph(osenum)) != GS_NO_GLYPH && |
632 | 30.1k | glyph >= GS_MIN_CID_GLYPH && |
633 | | |
634 | | /* According to PLRM, we don't need to raise a rangecheck error, |
635 | | if currentfont is changed in the proc of the operator 'cshow'. */ |
636 | 30.1k | gs_default_same_font (gs_text_current_font(osenum), |
637 | 0 | gs_text_current_font(penum), true) |
638 | 30.1k | ) { |
639 | 0 | gs_text_params_t text; |
640 | |
|
641 | 0 | if (!(penum->text.size == 1 && |
642 | 0 | penum->text.data.bytes[0] == |
643 | 0 | (gs_text_current_char(osenum) & 0xff)) |
644 | 0 | ) |
645 | 0 | return_error(gs_error_rangecheck); |
646 | 0 | text = penum->text; |
647 | 0 | text.operation = |
648 | 0 | (text.operation & |
649 | 0 | ~(TEXT_FROM_STRING | TEXT_FROM_BYTES | TEXT_FROM_CHARS | |
650 | 0 | TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_CHAR)) | |
651 | 0 | TEXT_FROM_SINGLE_GLYPH; |
652 | 0 | text.data.d_glyph = glyph; |
653 | 0 | text.size = 1; |
654 | 0 | gs_text_restart(penum, &text); |
655 | 0 | } |
656 | 30.1k | if (osenum && osenum->current_font->FontType == ft_user_defined && |
657 | 30.1k | osenum->orig_font->FontType == ft_composite && |
658 | 30.1k | ((const gs_font_type0 *)osenum->orig_font)->data.FMapType == fmap_CMap) { |
659 | | /* A special behavior defined in PLRM3 section 5.11 page 389. */ |
660 | 0 | penum->outer_CID = osenum->returned.current_glyph; |
661 | 0 | } |
662 | 30.1k | if (osenum == NULL && !(penum->text.operation & (TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH))) { |
663 | 30.1k | int ft = igs->root_font->FontType; |
664 | | |
665 | 30.1k | if ((ft >= ft_CID_encrypted && ft <= ft_CID_TrueType) || ft == ft_CID_bitmap) |
666 | 0 | return_error(gs_error_typecheck); |
667 | 30.1k | } |
668 | 30.1k | make_mark_estack(ep - (snumpush - 1), es_show, op_show_cleanup); |
669 | 30.1k | if (endproc == NULL) |
670 | 0 | endproc = finish_show; |
671 | 30.1k | make_null(&esslot(ep)); |
672 | 30.1k | make_int(&esodepth(ep), ref_stack_count_inline(&o_stack) - npop); /* Save stack depth for */ |
673 | 30.1k | make_int(&esddepth(ep), ref_stack_count_inline(&d_stack)); /* correct interrupt processing */ |
674 | 30.1k | make_int(&esgslevel(ep), igs->level); |
675 | 30.1k | make_null(&essfont(ep)); |
676 | 30.1k | make_null(&esrfont(ep)); |
677 | 30.1k | make_op_estack(&eseproc(ep), endproc); |
678 | 30.1k | make_istruct(ep, 0, penum); |
679 | 30.1k | esp = ep; |
680 | 30.1k | return 0; |
681 | 30.1k | } |
682 | | |
683 | | /* Continuation operator for character rendering. */ |
684 | | int |
685 | | op_show_continue(i_ctx_t *i_ctx_p) |
686 | 1.15M | { |
687 | 1.15M | int code = gs_text_update_dev_color(igs, senum); |
688 | | |
689 | 1.15M | if (code >= 0) |
690 | 1.15M | code = op_show_continue_dispatch(i_ctx_p, 0, gs_text_process(senum)); |
691 | 1.15M | return code; |
692 | 1.15M | } |
693 | | int |
694 | | op_show_continue_pop(i_ctx_t *i_ctx_p, int npop) |
695 | 30.1k | { |
696 | 30.1k | return op_show_continue_dispatch(i_ctx_p, npop, gs_text_process(senum)); |
697 | 30.1k | } |
698 | | /* |
699 | | * Note that op_show_continue_dispatch sets osp = op explicitly iff the |
700 | | * dispatch succeeds. This is so that the show operators don't pop anything |
701 | | * from the o-stack if they don't succeed. Note also that if it returns an |
702 | | * error, it has freed the enumerator. |
703 | | */ |
704 | | int |
705 | | op_show_continue_dispatch(i_ctx_t *i_ctx_p, int npop, int code) |
706 | 1.18M | { |
707 | 1.18M | os_ptr op = osp - npop; |
708 | 1.18M | gs_text_enum_t *penum = senum; |
709 | | |
710 | 1.18M | switch (code) { |
711 | 30.1k | case 0: { /* all done */ |
712 | 30.1k | os_ptr save_osp = osp; |
713 | | |
714 | 30.1k | osp = op; |
715 | 30.1k | code = (*real_opproc(&seproc)) (i_ctx_p); |
716 | 30.1k | op_show_free(i_ctx_p, code); |
717 | 30.1k | if (code < 0) { |
718 | 0 | osp = save_osp; |
719 | 0 | return code; |
720 | 0 | } |
721 | 30.1k | return o_pop_estack; |
722 | 30.1k | } |
723 | 0 | case TEXT_PROCESS_INTERVENE: { |
724 | 0 | ref *pslot = &sslot; /* only used for kshow */ |
725 | |
|
726 | 0 | push(2); |
727 | 0 | make_int(op - 1, gs_text_current_char(penum)); /* previous char */ |
728 | 0 | make_int(op, gs_text_next_char(penum)); |
729 | 0 | push_op_estack(op_show_continue); /* continue after kerning */ |
730 | 0 | *++esp = *pslot; /* kerning procedure */ |
731 | 0 | return o_push_estack; |
732 | 0 | } |
733 | 1.15M | case TEXT_PROCESS_RENDER: { |
734 | 1.15M | gs_font *pfont = gs_currentfont(igs); |
735 | 1.15M | font_data *pfdata = pfont_data(pfont); |
736 | 1.15M | gs_char chr = gs_text_current_char(penum); |
737 | 1.15M | gs_glyph glyph = gs_text_current_glyph(penum); |
738 | | |
739 | 1.15M | push(2); |
740 | 1.15M | op[-1] = pfdata->dict; /* push the font */ |
741 | | /* |
742 | | * For Type 1 and Type 4 fonts, prefer BuildChar to BuildGlyph |
743 | | * if there is no glyph, or if there is both a character and a |
744 | | * glyph and the glyph is the one that corresponds to the |
745 | | * character in the Encoding, so that PostScript procedures |
746 | | * appearing in the CharStrings dictionary will receive the |
747 | | * character code rather than the character name; for Type 3 |
748 | | * fonts, prefer BuildGlyph to BuildChar. For other font types |
749 | | * (such as CID fonts), only BuildGlyph will be present. |
750 | | */ |
751 | 1.15M | if (pfont->FontType == ft_user_defined) { |
752 | | /* Type 3 font, prefer BuildGlyph. */ |
753 | 190k | if (level2_enabled && |
754 | 190k | !r_has_type(&pfdata->BuildGlyph, t_null) && |
755 | 190k | glyph != GS_NO_GLYPH |
756 | 190k | ) { |
757 | 0 | glyph_ref(imemory, glyph, op); |
758 | 0 | esp[2] = pfdata->BuildGlyph; |
759 | 190k | } else if (r_has_type(&pfdata->BuildChar, t_null)) |
760 | 0 | goto err; |
761 | 190k | else if (chr == gs_no_char) { |
762 | | /* glyphshow, reverse map the character */ |
763 | | /* through the Encoding */ |
764 | 0 | ref gref; |
765 | 0 | const ref *pencoding = &pfdata->Encoding; |
766 | |
|
767 | 0 | glyph_ref(imemory, glyph, &gref); |
768 | 0 | if (!map_glyph_to_char(imemory, &gref, pencoding, |
769 | 0 | (ref *) op) |
770 | 0 | ) { /* Not found, try .notdef */ |
771 | 0 | name_enter_string(imemory, ".notdef", &gref); |
772 | 0 | if (!map_glyph_to_char(imemory, &gref, |
773 | 0 | pencoding, |
774 | 0 | (ref *) op) |
775 | 0 | ) |
776 | 0 | goto err; |
777 | 0 | } |
778 | 0 | esp[2] = pfdata->BuildChar; |
779 | 190k | } else { |
780 | 190k | make_int(op, chr & 0xff); |
781 | 190k | esp[2] = pfdata->BuildChar; |
782 | 190k | } |
783 | 964k | } else { |
784 | | /* |
785 | | * For a Type 1 or Type 4 font, prefer BuildChar or |
786 | | * BuildGlyph as described above: we know that both |
787 | | * BuildChar and BuildGlyph are present. For other font |
788 | | * types, only BuildGlyph is available. |
789 | | */ |
790 | 964k | ref eref, gref; |
791 | | |
792 | 964k | if (chr != gs_no_char && |
793 | 964k | !r_has_type(&pfdata->BuildChar, t_null) && |
794 | 964k | (glyph == GS_NO_GLYPH || |
795 | 964k | (!r_has_type(&pfdata->Encoding, t_null) && |
796 | 964k | array_get(imemory, &pfdata->Encoding, (long)(chr & 0xff), &eref) >= 0 && |
797 | 964k | (glyph_ref(imemory, glyph, &gref), obj_eq(imemory, &gref, &eref)))) |
798 | 964k | ) { |
799 | 964k | make_int(op, chr & 0xff); |
800 | 964k | esp[2] = pfdata->BuildChar; |
801 | 964k | } else { |
802 | | /* We might not have a glyph: substitute 0. **HACK** */ |
803 | 0 | if (glyph == GS_NO_GLYPH) |
804 | 0 | make_int(op, 0); |
805 | 0 | else |
806 | 0 | glyph_ref(imemory, glyph, op); |
807 | 0 | esp[2] = pfdata->BuildGlyph; |
808 | 0 | } |
809 | 964k | } |
810 | | /* Save the stack depths in case we bail out. */ |
811 | 1.15M | sodepth.value.intval = ref_stack_count(&o_stack) - 2; |
812 | 1.15M | sddepth.value.intval = ref_stack_count(&d_stack); |
813 | 1.15M | push_op_estack(op_show_continue); |
814 | 1.15M | ++esp; /* skip BuildChar or BuildGlyph proc */ |
815 | 1.15M | return o_push_estack; |
816 | 1.15M | } |
817 | 0 | case TEXT_PROCESS_CDEVPROC: |
818 | 0 | { gs_font *pfont = penum->current_font; |
819 | 0 | ref cnref; |
820 | 0 | op_proc_t cont = op_show_continue, exec_cont = 0; |
821 | 0 | gs_glyph glyph = penum->returned.current_glyph; |
822 | |
|
823 | 0 | pop(npop); |
824 | 0 | op = osp; |
825 | 0 | glyph_ref(imemory, glyph, &cnref); |
826 | 0 | if (pfont->FontType == ft_CID_TrueType) { |
827 | 0 | gs_font_type42 *pfont42 = (gs_font_type42 *)pfont; |
828 | 0 | uint glyph_index = pfont42->data.get_glyph_index(pfont42, glyph); |
829 | |
|
830 | 0 | code = zchar42_set_cache(i_ctx_p, (gs_font_base *)pfont42, |
831 | 0 | &cnref, glyph_index, cont, &exec_cont); |
832 | 0 | } else if (pfont->FontType == ft_CID_encrypted) |
833 | 0 | code = z1_set_cache(i_ctx_p, (gs_font_base *)pfont, |
834 | 0 | &cnref, glyph, cont, &exec_cont); |
835 | 0 | else |
836 | 0 | code = gs_note_error(gs_error_unregistered); /* Unimplemented. */ |
837 | 0 | if (exec_cont != 0) |
838 | 0 | code = gs_note_error(gs_error_unregistered); /* Must not happen. */ |
839 | 0 | if (code < 0) |
840 | 0 | goto err; |
841 | 0 | else |
842 | 0 | return code; |
843 | 0 | } |
844 | 1 | default: /* error */ |
845 | 1 | err: |
846 | 1 | if (code >= 0) |
847 | 0 | code = gs_note_error(gs_error_invalidfont); |
848 | 1 | return op_show_free(i_ctx_p, code); |
849 | 1.18M | } |
850 | 1.18M | } |
851 | | /* Reverse-map a glyph name to a character code for glyphshow. */ |
852 | | static bool |
853 | | map_glyph_to_char(const gs_memory_t *mem, const ref * pgref, const ref * pencoding, ref * pch) |
854 | 0 | { |
855 | 0 | uint esize = r_size(pencoding); |
856 | 0 | uint ch; |
857 | 0 | ref eref; |
858 | |
|
859 | 0 | for (ch = 0; ch < esize; ch++) { |
860 | 0 | array_get(mem, pencoding, (long)ch, &eref); |
861 | 0 | if (obj_eq(mem, pgref, &eref)) { |
862 | 0 | make_int(pch, ch); |
863 | 0 | return true; |
864 | 0 | } |
865 | 0 | } |
866 | 0 | return false; |
867 | 0 | } |
868 | | |
869 | | /* Find the index of the e-stack mark for the current show enumerator. */ |
870 | | /* Return 0 if we can't find the mark. */ |
871 | | static uint |
872 | | op_show_find_index(i_ctx_t *i_ctx_p) |
873 | 2.15M | { |
874 | 2.15M | ref_stack_enum_t rsenum; |
875 | 2.15M | uint count = 0; |
876 | | |
877 | 2.15M | ref_stack_enum_begin(&rsenum, &e_stack); |
878 | 2.15M | do { |
879 | 2.15M | es_ptr ep = rsenum.ptr; |
880 | 2.15M | uint size = rsenum.size; |
881 | | |
882 | 22.8M | for (ep += size - 1; size != 0; size--, ep--, count++) |
883 | 22.8M | if (r_is_estack_mark(ep) && estack_mark_index(ep) == es_show) |
884 | 2.12M | return count; |
885 | 2.15M | } while (ref_stack_enum_next(&rsenum)); |
886 | 30.3k | return 0; /* no mark */ |
887 | 2.15M | } |
888 | | |
889 | | /* Find the current show enumerator on the e-stack. */ |
890 | | gs_text_enum_t * |
891 | | op_show_find(i_ctx_t *i_ctx_p) |
892 | 2.15M | { |
893 | 2.15M | uint index = op_show_find_index(i_ctx_p); |
894 | | |
895 | 2.15M | if (index == 0) |
896 | 30.3k | return 0; /* no mark */ |
897 | 2.12M | return r_ptr(ref_stack_index(&e_stack, index - (snumpush - 1)), |
898 | 2.15M | gs_text_enum_t); |
899 | 2.15M | } |
900 | | |
901 | | /* |
902 | | * Return true if we only need the width from the rasterizer |
903 | | * and can short-circuit the full rendering of the character, |
904 | | * false if we need the actual character bits. This is only safe if |
905 | | * we know the character is well-behaved, i.e., is not defined by an |
906 | | * arbitrary PostScript procedure. |
907 | | */ |
908 | | bool |
909 | | zchar_show_width_only(const gs_text_enum_t * penum) |
910 | 1.15M | { |
911 | 1.15M | if (!gs_text_is_width_only(penum)) |
912 | 1.03M | return false; |
913 | 118k | switch (penum->orig_font->FontType) { |
914 | 2.04k | case ft_encrypted: |
915 | 2.04k | case ft_encrypted2: |
916 | 2.04k | case ft_CID_encrypted: |
917 | 2.04k | case ft_CID_TrueType: |
918 | 2.04k | case ft_CID_bitmap: |
919 | 2.04k | case ft_TrueType: |
920 | 2.04k | return true; |
921 | 116k | default: |
922 | 116k | return false; |
923 | 118k | } |
924 | 118k | } |
925 | | |
926 | | /* Shortcut the BuildChar or BuildGlyph procedure at the point */ |
927 | | /* of the setcharwidth or the setcachedevice[2] if we are in */ |
928 | | /* a stringwidth or cshow, or if we are only collecting the scalable */ |
929 | | /* width for an xfont character. */ |
930 | | static int |
931 | | op_show_return_width(i_ctx_t *i_ctx_p, uint npop, double *pwidth) |
932 | 1.02k | { |
933 | 1.02k | uint index = op_show_find_index(i_ctx_p); |
934 | 1.02k | es_ptr ep = (es_ptr) ref_stack_index(&e_stack, index - (snumpush - 1)); |
935 | 1.02k | int code = gs_text_setcharwidth(esenum(ep), pwidth); |
936 | 1.02k | uint ocount, dsaved, dcount; |
937 | | |
938 | 1.02k | if (code < 0) |
939 | 0 | return code; |
940 | | /* Restore the operand and dictionary stacks. */ |
941 | 1.02k | ocount = ref_stack_count(&o_stack) - (uint) esodepth(ep).value.intval; |
942 | 1.02k | if (ocount < npop) |
943 | 0 | return_error(gs_error_stackunderflow); |
944 | 1.02k | dsaved = (uint) esddepth(ep).value.intval; |
945 | 1.02k | dcount = ref_stack_count(&d_stack); |
946 | 1.02k | if (dcount < dsaved) |
947 | 0 | return_error(gs_error_dictstackunderflow); |
948 | 1.02k | while (dcount > dsaved) { |
949 | 0 | code = zend(i_ctx_p); |
950 | 0 | if (code < 0) |
951 | 0 | return code; |
952 | 0 | dcount--; |
953 | 0 | } |
954 | 1.02k | ref_stack_pop(&o_stack, ocount); |
955 | | /* We don't want to pop the mark or the continuation */ |
956 | | /* procedure (op_show_continue or cshow_continue). */ |
957 | 1.02k | pop_estack(i_ctx_p, index - snumpush); |
958 | 1.02k | return o_pop_estack; |
959 | 1.02k | } |
960 | | |
961 | | /* |
962 | | * Restore state after finishing, or unwinding from an error within, a show |
963 | | * operation. Note that we assume op == osp, and may reset osp. |
964 | | */ |
965 | | static int |
966 | | op_show_restore(i_ctx_t *i_ctx_p, bool for_error) |
967 | 30.1k | { |
968 | 30.1k | register es_ptr ep = esp + snumpush; |
969 | 30.1k | gs_text_enum_t *penum = esenum(ep); |
970 | 30.1k | int saved_level = esgslevel(ep).value.intval; |
971 | 30.1k | int code = 0; |
972 | | |
973 | 30.1k | if (for_error) { |
974 | | #if 0 /* Disabled for CPSI compatibility for 13-12-4. |
975 | | CPSI doesn't remove cshow, kshow proc operands. */ |
976 | | uint saved_count = esodepth(ep).value.intval; |
977 | | uint count = ref_stack_count(&o_stack); |
978 | | |
979 | | if (count > saved_count) /* if <, we're in trouble */ |
980 | | ref_stack_pop(&o_stack, count - saved_count); |
981 | | #endif |
982 | 27 | if (ep[1].value.opproc == op_show_continue && penum->enum_client_data != NULL) { |
983 | | /* Replace the continuation operaton on estack with the right operator : */ |
984 | 26 | op_proc_t proc; |
985 | | |
986 | 26 | *(void **)&proc = penum->enum_client_data; |
987 | 26 | make_op_estack(ep + 1, proc); |
988 | 26 | } |
989 | 27 | } |
990 | 30.1k | if (SHOW_IS_STRINGWIDTH(penum) && igs->text_rendering_mode != 3) { |
991 | | /* stringwidth does an extra gsave */ |
992 | 408 | --saved_level; |
993 | 408 | } |
994 | 30.1k | if (penum->text.operation & TEXT_REPLACE_WIDTHS) { |
995 | 0 | gs_free_const_object(penum->memory, penum->text.y_widths, "y_widths"); |
996 | 0 | if (penum->text.x_widths != penum->text.y_widths) |
997 | 0 | gs_free_const_object(penum->memory, penum->text.x_widths, "x_widths"); |
998 | 0 | } |
999 | | /* |
1000 | | * We might have been inside a cshow, in which case currentfont was |
1001 | | * reset temporarily, as though we were inside a BuildChar/ BuildGlyph |
1002 | | * procedure. To handle this case, set currentfont back to its original |
1003 | | * state. NOTE: this code previously used fstack[0] in the enumerator |
1004 | | * for the root font: we aren't sure that this change is correct. |
1005 | | */ |
1006 | 30.1k | gs_set_currentfont(igs, penum->orig_font); |
1007 | 30.2k | while (igs->level > saved_level && code >= 0) { |
1008 | 41 | if (igs->saved == 0 || igs->saved->saved == 0) { |
1009 | | /* |
1010 | | * Bad news: we got an error inside a save inside a BuildChar or |
1011 | | * BuildGlyph. Don't attempt to recover. |
1012 | | */ |
1013 | 0 | code = gs_note_error(gs_error_Fatal); |
1014 | 0 | } else |
1015 | 41 | code = gs_grestore(igs); |
1016 | 41 | } |
1017 | | |
1018 | | /* Possibly restore color. This occurs if we are going to a high |
1019 | | level device or if we were only doing a fill. |
1020 | | If we are going to be doing the stroke |
1021 | | operation through zstroke then we do not want to restore yet. */ |
1022 | 30.1k | if (penum->k_text_release) { |
1023 | 0 | gsicc_restore_blacktextvec(igs, true); |
1024 | 0 | } |
1025 | | |
1026 | 30.1k | gs_text_release(NULL, penum, "op_show_restore"); |
1027 | 30.1k | return code; |
1028 | 30.1k | } |
1029 | | /* Clean up after an error. */ |
1030 | | static int |
1031 | | op_show_cleanup(i_ctx_t *i_ctx_p) |
1032 | 26 | { |
1033 | 26 | return op_show_restore(i_ctx_p, true); |
1034 | 26 | } |
1035 | | /* Clean up after termination of a show operation. */ |
1036 | | int |
1037 | | op_show_free(i_ctx_t *i_ctx_p, int code) |
1038 | 30.1k | { |
1039 | 30.1k | int rcode; |
1040 | | |
1041 | 30.1k | esp -= snumpush; |
1042 | 30.1k | rcode = op_show_restore(i_ctx_p, code < 0); |
1043 | 30.1k | return (rcode < 0 ? rcode : code); |
1044 | 30.1k | } |
1045 | | |
1046 | | /* Get a FontBBox parameter from a font dictionary. */ |
1047 | | int |
1048 | | font_bbox_param(const gs_memory_t *mem, const ref * pfdict, double bbox[4]) |
1049 | 177k | { |
1050 | 177k | ref *pbbox; |
1051 | | |
1052 | | /* |
1053 | | * Pre-clear the bbox in case it's invalid. The Red Books say that |
1054 | | * FontBBox is required, but old Adobe interpreters don't require |
1055 | | * it, and a few user-written fonts don't supply it, or supply one |
1056 | | * of the wrong size (!); also, PageMaker 5.0 (an Adobe product!) |
1057 | | * sometimes emits an absurd bbox for Type 1 fonts converted from |
1058 | | * TrueType. |
1059 | | */ |
1060 | 177k | bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0.0; |
1061 | 177k | if (dict_find_string(pfdict, "FontBBox", &pbbox) > 0) { |
1062 | 177k | if (!r_is_array(pbbox)) |
1063 | 0 | return_error(gs_error_typecheck); |
1064 | 177k | if (r_size(pbbox) == 4) { |
1065 | 177k | const ref_packed *pbe = pbbox->value.packed; |
1066 | 177k | ref rbe[4]; |
1067 | 177k | int i; |
1068 | 177k | int code; |
1069 | 177k | float dx, dy, ratio; |
1070 | 177k | const float max_ratio = 12; /* From the bug 687594. */ |
1071 | | |
1072 | 887k | for (i = 0; i < 4; i++) { |
1073 | 710k | packed_get(mem, pbe, rbe + i); |
1074 | 710k | pbe = packed_next(pbe); |
1075 | 710k | } |
1076 | 177k | if ((code = num_params(rbe + 3, 4, bbox)) < 0) |
1077 | 0 | return code; |
1078 | | /* Require "reasonable" values. */ |
1079 | 177k | dx = bbox[2] - bbox[0]; |
1080 | 177k | dy = bbox[3] - bbox[1]; |
1081 | 177k | if (dx <= 0 || dy <= 0 || |
1082 | 177k | (ratio = dy / dx) < 1 / max_ratio || ratio > max_ratio |
1083 | 177k | ) |
1084 | 89.3k | bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0.0; |
1085 | 177k | } |
1086 | 177k | } else if (gs_currentcpsimode(mem)) { |
1087 | 0 | return_error(gs_error_invalidfont); /* CPSI requires FontBBox */ |
1088 | 0 | } |
1089 | 177k | return 0; |
1090 | 177k | } |