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