xref: /plan9/sys/src/cmd/gs/src/zchar.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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