xref: /plan9-contrib/sys/src/cmd/gs/src/gdevpsfx.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
13ff48bf5SDavid du Colombier /* Copyright (C) 2000 Aladdin Enterprises.  All rights reserved.
23ff48bf5SDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
53ff48bf5SDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
93ff48bf5SDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
153ff48bf5SDavid du Colombier */
163ff48bf5SDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gdevpsfx.c,v 1.25 2005/07/30 02:39:45 alexcher Exp $ */
183ff48bf5SDavid du Colombier /* Convert Type 1 Charstrings to Type 2 */
193ff48bf5SDavid du Colombier #include "math_.h"
203ff48bf5SDavid du Colombier #include "memory_.h"
213ff48bf5SDavid du Colombier #include "gx.h"
223ff48bf5SDavid du Colombier #include "gserrors.h"
233ff48bf5SDavid du Colombier #include "gxfixed.h"
243ff48bf5SDavid du Colombier #include "gxmatrix.h"		/* for gsfont.h */
253ff48bf5SDavid du Colombier #include "gxfont.h"
263ff48bf5SDavid du Colombier #include "gxfont1.h"
273ff48bf5SDavid du Colombier #include "gxtype1.h"
283ff48bf5SDavid du Colombier #include "stream.h"
293ff48bf5SDavid du Colombier #include "gdevpsf.h"
303ff48bf5SDavid du Colombier 
313ff48bf5SDavid du Colombier /* ------ Type 1 Charstring parsing ------ */
323ff48bf5SDavid du Colombier 
333ff48bf5SDavid du Colombier /*
343ff48bf5SDavid du Colombier  * The parsing code handles numbers on its own; it reports callsubr and
353ff48bf5SDavid du Colombier  * return operators to the caller, but also executes them.
363ff48bf5SDavid du Colombier  *
373ff48bf5SDavid du Colombier  * Only the following elements of the Type 1 state are used:
383ff48bf5SDavid du Colombier  *	ostack, os_count, ipstack, ips_count
393ff48bf5SDavid du Colombier  */
403ff48bf5SDavid du Colombier 
413ff48bf5SDavid du Colombier #define CE_OFFSET 32		/* offset for extended opcodes */
423ff48bf5SDavid du Colombier 
43*593dc095SDavid du Colombier typedef struct {
44*593dc095SDavid du Colombier     fixed v0, v1;		/* coordinates */
45*593dc095SDavid du Colombier     ushort index;		/* sequential index of hint */
46*593dc095SDavid du Colombier } cv_stem_hint;
47*593dc095SDavid du Colombier typedef struct {
48*593dc095SDavid du Colombier     int count;
49*593dc095SDavid du Colombier     int current;		/* cache cursor for search */
50*593dc095SDavid du Colombier     /*
51*593dc095SDavid du Colombier      * For dotsection and Type 1 Charstring hint replacement,
52*593dc095SDavid du Colombier      * we store active hints at the bottom of the table, and
53*593dc095SDavid du Colombier      * replaced hints at the top.
54*593dc095SDavid du Colombier      */
55*593dc095SDavid du Colombier     int replaced_count;		/* # of replaced hints at top */
56*593dc095SDavid du Colombier     cv_stem_hint data[max_total_stem_hints];
57*593dc095SDavid du Colombier } cv_stem_hint_table;
58*593dc095SDavid du Colombier 
593ff48bf5SDavid du Colombier /* Skip over the initial bytes in a Charstring, if any. */
603ff48bf5SDavid du Colombier private void
skip_iv(gs_type1_state * pcis)613ff48bf5SDavid du Colombier skip_iv(gs_type1_state *pcis)
623ff48bf5SDavid du Colombier {
633ff48bf5SDavid du Colombier     int skip = pcis->pfont->data.lenIV;
643ff48bf5SDavid du Colombier     ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1];
65*593dc095SDavid du Colombier     const byte *cip = ipsp->cs_data.bits.data;
663ff48bf5SDavid du Colombier     crypt_state state = crypt_charstring_seed;
673ff48bf5SDavid du Colombier 
683ff48bf5SDavid du Colombier     for (; skip > 0; ++cip, --skip)
693ff48bf5SDavid du Colombier 	decrypt_skip_next(*cip, state);
703ff48bf5SDavid du Colombier     ipsp->ip = cip;
713ff48bf5SDavid du Colombier     ipsp->dstate = state;
723ff48bf5SDavid du Colombier }
733ff48bf5SDavid du Colombier 
743ff48bf5SDavid du Colombier /*
753ff48bf5SDavid du Colombier  * Set up for parsing a Type 1 Charstring.
763ff48bf5SDavid du Colombier  *
773ff48bf5SDavid du Colombier  * Only uses the following elements of *pfont:
783ff48bf5SDavid du Colombier  *	data.lenIV
793ff48bf5SDavid du Colombier  */
803ff48bf5SDavid du Colombier private void
type1_next_init(gs_type1_state * pcis,const gs_glyph_data_t * pgd,gs_font_type1 * pfont)81*593dc095SDavid du Colombier type1_next_init(gs_type1_state *pcis, const gs_glyph_data_t *pgd,
823ff48bf5SDavid du Colombier 		gs_font_type1 *pfont)
833ff48bf5SDavid du Colombier {
84*593dc095SDavid du Colombier     gs_type1_interp_init(pcis, NULL, NULL, NULL, NULL, false, 0, pfont);
853ff48bf5SDavid du Colombier     pcis->flex_count = flex_max;
86*593dc095SDavid du Colombier     pcis->ipstack[0].cs_data = *pgd;
873ff48bf5SDavid du Colombier     skip_iv(pcis);
883ff48bf5SDavid du Colombier }
893ff48bf5SDavid du Colombier 
903ff48bf5SDavid du Colombier /* Clear the Type 1 operand stack. */
913ff48bf5SDavid du Colombier inline private void
type1_clear(gs_type1_state * pcis)923ff48bf5SDavid du Colombier type1_clear(gs_type1_state *pcis)
933ff48bf5SDavid du Colombier {
943ff48bf5SDavid du Colombier     pcis->os_count = 0;
953ff48bf5SDavid du Colombier }
963ff48bf5SDavid du Colombier 
973ff48bf5SDavid du Colombier /* Execute a callsubr. */
983ff48bf5SDavid du Colombier private int
type1_callsubr(gs_type1_state * pcis,int index)993ff48bf5SDavid du Colombier type1_callsubr(gs_type1_state *pcis, int index)
1003ff48bf5SDavid du Colombier {
1013ff48bf5SDavid du Colombier     gs_font_type1 *pfont = pcis->pfont;
1023ff48bf5SDavid du Colombier     ip_state_t *ipsp1 = &pcis->ipstack[pcis->ips_count];
1033ff48bf5SDavid du Colombier     int code = pfont->data.procs.subr_data(pfont, index, false,
104*593dc095SDavid du Colombier 					   &ipsp1->cs_data);
1053ff48bf5SDavid du Colombier 
1063ff48bf5SDavid du Colombier     if (code < 0)
1073ff48bf5SDavid du Colombier 	return_error(code);
1083ff48bf5SDavid du Colombier     pcis->ips_count++;
1093ff48bf5SDavid du Colombier     skip_iv(pcis);
1103ff48bf5SDavid du Colombier     return code;
1113ff48bf5SDavid du Colombier }
1123ff48bf5SDavid du Colombier 
1133ff48bf5SDavid du Colombier /* Add 1 or 3 stem hints. */
1143ff48bf5SDavid du Colombier private int
type1_stem1(gs_type1_state * pcis,cv_stem_hint_table * psht,const fixed * pv,fixed lsb,byte * active_hints)115*593dc095SDavid du Colombier type1_stem1(gs_type1_state *pcis, cv_stem_hint_table *psht, const fixed *pv,
116*593dc095SDavid du Colombier 	    fixed lsb, byte *active_hints)
1173ff48bf5SDavid du Colombier {
118*593dc095SDavid du Colombier     fixed v0 = pv[0] + lsb, v1 = v0 + pv[1];
119*593dc095SDavid du Colombier     cv_stem_hint *bot = &psht->data[0];
120*593dc095SDavid du Colombier     cv_stem_hint *orig_top = bot + psht->count;
121*593dc095SDavid du Colombier     cv_stem_hint *top = orig_top;
1223ff48bf5SDavid du Colombier 
123*593dc095SDavid du Colombier     if (psht->count >= max_total_stem_hints)
1243ff48bf5SDavid du Colombier 	return_error(gs_error_limitcheck);
1253ff48bf5SDavid du Colombier     while (top > bot &&
1263ff48bf5SDavid du Colombier 	   (v0 < top[-1].v0 || (v0 == top[-1].v0 && v1 < top[-1].v1))
1273ff48bf5SDavid du Colombier 	   ) {
1283ff48bf5SDavid du Colombier 	*top = top[-1];
1293ff48bf5SDavid du Colombier 	top--;
1303ff48bf5SDavid du Colombier     }
1313ff48bf5SDavid du Colombier     if (top > bot && v0 == top[-1].v0 && v1 == top[-1].v1) {
1323ff48bf5SDavid du Colombier 	/* Duplicate hint, don't add it. */
1333ff48bf5SDavid du Colombier 	memmove(top, top + 1, (char *)orig_top - (char *)top);
1343ff48bf5SDavid du Colombier 	if (active_hints) {
1353ff48bf5SDavid du Colombier 	    uint index = top[-1].index;
1363ff48bf5SDavid du Colombier 
1373ff48bf5SDavid du Colombier 	    active_hints[index >> 3] |= 0x80 >> (index & 7);
1383ff48bf5SDavid du Colombier 	}
1393ff48bf5SDavid du Colombier 	return 0;
1403ff48bf5SDavid du Colombier     }
1413ff48bf5SDavid du Colombier     top->v0 = v0;
1423ff48bf5SDavid du Colombier     top->v1 = v1;
1433ff48bf5SDavid du Colombier     psht->count++;
1443ff48bf5SDavid du Colombier     return 0;
1453ff48bf5SDavid du Colombier }
1463ff48bf5SDavid du Colombier private void
type1_stem3(gs_type1_state * pcis,cv_stem_hint_table * psht,const fixed * pv3,fixed lsb,byte * active_hints)147*593dc095SDavid du Colombier type1_stem3(gs_type1_state *pcis, cv_stem_hint_table *psht, const fixed *pv3,
148*593dc095SDavid du Colombier 	    fixed lsb, byte *active_hints)
1493ff48bf5SDavid du Colombier {
150*593dc095SDavid du Colombier     type1_stem1(pcis, psht, pv3, lsb, active_hints);
151*593dc095SDavid du Colombier     type1_stem1(pcis, psht, pv3 + 2, lsb, active_hints);
152*593dc095SDavid du Colombier     type1_stem1(pcis, psht, pv3 + 4, lsb, active_hints);
1533ff48bf5SDavid du Colombier }
1543ff48bf5SDavid du Colombier 
1553ff48bf5SDavid du Colombier /*
1563ff48bf5SDavid du Colombier  * Get the next operator from a Type 1 Charstring.  This procedure handles
1573ff48bf5SDavid du Colombier  * numbers, div, blend, pop, and callsubr/return.
1583ff48bf5SDavid du Colombier  */
1593ff48bf5SDavid du Colombier private int
type1_next(gs_type1_state * pcis)1603ff48bf5SDavid du Colombier type1_next(gs_type1_state *pcis)
1613ff48bf5SDavid du Colombier {
1623ff48bf5SDavid du Colombier     ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1];
163*593dc095SDavid du Colombier     const byte *cip, *cipe;
1643ff48bf5SDavid du Colombier     crypt_state state;
1653ff48bf5SDavid du Colombier #define CLEAR (csp = pcis->ostack - 1)
1663ff48bf5SDavid du Colombier     fixed *csp = &pcis->ostack[pcis->os_count - 1];
1673ff48bf5SDavid du Colombier     const bool encrypted = pcis->pfont->data.lenIV >= 0;
168*593dc095SDavid du Colombier     int c, code, num_results, c0;
1693ff48bf5SDavid du Colombier 
1703ff48bf5SDavid du Colombier  load:
1713ff48bf5SDavid du Colombier     cip = ipsp->ip;
172*593dc095SDavid du Colombier     cipe = ipsp->cs_data.bits.data + ipsp->cs_data.bits.size;
1733ff48bf5SDavid du Colombier     state = ipsp->dstate;
1743ff48bf5SDavid du Colombier     for (;;) {
175*593dc095SDavid du Colombier         if (cip >= cipe)
176*593dc095SDavid du Colombier 	    return_error(gs_error_invalidfont);
177*593dc095SDavid du Colombier 	c0 = *cip++;
1783ff48bf5SDavid du Colombier 	charstring_next(c0, state, c, encrypted);
1793ff48bf5SDavid du Colombier 	if (c >= c_num1) {
1803ff48bf5SDavid du Colombier 	    /* This is a number, decode it and push it on the stack. */
1813ff48bf5SDavid du Colombier 	    if (c < c_pos2_0) {	/* 1-byte number */
182*593dc095SDavid du Colombier 		decode_push_num1(csp, pcis->ostack, c);
1833ff48bf5SDavid du Colombier 	    } else if (c < cx_num4) {	/* 2-byte number */
184*593dc095SDavid du Colombier 		decode_push_num2(csp, pcis->ostack, c, cip, state, encrypted);
1853ff48bf5SDavid du Colombier 	    } else if (c == cx_num4) {	/* 4-byte number */
1863ff48bf5SDavid du Colombier 		long lw;
1873ff48bf5SDavid du Colombier 
1883ff48bf5SDavid du Colombier 		decode_num4(lw, cip, state, encrypted);
189*593dc095SDavid du Colombier 		CS_CHECK_PUSH(csp, pcis->ostack);
1903ff48bf5SDavid du Colombier 		*++csp = int2fixed(lw);
1913ff48bf5SDavid du Colombier 	    } else		/* not possible */
1923ff48bf5SDavid du Colombier 		return_error(gs_error_invalidfont);
1933ff48bf5SDavid du Colombier 	    continue;
1943ff48bf5SDavid du Colombier 	}
1953ff48bf5SDavid du Colombier #ifdef DEBUG
1963ff48bf5SDavid du Colombier 	if (gs_debug_c('1')) {
1973ff48bf5SDavid du Colombier 	    const fixed *p;
1983ff48bf5SDavid du Colombier 
1993ff48bf5SDavid du Colombier 	    for (p = pcis->ostack; p <= csp; ++p)
2003ff48bf5SDavid du Colombier 		dprintf1(" %g", fixed2float(*p));
2013ff48bf5SDavid du Colombier 	    if (c == cx_escape) {
2023ff48bf5SDavid du Colombier 		crypt_state cstate = state;
2033ff48bf5SDavid du Colombier 		int cn;
2043ff48bf5SDavid du Colombier 
2053ff48bf5SDavid du Colombier 		charstring_next(*cip, cstate, cn, encrypted);
2063ff48bf5SDavid du Colombier 		dprintf1(" [*%d]\n", cn);
2073ff48bf5SDavid du Colombier 	    } else
2083ff48bf5SDavid du Colombier 		dprintf1(" [%d]\n", c);
2093ff48bf5SDavid du Colombier 	}
2103ff48bf5SDavid du Colombier #endif
2113ff48bf5SDavid du Colombier 	switch ((char_command) c) {
2123ff48bf5SDavid du Colombier 	default:
2133ff48bf5SDavid du Colombier 	    break;
2143ff48bf5SDavid du Colombier 	case c_undef0:
2153ff48bf5SDavid du Colombier 	case c_undef2:
2163ff48bf5SDavid du Colombier 	case c_undef17:
2173ff48bf5SDavid du Colombier 	    return_error(gs_error_invalidfont);
2183ff48bf5SDavid du Colombier 	case c_callsubr:
219*593dc095SDavid du Colombier 	    code = type1_callsubr(pcis, fixed2int_var(*csp) +
220*593dc095SDavid du Colombier 				  pcis->pfont->data.subroutineNumberBias);
2213ff48bf5SDavid du Colombier 	    if (code < 0)
2223ff48bf5SDavid du Colombier 		return_error(code);
2233ff48bf5SDavid du Colombier 	    ipsp->ip = cip, ipsp->dstate = state;
2243ff48bf5SDavid du Colombier 	    --csp;
2253ff48bf5SDavid du Colombier 	    ++ipsp;
2263ff48bf5SDavid du Colombier 	    goto load;
2273ff48bf5SDavid du Colombier 	case c_return:
228*593dc095SDavid du Colombier 	    gs_glyph_data_free(&ipsp->cs_data, "type1_next");
2293ff48bf5SDavid du Colombier 	    pcis->ips_count--;
2303ff48bf5SDavid du Colombier 	    --ipsp;
2313ff48bf5SDavid du Colombier 	    goto load;
232*593dc095SDavid du Colombier 	case c_undoc15:
233*593dc095SDavid du Colombier 	    /* See gstype1.h for information on this opcode. */
234*593dc095SDavid du Colombier 	    CLEAR;
235*593dc095SDavid du Colombier 	    continue;
2363ff48bf5SDavid du Colombier 	case cx_escape:
2373ff48bf5SDavid du Colombier 	    charstring_next(*cip, state, c, encrypted);
2383ff48bf5SDavid du Colombier 	    ++cip;
2393ff48bf5SDavid du Colombier 	    switch ((char1_extended_command) c) {
2403ff48bf5SDavid du Colombier 	    default:
2413ff48bf5SDavid du Colombier 		c += CE_OFFSET;
2423ff48bf5SDavid du Colombier 		break;
2433ff48bf5SDavid du Colombier 	    case ce1_div:
2443ff48bf5SDavid du Colombier 		csp[-1] = float2fixed((double)csp[-1] / (double)*csp);
2453ff48bf5SDavid du Colombier 		--csp;
2463ff48bf5SDavid du Colombier 		continue;
2473ff48bf5SDavid du Colombier 	    case ce1_undoc15:	/* see gstype1.h */
2483ff48bf5SDavid du Colombier 		CLEAR;
2493ff48bf5SDavid du Colombier 		continue;
2503ff48bf5SDavid du Colombier 	    case ce1_callothersubr:
2513ff48bf5SDavid du Colombier 		switch (fixed2int_var(*csp)) {
2523ff48bf5SDavid du Colombier 		case 0:
2533ff48bf5SDavid du Colombier 		    pcis->ignore_pops = 2;
2543ff48bf5SDavid du Colombier 		    break;	/* pass to caller */
2553ff48bf5SDavid du Colombier 		case 3:
2563ff48bf5SDavid du Colombier 		    pcis->ignore_pops = 1;
2573ff48bf5SDavid du Colombier 		    break;	/* pass to caller */
2583ff48bf5SDavid du Colombier 		case 14:
2593ff48bf5SDavid du Colombier 		    num_results = 1; goto blend;
2603ff48bf5SDavid du Colombier 		case 15:
2613ff48bf5SDavid du Colombier 		    num_results = 2; goto blend;
2623ff48bf5SDavid du Colombier 		case 16:
2633ff48bf5SDavid du Colombier 		    num_results = 3; goto blend;
2643ff48bf5SDavid du Colombier 		case 17:
2653ff48bf5SDavid du Colombier 		    num_results = 4; goto blend;
2663ff48bf5SDavid du Colombier 		case 18:
2673ff48bf5SDavid du Colombier 		    num_results = 6;
2683ff48bf5SDavid du Colombier 		blend:
2693ff48bf5SDavid du Colombier 		    code = gs_type1_blend(pcis, csp, num_results);
2703ff48bf5SDavid du Colombier 		    if (code < 0)
2713ff48bf5SDavid du Colombier 			return code;
2723ff48bf5SDavid du Colombier 		    csp -= code;
2733ff48bf5SDavid du Colombier 		    continue;
2743ff48bf5SDavid du Colombier 		default:
2753ff48bf5SDavid du Colombier 		    break;	/* pass to caller */
2763ff48bf5SDavid du Colombier 		}
2773ff48bf5SDavid du Colombier 		break;
2783ff48bf5SDavid du Colombier 	    case ce1_pop:
2793ff48bf5SDavid du Colombier 		if (pcis->ignore_pops != 0) {
2803ff48bf5SDavid du Colombier 		    pcis->ignore_pops--;
2813ff48bf5SDavid du Colombier 		    continue;
2823ff48bf5SDavid du Colombier 		}
2833ff48bf5SDavid du Colombier 		return_error(gs_error_rangecheck);
2843ff48bf5SDavid du Colombier 	    }
2853ff48bf5SDavid du Colombier 	    break;
2863ff48bf5SDavid du Colombier 	}
2873ff48bf5SDavid du Colombier 	break;
2883ff48bf5SDavid du Colombier     }
2893ff48bf5SDavid du Colombier     ipsp->ip = cip, ipsp->dstate = state;
2903ff48bf5SDavid du Colombier     pcis->ips_count = ipsp + 1 - &pcis->ipstack[0];
2913ff48bf5SDavid du Colombier     pcis->os_count = csp + 1 - &pcis->ostack[0];
2923ff48bf5SDavid du Colombier     return c;
2933ff48bf5SDavid du Colombier }
2943ff48bf5SDavid du Colombier 
2953ff48bf5SDavid du Colombier /* ------ Output ------ */
2963ff48bf5SDavid du Colombier 
2973ff48bf5SDavid du Colombier /* Put 2 or 4 bytes on a stream (big-endian). */
2983ff48bf5SDavid du Colombier private void
sputc2(stream * s,int i)2993ff48bf5SDavid du Colombier sputc2(stream *s, int i)
3003ff48bf5SDavid du Colombier {
3013ff48bf5SDavid du Colombier     sputc(s, (byte)(i >> 8));
3023ff48bf5SDavid du Colombier     sputc(s, (byte)i);
3033ff48bf5SDavid du Colombier }
3043ff48bf5SDavid du Colombier private void
sputc4(stream * s,int i)3053ff48bf5SDavid du Colombier sputc4(stream *s, int i)
3063ff48bf5SDavid du Colombier {
3073ff48bf5SDavid du Colombier     sputc2(s, i >> 16);
3083ff48bf5SDavid du Colombier     sputc2(s, i);
3093ff48bf5SDavid du Colombier }
3103ff48bf5SDavid du Colombier 
3113ff48bf5SDavid du Colombier /* Put a Type 2 operator on a stream. */
3123ff48bf5SDavid du Colombier private void
type2_put_op(stream * s,int op)3133ff48bf5SDavid du Colombier type2_put_op(stream *s, int op)
3143ff48bf5SDavid du Colombier {
3153ff48bf5SDavid du Colombier     if (op >= CE_OFFSET) {
3163ff48bf5SDavid du Colombier 	spputc(s, cx_escape);
317*593dc095SDavid du Colombier 	spputc(s, (byte)(op - CE_OFFSET));
3183ff48bf5SDavid du Colombier     } else
319*593dc095SDavid du Colombier 	sputc(s, (byte)op);
3203ff48bf5SDavid du Colombier }
3213ff48bf5SDavid du Colombier 
3223ff48bf5SDavid du Colombier /* Put a Type 2 number on a stream. */
3233ff48bf5SDavid du Colombier private void
type2_put_int(stream * s,int i)3243ff48bf5SDavid du Colombier type2_put_int(stream *s, int i)
3253ff48bf5SDavid du Colombier {
3263ff48bf5SDavid du Colombier     if (i >= -107 && i <= 107)
3273ff48bf5SDavid du Colombier 	sputc(s, (byte)(i + 139));
3283ff48bf5SDavid du Colombier     else if (i <= 1131 && i >= 0)
3293ff48bf5SDavid du Colombier 	sputc2(s, (c_pos2_0 << 8) + i - 108);
3303ff48bf5SDavid du Colombier     else if (i >= -1131 && i < 0)
3313ff48bf5SDavid du Colombier 	sputc2(s, (c_neg2_0 << 8) - i - 108);
3323ff48bf5SDavid du Colombier     else if (i >= -32768 && i <= 32767) {
3333ff48bf5SDavid du Colombier 	spputc(s, c2_shortint);
3343ff48bf5SDavid du Colombier 	sputc2(s, i);
3353ff48bf5SDavid du Colombier     } else {
3363ff48bf5SDavid du Colombier 	/*
3373ff48bf5SDavid du Colombier 	 * We can't represent this number directly: compute it.
3383ff48bf5SDavid du Colombier 	 * (This can be done much more efficiently in particular cases;
3393ff48bf5SDavid du Colombier 	 * we'll do this if it ever seems worthwhile.)
3403ff48bf5SDavid du Colombier 	 */
3413ff48bf5SDavid du Colombier 	type2_put_int(s, i >> 10);
3423ff48bf5SDavid du Colombier 	type2_put_int(s, 1024);
3433ff48bf5SDavid du Colombier 	type2_put_op(s, CE_OFFSET + ce2_mul);
3443ff48bf5SDavid du Colombier 	type2_put_int(s, i & 1023);
3453ff48bf5SDavid du Colombier 	type2_put_op(s, CE_OFFSET + ce2_add);
3463ff48bf5SDavid du Colombier     }
3473ff48bf5SDavid du Colombier }
3483ff48bf5SDavid du Colombier 
3493ff48bf5SDavid du Colombier /* Put a fixed value on a stream. */
3503ff48bf5SDavid du Colombier private void
type2_put_fixed(stream * s,fixed v)3513ff48bf5SDavid du Colombier type2_put_fixed(stream *s, fixed v)
3523ff48bf5SDavid du Colombier {
3533ff48bf5SDavid du Colombier     if (fixed_is_int(v))
3543ff48bf5SDavid du Colombier 	type2_put_int(s, fixed2int_var(v));
3553ff48bf5SDavid du Colombier     else if (v >= int2fixed(-32768) && v < int2fixed(32768)) {
3563ff48bf5SDavid du Colombier 	/* We can represent this as a 16:16 number. */
3573ff48bf5SDavid du Colombier 	spputc(s, cx_num4);
3583ff48bf5SDavid du Colombier 	sputc4(s, v << (16 - _fixed_shift));
3593ff48bf5SDavid du Colombier     } else {
3603ff48bf5SDavid du Colombier 	type2_put_int(s, fixed2int_var(v));
3613ff48bf5SDavid du Colombier 	type2_put_fixed(s, fixed_fraction(v));
3623ff48bf5SDavid du Colombier 	type2_put_op(s, CE_OFFSET + ce2_add);
3633ff48bf5SDavid du Colombier     }
3643ff48bf5SDavid du Colombier }
3653ff48bf5SDavid du Colombier 
3663ff48bf5SDavid du Colombier /* Put a stem hint table on a stream. */
3673ff48bf5SDavid du Colombier private void
type2_put_stems(stream * s,int os_count,const cv_stem_hint_table * psht,int op)368*593dc095SDavid du Colombier type2_put_stems(stream *s, int os_count, const cv_stem_hint_table *psht, int op)
3693ff48bf5SDavid du Colombier {
3703ff48bf5SDavid du Colombier     fixed prev = 0;
371*593dc095SDavid du Colombier     int pushed = os_count;
3723ff48bf5SDavid du Colombier     int i;
3733ff48bf5SDavid du Colombier 
3743ff48bf5SDavid du Colombier     for (i = 0; i < psht->count; ++i, pushed += 2) {
3753ff48bf5SDavid du Colombier 	fixed v0 = psht->data[i].v0;
3763ff48bf5SDavid du Colombier 	fixed v1 = psht->data[i].v1;
3773ff48bf5SDavid du Colombier 
3783ff48bf5SDavid du Colombier 	if (pushed > ostack_size - 2) {
3793ff48bf5SDavid du Colombier 	    type2_put_op(s, op);
3803ff48bf5SDavid du Colombier 	    pushed = 0;
3813ff48bf5SDavid du Colombier 	}
3823ff48bf5SDavid du Colombier 	type2_put_fixed(s, v0 - prev);
3833ff48bf5SDavid du Colombier 	type2_put_fixed(s, v1 - v0);
3843ff48bf5SDavid du Colombier 	prev = v1;
3853ff48bf5SDavid du Colombier     }
3863ff48bf5SDavid du Colombier     type2_put_op(s, op);
3873ff48bf5SDavid du Colombier }
3883ff48bf5SDavid du Colombier 
3893ff48bf5SDavid du Colombier /* Put out a hintmask command. */
3903ff48bf5SDavid du Colombier private void
type2_put_hintmask(stream * s,const byte * mask,uint size)3913ff48bf5SDavid du Colombier type2_put_hintmask(stream *s, const byte *mask, uint size)
3923ff48bf5SDavid du Colombier {
3933ff48bf5SDavid du Colombier     uint ignore;
3943ff48bf5SDavid du Colombier 
3953ff48bf5SDavid du Colombier     type2_put_op(s, c2_hintmask);
3963ff48bf5SDavid du Colombier     sputs(s, mask, size, &ignore);
3973ff48bf5SDavid du Colombier }
3983ff48bf5SDavid du Colombier 
3993ff48bf5SDavid du Colombier /* ------ Main program ------ */
4003ff48bf5SDavid du Colombier 
401*593dc095SDavid du Colombier 
4023ff48bf5SDavid du Colombier /*
4033ff48bf5SDavid du Colombier  * Convert a Type 1 Charstring to (unencrypted) Type 2.
4043ff48bf5SDavid du Colombier  * For simplicity, we expand all Subrs in-line.
4053ff48bf5SDavid du Colombier  * We still need to optimize the output using these patterns:
4063ff48bf5SDavid du Colombier  *	(vhcurveto hvcurveto)* (vhcurveto hrcurveto | vrcurveto) =>
4073ff48bf5SDavid du Colombier  *	  vhcurveto
4083ff48bf5SDavid du Colombier  *	(hvcurveto vhcurveto)* (hvcurveto vrcurveto | hrcurveto) =>
4093ff48bf5SDavid du Colombier  *	  hvcurveto
4103ff48bf5SDavid du Colombier  */
4113ff48bf5SDavid du Colombier #define MAX_STACK ostack_size
4123ff48bf5SDavid du Colombier int
psf_convert_type1_to_type2(stream * s,const gs_glyph_data_t * pgd,gs_font_type1 * pfont)413*593dc095SDavid du Colombier psf_convert_type1_to_type2(stream *s, const gs_glyph_data_t *pgd,
4143ff48bf5SDavid du Colombier 			   gs_font_type1 *pfont)
4153ff48bf5SDavid du Colombier {
4163ff48bf5SDavid du Colombier     gs_type1_state cis;
417*593dc095SDavid du Colombier     cv_stem_hint_table hstem_hints;	/* horizontal stem hints */
418*593dc095SDavid du Colombier     cv_stem_hint_table vstem_hints;	/* vertical stem hints */
4193ff48bf5SDavid du Colombier     bool first = true;
4203ff48bf5SDavid du Colombier     bool replace_hints = false;
4213ff48bf5SDavid du Colombier     bool hints_changed = false;
422*593dc095SDavid du Colombier     enum {
423*593dc095SDavid du Colombier 	dotsection_in = 0,
424*593dc095SDavid du Colombier 	dotsection_out = -1
425*593dc095SDavid du Colombier     } dotsection_flag = dotsection_out;
4263ff48bf5SDavid du Colombier     byte active_hints[(max_total_stem_hints + 7) / 8];
4273ff48bf5SDavid du Colombier     byte dot_save_hints[(max_total_stem_hints + 7) / 8];
4283ff48bf5SDavid du Colombier     uint hintmask_size;
4293ff48bf5SDavid du Colombier #define HINTS_CHANGED()\
4303ff48bf5SDavid du Colombier   BEGIN\
4313ff48bf5SDavid du Colombier     hints_changed = replace_hints;\
4323ff48bf5SDavid du Colombier     if (hints_changed)\
4333ff48bf5SDavid du Colombier 	CHECK_OP();		/* see below */\
4343ff48bf5SDavid du Colombier   END
4353ff48bf5SDavid du Colombier #define CHECK_HINTS_CHANGED()\
4363ff48bf5SDavid du Colombier   BEGIN\
4373ff48bf5SDavid du Colombier     if (hints_changed) {\
4383ff48bf5SDavid du Colombier 	type2_put_hintmask(s, active_hints, hintmask_size);\
4393ff48bf5SDavid du Colombier 	hints_changed = false;\
4403ff48bf5SDavid du Colombier     }\
4413ff48bf5SDavid du Colombier   END
4423ff48bf5SDavid du Colombier     /*
4433ff48bf5SDavid du Colombier      * In order to combine Type 1 operators, we usually delay writing
4443ff48bf5SDavid du Colombier      * out operators (but not their operands).  We must keep track of
4453ff48bf5SDavid du Colombier      * the stack depth so we don't exceed it when combining operators.
4463ff48bf5SDavid du Colombier      */
4473ff48bf5SDavid du Colombier     int depth;			/* of operands on stack */
4483ff48bf5SDavid du Colombier     int prev_op;		/* operator to write, -1 if none */
4493ff48bf5SDavid du Colombier #define CLEAR_OP()\
4503ff48bf5SDavid du Colombier   (depth = 0, prev_op = -1)
4513ff48bf5SDavid du Colombier #define CHECK_OP()\
4523ff48bf5SDavid du Colombier   BEGIN\
4533ff48bf5SDavid du Colombier     if (prev_op >= 0) {\
4543ff48bf5SDavid du Colombier 	type2_put_op(s, prev_op);\
4553ff48bf5SDavid du Colombier 	CLEAR_OP();\
4563ff48bf5SDavid du Colombier     }\
4573ff48bf5SDavid du Colombier   END
458*593dc095SDavid du Colombier     fixed mx0 = 0, my0 = 0; /* See ce1_setcurrentpoint. */
4593ff48bf5SDavid du Colombier 
460*593dc095SDavid du Colombier     /*
461*593dc095SDavid du Colombier      * Do a first pass to collect hints.  Note that we must also process
462*593dc095SDavid du Colombier      * [h]sbw, because the hint coordinates are relative to the lsb.
463*593dc095SDavid du Colombier      */
464*593dc095SDavid du Colombier     hstem_hints.count = hstem_hints.replaced_count = hstem_hints.current = 0;
465*593dc095SDavid du Colombier     vstem_hints.count = vstem_hints.replaced_count = vstem_hints.current = 0;
466*593dc095SDavid du Colombier     type1_next_init(&cis, pgd, pfont);
4673ff48bf5SDavid du Colombier     for (;;) {
4683ff48bf5SDavid du Colombier 	int c = type1_next(&cis);
4693ff48bf5SDavid du Colombier 	fixed *csp = &cis.ostack[cis.os_count - 1];
4703ff48bf5SDavid du Colombier 
4713ff48bf5SDavid du Colombier 	switch (c) {
4723ff48bf5SDavid du Colombier 	default:
4733ff48bf5SDavid du Colombier 	    if (c < 0)
4743ff48bf5SDavid du Colombier 		return c;
4753ff48bf5SDavid du Colombier 	    type1_clear(&cis);
4763ff48bf5SDavid du Colombier 	    continue;
477*593dc095SDavid du Colombier 	case c1_hsbw:
478*593dc095SDavid du Colombier 	    gs_type1_sbw(&cis, cis.ostack[0], fixed_0, cis.ostack[1], fixed_0);
479*593dc095SDavid du Colombier 	    goto clear;
4803ff48bf5SDavid du Colombier 	case cx_hstem:
481*593dc095SDavid du Colombier 	    type1_stem1(&cis, &hstem_hints, csp - 1, cis.lsb.y, NULL);
4823ff48bf5SDavid du Colombier 	    goto clear;
4833ff48bf5SDavid du Colombier 	case cx_vstem:
484*593dc095SDavid du Colombier 	    type1_stem1(&cis, &vstem_hints, csp - 1, cis.lsb.x, NULL);
485*593dc095SDavid du Colombier 	    goto clear;
486*593dc095SDavid du Colombier 	case CE_OFFSET + ce1_sbw:
487*593dc095SDavid du Colombier 	    gs_type1_sbw(&cis, cis.ostack[0], cis.ostack[1],
488*593dc095SDavid du Colombier 			 cis.ostack[2], cis.ostack[3]);
4893ff48bf5SDavid du Colombier 	    goto clear;
4903ff48bf5SDavid du Colombier 	case CE_OFFSET + ce1_vstem3:
491*593dc095SDavid du Colombier 	    type1_stem3(&cis, &vstem_hints, csp - 5, cis.lsb.x, NULL);
4923ff48bf5SDavid du Colombier 	    goto clear;
4933ff48bf5SDavid du Colombier 	case CE_OFFSET + ce1_hstem3:
494*593dc095SDavid du Colombier 	    type1_stem3(&cis, &hstem_hints, csp - 5, cis.lsb.y, NULL);
4953ff48bf5SDavid du Colombier 	clear:
4963ff48bf5SDavid du Colombier 	    type1_clear(&cis);
4973ff48bf5SDavid du Colombier 	    continue;
4983ff48bf5SDavid du Colombier 	case ce1_callothersubr:
4993ff48bf5SDavid du Colombier 	    if (*csp == int2fixed(3))
5003ff48bf5SDavid du Colombier 		replace_hints = true;
5013ff48bf5SDavid du Colombier 	    cis.os_count -= 2;
5023ff48bf5SDavid du Colombier 	    continue;
5033ff48bf5SDavid du Colombier 	case CE_OFFSET + ce1_dotsection:
5043ff48bf5SDavid du Colombier 	    replace_hints = true;
5053ff48bf5SDavid du Colombier 	    continue;
5063ff48bf5SDavid du Colombier 	case CE_OFFSET + ce1_seac:
5073ff48bf5SDavid du Colombier 	case cx_endchar:
5083ff48bf5SDavid du Colombier 	    break;
5093ff48bf5SDavid du Colombier 	}
5103ff48bf5SDavid du Colombier 	break;
5113ff48bf5SDavid du Colombier     }
5123ff48bf5SDavid du Colombier     /*
5133ff48bf5SDavid du Colombier      * Number the hints for hintmask.  We must do this even if we never
5143ff48bf5SDavid du Colombier      * replace hints, because type1_stem# uses the index to set bits in
5153ff48bf5SDavid du Colombier      * active_hints.
5163ff48bf5SDavid du Colombier      */
5173ff48bf5SDavid du Colombier     {
5183ff48bf5SDavid du Colombier 	int i;
5193ff48bf5SDavid du Colombier 
520*593dc095SDavid du Colombier 	for (i = 0; i < hstem_hints.count; ++i)
521*593dc095SDavid du Colombier 	    hstem_hints.data[i].index = i;
522*593dc095SDavid du Colombier 	for (i = 0; i < vstem_hints.count; ++i)
523*593dc095SDavid du Colombier 	    vstem_hints.data[i].index = i + hstem_hints.count;
5243ff48bf5SDavid du Colombier     }
5253ff48bf5SDavid du Colombier     if (replace_hints) {
5263ff48bf5SDavid du Colombier 	hintmask_size =
527*593dc095SDavid du Colombier 	    (hstem_hints.count + vstem_hints.count + 7) / 8;
5283ff48bf5SDavid du Colombier 	memset(active_hints, 0, hintmask_size);
5293ff48bf5SDavid du Colombier     } else
5303ff48bf5SDavid du Colombier 	hintmask_size = 0;
5313ff48bf5SDavid du Colombier 
5323ff48bf5SDavid du Colombier     /* Do a second pass to write the result. */
533*593dc095SDavid du Colombier     type1_next_init(&cis, pgd, pfont);
5343ff48bf5SDavid du Colombier     CLEAR_OP();
5353ff48bf5SDavid du Colombier     for (;;) {
5363ff48bf5SDavid du Colombier 	int c = type1_next(&cis);
5373ff48bf5SDavid du Colombier 	fixed *csp = &cis.ostack[cis.os_count - 1];
5383ff48bf5SDavid du Colombier #define POP(n)\
5393ff48bf5SDavid du Colombier   (csp -= (n), cis.os_count -= (n))
5403ff48bf5SDavid du Colombier 	int i;
5413ff48bf5SDavid du Colombier 	fixed mx, my;
5423ff48bf5SDavid du Colombier 
5433ff48bf5SDavid du Colombier 	switch (c) {
5443ff48bf5SDavid du Colombier 	default:
5453ff48bf5SDavid du Colombier 	    if (c < 0)
5463ff48bf5SDavid du Colombier 		return c;
5473ff48bf5SDavid du Colombier 	    if (c >= CE_OFFSET)
5483ff48bf5SDavid du Colombier 		return_error(gs_error_rangecheck);
5493ff48bf5SDavid du Colombier 	    /* The Type 1 use of all other operators is the same in Type 2. */
5503ff48bf5SDavid du Colombier 	copy:
5513ff48bf5SDavid du Colombier 	    CHECK_OP();
5523ff48bf5SDavid du Colombier 	    CHECK_HINTS_CHANGED();
5533ff48bf5SDavid du Colombier 	put:
5543ff48bf5SDavid du Colombier 	    for (i = 0; i < cis.os_count; ++i)
5553ff48bf5SDavid du Colombier 		type2_put_fixed(s, cis.ostack[i]);
5563ff48bf5SDavid du Colombier 	    depth += cis.os_count;
5573ff48bf5SDavid du Colombier 	    prev_op = c;
5583ff48bf5SDavid du Colombier 	    type1_clear(&cis);
5593ff48bf5SDavid du Colombier 	    continue;
5603ff48bf5SDavid du Colombier 	case cx_hstem:
561*593dc095SDavid du Colombier 	    type1_stem1(&cis, &hstem_hints, csp - 1, cis.lsb.y, active_hints);
5623ff48bf5SDavid du Colombier 	hint:
5633ff48bf5SDavid du Colombier 	    HINTS_CHANGED();
5643ff48bf5SDavid du Colombier 	    type1_clear(&cis);
5653ff48bf5SDavid du Colombier 	    continue;
5663ff48bf5SDavid du Colombier 	case cx_vstem:
567*593dc095SDavid du Colombier 	    type1_stem1(&cis, &vstem_hints, csp - 1, cis.lsb.x, active_hints);
5683ff48bf5SDavid du Colombier 	    goto hint;
5693ff48bf5SDavid du Colombier 	case CE_OFFSET + ce1_vstem3:
570*593dc095SDavid du Colombier 	    type1_stem3(&cis, &vstem_hints, csp - 5, cis.lsb.x, active_hints);
5713ff48bf5SDavid du Colombier 	    goto hint;
5723ff48bf5SDavid du Colombier 	case CE_OFFSET + ce1_hstem3:
573*593dc095SDavid du Colombier 	    type1_stem3(&cis, &hstem_hints, csp - 5, cis.lsb.y, active_hints);
5743ff48bf5SDavid du Colombier 	    goto hint;
5753ff48bf5SDavid du Colombier 	case CE_OFFSET + ce1_dotsection:
576*593dc095SDavid du Colombier 	    if (dotsection_flag == dotsection_out) {
5773ff48bf5SDavid du Colombier 		memcpy(dot_save_hints, active_hints, hintmask_size);
5783ff48bf5SDavid du Colombier 		memset(active_hints, 0, hintmask_size);
579*593dc095SDavid du Colombier 		dotsection_flag = dotsection_in;
5803ff48bf5SDavid du Colombier 	    } else {
5813ff48bf5SDavid du Colombier 		memcpy(active_hints, dot_save_hints, hintmask_size);
582*593dc095SDavid du Colombier 		dotsection_flag = dotsection_out;
5833ff48bf5SDavid du Colombier 	    }
5843ff48bf5SDavid du Colombier 	    HINTS_CHANGED();
5853ff48bf5SDavid du Colombier 	    continue;
5863ff48bf5SDavid du Colombier 	case c1_closepath:
587*593dc095SDavid du Colombier 	    continue;
5883ff48bf5SDavid du Colombier 	case CE_OFFSET + ce1_setcurrentpoint:
589*593dc095SDavid du Colombier 	    if (first) {
590*593dc095SDavid du Colombier 		/*  A workaround for fonts which use ce1_setcurrentpoint
591*593dc095SDavid du Colombier 		    in an illegal way for shifting a path.
592*593dc095SDavid du Colombier 		    See t1_hinter__setcurrentpoint for more information. */
593*593dc095SDavid du Colombier 		mx0 = csp[-1], my0 = *csp;
594*593dc095SDavid du Colombier 	    }
5953ff48bf5SDavid du Colombier 	    continue;
5963ff48bf5SDavid du Colombier 	case cx_vmoveto:
5973ff48bf5SDavid du Colombier 	    mx = 0, my = *csp;
5983ff48bf5SDavid du Colombier 	    POP(1); goto move;
5993ff48bf5SDavid du Colombier 	case cx_hmoveto:
6003ff48bf5SDavid du Colombier 	    mx = *csp, my = 0;
6013ff48bf5SDavid du Colombier 	    POP(1); goto move;
6023ff48bf5SDavid du Colombier 	case cx_rmoveto:
6033ff48bf5SDavid du Colombier 	    mx = csp[-1], my = *csp;
6043ff48bf5SDavid du Colombier 	    POP(2);
6053ff48bf5SDavid du Colombier 	move:
6063ff48bf5SDavid du Colombier 	    CHECK_OP();
6073ff48bf5SDavid du Colombier 	    if (first) {
6083ff48bf5SDavid du Colombier 		if (cis.os_count)
6093ff48bf5SDavid du Colombier 		    type2_put_fixed(s, *csp); /* width */
610*593dc095SDavid du Colombier 		mx += cis.lsb.x + mx0, my += cis.lsb.y + my0;
6113ff48bf5SDavid du Colombier 		first = false;
6123ff48bf5SDavid du Colombier 	    }
6133ff48bf5SDavid du Colombier 	    if (cis.flex_count != flex_max) {
6143ff48bf5SDavid du Colombier 		/* We're accumulating points for a flex. */
6153ff48bf5SDavid du Colombier 		if (type1_next(&cis) != ce1_callothersubr)
6163ff48bf5SDavid du Colombier 		    return_error(gs_error_rangecheck);
6173ff48bf5SDavid du Colombier 		csp = &cis.ostack[cis.os_count - 1];
6183ff48bf5SDavid du Colombier 		if (*csp != int2fixed(2) || csp[-1] != fixed_0)
6193ff48bf5SDavid du Colombier 		    return_error(gs_error_rangecheck);
6203ff48bf5SDavid du Colombier 		cis.flex_count++;
6213ff48bf5SDavid du Colombier 		csp[-1] = mx, *csp = my;
6223ff48bf5SDavid du Colombier 		continue;
6233ff48bf5SDavid du Colombier 	    }
6243ff48bf5SDavid du Colombier 	    CHECK_HINTS_CHANGED();
6253ff48bf5SDavid du Colombier 	    if (mx == 0) {
6263ff48bf5SDavid du Colombier 		type2_put_fixed(s, my);
6273ff48bf5SDavid du Colombier 		depth = 1, prev_op = cx_vmoveto;
6283ff48bf5SDavid du Colombier 	    } else if (my == 0) {
6293ff48bf5SDavid du Colombier 		type2_put_fixed(s, mx);
6303ff48bf5SDavid du Colombier 		depth = 1, prev_op = cx_hmoveto;
6313ff48bf5SDavid du Colombier 	    } else {
6323ff48bf5SDavid du Colombier 		type2_put_fixed(s, mx);
6333ff48bf5SDavid du Colombier 		type2_put_fixed(s, my);
6343ff48bf5SDavid du Colombier 		depth = 2, prev_op = cx_rmoveto;
6353ff48bf5SDavid du Colombier 	    }
6363ff48bf5SDavid du Colombier 	    type1_clear(&cis);
6373ff48bf5SDavid du Colombier 	    continue;
6383ff48bf5SDavid du Colombier 	case c1_hsbw:
6393ff48bf5SDavid du Colombier 	    gs_type1_sbw(&cis, cis.ostack[0], fixed_0, cis.ostack[1], fixed_0);
6403ff48bf5SDavid du Colombier 	    /*
6413ff48bf5SDavid du Colombier 	     * Leave the l.s.b. on the operand stack for the initial hint,
6423ff48bf5SDavid du Colombier 	     * moveto, or endchar command.
6433ff48bf5SDavid du Colombier 	     */
6443ff48bf5SDavid du Colombier 	    cis.ostack[0] = cis.ostack[1];
6453ff48bf5SDavid du Colombier 	sbw:
6463ff48bf5SDavid du Colombier 	    if (cis.ostack[0] == pfont->data.defaultWidthX)
6473ff48bf5SDavid du Colombier 		cis.os_count = 0;
6483ff48bf5SDavid du Colombier 	    else {
6493ff48bf5SDavid du Colombier 		cis.ostack[0] -= pfont->data.nominalWidthX;
6503ff48bf5SDavid du Colombier 		cis.os_count = 1;
6513ff48bf5SDavid du Colombier 	    }
652*593dc095SDavid du Colombier 	    if (hstem_hints.count) {
6533ff48bf5SDavid du Colombier 		if (cis.os_count)
6543ff48bf5SDavid du Colombier 		    type2_put_fixed(s, cis.ostack[0]);
655*593dc095SDavid du Colombier 		type2_put_stems(s, cis.os_count, &hstem_hints,
6563ff48bf5SDavid du Colombier 				(replace_hints ? c2_hstemhm : cx_hstem));
657*593dc095SDavid du Colombier 		cis.os_count = 0;
6583ff48bf5SDavid du Colombier 	    }
659*593dc095SDavid du Colombier 	    if (vstem_hints.count) {
6603ff48bf5SDavid du Colombier 		if (cis.os_count)
6613ff48bf5SDavid du Colombier 		    type2_put_fixed(s, cis.ostack[0]);
662*593dc095SDavid du Colombier 		type2_put_stems(s, cis.os_count, &vstem_hints,
6633ff48bf5SDavid du Colombier 				(replace_hints ? c2_vstemhm : cx_vstem));
664*593dc095SDavid du Colombier 		cis.os_count = 0;
6653ff48bf5SDavid du Colombier 	    }
6663ff48bf5SDavid du Colombier 	    continue;
6673ff48bf5SDavid du Colombier 	case CE_OFFSET + ce1_seac:
6683ff48bf5SDavid du Colombier 	    /*
6693ff48bf5SDavid du Colombier 	     * It is an undocumented feature of the Type 2 CharString
6703ff48bf5SDavid du Colombier 	     * format that endchar + 4 or 5 operands is equivalent to
6713ff48bf5SDavid du Colombier 	     * seac with an implicit asb operand + endchar with 0 or 1
6723ff48bf5SDavid du Colombier 	     * operands.  Remove the asb argument from the stack, but
6733ff48bf5SDavid du Colombier 	     * adjust the adx argument to compensate for the fact that
6743ff48bf5SDavid du Colombier 	     * Type 2 CharStrings don't have any concept of l.s.b.
6753ff48bf5SDavid du Colombier 	     */
6763ff48bf5SDavid du Colombier 	    csp[-3] += cis.lsb.x - csp[-4];
6773ff48bf5SDavid du Colombier 	    memmove(csp - 4, csp - 3, sizeof(*csp) * 4);
6783ff48bf5SDavid du Colombier 	    POP(1);
6793ff48bf5SDavid du Colombier 	    /* (falls through) */
6803ff48bf5SDavid du Colombier 	case cx_endchar:
6813ff48bf5SDavid du Colombier 	    CHECK_OP();
6823ff48bf5SDavid du Colombier 	    for (i = 0; i < cis.os_count; ++i)
6833ff48bf5SDavid du Colombier 		type2_put_fixed(s, cis.ostack[i]);
6843ff48bf5SDavid du Colombier 	    type2_put_op(s, cx_endchar);
6853ff48bf5SDavid du Colombier 	    return 0;
6863ff48bf5SDavid du Colombier 	case CE_OFFSET + ce1_sbw:
6873ff48bf5SDavid du Colombier 	    gs_type1_sbw(&cis, cis.ostack[0], cis.ostack[1],
6883ff48bf5SDavid du Colombier 			 cis.ostack[2], cis.ostack[3]);
6893ff48bf5SDavid du Colombier 	    cis.ostack[0] = cis.ostack[2];
6903ff48bf5SDavid du Colombier 	    goto sbw;
6913ff48bf5SDavid du Colombier 	case ce1_callothersubr:
6923ff48bf5SDavid du Colombier 	    CHECK_OP();
6933ff48bf5SDavid du Colombier 	    switch (fixed2int_var(*csp)) {
6943ff48bf5SDavid du Colombier 	    default:
6953ff48bf5SDavid du Colombier 		return_error(gs_error_rangecheck);
6963ff48bf5SDavid du Colombier 	    case 0:
6973ff48bf5SDavid du Colombier 		/*
6983ff48bf5SDavid du Colombier 		 * The operand stack contains: delta to reference point,
6993ff48bf5SDavid du Colombier 		 * 6 deltas for the two curves, fd, final point, 3, 0.
7003ff48bf5SDavid du Colombier 		 */
7013ff48bf5SDavid du Colombier 		csp[-18] += csp[-16], csp[-17] += csp[-15];
7023ff48bf5SDavid du Colombier 		memmove(csp - 16, csp - 14, sizeof(*csp) * 11);
7033ff48bf5SDavid du Colombier 		cis.os_count -= 6, csp -= 6;
7043ff48bf5SDavid du Colombier 		/*
7053ff48bf5SDavid du Colombier 		 * We could optimize by using [h]flex[1],
7063ff48bf5SDavid du Colombier 		 * but it isn't worth the trouble.
7073ff48bf5SDavid du Colombier 		 */
7083ff48bf5SDavid du Colombier 		c = CE_OFFSET + ce2_flex;
7093ff48bf5SDavid du Colombier 		cis.flex_count = flex_max;	/* not inside flex */
7103ff48bf5SDavid du Colombier 		cis.ignore_pops = 2;
7113ff48bf5SDavid du Colombier 		goto copy;
7123ff48bf5SDavid du Colombier 	    case 1:
7133ff48bf5SDavid du Colombier 		cis.flex_count = 0;
7143ff48bf5SDavid du Colombier 		cis.os_count -= 2;
7153ff48bf5SDavid du Colombier 		continue;
7163ff48bf5SDavid du Colombier 	    /*case 2:*/		/* detected in *moveto */
7173ff48bf5SDavid du Colombier 	    case 3:
7183ff48bf5SDavid du Colombier 		memset(active_hints, 0, hintmask_size);
7193ff48bf5SDavid du Colombier 		HINTS_CHANGED();
7203ff48bf5SDavid du Colombier 		cis.ignore_pops = 1;
7213ff48bf5SDavid du Colombier 		cis.os_count -= 2;
7223ff48bf5SDavid du Colombier 		continue;
7233ff48bf5SDavid du Colombier 	    case 12:
7243ff48bf5SDavid du Colombier 	    case 13:
7253ff48bf5SDavid du Colombier 		/* Counter control is not implemented. */
7263ff48bf5SDavid du Colombier 		cis.os_count -= 2 + fixed2int(csp[-1]);
7273ff48bf5SDavid du Colombier 		continue;
7283ff48bf5SDavid du Colombier 	    }
7293ff48bf5SDavid du Colombier 	    /*
7303ff48bf5SDavid du Colombier 	     * The remaining cases are strictly for optimization.
7313ff48bf5SDavid du Colombier 	     */
7323ff48bf5SDavid du Colombier 	case cx_rlineto:
7333ff48bf5SDavid du Colombier 	    if (depth > MAX_STACK - 2)
7343ff48bf5SDavid du Colombier 		goto copy;
7353ff48bf5SDavid du Colombier 	    switch (prev_op) {
7363ff48bf5SDavid du Colombier 	    case cx_rlineto:	/* rlineto+ => rlineto */
7373ff48bf5SDavid du Colombier 		goto put;
7383ff48bf5SDavid du Colombier 	    case cx_rrcurveto:	/* rrcurveto+ rlineto => rcurveline */
7393ff48bf5SDavid du Colombier 		c = c2_rcurveline;
7403ff48bf5SDavid du Colombier 		goto put;
7413ff48bf5SDavid du Colombier 	    default:
7423ff48bf5SDavid du Colombier 		goto copy;
7433ff48bf5SDavid du Colombier 	    }
7443ff48bf5SDavid du Colombier 	case cx_hlineto:  /* hlineto (vlineto hlineto)* [vlineto] => hlineto */
7453ff48bf5SDavid du Colombier 	    if (depth > MAX_STACK - 1 ||
7463ff48bf5SDavid du Colombier 		prev_op != (depth & 1 ? cx_vlineto : cx_hlineto))
7473ff48bf5SDavid du Colombier 		goto copy;
7483ff48bf5SDavid du Colombier 	    c = prev_op;
7493ff48bf5SDavid du Colombier 	    goto put;
7503ff48bf5SDavid du Colombier 	case cx_vlineto:  /* vlineto (hlineto vlineto)* [hlineto] => vlineto */
7513ff48bf5SDavid du Colombier 	    if (depth > MAX_STACK - 1 ||
7523ff48bf5SDavid du Colombier 		prev_op != (depth & 1 ? cx_hlineto : cx_vlineto))
7533ff48bf5SDavid du Colombier 		goto copy;
7543ff48bf5SDavid du Colombier 	    c = prev_op;
7553ff48bf5SDavid du Colombier 	    goto put;
7563ff48bf5SDavid du Colombier 	case cx_hvcurveto: /* hvcurveto (vhcurveto hvcurveto)* => hvcurveto */
7573ff48bf5SDavid du Colombier 				/* (vhcurveto hvcurveto)+ => vhcurveto  */
7583ff48bf5SDavid du Colombier 	    /*
7593ff48bf5SDavid du Colombier 	     * We have to check (depth & 1) because the last curve might
7603ff48bf5SDavid du Colombier 	     * have 5 parameters rather than 4 (see rrcurveto below).
7613ff48bf5SDavid du Colombier 	     */
7623ff48bf5SDavid du Colombier 	    if ((depth & 1) || depth > MAX_STACK - 4 ||
7633ff48bf5SDavid du Colombier 		prev_op != (depth & 4 ? cx_vhcurveto : cx_hvcurveto))
7643ff48bf5SDavid du Colombier 		goto copy;
7653ff48bf5SDavid du Colombier 	    c = prev_op;
7663ff48bf5SDavid du Colombier 	    goto put;
7673ff48bf5SDavid du Colombier 	case cx_vhcurveto: /* vhcurveto (hvcurveto vhcurveto)* => vhcurveto */
7683ff48bf5SDavid du Colombier 				/* (hvcurveto vhcurveto)+ => hvcurveto  */
7693ff48bf5SDavid du Colombier 	    /* See above re the (depth & 1) check. */
7703ff48bf5SDavid du Colombier 	    if ((depth & 1) || depth > MAX_STACK - 4 ||
7713ff48bf5SDavid du Colombier 		prev_op != (depth & 4 ? cx_hvcurveto : cx_vhcurveto))
7723ff48bf5SDavid du Colombier 		goto copy;
7733ff48bf5SDavid du Colombier 	    c = prev_op;
7743ff48bf5SDavid du Colombier 	    goto put;
7753ff48bf5SDavid du Colombier 	case cx_rrcurveto:
7763ff48bf5SDavid du Colombier 	    if (depth == 0) {
7773ff48bf5SDavid du Colombier 		if (csp[-1] == 0) {
7783ff48bf5SDavid du Colombier 		    /* A|0 B C D 0 F rrcurveto => [A] B C D F vvcurveto */
7793ff48bf5SDavid du Colombier 		    c = c2_vvcurveto;
7803ff48bf5SDavid du Colombier 		    csp[-1] = csp[0];
7813ff48bf5SDavid du Colombier 		    if (csp[-5] == 0) {
782*593dc095SDavid du Colombier 			memmove(csp - 5, csp - 4, sizeof(*csp) * 4);
7833ff48bf5SDavid du Colombier 			POP(2);
7843ff48bf5SDavid du Colombier 		    } else
7853ff48bf5SDavid du Colombier 			POP(1);
7863ff48bf5SDavid du Colombier 		} else if (*csp == 0) {
7873ff48bf5SDavid du Colombier 		    /* A B|0 C D E 0 rrcurveto => [B] A C D E hhcurveto */
7883ff48bf5SDavid du Colombier 		    c = c2_hhcurveto;
7893ff48bf5SDavid du Colombier 		    if (csp[-4] == 0) {
790*593dc095SDavid du Colombier 			memmove(csp - 4, csp - 3, sizeof(*csp) * 3);
7913ff48bf5SDavid du Colombier 			POP(2);
7923ff48bf5SDavid du Colombier 		    } else {
7933ff48bf5SDavid du Colombier 			*csp = csp[-5], csp[-5] = csp[-4], csp[-4] = *csp;
7943ff48bf5SDavid du Colombier 			POP(1);
7953ff48bf5SDavid du Colombier 		    }
7963ff48bf5SDavid du Colombier 		}
7973ff48bf5SDavid du Colombier 		/*
7983ff48bf5SDavid du Colombier 		 * We could also optimize:
7993ff48bf5SDavid du Colombier 		 *   0 B C D E F|0 rrcurveto => B C D E [F] vhcurveto
8003ff48bf5SDavid du Colombier 		 *   A 0 C D E|0 F rrcurveto => A C D F [E] hvcurveto
8013ff48bf5SDavid du Colombier 		 * but this gets in the way of subsequent optimization
8023ff48bf5SDavid du Colombier 		 * of multiple rrcurvetos, so we don't do it.
8033ff48bf5SDavid du Colombier 		 */
8043ff48bf5SDavid du Colombier 		goto copy;
8053ff48bf5SDavid du Colombier 	    }
8063ff48bf5SDavid du Colombier 	    if (depth > MAX_STACK - 6)
8073ff48bf5SDavid du Colombier 		goto copy;
8083ff48bf5SDavid du Colombier 	    switch (prev_op) {
8093ff48bf5SDavid du Colombier 	    case c2_hhcurveto:	/* hrcurveto (x1 0 x2 y2 x3 0 rrcurveto)* => */
8103ff48bf5SDavid du Colombier 				/* hhcurveto */
8113ff48bf5SDavid du Colombier 		if (csp[-4] == 0 && *csp == 0) {
812*593dc095SDavid du Colombier 		    memmove(csp - 4, csp - 3, sizeof(*csp) * 3);
8133ff48bf5SDavid du Colombier 		    c = prev_op;
8143ff48bf5SDavid du Colombier 		    POP(2);
8153ff48bf5SDavid du Colombier 		    goto put;
8163ff48bf5SDavid du Colombier 		}
8173ff48bf5SDavid du Colombier 		goto copy;
8183ff48bf5SDavid du Colombier 	    case c2_vvcurveto:	/* rvcurveto (0 y1 x2 y2 0 y3 rrcurveto)* => */
8193ff48bf5SDavid du Colombier 				/* vvcurveto */
8203ff48bf5SDavid du Colombier 		if (csp[-5] == 0 && csp[-1] == 0) {
821*593dc095SDavid du Colombier 		    memmove(csp - 5, csp - 4, sizeof(*csp) * 3);
8223ff48bf5SDavid du Colombier 		    csp[-2] = *csp;
8233ff48bf5SDavid du Colombier 		    c = prev_op;
8243ff48bf5SDavid du Colombier 		    POP(2);
8253ff48bf5SDavid du Colombier 		    goto put;
8263ff48bf5SDavid du Colombier 		}
8273ff48bf5SDavid du Colombier 		goto copy;
8283ff48bf5SDavid du Colombier 	    case cx_hvcurveto:
8293ff48bf5SDavid du Colombier 		if (depth & 1)
8303ff48bf5SDavid du Colombier 		    goto copy;
8313ff48bf5SDavid du Colombier 		if (!(depth & 4))
8323ff48bf5SDavid du Colombier 		    goto hrc;
8333ff48bf5SDavid du Colombier 	    vrc:  /* (vhcurveto hvcurveto)+ vrcurveto => vhcurveto */
8343ff48bf5SDavid du Colombier 		/* hvcurveto (vhcurveto hvcurveto)* vrcurveto => hvcurveto */
8353ff48bf5SDavid du Colombier 		if (csp[-5] != 0)
8363ff48bf5SDavid du Colombier 		    goto copy;
837*593dc095SDavid du Colombier 		memmove(csp - 5, csp - 4, sizeof(*csp) * 5);
8383ff48bf5SDavid du Colombier 		c = prev_op;
8393ff48bf5SDavid du Colombier 		POP(1);
8403ff48bf5SDavid du Colombier 		goto put;
8413ff48bf5SDavid du Colombier 	    case cx_vhcurveto:
8423ff48bf5SDavid du Colombier 		if (depth & 1)
8433ff48bf5SDavid du Colombier 		    goto copy;
8443ff48bf5SDavid du Colombier 		if (!(depth & 4))
8453ff48bf5SDavid du Colombier 		    goto vrc;
8463ff48bf5SDavid du Colombier 	    hrc:  /* (hvcurveto vhcurveto)+ hrcurveto => hvcurveto */
8473ff48bf5SDavid du Colombier 		/* vhcurveto (hvcurveto vhcurveto)* hrcurveto => vhcurveto */
8483ff48bf5SDavid du Colombier 		if (csp[-4] != 0)
8493ff48bf5SDavid du Colombier 		    goto copy;
8503ff48bf5SDavid du Colombier 		/* A 0 C D E F => A C D F E */
851*593dc095SDavid du Colombier 		memmove(csp - 4, csp - 3, sizeof(*csp) * 2);
8523ff48bf5SDavid du Colombier 		csp[-2] = *csp;
8533ff48bf5SDavid du Colombier 		c = prev_op;
8543ff48bf5SDavid du Colombier 		POP(1);
8553ff48bf5SDavid du Colombier 		goto put;
8563ff48bf5SDavid du Colombier 	    case cx_rlineto:	/* rlineto+ rrcurveto => rlinecurve */
8573ff48bf5SDavid du Colombier 		c = c2_rlinecurve;
8583ff48bf5SDavid du Colombier 		goto put;
8593ff48bf5SDavid du Colombier 	    case cx_rrcurveto:	/* rrcurveto+ => rrcurveto */
8603ff48bf5SDavid du Colombier 		goto put;
8613ff48bf5SDavid du Colombier 	    default:
8623ff48bf5SDavid du Colombier 		goto copy;
8633ff48bf5SDavid du Colombier 	    }
8643ff48bf5SDavid du Colombier 	}
8653ff48bf5SDavid du Colombier     }
8663ff48bf5SDavid du Colombier }
867