xref: /plan9/sys/src/cmd/gs/src/zchar1.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1993, 2000, 2002 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: zchar1.c,v 1.44 2005/04/14 19:10:14 raph Exp $ */
18 /* Type 1 character display operator */
19 #include "memory_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "gsstruct.h"
23 #include "gxfixed.h"
24 #include "gxmatrix.h"
25 #include "gxdevice.h"		/* for gxfont.h */
26 #include "gxfont.h"
27 #include "gxfont1.h"
28 #include "gxtype1.h"
29 #include "gzstate.h"		/* for path for gs_type1_init */
30 				/* (should only be gsstate.h) */
31 #include "gscencs.h"
32 #include "gspaint.h"		/* for gs_fill, gs_stroke */
33 #include "gspath.h"
34 #include "gsrect.h"
35 #include "estack.h"
36 #include "ialloc.h"
37 #include "ichar.h"
38 #include "ichar1.h"
39 #include "icharout.h"
40 #include "idict.h"
41 #include "ifont.h"
42 #include "igstate.h"
43 #include "iname.h"
44 #include "iutil.h"
45 #include "store.h"
46 
47 /*
48  * Properly designed fonts, which have no self-intersecting outlines
49  * and in which outer and inner outlines are drawn in opposite
50  * directions, aren't affected by choice of filling rule; but some
51  * badly designed fonts in the Genoa test suite seem to require
52  * using the even-odd rule to match Adobe interpreters.
53  */
54 #define GS_CHAR_FILL gs_eofill	/* gs_fill or gs_eofill */
55 
56 /* ============== PATCH BEG=================== */
57 /*
58  * On April 4, 2002, we received bug report #539359
59  * which we interpret as some Genoa test are now obsolete,
60  * so we need to drop the bad font tolerance feature
61  * explained above. This temporary patch changes
62  * the even-odd rule back to non-zero rule.
63  * This patch to be kept until we accumulate
64  * enough information from regression testing and
65  * from user responses.
66  */
67 
68 #undef  GS_CHAR_FILL
69 #define GS_CHAR_FILL gs_fill	/* gs_fill or gs_eofill */
70 
71 /* ============== PATCH END=================== */
72 
73 /* ---------------- Utilities ---------------- */
74 
75 /* Test whether a font is a CharString font. */
76 private bool
font_uses_charstrings(const gs_font * pfont)77 font_uses_charstrings(const gs_font *pfont)
78 {
79     return (pfont->FontType == ft_encrypted ||
80 	    pfont->FontType == ft_encrypted2 ||
81 	    pfont->FontType == ft_disk_based);
82 }
83 
84 /* Initialize a Type 1 interpreter. */
85 private int
type1_exec_init(gs_type1_state * pcis,gs_text_enum_t * penum,gs_state * pgs,gs_font_type1 * pfont1)86 type1_exec_init(gs_type1_state *pcis, gs_text_enum_t *penum,
87 		gs_state *pgs, gs_font_type1 *pfont1)
88 {
89     /*
90      * We have to disregard penum->pis and penum->path, and render to
91      * the current gstate and path.  This is a design bug that we will
92      * have to address someday!
93      */
94 
95     int alpha_bits = 1;
96     gs_log2_scale_point log2_subpixels;
97 
98     if (color_is_pure(pgs->dev_color)) /* Keep consistency with alpha_buffer_bits() */
99 	alpha_bits = (*dev_proc(pgs->device, get_alpha_bits)) (pgs->device, go_text);
100     if (alpha_bits <= 1) {
101 	/* We render to cache device or the target device has no alpha bits. */
102 	log2_subpixels = penum->log2_scale;
103     } else {
104 	/* We'll render to target device through alpha buffer. */
105 	/* Keep consistency with alpha_buffer_init() */
106 	log2_subpixels.x = log2_subpixels.y = ilog2(alpha_bits);
107     }
108     return gs_type1_interp_init(pcis, (gs_imager_state *)pgs, pgs->path,
109 				&penum->log2_scale, &log2_subpixels,
110 				(penum->text.operation & TEXT_DO_ANY_CHARPATH) != 0 ||
111 				penum->device_disabled_grid_fitting,
112 				pfont1->PaintType, pfont1);
113 }
114 
115 /* ---------------- .type1execchar ---------------- */
116 
117 /*
118  * This is the workhorse for %Type1/2BuildChar, %Type1/2BuildGlyph,
119  * CCRun, and CID fonts.  Eventually this will appear in the C API;
120  * even now, its normal control path doesn't use any continuations.
121  */
122 
123 /*
124  * Define the state record for this operator, which must save the metrics
125  * separately as well as the Type 1 interpreter state.
126  */
127 typedef struct gs_type1exec_state_s {
128     gs_type1_state cis;		/* must be first */
129     i_ctx_t *i_ctx_p;		/* so push/pop can access o-stack */
130     double sbw[4];
131     int /*metrics_present */ present;
132     gs_rect char_bbox;
133     bool use_FontBBox_as_Metrics2;
134     /*
135      * The following elements are only used locally to make the stack clean
136      * for OtherSubrs: they don't need to be declared for the garbage
137      * collector.
138      */
139     ref save_args[6];
140     int num_args;
141     bool AlignToPixels;
142 } gs_type1exec_state;
143 
144 gs_private_st_suffix_add1(st_gs_type1exec_state, gs_type1exec_state,
145 			  "gs_type1exec_state", gs_type1exec_state_enum_ptrs,
146 			  gs_type1exec_state_reloc_ptrs, st_gs_type1_state,
147 			  i_ctx_p);
148 
149 /* Forward references */
150 private int bbox_continue(i_ctx_t *);
151 private int nobbox_continue(i_ctx_t *);
152 private int type1_push_OtherSubr(i_ctx_t *, const gs_type1exec_state *,
153 				 int (*)(i_ctx_t *), const ref *);
154 private int type1_call_OtherSubr(i_ctx_t *, const gs_type1exec_state *,
155 				 int (*)(i_ctx_t *), const ref *);
156 private int type1_callout_dispatch(i_ctx_t *, int (*)(i_ctx_t *), int);
157 private int type1_continue_dispatch(i_ctx_t *, gs_type1exec_state *,
158 				    const ref *, ref *, int);
159 private int op_type1_cleanup(i_ctx_t *);
160 private void op_type1_free(i_ctx_t *);
161 private int bbox_getsbw_continue(i_ctx_t *);
162 private int type1exec_bbox(i_ctx_t *, gs_type1exec_state *, gs_font *, op_proc_t *exec_cont);
163 private int bbox_finish_fill(i_ctx_t *);
164 private int bbox_finish_stroke(i_ctx_t *);
165 private int bbox_fill(i_ctx_t *);
166 private int bbox_stroke(i_ctx_t *);
167 private int nobbox_finish(i_ctx_t *, gs_type1exec_state *);
168 private int nobbox_draw(i_ctx_t *, int (*)(gs_state *));
169 private int nobbox_fill(i_ctx_t *);
170 private int nobbox_stroke(i_ctx_t *);
171 
172 /* <font> <code|name> <name> <charstring> .type1execchar - */
173 private int
ztype1execchar(i_ctx_t * i_ctx_p)174 ztype1execchar(i_ctx_t *i_ctx_p)
175 {
176     return charstring_execchar(i_ctx_p, (1 << (int)ft_encrypted) |
177 			       (1 << (int)ft_disk_based));
178 }
179 int
charstring_execchar(i_ctx_t * i_ctx_p,int font_type_mask)180 charstring_execchar(i_ctx_t *i_ctx_p, int font_type_mask)
181 {
182     os_ptr op = osp;
183     gs_font *pfont;
184     int code = font_param(op - 3, &pfont);
185     gs_font_base *const pbfont = (gs_font_base *) pfont;
186     gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont;
187     const gs_type1_data *pdata;
188     gs_text_enum_t *penum = op_show_find(i_ctx_p);
189     gs_type1exec_state cxs;
190     gs_type1_state *const pcis = &cxs.cis;
191 
192     if (code < 0)
193 	return code;
194     if (penum == 0 ||
195 	pfont->FontType >= sizeof(font_type_mask) * 8 ||
196 	!(font_type_mask & (1 << (int)pfont->FontType)))
197 	return_error(e_undefined);
198     pdata = &pfont1->data;
199     /*
200      * Any reasonable implementation would execute something like
201      *    1 setmiterlimit 0 setlinejoin 0 setlinecap
202      * here, but the Adobe implementations don't.
203      *
204      * If this is a stroked font, set the stroke width.
205      */
206     if (pfont->PaintType)
207 	gs_setlinewidth(igs, pfont->StrokeWidth);
208     check_estack(3);		/* for continuations */
209     /*
210      * Execute the definition of the character.
211      */
212     if (r_is_proc(op))
213 	return zchar_exec_char_proc(i_ctx_p);
214     /*
215      * The definition must be a Type 1 CharString.
216      * Note that we do not require read access: this is deliberate.
217      */
218     check_type(*op, t_string);
219     if (r_size(op) <= max(pdata->lenIV, 0))
220 	return_error(e_invalidfont);
221     /*
222      * In order to make character oversampling work, we must
223      * set up the cache before calling .type1addpath.
224      * To do this, we must get the bounding box from the FontBBox,
225      * and the width from the CharString or the Metrics.
226      * If the FontBBox isn't valid, we can't do any of this.
227      */
228 
229     if ((penum->FontBBox_as_Metrics2.x == 0 &&
230 	 penum->FontBBox_as_Metrics2.y == 0) ||
231 	gs_rootfont(igs)->WMode == 0 ) {
232 	code = zchar_get_metrics(pbfont, op - 1, cxs.sbw);
233 	if (code < 0)
234 	    return code;
235 	cxs.present = code;
236 	cxs.use_FontBBox_as_Metrics2 = false;
237     }  else {  /* pass here if FontType==9,11 && WMode==1*/
238 	cxs.sbw[0] = penum->FontBBox_as_Metrics2.x / 2;
239 	cxs.sbw[1] = penum->FontBBox_as_Metrics2.y;
240 	cxs.sbw[2] = 0;
241 	cxs.sbw[3] = -penum->FontBBox_as_Metrics2.x; /* Sic! */
242 	cxs.use_FontBBox_as_Metrics2 = true;
243     }
244     /* Establish a current point. */
245     code = gs_moveto(igs, 0.0, 0.0);
246     if (code < 0)
247 	return code;
248     code = type1_exec_init(pcis, penum, igs, pfont1);
249     if (code < 0)
250 	return code;
251     gs_type1_set_callback_data(pcis, &cxs);
252     if (pfont1->FontBBox.q.x > pfont1->FontBBox.p.x &&
253 	pfont1->FontBBox.q.y > pfont1->FontBBox.p.y
254 	) {
255 	/* The FontBBox appears to be valid. */
256 	op_proc_t exec_cont = 0;
257 
258 	cxs.char_bbox = pfont1->FontBBox;
259 	code = type1exec_bbox(i_ctx_p, &cxs, pfont, &exec_cont);
260 	if (code >= 0 && exec_cont != 0)
261 	    code = (*exec_cont)(i_ctx_p);
262 	return code;
263     } else {
264 	/*
265 	 * The FontBBox is not valid.  In this case,
266 	 * we create the path first, then do the setcachedevice.
267 	 * If we are oversampling (in this case, only for anti-
268 	 * aliasing, not just to improve quality), we have to
269 	 * create the path twice, since we can't know the
270 	 * oversampling factor until after setcachedevice.
271 	 */
272 	const ref *opstr = op;
273 	ref other_subr;
274 
275 	if (cxs.present == metricsSideBearingAndWidth) {
276 	    gs_point sbpt;
277 
278 	    sbpt.x = cxs.sbw[0], sbpt.y = cxs.sbw[1];
279 	    gs_type1_set_lsb(pcis, &sbpt);
280 	}
281 	/* Continue interpreting. */
282       icont:
283 	code = type1_continue_dispatch(i_ctx_p, &cxs, opstr, &other_subr, 4);
284 	op = osp;		/* OtherSubrs might change it */
285 	switch (code) {
286 	    case 0:		/* all done */
287 		return nobbox_finish(i_ctx_p, &cxs);
288 	    default:		/* code < 0, error */
289 		return code;
290 	    case type1_result_callothersubr:	/* unknown OtherSubr */
291 		return type1_call_OtherSubr(i_ctx_p, &cxs, nobbox_continue,
292 					    &other_subr);
293 	    case type1_result_sbw:	/* [h]sbw, just continue */
294 		if (cxs.present != metricsSideBearingAndWidth)
295 		    type1_cis_get_metrics(pcis, cxs.sbw);
296 		opstr = 0;
297 		goto icont;
298 	}
299     }
300 }
301 
302 /* -------- bbox case -------- */
303 
304 /* Do all the work for the case where we have a bounding box. */
305 /* Returns exec_cont - a function, which must be called by caller after this function. */
306 private int
type1exec_bbox(i_ctx_t * i_ctx_p,gs_type1exec_state * pcxs,gs_font * pfont,op_proc_t * exec_cont)307 type1exec_bbox(i_ctx_t *i_ctx_p, gs_type1exec_state * pcxs,
308 	       gs_font * pfont, op_proc_t *exec_cont)
309 {
310     os_ptr op = osp;
311     gs_type1_state *const pcis = &pcxs->cis;
312     gs_font_base *const pbfont = (gs_font_base *) pfont;
313     op_proc_t cont = (pbfont->PaintType == 0 ? bbox_finish_fill : bbox_finish_stroke);
314 
315 
316     /*
317      * We appear to have a valid bounding box.  If we don't have Metrics for
318      * this character, start interpreting the CharString; do the
319      * setcachedevice as soon as we know the (side bearing and) width.
320      */
321     if (pcxs->present == metricsNone) {
322 	/* Get the width from the CharString, */
323 	/* then set the cache device. */
324 	ref cnref;
325 	ref other_subr;
326 	int code;
327 
328 	/* Since an OtherSubr callout might change osp, */
329 	/* save the character name now. */
330 	ref_assign(&cnref, op - 1);
331 	code = type1_continue_dispatch(i_ctx_p, pcxs, op, &other_subr, 4);
332 	op = osp;		/* OtherSubrs might change it */
333 	switch (code) {
334 	    default:		/* code < 0 or done, error */
335 		return ((code < 0 ? code :
336 			 gs_note_error(e_invalidfont)));
337 	    case type1_result_callothersubr:	/* unknown OtherSubr */
338 		return type1_call_OtherSubr(i_ctx_p, pcxs,
339 					    bbox_getsbw_continue,
340 					    &other_subr);
341 	    case type1_result_sbw:	/* [h]sbw, done */
342 		break;
343 	}
344 	type1_cis_get_metrics(pcis, pcxs->sbw);
345 	return zchar_set_cache(i_ctx_p, pbfont, &cnref,
346 			       NULL, pcxs->sbw + 2,
347 			       &pcxs->char_bbox,
348 			       cont, exec_cont, NULL);
349     } else {
350 	/* We have the width and bounding box: */
351 	/* set up the cache device now. */
352  	return zchar_set_cache(i_ctx_p, pbfont, op - 1,
353 			       (pcxs->present == metricsSideBearingAndWidth
354 			        && !pcxs->use_FontBBox_as_Metrics2 ?
355 			        pcxs->sbw : NULL),
356 			       pcxs->sbw + 2,
357 			       &pcxs->char_bbox,
358 			       cont, exec_cont,
359 			       (pcxs->use_FontBBox_as_Metrics2 ? pcxs->sbw : NULL));
360     }
361 }
362 
363 /* Continue from an OtherSubr callout while getting metrics. */
364 private int
bbox_getsbw_continue(i_ctx_t * i_ctx_p)365 bbox_getsbw_continue(i_ctx_t *i_ctx_p)
366 {
367     os_ptr op = osp;
368     ref other_subr;
369     gs_type1exec_state *pcxs = r_ptr(esp, gs_type1exec_state);
370     gs_type1_state *const pcis = &pcxs->cis;
371     int code;
372 
373     code = type1_continue_dispatch(i_ctx_p, pcxs, NULL, &other_subr, 4);
374     op = osp;			/* in case z1_push/pop_proc was called */
375     switch (code) {
376 	default:		/* code < 0 or done, error */
377 	    op_type1_free(i_ctx_p);
378 	    return ((code < 0 ? code : gs_note_error(e_invalidfont)));
379 	case type1_result_callothersubr:	/* unknown OtherSubr */
380 	    return type1_push_OtherSubr(i_ctx_p, pcxs, bbox_getsbw_continue,
381 					&other_subr);
382 	case type1_result_sbw: {	/* [h]sbw, done */
383 	    double sbw[4];
384 	    const gs_font_base *const pbfont =
385 		(const gs_font_base *)pcis->pfont;
386 	    gs_rect bbox;
387 	    op_proc_t cont = (pbfont->PaintType == 0 ? bbox_finish_fill : bbox_finish_stroke), exec_cont = 0;
388 
389 	    /* Get the metrics before freeing the state. */
390 	    type1_cis_get_metrics(pcis, sbw);
391 	    bbox = pcxs->char_bbox;
392 	    op_type1_free(i_ctx_p);
393 	    code = zchar_set_cache(i_ctx_p, pbfont, op - 1, sbw, sbw + 2, &bbox,
394 				   cont, &exec_cont, NULL);
395 	    if (code >= 0 && exec_cont != 0)
396 		code = (*exec_cont)(i_ctx_p);
397 	    return code;
398 	}
399     }
400 }
401 
402 /* <font> <code|name> <name> <charstring> <sbx> <sby> %bbox_{fill|stroke} - */
403 /* <font> <code|name> <name> <charstring> %bbox_{fill|stroke} - */
404 private int bbox_finish(i_ctx_t *i_ctx_p, op_proc_t cont, op_proc_t *exec_cont);
405 private int
bbox_finish_fill(i_ctx_t * i_ctx_p)406 bbox_finish_fill(i_ctx_t *i_ctx_p)
407 {
408     op_proc_t exec_cont = 0;
409     int code;
410 
411     code = bbox_finish(i_ctx_p, bbox_fill, &exec_cont);
412     if (code >= 0 && exec_cont != 0)
413 	code = exec_cont(i_ctx_p);
414     return code;
415 }
416 private int
bbox_finish_stroke(i_ctx_t * i_ctx_p)417 bbox_finish_stroke(i_ctx_t *i_ctx_p)
418 {
419     op_proc_t exec_cont = 0;
420     int code;
421 
422     code = bbox_finish(i_ctx_p, bbox_stroke, &exec_cont);
423     if (code >= 0 && exec_cont != 0)
424 	code = exec_cont(i_ctx_p);
425     return code;
426 }
427 
428 private int
bbox_finish(i_ctx_t * i_ctx_p,op_proc_t cont,op_proc_t * exec_cont)429 bbox_finish(i_ctx_t *i_ctx_p, op_proc_t cont, op_proc_t *exec_cont)
430 {   /* Returns exec_cont - a function, which must be called by caller after this function. */
431     os_ptr op = osp;
432     gs_font *pfont;
433     int code;
434     gs_text_enum_t *penum = op_show_find(i_ctx_p);
435     gs_type1exec_state cxs;	/* stack allocate to avoid sandbars */
436     gs_type1_state *const pcis = &cxs.cis;
437     double sbxy[2];
438     gs_point sbpt;
439     gs_point *psbpt = 0;
440     os_ptr opc = op;
441     const ref *opstr;
442     ref other_subr;
443 
444     if (!r_has_type(opc, t_string)) {
445 	check_op(3);
446 	code = num_params(op, 2, sbxy);
447 	if (code < 0)
448 	    return code;
449 	sbpt.x = sbxy[0];
450 	sbpt.y = sbxy[1];
451 	psbpt = &sbpt;
452 	opc -= 2;
453 	check_type(*opc, t_string);
454     }
455     code = font_param(opc - 3, &pfont);
456     if (code < 0)
457 	return code;
458     if (penum == 0 || !font_uses_charstrings(pfont))
459 	return_error(e_undefined);
460     {
461 	gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont;
462 	int lenIV = pfont1->data.lenIV;
463 
464 	if (lenIV > 0 && r_size(opc) <= lenIV)
465 	    return_error(e_invalidfont);
466 	check_estack(5);	/* in case we need to do a callout */
467 	code = type1_exec_init(pcis, penum, igs, pfont1);
468 	if (code < 0)
469 	    return code;
470 	if (psbpt)
471 	    gs_type1_set_lsb(pcis, psbpt);
472     }
473     opstr = opc;
474   icont:
475     code = type1_continue_dispatch(i_ctx_p, &cxs, opstr, &other_subr,
476 				   (psbpt ? 6 : 4));
477     op = osp;		/* OtherSubrs might have altered it */
478     switch (code) {
479 	case 0:		/* all done */
480 	    /* Call the continuation now. */
481 	    if (psbpt)
482 		pop(2);
483 	    *exec_cont = cont;
484 	    return 0;
485 	case type1_result_callothersubr:	/* unknown OtherSubr */
486 	    push_op_estack(cont);	/* call later */
487 	    return type1_call_OtherSubr(i_ctx_p, &cxs, bbox_continue,
488 					&other_subr);
489 	case type1_result_sbw:	/* [h]sbw, just continue */
490 	    opstr = 0;
491 	    goto icont;
492 	default:		/* code < 0, error */
493 	    return code;
494     }
495 }
496 
497 private int
bbox_continue(i_ctx_t * i_ctx_p)498 bbox_continue(i_ctx_t *i_ctx_p)
499 {
500     os_ptr op = osp;
501     int npop = (r_has_type(op, t_string) ? 4 : 6);
502     int code = type1_callout_dispatch(i_ctx_p, bbox_continue, npop);
503 
504     if (code == 0) {
505 	op = osp;		/* OtherSubrs might have altered it */
506 	npop -= 4;		/* nobbox_fill/stroke handles the rest */
507 	pop(npop);
508 	op -= npop;
509 	op_type1_free(i_ctx_p);
510     }
511     return code;
512 }
513 
514 /*
515  * Check the path against FontBBox before drawing.  The original operands
516  * of type1execchar are still on the o-stack.
517  * Returns exec_cont - a function, which must be called by caller after this function.
518  */
519 private int
bbox_draw(i_ctx_t * i_ctx_p,int (* draw)(gs_state *),op_proc_t * exec_cont)520 bbox_draw(i_ctx_t *i_ctx_p, int (*draw)(gs_state *), op_proc_t *exec_cont)
521 {
522     os_ptr op = osp;
523     gs_rect bbox;
524     gs_font *pfont;
525     gs_text_enum_t *penum;
526     gs_font_base * pbfont;
527     gs_font_type1 * pfont1;
528     gs_type1exec_state cxs;
529     int code;
530 
531     if (igs->in_cachedevice < 2)	/* not caching */
532 	return nobbox_draw(i_ctx_p, draw);
533     if ((code = font_param(op - 3, &pfont)) < 0)
534 	return code;
535     penum = op_show_find(i_ctx_p);
536     if (penum == 0 || !font_uses_charstrings(pfont))
537 	return_error(e_undefined);
538     if ((code = gs_pathbbox(igs, &bbox)) < 0) {
539 	/*
540 	 * If the matrix is singular, all user coordinates map onto a
541 	 * straight line.  Don't bother rendering the character at all.
542 	 */
543 	if (code == e_undefinedresult) {
544 	    pop(4);
545 	    gs_newpath(igs);
546 	    return 0;
547 	}
548 	return code;
549     }
550     if (draw == gs_stroke) {
551 	/* Expand the bounding box by the line width. */
552 	float width = gs_currentlinewidth(igs) * 1.41422;
553 
554 	bbox.p.x -= width, bbox.p.y -= width;
555 	bbox.q.x += width, bbox.q.y += width;
556     }
557     pbfont = (gs_font_base *)pfont;
558     if (rect_within(bbox, pbfont->FontBBox))	/* within bounds */
559 	return nobbox_draw(i_ctx_p, draw);
560     /* Enlarge the FontBBox to save work in the future. */
561     rect_merge(pbfont->FontBBox, bbox);
562     /* Dismantle everything we've done, and start over. */
563     gs_text_retry(penum);
564     pfont1 = (gs_font_type1 *) pfont;
565     if ((penum->FontBBox_as_Metrics2.x == 0 &&
566 	 penum->FontBBox_as_Metrics2.y == 0) ||
567 	gs_rootfont(igs)->WMode == 0 ) {
568 	code = zchar_get_metrics(pbfont, op - 1, cxs.sbw);
569 	if (code < 0)
570 	    return code;
571 	cxs.present = code;
572 	cxs.use_FontBBox_as_Metrics2 = false;
573     }  else {
574 	cxs.sbw[0] = penum->FontBBox_as_Metrics2.x / 2;
575 	cxs.sbw[1] = penum->FontBBox_as_Metrics2.y;
576 	cxs.sbw[2] = 0;
577 	cxs.sbw[3] = -penum->FontBBox_as_Metrics2.x; /* Sic! */
578 	cxs.use_FontBBox_as_Metrics2 = true;
579 	cxs.present = metricsSideBearingAndWidth;
580     }
581     code = type1_exec_init(&cxs.cis, penum, igs, pfont1);
582     if (code < 0)
583 	return code;
584     cxs.char_bbox = pfont1->FontBBox;
585     code = type1exec_bbox(i_ctx_p, &cxs, pfont, exec_cont);
586     return code;
587 }
588 private int
bbox_fill(i_ctx_t * i_ctx_p)589 bbox_fill(i_ctx_t *i_ctx_p)
590 {
591     op_proc_t exec_cont = 0;
592     int code;
593 
594     /* See above re GS_CHAR_FILL. */
595     code = bbox_draw(i_ctx_p, GS_CHAR_FILL, &exec_cont);
596     if (code >= 0 && exec_cont != 0)
597 	code = (*exec_cont)(i_ctx_p);
598     return code;
599 }
600 private int
bbox_stroke(i_ctx_t * i_ctx_p)601 bbox_stroke(i_ctx_t *i_ctx_p)
602 {
603     op_proc_t exec_cont = 0;
604     int code;
605 
606     code = bbox_draw(i_ctx_p, gs_stroke, &exec_cont);
607     if (code >= 0 && exec_cont != 0)
608 	code = (*exec_cont)(i_ctx_p);
609     return code;
610 }
611 
612 /* -------- Common code -------- */
613 
614 /* Handle the results of interpreting the CharString. */
615 /* pcref points to a t_string ref. */
616 private int
type1_continue_dispatch(i_ctx_t * i_ctx_p,gs_type1exec_state * pcxs,const ref * pcref,ref * pos,int num_args)617 type1_continue_dispatch(i_ctx_t *i_ctx_p, gs_type1exec_state *pcxs,
618 			const ref * pcref, ref *pos, int num_args)
619 {
620     int value;
621     int code;
622     gs_glyph_data_t cs_data;
623     gs_glyph_data_t *pcsd;
624 
625     cs_data.memory = imemory;
626     if (pcref == 0) {
627 	pcsd = 0;
628     } else {
629 	gs_glyph_data_from_string(&cs_data, pcref->value.const_bytes,
630 				  r_size(pcref), NULL);
631 	pcsd = &cs_data;
632     }
633     /*
634      * Since OtherSubrs may push or pop values on the PostScript operand
635      * stack, remove the arguments of .type1execchar before calling the
636      * Type 1 interpreter, and put them back afterwards unless we're
637      * about to execute an OtherSubr procedure.  Also, we must set up
638      * the callback data for pushing OtherSubrs arguments.
639      */
640     pcxs->i_ctx_p = i_ctx_p;
641     pcxs->num_args = num_args;
642     memcpy(pcxs->save_args, osp - (num_args - 1), num_args * sizeof(ref));
643     osp -= num_args;
644     gs_type1_set_callback_data(&pcxs->cis, pcxs);
645     code = pcxs->cis.pfont->data.interpret(&pcxs->cis, pcsd, &value);
646     switch (code) {
647 	case type1_result_callothersubr: {
648 	    /*
649 	     * The Type 1 interpreter handles all known OtherSubrs,
650 	     * so this must be an unknown one.
651 	     */
652 	    const font_data *pfdata = pfont_data(gs_currentfont(igs));
653 
654 	    code = array_get(imemory, &pfdata->u.type1.OtherSubrs, (long)value, pos);
655 	    if (code >= 0)
656 		return type1_result_callothersubr;
657 	}
658     }
659     /* Put back the arguments removed above. */
660     memcpy(osp + 1, pcxs->save_args, num_args * sizeof(ref));
661     osp += num_args;
662     return code;
663 }
664 
665 /*
666  * Push a continuation, the arguments removed for the OtherSubr, and
667  * the OtherSubr procedure.
668  */
669 private int
type1_push_OtherSubr(i_ctx_t * i_ctx_p,const gs_type1exec_state * pcxs,int (* cont)(i_ctx_t *),const ref * pos)670 type1_push_OtherSubr(i_ctx_t *i_ctx_p, const gs_type1exec_state *pcxs,
671 		     int (*cont)(i_ctx_t *), const ref *pos)
672 {
673     int i, n = pcxs->num_args;
674 
675     push_op_estack(cont);
676     /*
677      * Push the saved arguments (in reverse order, so they will get put
678      * back on the operand stack in the correct order) on the e-stack.
679      */
680     for (i = n; --i >= 0; ) {
681 	*++esp = pcxs->save_args[i];
682 	r_clear_attrs(esp, a_executable);  /* just in case */
683     }
684     ++esp;
685     *esp = *pos;
686     return o_push_estack;
687 }
688 
689 /*
690  * Do a callout to an OtherSubr implemented in PostScript.
691  * The caller must have done a check_estack(4 + num_args).
692  */
693 private int
type1_call_OtherSubr(i_ctx_t * i_ctx_p,const gs_type1exec_state * pcxs,int (* cont)(i_ctx_t *),const ref * pos)694 type1_call_OtherSubr(i_ctx_t *i_ctx_p, const gs_type1exec_state * pcxs,
695 		     int (*cont) (i_ctx_t *),
696 		     const ref * pos)
697 {
698     /* Move the Type 1 interpreter state to the heap. */
699     gs_type1exec_state *hpcxs =
700 	ialloc_struct(gs_type1exec_state, &st_gs_type1exec_state,
701 		      "type1_call_OtherSubr");
702 
703     if (hpcxs == 0)
704 	return_error(e_VMerror);
705     *hpcxs = *pcxs;
706     gs_type1_set_callback_data(&hpcxs->cis, hpcxs);
707     push_mark_estack(es_show, op_type1_cleanup);
708     ++esp;
709     make_istruct(esp, 0, hpcxs);
710     return type1_push_OtherSubr(i_ctx_p, pcxs, cont, pos);
711 }
712 
713 /* Continue from an OtherSubr callout while building the path. */
714 private int
type1_callout_dispatch(i_ctx_t * i_ctx_p,int (* cont)(i_ctx_t *),int num_args)715 type1_callout_dispatch(i_ctx_t *i_ctx_p, int (*cont)(i_ctx_t *),
716 		       int num_args)
717 {
718     ref other_subr;
719     gs_type1exec_state *pcxs = r_ptr(esp, gs_type1exec_state);
720     int code;
721 
722   icont:
723     code = type1_continue_dispatch(i_ctx_p, pcxs, NULL, &other_subr,
724 				   num_args);
725     switch (code) {
726 	case 0:		/* callout done, cont is on e-stack */
727 	    return 0;
728 	default:		/* code < 0 or done, error */
729 	    op_type1_free(i_ctx_p);
730 	    return ((code < 0 ? code : gs_note_error(e_invalidfont)));
731 	case type1_result_callothersubr:	/* unknown OtherSubr */
732 	    return type1_push_OtherSubr(i_ctx_p, pcxs, cont, &other_subr);
733 	case type1_result_sbw:	/* [h]sbw, just continue */
734 	    goto icont;
735     }
736 }
737 
738 /* Clean up after a Type 1 callout. */
739 private int
op_type1_cleanup(i_ctx_t * i_ctx_p)740 op_type1_cleanup(i_ctx_t *i_ctx_p)
741 {
742     ifree_object(r_ptr(esp + 2, void), "op_type1_cleanup");
743     return 0;
744 }
745 private void
op_type1_free(i_ctx_t * i_ctx_p)746 op_type1_free(i_ctx_t *i_ctx_p)
747 {
748     ifree_object(r_ptr(esp, void), "op_type1_free");
749     /*
750      * In order to avoid popping from the e-stack and then pushing onto
751      * it, which would violate an interpreter invariant, we simply
752      * overwrite the two e-stack items being discarded (hpcxs and the
753      * cleanup operator) with empty procedures.
754      */
755     make_empty_const_array(esp - 1, a_readonly + a_executable);
756     make_empty_const_array(esp, a_readonly + a_executable);
757 }
758 
759 /* -------- no-bbox case -------- */
760 
761 private int
nobbox_continue(i_ctx_t * i_ctx_p)762 nobbox_continue(i_ctx_t *i_ctx_p)
763 {
764     int code = type1_callout_dispatch(i_ctx_p, nobbox_continue, 4);
765 
766     if (code)
767 	return code;
768     {
769 	gs_type1exec_state *pcxs = r_ptr(esp, gs_type1exec_state);
770 	gs_type1exec_state cxs;
771 
772 	cxs = *pcxs;
773 	gs_type1_set_callback_data(&cxs.cis, &cxs);
774 	op_type1_free(i_ctx_p);
775 	return nobbox_finish(i_ctx_p, &cxs);
776     }
777 }
778 
779 /* Finish the no-FontBBox case after constructing the path. */
780 /* If we are oversampling for anti-aliasing, we have to go around again. */
781 /* <font> <code|name> <name> <charstring> %nobbox_continue - */
782 private int
nobbox_finish(i_ctx_t * i_ctx_p,gs_type1exec_state * pcxs)783 nobbox_finish(i_ctx_t *i_ctx_p, gs_type1exec_state * pcxs)
784 {
785     os_ptr op = osp;
786     int code;
787     gs_text_enum_t *penum = op_show_find(i_ctx_p);
788     gs_font *pfont;
789 
790     if ((code = gs_pathbbox(igs, &pcxs->char_bbox)) < 0 ||
791 	(code = font_param(op - 3, &pfont)) < 0
792 	)
793 	return code;
794     if (penum == 0 || !font_uses_charstrings(pfont))
795 	return_error(e_undefined);
796     {
797 	gs_font_base *const pbfont = (gs_font_base *) pfont;
798 	gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont;
799 	op_proc_t cont, exec_cont = 0;
800 
801 	if (pcxs->present == metricsNone) {
802 	    gs_point endpt;
803 
804 	    if ((code = gs_currentpoint(igs, &endpt)) < 0)
805 		return code;
806 	    pcxs->sbw[2] = endpt.x, pcxs->sbw[3] = endpt.y;
807 	    pcxs->present = metricsSideBearingAndWidth;
808 	}
809 	/*
810 	 * We only need to rebuild the path from scratch if we might
811 	 * oversample for anti-aliasing.
812 	 */
813 	if ((*dev_proc(igs->device, get_alpha_bits))(igs->device, go_text) > 1
814 	    ) {
815 	    gs_newpath(igs);
816 	    gs_moveto(igs, 0.0, 0.0);
817 	    code = type1_exec_init(&pcxs->cis, penum, igs, pfont1);
818 	    if (code < 0)
819 		return code;
820 	    code = type1exec_bbox(i_ctx_p, pcxs, pfont, &exec_cont);
821 	} else {
822 	    cont = (pbfont->PaintType == 0 ? nobbox_fill : nobbox_stroke), exec_cont = 0;
823 	    code = zchar_set_cache(i_ctx_p, pbfont, op - 1, NULL,
824 				   pcxs->sbw + 2,
825 				   &pcxs->char_bbox,
826 				   cont, &exec_cont,
827 				   (pcxs->use_FontBBox_as_Metrics2 ? pcxs->sbw : NULL));
828 	}
829 	if (code >= 0 && exec_cont != 0)
830 	    code = (*exec_cont)(i_ctx_p);
831 	return code;
832     }
833 }
834 /* Finish by popping the operands and filling or stroking. */
835 private int
nobbox_draw(i_ctx_t * i_ctx_p,int (* draw)(gs_state *))836 nobbox_draw(i_ctx_t *i_ctx_p, int (*draw)(gs_state *))
837 {
838     int code = draw(igs);
839 
840     if (code >= 0)
841 	pop(4);
842     return code;
843 }
844 private int
nobbox_fill(i_ctx_t * i_ctx_p)845 nobbox_fill(i_ctx_t *i_ctx_p)
846 {
847     /* See above re GS_CHAR_FILL. */
848     return nobbox_draw(i_ctx_p, GS_CHAR_FILL);
849 }
850 private int
nobbox_stroke(i_ctx_t * i_ctx_p)851 nobbox_stroke(i_ctx_t *i_ctx_p)
852 {
853     /* As a compatibility to Adobe, use the exact "StrokeWidth".
854        Reset fill_adjust for that. */
855     int code;
856     gs_fixed_point fa = i_ctx_p->pgs->fill_adjust;
857 
858     i_ctx_p->pgs->fill_adjust.x = i_ctx_p->pgs->fill_adjust.y = 0;
859     code = nobbox_draw(i_ctx_p, gs_stroke);
860     i_ctx_p->pgs->fill_adjust = fa;
861     return code;
862 }
863 
864 /* <font> <array> .setweightvector - */
865 private int
zsetweightvector(i_ctx_t * i_ctx_p)866 zsetweightvector(i_ctx_t *i_ctx_p)
867 {
868     os_ptr op = osp;
869     gs_font *pfont;
870     int code = font_param(op - 1, &pfont);
871     gs_font_type1 *pfont1;
872     int size;
873 
874     if (code < 0) {
875 	/* The font was not defined yet. Just ignore. See lib/gs_type1.ps . */
876 	pop(2);
877 	return 0;
878     }
879     if (pfont->FontType != ft_encrypted && pfont->FontType != ft_encrypted2)
880 	return_error(e_invalidfont);
881     pfont1 = (gs_font_type1 *)pfont;
882     size = r_size(op);
883     if (size != pfont1->data.WeightVector.count)
884 	return_error(e_invalidfont);
885     code = process_float_array(imemory, op, size, pfont1->data.WeightVector.values);
886     if (code < 0)
887 	return code;
888     pop(2);
889     return 0;
890 }
891 
892 /* ------ Initialization procedure ------ */
893 
894 const op_def zchar1_op_defs[] =
895 {
896     {"4.type1execchar", ztype1execchar},
897 		/* Internal operators */
898     {"4%bbox_getsbw_continue", bbox_getsbw_continue},
899     {"4%bbox_continue", bbox_continue},
900     {"4%bbox_finish_fill", bbox_finish_fill},
901     {"4%bbox_finish_stroke", bbox_finish_stroke},
902     {"4%nobbox_continue", nobbox_continue},
903     {"4%nobbox_fill", nobbox_fill},
904     {"4%nobbox_stroke", nobbox_stroke},
905     {"4.setweightvector", zsetweightvector},
906     op_def_end(0)
907 };
908 
909 /* ------ Auxiliary procedures for type 1 fonts ------ */
910 
911 private int
z1_glyph_data(gs_font_type1 * pfont,gs_glyph glyph,gs_glyph_data_t * pgd)912 z1_glyph_data(gs_font_type1 * pfont, gs_glyph glyph, gs_glyph_data_t *pgd)
913 {
914     ref gref;
915 
916     glyph_ref(pfont->memory, glyph, &gref);
917     return zchar_charstring_data((gs_font *)pfont, &gref, pgd);
918 }
919 
920 private int
z1_subr_data(gs_font_type1 * pfont,int index,bool global,gs_glyph_data_t * pgd)921 z1_subr_data(gs_font_type1 * pfont, int index, bool global,
922 	     gs_glyph_data_t *pgd)
923 {
924     const font_data *pfdata = pfont_data(pfont);
925     ref subr;
926     int code;
927 
928     code = array_get(pfont->memory, (global ? &pfdata->u.type1.GlobalSubrs :
929 		      &pfdata->u.type1.Subrs),
930 		     index, &subr);
931     if (code < 0)
932 	return code;
933     check_type_only(subr, t_string);
934     gs_glyph_data_from_string(pgd, subr.value.const_bytes, r_size(&subr),
935 			      NULL);
936     return 0;
937 }
938 
939 private int
z1_seac_data(gs_font_type1 * pfont,int ccode,gs_glyph * pglyph,gs_const_string * gstr,gs_glyph_data_t * pgd)940 z1_seac_data(gs_font_type1 *pfont, int ccode, gs_glyph *pglyph,
941 	     gs_const_string *gstr, gs_glyph_data_t *pgd)
942 {
943     gs_glyph glyph = gs_c_known_encode((gs_char)ccode,
944 				       ENCODING_INDEX_STANDARD);
945     int code;
946     ref rglyph;
947 
948     if (glyph == GS_NO_GLYPH)
949 	return_error(e_rangecheck);
950     if ((code = gs_c_glyph_name(glyph, gstr)) < 0 ||
951 	(code = name_ref(pfont->memory, gstr->data, gstr->size, &rglyph, 0)) < 0
952 	)
953 	return code;
954     if (pglyph)
955 	*pglyph = name_index(pfont->memory, &rglyph);
956     if (pgd)
957 	code = zchar_charstring_data((gs_font *)pfont, &rglyph, pgd);
958     return code;
959 }
960 
961 private int
z1_push(void * callback_data,const fixed * pf,int count)962 z1_push(void *callback_data, const fixed * pf, int count)
963 {
964     gs_type1exec_state *pcxs = callback_data;
965     i_ctx_t *i_ctx_p = pcxs->i_ctx_p;
966     const fixed *p = pf + count - 1;
967     int i;
968 
969     check_ostack(count);
970     for (i = 0; i < count; i++, p--) {
971 	osp++;
972 	make_real(osp, fixed2float(*p));
973     }
974     return 0;
975 }
976 
977 private int
z1_pop(void * callback_data,fixed * pf)978 z1_pop(void *callback_data, fixed * pf)
979 {
980     gs_type1exec_state *pcxs = callback_data;
981     i_ctx_t *i_ctx_p = pcxs->i_ctx_p;
982     double val;
983     int code = real_param(osp, &val);
984 
985     if (code < 0)
986 	return code;
987     *pf = float2fixed(val);
988     osp--;
989     return 0;
990 }
991 
992 /* Define the Type 1 procedure vector. */
993 const gs_type1_data_procs_t z1_data_procs = {
994     z1_glyph_data, z1_subr_data, z1_seac_data, z1_push, z1_pop
995 };
996 
997 /* ------ Font procedures for Type 1 fonts ------ */
998 
999 /*
1000  * Get a Type 1 or Type 2 glyph outline.  This is the glyph_outline
1001  * procedure for the font.
1002  */
1003 int
zchar1_glyph_outline(gs_font * font,int WMode,gs_glyph glyph,const gs_matrix * pmat,gx_path * ppath,double sbw[4])1004 zchar1_glyph_outline(gs_font *font, int WMode, gs_glyph glyph, const gs_matrix *pmat,
1005 		     gx_path *ppath, double sbw[4])
1006 {
1007     gs_font_type1 *const pfont1 = (gs_font_type1 *)font;
1008     ref gref;
1009     gs_glyph_data_t gdata;
1010     int code;
1011 
1012     glyph_ref(font->memory, glyph, &gref);
1013     gdata.memory = font->memory;
1014     code = zchar_charstring_data(font, &gref, &gdata);
1015     if (code < 0)
1016 	return code;
1017     return zcharstring_outline(pfont1, WMode, &gref, &gdata, pmat, ppath, sbw);
1018 }
1019 /*
1020  * Get a glyph outline given a CharString.  The glyph_outline procedure
1021  * for CIDFontType 0 fonts uses this.
1022  */
1023 int
zcharstring_outline(gs_font_type1 * pfont1,int WMode,const ref * pgref,const gs_glyph_data_t * pgd_orig,const gs_matrix * pmat,gx_path * ppath,double sbw[4])1024 zcharstring_outline(gs_font_type1 *pfont1, int WMode, const ref *pgref,
1025 		    const gs_glyph_data_t *pgd_orig,
1026 		    const gs_matrix *pmat, gx_path *ppath, double sbw[4])
1027 {
1028     const gs_glyph_data_t *pgd = pgd_orig;
1029     int code;
1030     gs_type1exec_state cxs;
1031     gs_type1_state *const pcis = &cxs.cis;
1032     const gs_type1_data *pdata;
1033     int value;
1034     gs_imager_state gis;
1035     double wv[4];
1036     gs_point mpt;
1037 
1038     pdata = &pfont1->data;
1039     if (pgd->bits.size <= max(pdata->lenIV, 0))
1040 	return_error(e_invalidfont);
1041 #if 0 /* Ignore CDevProc for now. */
1042     if (zchar_get_CDevProc((const gs_font_base *)pfont1, &pcdevproc))
1043 	return_error(e_rangecheck); /* can't call CDevProc from here */
1044 #endif
1045     switch (WMode) {
1046     default:
1047 	code = zchar_get_metrics2((gs_font_base *)pfont1, pgref, wv);
1048 	sbw[0] = wv[2];
1049 	sbw[1] = wv[3];
1050 	sbw[2] = wv[0];
1051 	sbw[3] = wv[1];
1052 	if (code)
1053 	    break;
1054 	/* falls through */
1055     case 0:
1056 	code = zchar_get_metrics((gs_font_base *)pfont1, pgref, sbw);
1057     }
1058     if (code < 0)
1059 	return code;
1060     cxs.present = code;
1061     /* Initialize just enough of the imager state. */
1062     if (pmat)
1063 	gs_matrix_fixed_from_matrix(&gis.ctm, pmat);
1064     else {
1065 	gs_matrix imat;
1066 
1067 	gs_make_identity(&imat);
1068 	gs_matrix_fixed_from_matrix(&gis.ctm, &imat);
1069     }
1070     gis.flatness = 0;
1071     code = gs_type1_interp_init(&cxs.cis, &gis, ppath, NULL, NULL, true, 0,
1072 				pfont1);
1073     if (code < 0)
1074 	return code;
1075     cxs.cis.no_grid_fitting = true;
1076     gs_type1_set_callback_data(pcis, &cxs);
1077     switch (cxs.present) {
1078     case metricsSideBearingAndWidth:
1079 	mpt.x = sbw[0], mpt.y = sbw[1];
1080 	gs_type1_set_lsb(pcis, &mpt);
1081 	/* falls through */
1082     case metricsWidthOnly:
1083 	mpt.x = sbw[2], mpt.y = sbw[3];
1084 	gs_type1_set_width(pcis, &mpt);
1085     case metricsNone:
1086 	;
1087     }
1088     /* Continue interpreting. */
1089 icont:
1090     code = pfont1->data.interpret(pcis, pgd, &value);
1091     switch (code) {
1092     case 0:		/* all done */
1093 	/* falls through */
1094     default:		/* code < 0, error */
1095 	return code;
1096     case type1_result_callothersubr:	/* unknown OtherSubr */
1097 	return_error(e_rangecheck); /* can't handle it */
1098     case type1_result_sbw:	/* [h]sbw, just continue */
1099 	type1_cis_get_metrics(pcis, cxs.sbw);
1100 	type1_cis_get_metrics(pcis, sbw);
1101 	pgd = 0;
1102 	goto icont;
1103     }
1104 }
1105 
1106 /*
1107  * Redefine glyph_info to take Metrics[2] and CDevProc into account (unless
1108  * GLYPH_INFO_OUTLINE_WIDTHS is set).  If CDevProc is present, return
1109  * e_rangecheck, since we can't call the interpreter from here.
1110  */
1111 int
z1_glyph_info_generic(gs_font * font,gs_glyph glyph,const gs_matrix * pmat,int members,gs_glyph_info_t * info,font_proc_glyph_info ((* proc)),int wmode)1112 z1_glyph_info_generic(gs_font *font, gs_glyph glyph, const gs_matrix *pmat,
1113 	      int members, gs_glyph_info_t *info, font_proc_glyph_info((*proc)), int wmode)
1114 {
1115     ref gref;
1116     ref *pcdevproc;
1117     gs_font_base *const pbfont = (gs_font_base *)font;
1118     int width_members = members & (GLYPH_INFO_WIDTH0 << wmode);
1119     int outline_widths = members & GLYPH_INFO_OUTLINE_WIDTHS;
1120     bool modified_widths = false;
1121     int default_members = members & ~(width_members + outline_widths +
1122                                       GLYPH_INFO_VVECTOR0 + GLYPH_INFO_VVECTOR1 +
1123 				      GLYPH_INFO_CDEVPROC);
1124     int done_members = 0;
1125     int code;
1126 
1127     if (!width_members)
1128 	return (*proc)(font, glyph, pmat, members, info);
1129     if (!outline_widths && zchar_get_CDevProc(pbfont, &pcdevproc)) {
1130 	done_members |= GLYPH_INFO_CDEVPROC;
1131 	if (members & GLYPH_INFO_CDEVPROC) {
1132 	    info->members = done_members;
1133 	    return_error(e_rangecheck);
1134 	} else {
1135 	    /* Ignore CDevProc. Used to compure MissingWidth.*/
1136 	}
1137     }
1138     glyph_ref(pbfont->memory, glyph, &gref);
1139     if (width_members == GLYPH_INFO_WIDTH1) {
1140 	double wv[4];
1141 	code = zchar_get_metrics2(pbfont, &gref, wv);
1142 	if (code > 0) {
1143 	    modified_widths = true;
1144 	    info->width[1].x = wv[0];
1145 	    info->width[1].y = wv[1];
1146 	    info->v.x = wv[2];
1147 	    info->v.y = wv[3];
1148 	    done_members = width_members | GLYPH_INFO_VVECTOR1;
1149 	    width_members = 0;
1150 	}
1151     }
1152     if (width_members) {
1153 	double sbw[4];
1154 	code = zchar_get_metrics(pbfont, &gref, sbw);
1155 	if (code > 0) {
1156 	    modified_widths = true;
1157 	    info->width[wmode].x = sbw[2];
1158 	    info->width[wmode].y = sbw[3];
1159 	    if (code == metricsSideBearingAndWidth) {
1160 		info->v.x = sbw[0];
1161 		info->v.y = sbw[1];
1162 		width_members |= GLYPH_INFO_VVECTOR0;
1163 	    } else {
1164 		info->v.x = 0;
1165 		info->v.y = 0;
1166 	    }
1167 	    done_members = width_members;
1168 	    width_members = 0;
1169 	}
1170     }
1171 
1172     if (outline_widths) {
1173 	if (modified_widths || zchar_get_CDevProc(pbfont, &pcdevproc)) {
1174 	    /* Discard the modified widths, but indicate they exist. */
1175 	    width_members |= done_members;
1176 	    done_members = outline_widths;
1177 	}
1178     }
1179     default_members |= width_members;
1180     if (default_members) {
1181 	code = (*proc)(font, glyph, pmat, default_members, info);
1182 
1183 	if (code < 0)
1184 	    return code;
1185     } else
1186 	info->members = 0;
1187     info->members |= done_members;
1188     return 0;
1189 }
1190 
1191 int
z1_glyph_info(gs_font * font,gs_glyph glyph,const gs_matrix * pmat,int members,gs_glyph_info_t * info)1192 z1_glyph_info(gs_font *font, gs_glyph glyph, const gs_matrix *pmat,
1193 	      int members, gs_glyph_info_t *info)
1194 {
1195     int wmode = font->WMode;
1196 
1197     return z1_glyph_info_generic(font, glyph, pmat, members, info,
1198 				    &gs_type1_glyph_info, wmode);
1199 }
1200 
1201 /* Get a Type 1 or Type 9 character metrics and set the cache device. */
1202 int
z1_set_cache(i_ctx_t * i_ctx_p,gs_font_base * pbfont,ref * cnref,gs_glyph glyph,op_proc_t cont,op_proc_t * exec_cont)1203 z1_set_cache(i_ctx_t *i_ctx_p, gs_font_base *pbfont, ref *cnref,
1204 	    gs_glyph glyph, op_proc_t cont, op_proc_t *exec_cont)
1205 {   /* This function is similar to zchar42_set_cache. */
1206     double sbw[4];
1207     gs_glyph_info_t info;
1208     int wmode = gs_rootfont(igs)->WMode;
1209     int code;
1210     gs_matrix id_matrix = { identity_matrix_body };
1211 
1212     code = gs_default_glyph_info((gs_font *)pbfont, glyph, &id_matrix,
1213 		((GLYPH_INFO_WIDTH0 | GLYPH_INFO_VVECTOR0) << wmode) | GLYPH_INFO_BBOX,
1214 	        &info);
1215     if (code < 0)
1216 	return code;
1217     sbw[0] = info.v.x;
1218     sbw[1] = info.v.y;
1219     sbw[2] = info.width[wmode].x;
1220     sbw[3] = info.width[wmode].y;
1221     return zchar_set_cache(i_ctx_p, pbfont, cnref, NULL,
1222 			   sbw + 2, &info.bbox,
1223 			   cont, exec_cont,
1224 			   wmode ? sbw : NULL);
1225 }
1226