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