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

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

Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
/* Copyright (C) 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
}