1 /* Copyright (C) 1989, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /*$Id: zchar.c,v 1.17 2005/06/19 21:10:58 igor Exp $ */
18 /* Character operators */
19 #include "ghost.h"
20 #include "oper.h"
21 #include "gsstruct.h"
22 #include "gstext.h"
23 #include "gxarith.h"
24 #include "gxfixed.h"
25 #include "gxmatrix.h" /* for ifont.h */
26 #include "gxdevice.h" /* for gxfont.h */
27 #include "gxfont.h"
28 #include "gxfont42.h"
29 #include "gxfont0.h"
30 #include "gzstate.h"
31 #include "dstack.h" /* for stack depth */
32 #include "estack.h"
33 #include "ialloc.h"
34 #include "ichar.h"
35 #include "ichar1.h"
36 #include "idict.h"
37 #include "ifont.h"
38 #include "igstate.h"
39 #include "ilevel.h"
40 #include "iname.h"
41 #include "ipacked.h"
42 #include "store.h"
43 #include "zchar42.h"
44
45 /* Forward references */
46 private bool map_glyph_to_char(const gs_memory_t *mem,
47 const ref *, const ref *, ref *);
48 private int finish_show(i_ctx_t *);
49 private int op_show_cleanup(i_ctx_t *);
50 private int op_show_return_width(i_ctx_t *, uint, double *);
51
52 /* <string> show - */
53 private int
zshow(i_ctx_t * i_ctx_p)54 zshow(i_ctx_t *i_ctx_p)
55 {
56 os_ptr op = osp;
57 gs_text_enum_t *penum;
58 int code = op_show_setup(i_ctx_p, op);
59
60 if (code != 0 ||
61 (code = gs_show_begin(igs, op->value.bytes, r_size(op), imemory, &penum)) < 0)
62 return code;
63 if ((code = op_show_finish_setup(i_ctx_p, penum, 1, finish_show)) < 0) {
64 ifree_object(penum, "op_show_enum_setup");
65 return code;
66 }
67 return op_show_continue_pop(i_ctx_p, 1);
68 }
69
70 /* <ax> <ay> <string> ashow - */
71 private int
zashow(i_ctx_t * i_ctx_p)72 zashow(i_ctx_t *i_ctx_p)
73 {
74 os_ptr op = osp;
75 gs_text_enum_t *penum;
76 double axy[2];
77 int code = num_params(op - 1, 2, axy);
78
79 if (code < 0 ||
80 (code = op_show_setup(i_ctx_p, op)) != 0 ||
81 (code = gs_ashow_begin(igs, axy[0], axy[1], op->value.bytes, r_size(op), imemory, &penum)) < 0)
82 return code;
83 if ((code = op_show_finish_setup(i_ctx_p, penum, 3, finish_show)) < 0) {
84 ifree_object(penum, "op_show_enum_setup");
85 return code;
86 }
87 return op_show_continue_pop(i_ctx_p, 3);
88 }
89
90 /* <cx> <cy> <char> <string> widthshow - */
91 private int
zwidthshow(i_ctx_t * i_ctx_p)92 zwidthshow(i_ctx_t *i_ctx_p)
93 {
94 os_ptr op = osp;
95 gs_text_enum_t *penum;
96 double cxy[2];
97 int code;
98
99 check_type(op[-1], t_integer);
100 if ((gs_char) (op[-1].value.intval) != op[-1].value.intval)
101 return_error(e_rangecheck);
102 if ((code = num_params(op - 2, 2, cxy)) < 0 ||
103 (code = op_show_setup(i_ctx_p, op)) != 0 ||
104 (code = gs_widthshow_begin(igs, cxy[0], cxy[1],
105 (gs_char) op[-1].value.intval,
106 op->value.bytes, r_size(op),
107 imemory, &penum)) < 0)
108 return code;
109 if ((code = op_show_finish_setup(i_ctx_p, penum, 4, finish_show)) < 0) {
110 ifree_object(penum, "op_show_enum_setup");
111 return code;
112 }
113 return op_show_continue_pop(i_ctx_p, 4);
114 }
115
116 /* <cx> <cy> <char> <ax> <ay> <string> awidthshow - */
117 private int
zawidthshow(i_ctx_t * i_ctx_p)118 zawidthshow(i_ctx_t *i_ctx_p)
119 {
120 os_ptr op = osp;
121 gs_text_enum_t *penum;
122 double cxy[2], axy[2];
123 int code;
124
125 check_type(op[-3], t_integer);
126 if ((gs_char) (op[-3].value.intval) != op[-3].value.intval)
127 return_error(e_rangecheck);
128 if ((code = num_params(op - 4, 2, cxy)) < 0 ||
129 (code = num_params(op - 1, 2, axy)) < 0 ||
130 (code = op_show_setup(i_ctx_p, op)) != 0 ||
131 (code = gs_awidthshow_begin(igs, cxy[0], cxy[1],
132 (gs_char) op[-3].value.intval,
133 axy[0], axy[1],
134 op->value.bytes, r_size(op),
135 imemory, &penum)) < 0)
136 return code;
137 if ((code = op_show_finish_setup(i_ctx_p, penum, 6, finish_show)) < 0) {
138 ifree_object(penum, "op_show_enum_setup");
139 return code;
140 }
141 return op_show_continue_pop(i_ctx_p, 6);
142 }
143
144 /* <proc> <string> kshow - */
145 private int
zkshow(i_ctx_t * i_ctx_p)146 zkshow(i_ctx_t *i_ctx_p)
147 {
148 os_ptr op = osp;
149 gs_text_enum_t *penum;
150 int code;
151
152 check_proc(op[-1]);
153 if ((code = op_show_setup(i_ctx_p, op)) != 0 ||
154 (code = gs_kshow_begin(igs, op->value.bytes, r_size(op),
155 imemory, &penum)) < 0)
156 return code;
157 if ((code = op_show_finish_setup(i_ctx_p, penum, 2, finish_show)) < 0) {
158 ifree_object(penum, "op_show_enum_setup");
159 return code;
160 }
161 sslot = op[-1]; /* save kerning proc */
162 return op_show_continue_pop(i_ctx_p, 2);
163 }
164
165 /* Common finish procedure for all show operations. */
166 /* Doesn't have to do anything. */
167 private int
finish_show(i_ctx_t * i_ctx_p)168 finish_show(i_ctx_t *i_ctx_p)
169 {
170 return 0;
171 }
172
173 /* <string> stringwidth <wx> <wy> */
174 private int
zstringwidth(i_ctx_t * i_ctx_p)175 zstringwidth(i_ctx_t *i_ctx_p)
176 {
177 os_ptr op = osp;
178 gs_text_enum_t *penum;
179 int code = op_show_setup(i_ctx_p, op);
180
181 if (code != 0 ||
182 (code = gs_stringwidth_begin(igs, op->value.bytes, r_size(op),
183 imemory, &penum)) < 0)
184 return code;
185 if ((code = op_show_finish_setup(i_ctx_p, penum, 1, finish_stringwidth)) < 0) {
186 ifree_object(penum, "op_show_enum_setup");
187 return code;
188 }
189 return op_show_continue_pop(i_ctx_p, 1);
190 }
191 /* Finishing procedure for stringwidth. */
192 /* Pushes the accumulated width. */
193 /* This is exported for .glyphwidth (in zcharx.c). */
194 int
finish_stringwidth(i_ctx_t * i_ctx_p)195 finish_stringwidth(i_ctx_t *i_ctx_p)
196 {
197 os_ptr op = osp;
198 gs_point width;
199
200 gs_text_total_width(senum, &width);
201 push(2);
202 make_real(op - 1, width.x);
203 make_real(op, width.y);
204 return 0;
205 }
206
207 /* Common code for charpath and .charboxpath. */
208 private int
zchar_path(i_ctx_t * i_ctx_p,int (* begin)(gs_state *,const byte *,uint,bool,gs_memory_t *,gs_text_enum_t **))209 zchar_path(i_ctx_t *i_ctx_p,
210 int (*begin)(gs_state *, const byte *, uint,
211 bool, gs_memory_t *, gs_text_enum_t **))
212 {
213 os_ptr op = osp;
214 gs_text_enum_t *penum;
215 int code;
216
217 check_type(*op, t_boolean);
218 code = op_show_setup(i_ctx_p, op - 1);
219 if (code != 0 ||
220 (code = begin(igs, op[-1].value.bytes, r_size(op - 1),
221 op->value.boolval, imemory, &penum)) < 0)
222 return code;
223 if ((code = op_show_finish_setup(i_ctx_p, penum, 2, finish_show)) < 0) {
224 ifree_object(penum, "op_show_enum_setup");
225 return code;
226 }
227 return op_show_continue_pop(i_ctx_p, 2);
228 }
229 /* <string> <outline_bool> charpath - */
230 private int
zcharpath(i_ctx_t * i_ctx_p)231 zcharpath(i_ctx_t *i_ctx_p)
232 {
233 return zchar_path(i_ctx_p, gs_charpath_begin);
234 }
235 /* <string> <box_bool> .charboxpath - */
236 private int
zcharboxpath(i_ctx_t * i_ctx_p)237 zcharboxpath(i_ctx_t *i_ctx_p)
238 {
239 return zchar_path(i_ctx_p, gs_charboxpath_begin);
240 }
241
242 /* <wx> <wy> <llx> <lly> <urx> <ury> setcachedevice - */
243 int
zsetcachedevice(i_ctx_t * i_ctx_p)244 zsetcachedevice(i_ctx_t *i_ctx_p)
245 {
246 os_ptr op = osp;
247 double wbox[6];
248 gs_text_enum_t *penum = op_show_find(i_ctx_p);
249 int code = num_params(op, 6, wbox);
250
251 if (penum == 0)
252 return_error(e_undefined);
253 if (code < 0)
254 return code;
255 if (zchar_show_width_only(penum))
256 return op_show_return_width(i_ctx_p, 6, &wbox[0]);
257 code = gs_text_setcachedevice(penum, wbox);
258 if (code < 0)
259 return code;
260 pop(6);
261 if (code == 1)
262 clear_pagedevice(istate);
263 return 0;
264 }
265
266 /* <w0x> <w0y> <llx> <lly> <urx> <ury> <w1x> <w1y> <vx> <vy> setcachedevice2 - */
267 int
zsetcachedevice2(i_ctx_t * i_ctx_p)268 zsetcachedevice2(i_ctx_t *i_ctx_p)
269 {
270 os_ptr op = osp;
271 double wbox[10];
272 gs_text_enum_t *penum = op_show_find(i_ctx_p);
273 int code = num_params(op, 10, wbox);
274
275 if (penum == 0)
276 return_error(e_undefined);
277 if (code < 0)
278 return code;
279 if (zchar_show_width_only(penum))
280 return op_show_return_width(i_ctx_p, 10,
281 (gs_rootfont(igs)->WMode ?
282 &wbox[6] : &wbox[0]));
283 code = gs_text_setcachedevice2(penum, wbox);
284 if (code < 0)
285 return code;
286 pop(10);
287 if (code == 1)
288 clear_pagedevice(istate);
289 return 0;
290 }
291
292 /* <wx> <wy> setcharwidth - */
293 private int
zsetcharwidth(i_ctx_t * i_ctx_p)294 zsetcharwidth(i_ctx_t *i_ctx_p)
295 {
296 os_ptr op = osp;
297 double width[2];
298 gs_text_enum_t *penum = op_show_find(i_ctx_p);
299 int code = num_params(op, 2, width);
300
301 if (penum == 0)
302 return_error(e_undefined);
303 if (code < 0)
304 return code;
305 if (zchar_show_width_only(penum))
306 return op_show_return_width(i_ctx_p, 2, &width[0]);
307 code = gs_text_setcharwidth(penum, width);
308 if (code < 0)
309 return code;
310 pop(2);
311 return 0;
312 }
313
314 /* <dict> .fontbbox <llx> <lly> <urx> <ury> -true- */
315 /* <dict> .fontbbox -false- */
316 private int
zfontbbox(i_ctx_t * i_ctx_p)317 zfontbbox(i_ctx_t *i_ctx_p)
318 {
319 os_ptr op = osp;
320 double bbox[4];
321 int code;
322
323 check_type(*op, t_dictionary);
324 check_dict_read(*op);
325 code = font_bbox_param(imemory, op, bbox);
326 if (code < 0)
327 return code;
328 if (bbox[0] < bbox[2] && bbox[1] < bbox[3]) {
329 push(4);
330 make_reals(op - 4, bbox, 4);
331 make_true(op);
332 } else { /* No bbox, or an empty one. */
333 make_false(op);
334 }
335 return 0;
336 }
337
338 /* ------ Initialization procedure ------ */
339
340 const op_def zchar_op_defs[] =
341 {
342 {"3ashow", zashow},
343 {"6awidthshow", zawidthshow},
344 {"2charpath", zcharpath},
345 {"2.charboxpath", zcharboxpath},
346 {"2kshow", zkshow},
347 {"6setcachedevice", zsetcachedevice},
348 {":setcachedevice2", zsetcachedevice2},
349 {"2setcharwidth", zsetcharwidth},
350 {"1show", zshow},
351 {"1stringwidth", zstringwidth},
352 {"4widthshow", zwidthshow},
353 /* Extensions */
354 {"1.fontbbox", zfontbbox},
355 /* Internal operators */
356 {"0%finish_show", finish_show},
357 {"0%finish_stringwidth", finish_stringwidth},
358 {"0%op_show_continue", op_show_continue},
359 op_def_end(0)
360 };
361
362 /* ------ Subroutines ------ */
363
364 /* Most of these are exported for zchar2.c. */
365
366 /* Convert a glyph to a ref. */
367 void
glyph_ref(const gs_memory_t * mem,gs_glyph glyph,ref * gref)368 glyph_ref(const gs_memory_t *mem, gs_glyph glyph, ref * gref)
369 {
370 if (glyph < gs_min_cid_glyph)
371 name_index_ref(mem, glyph, gref);
372 else
373 make_int(gref, glyph - gs_min_cid_glyph);
374 }
375
376 /* Prepare to set up for a text operator. */
377 /* Don't change any state yet. */
378 int
op_show_setup(i_ctx_t * i_ctx_p,os_ptr op)379 op_show_setup(i_ctx_t *i_ctx_p, os_ptr op)
380 {
381 check_read_type(*op, t_string);
382 return op_show_enum_setup(i_ctx_p);
383 }
384 int
op_show_enum_setup(i_ctx_t * i_ctx_p)385 op_show_enum_setup(i_ctx_t *i_ctx_p)
386 {
387 check_estack(snumpush + 2);
388 return 0;
389 }
390
391 /* Finish setting up a text operator. */
392 int
op_show_finish_setup(i_ctx_t * i_ctx_p,gs_text_enum_t * penum,int npop,op_proc_t endproc)393 op_show_finish_setup(i_ctx_t *i_ctx_p, gs_text_enum_t * penum, int npop,
394 op_proc_t endproc /* end procedure */ )
395 {
396 gs_text_enum_t *osenum = op_show_find(i_ctx_p);
397 es_ptr ep = esp + snumpush;
398 gs_glyph glyph;
399
400 /*
401 * If we are in the procedure of a cshow for a CID font and this is
402 * a show operator, do something special, per the Red Book.
403 */
404 if (osenum &&
405 SHOW_IS_ALL_OF(osenum,
406 TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_INTERVENE) &&
407 SHOW_IS_ALL_OF(penum, TEXT_FROM_STRING | TEXT_RETURN_WIDTH) &&
408 (glyph = gs_text_current_glyph(osenum)) != gs_no_glyph &&
409 glyph >= gs_min_cid_glyph &&
410
411 /* According to PLRM, we don't need to raise a rangecheck error,
412 if currentfont is changed in the proc of the operator 'cshow'. */
413 gs_default_same_font (gs_text_current_font(osenum),
414 gs_text_current_font(penum), true)
415 ) {
416 gs_text_params_t text;
417
418 if (!(penum->text.size == 1 &&
419 penum->text.data.bytes[0] ==
420 (gs_text_current_char(osenum) & 0xff))
421 )
422 return_error(e_rangecheck);
423 text = penum->text;
424 text.operation =
425 (text.operation &
426 ~(TEXT_FROM_STRING | TEXT_FROM_BYTES | TEXT_FROM_CHARS |
427 TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_CHAR)) |
428 TEXT_FROM_SINGLE_GLYPH;
429 text.data.d_glyph = glyph;
430 text.size = 1;
431 gs_text_restart(penum, &text);
432 }
433 if (osenum && osenum->current_font->FontType == ft_user_defined &&
434 osenum->fstack.depth >= 1 &&
435 osenum->fstack.items[0].font->FontType == ft_composite &&
436 ((const gs_font_type0 *)osenum->fstack.items[0].font)->data.FMapType == fmap_CMap) {
437 /* A special behavior defined in PLRM3 section 5.11 page 389. */
438 penum->outer_CID = osenum->returned.current_glyph;
439 }
440 make_mark_estack(ep - (snumpush - 1), es_show, op_show_cleanup);
441 if (endproc == NULL)
442 endproc = finish_show;
443 make_null(&esslot(ep));
444 make_int(&esodepth(ep), ref_stack_count_inline(&o_stack) - npop); /* Save stack depth for */
445 make_int(&esddepth(ep), ref_stack_count_inline(&d_stack)); /* correct interrupt processing */
446 make_int(&esgslevel(ep), igs->level);
447 make_null(&essfont(ep));
448 make_null(&esrfont(ep));
449 make_op_estack(&eseproc(ep), endproc);
450 make_istruct(ep, 0, penum);
451 esp = ep;
452 return 0;
453 }
454
455 /* Continuation operator for character rendering. */
456 int
op_show_continue(i_ctx_t * i_ctx_p)457 op_show_continue(i_ctx_t *i_ctx_p)
458 {
459 int code = gs_text_update_dev_color(igs, senum);
460
461 if (code >= 0)
462 code = op_show_continue_dispatch(i_ctx_p, 0, gs_text_process(senum));
463 return code;
464 }
465 int
op_show_continue_pop(i_ctx_t * i_ctx_p,int npop)466 op_show_continue_pop(i_ctx_t *i_ctx_p, int npop)
467 {
468 return op_show_continue_dispatch(i_ctx_p, npop, gs_text_process(senum));
469 }
470 /*
471 * Note that op_show_continue_dispatch sets osp = op explicitly iff the
472 * dispatch succeeds. This is so that the show operators don't pop anything
473 * from the o-stack if they don't succeed. Note also that if it returns an
474 * error, it has freed the enumerator.
475 */
476 int
op_show_continue_dispatch(i_ctx_t * i_ctx_p,int npop,int code)477 op_show_continue_dispatch(i_ctx_t *i_ctx_p, int npop, int code)
478 {
479 os_ptr op = osp - npop;
480 gs_text_enum_t *penum = senum;
481
482 switch (code) {
483 case 0: { /* all done */
484 os_ptr save_osp = osp;
485
486 osp = op;
487 code = (*real_opproc(&seproc)) (i_ctx_p);
488 op_show_free(i_ctx_p, code);
489 if (code < 0) {
490 osp = save_osp;
491 return code;
492 }
493 return o_pop_estack;
494 }
495 case TEXT_PROCESS_INTERVENE: {
496 ref *pslot = &sslot; /* only used for kshow */
497
498 push(2);
499 make_int(op - 1, gs_text_current_char(penum)); /* previous char */
500 make_int(op, gs_text_next_char(penum));
501 push_op_estack(op_show_continue); /* continue after kerning */
502 *++esp = *pslot; /* kerning procedure */
503 return o_push_estack;
504 }
505 case TEXT_PROCESS_RENDER: {
506 gs_font *pfont = gs_currentfont(igs);
507 font_data *pfdata = pfont_data(pfont);
508 gs_char chr = gs_text_current_char(penum);
509 gs_glyph glyph = gs_text_current_glyph(penum);
510
511 push(2);
512 op[-1] = pfdata->dict; /* push the font */
513 /*
514 * For Type 1 and Type 4 fonts, prefer BuildChar to BuildGlyph
515 * if there is no glyph, or if there is both a character and a
516 * glyph and the glyph is the one that corresponds to the
517 * character in the Encoding, so that PostScript procedures
518 * appearing in the CharStrings dictionary will receive the
519 * character code rather than the character name; for Type 3
520 * fonts, prefer BuildGlyph to BuildChar. For other font types
521 * (such as CID fonts), only BuildGlyph will be present.
522 */
523 if (pfont->FontType == ft_user_defined) {
524 /* Type 3 font, prefer BuildGlyph. */
525 if (level2_enabled &&
526 !r_has_type(&pfdata->BuildGlyph, t_null) &&
527 glyph != gs_no_glyph
528 ) {
529 glyph_ref(imemory, glyph, op);
530 esp[2] = pfdata->BuildGlyph;
531 } else if (r_has_type(&pfdata->BuildChar, t_null))
532 goto err;
533 else if (chr == gs_no_char) {
534 /* glyphshow, reverse map the character */
535 /* through the Encoding */
536 ref gref;
537 const ref *pencoding = &pfdata->Encoding;
538
539 glyph_ref(imemory, glyph, &gref);
540 if (!map_glyph_to_char(imemory, &gref, pencoding,
541 (ref *) op)
542 ) { /* Not found, try .notdef */
543 name_enter_string(imemory, ".notdef", &gref);
544 if (!map_glyph_to_char(imemory, &gref,
545 pencoding,
546 (ref *) op)
547 )
548 goto err;
549 }
550 esp[2] = pfdata->BuildChar;
551 } else {
552 make_int(op, chr & 0xff);
553 esp[2] = pfdata->BuildChar;
554 }
555 } else {
556 /*
557 * For a Type 1 or Type 4 font, prefer BuildChar or
558 * BuildGlyph as described above: we know that both
559 * BuildChar and BuildGlyph are present. For other font
560 * types, only BuildGlyph is available.
561 */
562 ref eref, gref;
563
564 if (chr != gs_no_char &&
565 !r_has_type(&pfdata->BuildChar, t_null) &&
566 (glyph == gs_no_glyph ||
567 (array_get(imemory, &pfdata->Encoding, (long)(chr & 0xff), &eref) >= 0 &&
568 (glyph_ref(imemory, glyph, &gref), obj_eq(imemory, &gref, &eref))))
569 ) {
570 make_int(op, chr & 0xff);
571 esp[2] = pfdata->BuildChar;
572 } else {
573 /* We might not have a glyph: substitute 0. **HACK** */
574 if (glyph == gs_no_glyph)
575 make_int(op, 0);
576 else
577 glyph_ref(imemory, glyph, op);
578 esp[2] = pfdata->BuildGlyph;
579 }
580 }
581 /* Save the stack depths in case we bail out. */
582 sodepth.value.intval = ref_stack_count(&o_stack) - 2;
583 sddepth.value.intval = ref_stack_count(&d_stack);
584 push_op_estack(op_show_continue);
585 ++esp; /* skip BuildChar or BuildGlyph proc */
586 return o_push_estack;
587 }
588 case TEXT_PROCESS_CDEVPROC:
589 { gs_font *pfont = penum->current_font;
590 ref cnref;
591 op_proc_t cont = op_show_continue, exec_cont = 0;
592 gs_glyph glyph = penum->returned.current_glyph;
593 int code;
594
595 pop(npop);
596 op = osp;
597 glyph_ref(imemory, glyph, &cnref);
598 if (pfont->FontType == ft_CID_TrueType) {
599 gs_font_type42 *pfont42 = (gs_font_type42 *)pfont;
600 uint glyph_index = pfont42->data.get_glyph_index(pfont42, glyph);
601
602 code = zchar42_set_cache(i_ctx_p, (gs_font_base *)pfont42,
603 &cnref, glyph_index, cont, &exec_cont, false);
604 } else if (pfont->FontType == ft_CID_encrypted)
605 code = z1_set_cache(i_ctx_p, (gs_font_base *)pfont,
606 &cnref, glyph, cont, &exec_cont);
607 else
608 return_error(e_unregistered); /* Unimplemented. */
609 if (exec_cont != 0)
610 return_error(e_unregistered); /* Must not happen. */
611 return code;
612 }
613 default: /* error */
614 err:
615 if (code >= 0)
616 code = gs_note_error(e_invalidfont);
617 return op_show_free(i_ctx_p, code);
618 }
619 }
620 /* Reverse-map a glyph name to a character code for glyphshow. */
621 private bool
map_glyph_to_char(const gs_memory_t * mem,const ref * pgref,const ref * pencoding,ref * pch)622 map_glyph_to_char(const gs_memory_t *mem, const ref * pgref, const ref * pencoding, ref * pch)
623 {
624 uint esize = r_size(pencoding);
625 uint ch;
626 ref eref;
627
628 for (ch = 0; ch < esize; ch++) {
629 array_get(mem, pencoding, (long)ch, &eref);
630 if (obj_eq(mem, pgref, &eref)) {
631 make_int(pch, ch);
632 return true;
633 }
634 }
635 return false;
636 }
637
638 /* Find the index of the e-stack mark for the current show enumerator. */
639 /* Return 0 if we can't find the mark. */
640 private uint
op_show_find_index(i_ctx_t * i_ctx_p)641 op_show_find_index(i_ctx_t *i_ctx_p)
642 {
643 ref_stack_enum_t rsenum;
644 uint count = 0;
645
646 ref_stack_enum_begin(&rsenum, &e_stack);
647 do {
648 es_ptr ep = rsenum.ptr;
649 uint size = rsenum.size;
650
651 for (ep += size - 1; size != 0; size--, ep--, count++)
652 if (r_is_estack_mark(ep) && estack_mark_index(ep) == es_show)
653 return count;
654 } while (ref_stack_enum_next(&rsenum));
655 return 0; /* no mark */
656 }
657
658 /* Find the current show enumerator on the e-stack. */
659 gs_text_enum_t *
op_show_find(i_ctx_t * i_ctx_p)660 op_show_find(i_ctx_t *i_ctx_p)
661 {
662 uint index = op_show_find_index(i_ctx_p);
663
664 if (index == 0)
665 return 0; /* no mark */
666 return r_ptr(ref_stack_index(&e_stack, index - (snumpush - 1)),
667 gs_text_enum_t);
668 }
669
670 /*
671 * Return true if we only need the width from the rasterizer
672 * and can short-circuit the full rendering of the character,
673 * false if we need the actual character bits. This is only safe if
674 * we know the character is well-behaved, i.e., is not defined by an
675 * arbitrary PostScript procedure.
676 */
677 bool
zchar_show_width_only(const gs_text_enum_t * penum)678 zchar_show_width_only(const gs_text_enum_t * penum)
679 {
680 if (!gs_text_is_width_only(penum))
681 return false;
682 switch (penum->orig_font->FontType) {
683 case ft_encrypted:
684 case ft_encrypted2:
685 case ft_CID_encrypted:
686 case ft_CID_TrueType:
687 case ft_CID_bitmap:
688 case ft_TrueType:
689 return true;
690 default:
691 return false;
692 }
693 }
694
695 /* Shortcut the BuildChar or BuildGlyph procedure at the point */
696 /* of the setcharwidth or the setcachedevice[2] if we are in */
697 /* a stringwidth or cshow, or if we are only collecting the scalable */
698 /* width for an xfont character. */
699 private int
op_show_return_width(i_ctx_t * i_ctx_p,uint npop,double * pwidth)700 op_show_return_width(i_ctx_t *i_ctx_p, uint npop, double *pwidth)
701 {
702 uint index = op_show_find_index(i_ctx_p);
703 es_ptr ep = (es_ptr) ref_stack_index(&e_stack, index - (snumpush - 1));
704 int code = gs_text_setcharwidth(esenum(ep), pwidth);
705 uint ocount, dsaved, dcount;
706
707 if (code < 0)
708 return code;
709 /* Restore the operand and dictionary stacks. */
710 ocount = ref_stack_count(&o_stack) - (uint) esodepth(ep).value.intval;
711 if (ocount < npop)
712 return_error(e_stackunderflow);
713 dsaved = (uint) esddepth(ep).value.intval;
714 dcount = ref_stack_count(&d_stack);
715 if (dcount < dsaved)
716 return_error(e_dictstackunderflow);
717 while (dcount > dsaved) {
718 code = zend(i_ctx_p);
719 if (code < 0)
720 return code;
721 dcount--;
722 }
723 ref_stack_pop(&o_stack, ocount);
724 /* We don't want to pop the mark or the continuation */
725 /* procedure (op_show_continue or cshow_continue). */
726 pop_estack(i_ctx_p, index - snumpush);
727 return o_pop_estack;
728 }
729
730 /*
731 * Restore state after finishing, or unwinding from an error within, a show
732 * operation. Note that we assume op == osp, and may reset osp.
733 */
734 private int
op_show_restore(i_ctx_t * i_ctx_p,bool for_error)735 op_show_restore(i_ctx_t *i_ctx_p, bool for_error)
736 {
737 register es_ptr ep = esp + snumpush;
738 gs_text_enum_t *penum = esenum(ep);
739 int saved_level = esgslevel(ep).value.intval;
740 int code = 0;
741
742 if (for_error) {
743 uint saved_count = esodepth(ep).value.intval;
744 uint count = ref_stack_count(&o_stack);
745
746 if (count > saved_count) /* if <, we're in trouble */
747 ref_stack_pop(&o_stack, count - saved_count);
748 }
749 if (SHOW_IS_STRINGWIDTH(penum) && igs->text_rendering_mode != 3) {
750 /* stringwidth does an extra gsave */
751 --saved_level;
752 }
753 if (penum->text.operation & TEXT_REPLACE_WIDTHS) {
754 gs_free_const_object(penum->memory, penum->text.y_widths, "y_widths");
755 if (penum->text.x_widths != penum->text.y_widths)
756 gs_free_const_object(penum->memory, penum->text.x_widths, "x_widths");
757 }
758 /*
759 * We might have been inside a cshow, in which case currentfont was
760 * reset temporarily, as though we were inside a BuildChar/ BuildGlyph
761 * procedure. To handle this case, set currentfont back to its original
762 * state. NOTE: this code previously used fstack[0] in the enumerator
763 * for the root font: we aren't sure that this change is correct.
764 */
765 gs_set_currentfont(igs, penum->orig_font);
766 while (igs->level > saved_level && code >= 0) {
767 if (igs->saved == 0 || igs->saved->saved == 0) {
768 /*
769 * Bad news: we got an error inside a save inside a BuildChar or
770 * BuildGlyph. Don't attempt to recover.
771 */
772 code = gs_note_error(e_Fatal);
773 } else
774 code = gs_grestore(igs);
775 }
776 gs_text_release(penum, "op_show_restore");
777 return code;
778 }
779 /* Clean up after an error. */
780 private int
op_show_cleanup(i_ctx_t * i_ctx_p)781 op_show_cleanup(i_ctx_t *i_ctx_p)
782 {
783 return op_show_restore(i_ctx_p, true);
784 }
785 /* Clean up after termination of a show operation. */
786 int
op_show_free(i_ctx_t * i_ctx_p,int code)787 op_show_free(i_ctx_t *i_ctx_p, int code)
788 {
789 int rcode;
790
791 esp -= snumpush;
792 rcode = op_show_restore(i_ctx_p, code < 0);
793 return (rcode < 0 ? rcode : code);
794 }
795
796 /* Get a FontBBox parameter from a font dictionary. */
797 int
font_bbox_param(const gs_memory_t * mem,const ref * pfdict,double bbox[4])798 font_bbox_param(const gs_memory_t *mem, const ref * pfdict, double bbox[4])
799 {
800 ref *pbbox;
801
802 /*
803 * Pre-clear the bbox in case it's invalid. The Red Books say that
804 * FontBBox is required, but the Adobe interpreters don't require
805 * it, and a few user-written fonts don't supply it, or supply one
806 * of the wrong size (!); also, PageMaker 5.0 (an Adobe product!)
807 * sometimes emits an absurd bbox for Type 1 fonts converted from
808 * TrueType.
809 */
810 bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0.0;
811 if (dict_find_string(pfdict, "FontBBox", &pbbox) > 0) {
812 if (!r_is_array(pbbox))
813 return_error(e_typecheck);
814 if (r_size(pbbox) == 4) {
815 const ref_packed *pbe = pbbox->value.packed;
816 ref rbe[4];
817 int i;
818 int code;
819 float dx, dy, ratio;
820 const float max_ratio = 12; /* From the bug 687594. */
821
822 for (i = 0; i < 4; i++) {
823 packed_get(mem, pbe, rbe + i);
824 pbe = packed_next(pbe);
825 }
826 if ((code = num_params(rbe + 3, 4, bbox)) < 0)
827 return code;
828 /* Require "reasonable" values. */
829 dx = bbox[2] - bbox[0];
830 dy = bbox[3] - bbox[1];
831 if (dx <= 0 || dy <= 0 ||
832 (ratio = dy / dx) < 1 / max_ratio || ratio > max_ratio
833 )
834 bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0.0;
835 }
836 }
837 return 0;
838 }
839