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