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