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