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