xref: /plan9/sys/src/cmd/gs/src/gxtype1.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1997, 1998, 1999, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gxtype1.c,v 1.41 2004/11/19 04:39:11 ray Exp $ */
18 /* Adobe Type 1 font interpreter support */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsccode.h"
24 #include "gsline.h"
25 #include "gsstruct.h"
26 #include "gxarith.h"
27 #include "gxchrout.h"
28 #include "gxfixed.h"
29 #include "gxistate.h"
30 #include "gxmatrix.h"
31 #include "gxcoord.h"
32 #include "gxfont.h"
33 #include "gxfont1.h"
34 #include "gxtype1.h"
35 #include "gzpath.h"
36 
37 /*
38  * The routines in this file are used for both Type 1 and Type 2
39  * charstring interpreters.
40  */
41 
42 /*
43  * Define whether or not to force hints to "big pixel" boundaries
44  * when rasterizing at higher resolution.  With the current algorithms,
45  * a value of 1 is better for devices without alpha capability,
46  * but 0 is better if alpha is available.
47  */
48 #define FORCE_HINTS_TO_BIG_PIXELS 1
49 
50 /* Structure descriptor */
51 public_st_gs_font_type1();
52 
53 /* Define the structure type for a Type 1 interpreter state. */
54 public_st_gs_type1_state();
55 /* GC procedures */
56 private
ENUM_PTRS_WITH(gs_type1_state_enum_ptrs,gs_type1_state * pcis)57 ENUM_PTRS_WITH(gs_type1_state_enum_ptrs, gs_type1_state *pcis)
58 {
59     index -= 4;
60     if (index < pcis->ips_count * ST_GLYPH_DATA_NUM_PTRS)
61 	return ENUM_USING(st_glyph_data,
62 			&pcis->ipstack[index / ST_GLYPH_DATA_NUM_PTRS].cs_data,
63 			  sizeof(pcis->ipstack[0].cs_data),
64 			  index % ST_GLYPH_DATA_NUM_PTRS);
65     return 0;
66 }
67 ENUM_PTR3(0, gs_type1_state, pfont, pis, path);
68 ENUM_PTR(3, gs_type1_state, callback_data);
69 ENUM_PTRS_END
RELOC_PTRS_WITH(gs_type1_state_reloc_ptrs,gs_type1_state * pcis)70 private RELOC_PTRS_WITH(gs_type1_state_reloc_ptrs, gs_type1_state *pcis)
71 {
72     int i;
73 
74     RELOC_PTR(gs_type1_state, pfont);
75     RELOC_PTR(gs_type1_state, pis);
76     RELOC_PTR(gs_type1_state, path);
77     RELOC_PTR(gs_type1_state, callback_data);
78     for (i = 0; i < pcis->ips_count; i++) {
79 	ip_state_t *ipsp = &pcis->ipstack[i];
80 	int diff = ipsp->ip - ipsp->cs_data.bits.data;
81 
82 	RELOC_USING(st_glyph_data, &ipsp->cs_data, sizeof(ipsp->cs_data));
83 	ipsp->ip = ipsp->cs_data.bits.data + diff;
84     }
85 } RELOC_PTRS_END
86 
87 /* Define a string to interact with unique_name in lib/pdf_font.ps .
88    The string is used to resolve glyph name conflict while
89    converting PDF Widths into Metrics.
90  */
91 const char gx_extendeg_glyph_name_separator[] = "~GS~";
92 
93 
94 /* ------ Interpreter services ------ */
95 
96 #define s (*ps)
97 
98 /* Initialize a Type 1 interpreter. */
99 /* The caller must supply a string to the first call of gs_type1_interpret. */
100 int
gs_type1_interp_init(register gs_type1_state * pcis,gs_imager_state * pis,gx_path * ppath,const gs_log2_scale_point * pscale,const gs_log2_scale_point * psubpixels,bool no_grid_fitting,int paint_type,gs_font_type1 * pfont)101 gs_type1_interp_init(register gs_type1_state * pcis, gs_imager_state * pis,
102     gx_path * ppath, const gs_log2_scale_point * pscale,
103     const gs_log2_scale_point * psubpixels, bool no_grid_fitting,
104 		     int paint_type, gs_font_type1 * pfont)
105 {
106     static const gs_log2_scale_point no_scale = {0, 0};
107     const gs_log2_scale_point *plog2_scale =
108 	(FORCE_HINTS_TO_BIG_PIXELS && pscale != NULL ? pscale : &no_scale);
109     const gs_log2_scale_point *plog2_subpixels =
110 	(FORCE_HINTS_TO_BIG_PIXELS ? (psubpixels != NULL ? psubpixels : plog2_scale) : &no_scale);
111 
112     if_debug0('1', "[1]gs_type1_interp_init\n");
113     pcis->pfont = pfont;
114     pcis->pis = pis;
115     pcis->path = ppath;
116     pcis->callback_data = pfont; /* default callback data */
117     pcis->no_grid_fitting = no_grid_fitting;
118     pcis->paint_type = paint_type;
119     pcis->os_count = 0;
120     pcis->ips_count = 1;
121     pcis->ipstack[0].ip = 0;
122     gs_glyph_data_from_null(&pcis->ipstack[0].cs_data);
123     pcis->ignore_pops = 0;
124     pcis->init_done = -1;
125     pcis->sb_set = false;
126     pcis->width_set = false;
127     pcis->num_hints = 0;
128     pcis->seac_accent = -1;
129     pcis->log2_subpixels = *plog2_subpixels;
130 
131     /* Set the sampling scale. */
132     set_pixel_scale(&pcis->scale.x, plog2_scale->x);
133     set_pixel_scale(&pcis->scale.y, plog2_scale->y);
134 
135     return 0;
136 }
137 
138 /* Set the push/pop callback data. */
139 void
gs_type1_set_callback_data(gs_type1_state * pcis,void * callback_data)140 gs_type1_set_callback_data(gs_type1_state *pcis, void *callback_data)
141 {
142     pcis->callback_data = callback_data;
143 }
144 
145 
146 /* Preset the left side bearing and/or width. */
147 void
gs_type1_set_lsb(gs_type1_state * pcis,const gs_point * psbpt)148 gs_type1_set_lsb(gs_type1_state * pcis, const gs_point * psbpt)
149 {
150     pcis->lsb.x = float2fixed(psbpt->x);
151     pcis->lsb.y = float2fixed(psbpt->y);
152     pcis->sb_set = true;
153 }
154 void
gs_type1_set_width(gs_type1_state * pcis,const gs_point * pwpt)155 gs_type1_set_width(gs_type1_state * pcis, const gs_point * pwpt)
156 {
157     pcis->width.x = float2fixed(pwpt->x);
158     pcis->width.y = float2fixed(pwpt->y);
159     pcis->width_set = true;
160 }
161 
162 /* Finish initializing the interpreter if we are actually rasterizing */
163 /* the character, as opposed to just computing the side bearing and width. */
164 void
gs_type1_finish_init(gs_type1_state * pcis)165 gs_type1_finish_init(gs_type1_state * pcis)
166 {
167     gs_imager_state *pis = pcis->pis;
168     const int max_coeff_bits = 11;	/* max coefficient in char space */
169 
170     /* Set up the fixed version of the transformation. */
171     gx_matrix_to_fixed_coeff(&ctm_only(pis), &pcis->fc, max_coeff_bits);
172 
173     /* Set the current point of the path to the origin, */
174     pcis->origin.x = pcis->path->position.x;
175     pcis->origin.y = pcis->path->position.y;
176 
177     /* Initialize hint-related scalars. */
178     pcis->asb_diff = pcis->adxy.x = pcis->adxy.y = 0;
179     pcis->flex_count = flex_max;	/* not in Flex */
180     pcis->vs_offset.x = pcis->vs_offset.y = 0;
181 
182 
183     /* Compute the flatness needed for accurate rendering. */
184     pcis->flatness = gs_char_flatness(pis, 0.001);
185 
186     pcis->init_done = 1;
187 }
188 
189 
190 #undef s
191 
192 /* Record the side bearing and character width. */
193 int
gs_type1_sbw(gs_type1_state * pcis,fixed lsbx,fixed lsby,fixed wx,fixed wy)194 gs_type1_sbw(gs_type1_state * pcis, fixed lsbx, fixed lsby, fixed wx, fixed wy)
195 {
196     if (!pcis->sb_set)
197 	pcis->lsb.x = lsbx, pcis->lsb.y = lsby,
198 	    pcis->sb_set = true;	/* needed for accented chars */
199     if (!pcis->width_set)
200 	pcis->width.x = wx, pcis->width.y = wy,
201 	    pcis->width_set = true;
202     if_debug4('1', "[1]sb=(%g,%g) w=(%g,%g)\n",
203 	      fixed2float(pcis->lsb.x), fixed2float(pcis->lsb.y),
204 	      fixed2float(pcis->width.x), fixed2float(pcis->width.y));
205     return 0;
206 }
207 
208 /* Blend values for a Multiple Master font instance. */
209 /* The stack holds values ... K*N othersubr#. */
210 int
gs_type1_blend(gs_type1_state * pcis,fixed * csp,int num_results)211 gs_type1_blend(gs_type1_state *pcis, fixed *csp, int num_results)
212 {
213     gs_type1_data *pdata = &pcis->pfont->data;
214     int num_values = fixed2int_var(csp[-1]);
215     int k1 = num_values / num_results - 1;
216     int i, j;
217     fixed *base;
218     fixed *deltas;
219 
220     if (num_values < num_results ||
221 	num_values % num_results != 0
222 	)
223 	return_error(gs_error_invalidfont);
224     base = csp - 1 - num_values;
225     deltas = base + num_results - 1;
226     for (j = 0; j < num_results;
227 	 j++, base++, deltas += k1
228 	 )
229 	for (i = 1; i <= k1; i++)
230 	    *base += (fixed)(deltas[i] *
231 		pdata->WeightVector.values[i]);
232     pcis->ignore_pops = num_results;
233     return num_values - num_results + 2;
234 }
235 
236 /*
237  * Handle a seac.  Do the base character now; when it finishes (detected
238  * in endchar), do the accent.  Note that we pass only 4 operands on the
239  * stack, and pass asb separately.
240  */
241 int
gs_type1_seac(gs_type1_state * pcis,const fixed * cstack,fixed asb,ip_state_t * ipsp)242 gs_type1_seac(gs_type1_state * pcis, const fixed * cstack, fixed asb,
243 	      ip_state_t * ipsp)
244 {
245     gs_font_type1 *pfont = pcis->pfont;
246     gs_glyph_data_t bgdata;
247     gs_const_string gstr;
248     int code;
249 
250     /* Save away all the operands. */
251     pcis->seac_accent = fixed2int_var(cstack[3]);
252     pcis->save_asb = asb;
253     pcis->save_lsb = pcis->lsb;
254     pcis->save_adxy.x = cstack[0];
255     pcis->save_adxy.y = cstack[1];
256     pcis->os_count = 0;		/* clear */
257     /* Ask the caller to provide the base character's CharString. */
258     code = pfont->data.procs.seac_data
259 	(pfont, fixed2int_var(cstack[2]), NULL, &gstr, &bgdata);
260     if (code < 0)
261 	return code;
262     /* Continue with the supplied string. */
263     ipsp->cs_data = bgdata;
264     return 0;
265 }
266 
267 /*
268  * Handle the end of a character.  Return 0 if this is really the end of a
269  * character, or 1 if we still have to process the accent of a seac.
270  * In the latter case, the interpreter control stack has been set up to
271  * point to the start of the accent's CharString; the caller must
272  * also set ptx/y to pcis->position.x/y.
273  */
274 int
gs_type1_endchar(gs_type1_state * pcis)275 gs_type1_endchar(gs_type1_state * pcis)
276 {
277     gs_imager_state *pis = pcis->pis;
278 
279     if (pcis->seac_accent >= 0) {	/* We just finished the base character of a seac. */
280 	/* Do the accent. */
281 	gs_font_type1 *pfont = pcis->pfont;
282 	gs_glyph_data_t agdata;
283 	int achar = pcis->seac_accent;
284 	gs_const_string gstr;
285 	int code;
286 
287 	agdata.memory = pfont->memory;
288 	pcis->seac_accent = -1;
289 	/* Reset the coordinate system origin */
290 	pcis->asb_diff = pcis->save_asb - pcis->save_lsb.x;
291 	pcis->adxy = pcis->save_adxy;
292 	pcis->os_count = 0;	/* clear */
293 	/* Clear the ipstack, in case the base character */
294 	/* ended inside a subroutine. */
295 	pcis->ips_count = 1;
296 	/* Ask the caller to provide the accent's CharString. */
297 	code = pfont->data.procs.seac_data(pfont, achar, NULL, &gstr, &agdata);
298 	if (code == gs_error_undefined) {
299 	    /*
300 	     * The font is missing the accent's CharString (due to
301 	     * bad subsetting).  Just end drawing here without error.
302 	     * This is like Acrobat Reader behaves.
303 	     */
304 	    char buf0[gs_font_name_max + 1], buf1[30];
305 	    int l0 = min(pcis->pfont->font_name.size, sizeof(buf0) - 1);
306 	    int l1 = min(gstr.size, sizeof(buf1) - 1);
307 
308 	    memcpy(buf0, pcis->pfont->font_name.chars, l0);
309 	    buf0[l0] = 0;
310 	    memcpy(buf1, gstr.data, l1);
311 	    buf1[l1] = 0;
312 	    eprintf2("The font '%s' misses the glyph '%s' . Continue skipping the glyph.", buf0, buf1);
313 	    return 0;
314 	}
315 	if (code < 0)
316 	    return code;
317 	/* Continue with the supplied string. */
318 	pcis->ips_count = 1;
319 	pcis->ipstack[0].cs_data = agdata;
320 	return 1;
321     }
322     if (pcis->pfont->PaintType == 0)
323 	pis->fill_adjust.x = pis->fill_adjust.y = -1;
324     /* Set the flatness for curve rendering. */
325     if (!pcis->no_grid_fitting)
326 	gs_imager_setflat(pis, pcis->flatness);
327     return 0;
328 }
329 
330 /* Get the metrics (l.s.b. and width) from the Type 1 interpreter. */
331 void
type1_cis_get_metrics(const gs_type1_state * pcis,double psbw[4])332 type1_cis_get_metrics(const gs_type1_state * pcis, double psbw[4])
333 {
334     psbw[0] = fixed2float(pcis->lsb.x);
335     psbw[1] = fixed2float(pcis->lsb.y);
336     psbw[2] = fixed2float(pcis->width.x);
337     psbw[3] = fixed2float(pcis->width.y);
338 }
339 
340 /* ------ Font procedures ------ */
341 
342 
343 /*
344  * If a Type 1 character is defined with 'seac', store the character codes
345  * in chars[0] and chars[1] and return 1; otherwise, return 0 or <0.
346  * This is exported only for the benefit of font copying.
347  */
348 int
gs_type1_piece_codes(gs_font_type1 * pfont,const gs_glyph_data_t * pgd,gs_char * chars)349 gs_type1_piece_codes(/*const*/ gs_font_type1 *pfont,
350 		     const gs_glyph_data_t *pgd, gs_char *chars)
351 {
352     gs_type1_data *const pdata = &pfont->data;
353     /*
354      * Decode the CharString looking for seac.  We have to process
355      * callsubr, callothersubr, and return operators, but if we see
356      * any other operators other than [h]sbw, pop, hint operators,
357      * or endchar, we can return immediately.  We have to include
358      * endchar because it is an (undocumented) equivalent for seac
359      * in Type 2 CharStrings: see the cx_endchar case in
360      * gs_type2_interpret in gstype2.c.
361      *
362      * It's really unfortunate that we have to duplicate so much parsing
363      * code, but factoring out the parser from the interpreter would
364      * involve more restructuring than we're prepared to do right now.
365      */
366     bool encrypted = pdata->lenIV >= 0;
367     fixed cstack[ostack_size];
368     fixed *csp;
369     ip_state_t ipstack[ipstack_size + 1];
370     ip_state_t *ipsp = &ipstack[0];
371     const byte *cip;
372     crypt_state state;
373     int c;
374     int code;
375 
376     CLEAR_CSTACK(cstack, csp);
377     cip = pgd->bits.data;
378  call:
379     state = crypt_charstring_seed;
380     if (encrypted) {
381 	int skip = pdata->lenIV;
382 
383 	/* Skip initial random bytes */
384 	for (; skip > 0; ++cip, --skip)
385 	    decrypt_skip_next(*cip, state);
386     }
387  top:
388     for (;;) {
389 	uint c0 = *cip++;
390 
391 	charstring_next(c0, state, c, encrypted);
392 	if (c >= c_num1) {
393 	    /* This is a number, decode it and push it on the stack. */
394 	    if (c < c_pos2_0) {	/* 1-byte number */
395 		decode_push_num1(csp, cstack, c);
396 	    } else if (c < cx_num4) {	/* 2-byte number */
397 		decode_push_num2(csp, cstack, c, cip, state, encrypted);
398 	    } else if (c == cx_num4) {	/* 4-byte number */
399 		long lw;
400 
401 		decode_num4(lw, cip, state, encrypted);
402 		CS_CHECK_PUSH(csp, cstack);
403 		*++csp = int2fixed(lw);
404 	    } else		/* not possible */
405 		return_error(gs_error_invalidfont);
406 	    continue;
407 	}
408 #define cnext CLEAR_CSTACK(cstack, csp); goto top
409 	switch ((char_command) c) {
410 	default:
411 	    goto out;
412 	case c_callsubr:
413 	    c = fixed2int_var(*csp) + pdata->subroutineNumberBias;
414 	    code = pdata->procs.subr_data
415 		(pfont, c, false, &ipsp[1].cs_data);
416 	    if (code < 0)
417 		return_error(code);
418 	    --csp;
419 	    ipsp->ip = cip, ipsp->dstate = state;
420 	    ++ipsp;
421 	    cip = ipsp->cs_data.bits.data;
422 	    goto call;
423 	case c_return:
424 	    gs_glyph_data_free(&ipsp->cs_data, "gs_type1_piece_codes");
425 	    --ipsp;
426 	    cip = ipsp->ip, state = ipsp->dstate;
427 	    goto top;
428 	case cx_hstem:
429 	case cx_vstem:
430 	case c1_hsbw:
431 	    cnext;
432 	case cx_endchar:
433 	    if (csp < cstack + 3)
434 		goto out;	/* not seac */
435 	do_seac:
436 	    /* This is the payoff for all this code! */
437 	    chars[0] = fixed2int(csp[-1]);
438 	    chars[1] = fixed2int(csp[0]);
439 	    return 1;
440 	case cx_escape:
441 	    charstring_next(*cip, state, c, encrypted);
442 	    ++cip;
443 	    switch ((char1_extended_command) c) {
444 	    default:
445 		goto out;
446 	    case ce1_vstem3:
447 	    case ce1_hstem3:
448 	    case ce1_sbw:
449 		cnext;
450 	    case ce1_pop:
451 		/*
452 		 * pop must do nothing, since it is used after
453 		 * subr# 1 3 callothersubr.
454 		 */
455 		goto top;
456 	    case ce1_seac:
457 		goto do_seac;
458 	    case ce1_callothersubr:
459 		switch (fixed2int_var(*csp)) {
460 		default:
461 		    goto out;
462 		case 3:
463 		    csp -= 2;
464 		    goto top;
465 		case 12:
466 		case 13:
467 		case 14:
468 		case 15:
469 		case 16:
470 		case 17:
471 		case 18:
472 		    cnext;
473 		}
474 	    }
475 	}
476 #undef cnext
477     }
478  out:
479     return 0;
480 }
481 
482 /*
483  * Get PIECES and/or NUM_PIECES of a Type 1 glyph.  Sets info->num_pieces
484  * and/or stores into info->pieces.  Updates info->members.  This is a
485  * single-use procedure broken out only for readability.
486  */
487 private int
gs_type1_glyph_pieces(gs_font_type1 * pfont,const gs_glyph_data_t * pgd,int members,gs_glyph_info_t * info)488 gs_type1_glyph_pieces(gs_font_type1 *pfont, const gs_glyph_data_t *pgd,
489 		      int members, gs_glyph_info_t *info)
490 {
491     gs_char chars[2];
492     gs_glyph glyphs[2];
493     int code = gs_type1_piece_codes(pfont, pgd, chars);
494     gs_type1_data *const pdata = &pfont->data;
495     gs_glyph *pieces =
496 	(members & GLYPH_INFO_PIECES ? info->pieces : glyphs);
497     gs_const_string gstr;
498     int acode, bcode;
499 
500     info->num_pieces = 0;	/* default */
501     if (code <= 0)		/* no seac, possibly error */
502 	return code;
503     bcode = pdata->procs.seac_data(pfont, chars[0], &pieces[0], &gstr, NULL);
504     acode = pdata->procs.seac_data(pfont, chars[1], &pieces[1], &gstr, NULL);
505     code = (bcode < 0 ? bcode : acode);
506     info->num_pieces = 2;
507     return code;
508 }
509 
510 int
gs_type1_glyph_info(gs_font * font,gs_glyph glyph,const gs_matrix * pmat,int members,gs_glyph_info_t * info)511 gs_type1_glyph_info(gs_font *font, gs_glyph glyph, const gs_matrix *pmat,
512 		    int members, gs_glyph_info_t *info)
513 {
514     gs_font_type1 *const pfont = (gs_font_type1 *)font;
515     gs_type1_data *const pdata = &pfont->data;
516     int wmode = ((members & GLYPH_INFO_WIDTH1) != 0);
517     int piece_members = members & (GLYPH_INFO_NUM_PIECES | GLYPH_INFO_PIECES);
518     int width_members = (members & ((GLYPH_INFO_WIDTH0 << wmode) | (GLYPH_INFO_VVECTOR0 << wmode)));
519     int default_members = members & ~(piece_members | GLYPH_INFO_WIDTHS |
520 				     GLYPH_INFO_VVECTOR0 | GLYPH_INFO_VVECTOR1 |
521 				     GLYPH_INFO_OUTLINE_WIDTHS);
522     int code = 0;
523     gs_glyph_data_t gdata;
524 
525     if (default_members) {
526 	code = gs_default_glyph_info(font, glyph, pmat, default_members, info);
527 
528 	if (code < 0)
529 	    return code;
530     } else
531 	info->members = 0;
532 
533     if (default_members == members)
534 	return code;		/* all done */
535 
536     gdata.memory = pfont->memory;
537     if ((code = pdata->procs.glyph_data(pfont, glyph, &gdata)) < 0)
538 	return code;		/* non-existent glyph */
539 
540     if (piece_members) {
541 	code = gs_type1_glyph_pieces(pfont, &gdata, members, info);
542 	if (code < 0)
543 	    return code;
544 	info->members |= piece_members;
545     }
546 
547     if (width_members) {
548 	/*
549 	 * Interpret the CharString until we get to the [h]sbw.
550 	 */
551 	gs_imager_state gis;
552 	gs_type1_state cis;
553 	int value;
554 
555 	/* Initialize just enough of the imager state. */
556 	if (pmat)
557 	    gs_matrix_fixed_from_matrix(&gis.ctm, pmat);
558 	else {
559 	    gs_matrix imat;
560 
561 	    gs_make_identity(&imat);
562 	    gs_matrix_fixed_from_matrix(&gis.ctm, &imat);
563 	}
564 	gis.flatness = 0;
565 	code = gs_type1_interp_init(&cis, &gis, NULL /* no path needed */,
566 				    NULL, NULL, true, 0, pfont);
567 	if (code < 0)
568 	    return code;
569 	cis.no_grid_fitting = true;
570 	code = pdata->interpret(&cis, &gdata, &value);
571 	switch (code) {
572 	case 0:		/* done with no [h]sbw, error */
573 	    code = gs_note_error(gs_error_invalidfont);
574 	default:		/* code < 0, error */
575 	    return code;
576 	case type1_result_callothersubr:	/* unknown OtherSubr */
577 	    return_error(gs_error_rangecheck); /* can't handle it */
578 	case type1_result_sbw:
579 	    info->width[wmode].x = fixed2float(cis.width.x);
580 	    info->width[wmode].y = fixed2float(cis.width.y);
581 	    info->v.x = fixed2float(cis.lsb.x);
582 	    info->v.y = fixed2float(cis.lsb.y);
583 	    break;
584 	}
585 	info->members |= width_members | (GLYPH_INFO_VVECTOR0 << wmode);
586     }
587 
588     gs_glyph_data_free(&gdata, "gs_type1_glyph_info");
589     return code;
590 }
591 
592 /* Get font parent (a Type 9 font). */
593 const gs_font_base *
gs_font_parent(const gs_font_base * pbfont)594 gs_font_parent(const gs_font_base *pbfont)
595 {
596     if (pbfont->FontType == ft_encrypted || pbfont->FontType == ft_encrypted2) {
597 	const gs_font_type1 *pfont1 = (const gs_font_type1 *)pbfont;
598 
599 	if (pfont1->data.parent != NULL)
600 	    return pfont1->data.parent;
601     }
602     return pbfont;
603 }
604