Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_tlsv12/sys/src/cmd/gs/src/zchar.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
168
finish_show(i_ctx_t *i_ctx_p)
169
{
170
    return 0;
171
}
172
 
173
/* <string> stringwidth <wx> <wy> */
174
private int
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
}