xref: /plan9/sys/src/cmd/gs/src/gdevpsfx.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gdevpsfx.c,v 1.25 2005/07/30 02:39:45 alexcher Exp $ */
18 /* Convert Type 1 Charstrings to Type 2 */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gxfixed.h"
24 #include "gxmatrix.h"		/* for gsfont.h */
25 #include "gxfont.h"
26 #include "gxfont1.h"
27 #include "gxtype1.h"
28 #include "stream.h"
29 #include "gdevpsf.h"
30 
31 /* ------ Type 1 Charstring parsing ------ */
32 
33 /*
34  * The parsing code handles numbers on its own; it reports callsubr and
35  * return operators to the caller, but also executes them.
36  *
37  * Only the following elements of the Type 1 state are used:
38  *	ostack, os_count, ipstack, ips_count
39  */
40 
41 #define CE_OFFSET 32		/* offset for extended opcodes */
42 
43 typedef struct {
44     fixed v0, v1;		/* coordinates */
45     ushort index;		/* sequential index of hint */
46 } cv_stem_hint;
47 typedef struct {
48     int count;
49     int current;		/* cache cursor for search */
50     /*
51      * For dotsection and Type 1 Charstring hint replacement,
52      * we store active hints at the bottom of the table, and
53      * replaced hints at the top.
54      */
55     int replaced_count;		/* # of replaced hints at top */
56     cv_stem_hint data[max_total_stem_hints];
57 } cv_stem_hint_table;
58 
59 /* Skip over the initial bytes in a Charstring, if any. */
60 private void
skip_iv(gs_type1_state * pcis)61 skip_iv(gs_type1_state *pcis)
62 {
63     int skip = pcis->pfont->data.lenIV;
64     ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1];
65     const byte *cip = ipsp->cs_data.bits.data;
66     crypt_state state = crypt_charstring_seed;
67 
68     for (; skip > 0; ++cip, --skip)
69 	decrypt_skip_next(*cip, state);
70     ipsp->ip = cip;
71     ipsp->dstate = state;
72 }
73 
74 /*
75  * Set up for parsing a Type 1 Charstring.
76  *
77  * Only uses the following elements of *pfont:
78  *	data.lenIV
79  */
80 private void
type1_next_init(gs_type1_state * pcis,const gs_glyph_data_t * pgd,gs_font_type1 * pfont)81 type1_next_init(gs_type1_state *pcis, const gs_glyph_data_t *pgd,
82 		gs_font_type1 *pfont)
83 {
84     gs_type1_interp_init(pcis, NULL, NULL, NULL, NULL, false, 0, pfont);
85     pcis->flex_count = flex_max;
86     pcis->ipstack[0].cs_data = *pgd;
87     skip_iv(pcis);
88 }
89 
90 /* Clear the Type 1 operand stack. */
91 inline private void
type1_clear(gs_type1_state * pcis)92 type1_clear(gs_type1_state *pcis)
93 {
94     pcis->os_count = 0;
95 }
96 
97 /* Execute a callsubr. */
98 private int
type1_callsubr(gs_type1_state * pcis,int index)99 type1_callsubr(gs_type1_state *pcis, int index)
100 {
101     gs_font_type1 *pfont = pcis->pfont;
102     ip_state_t *ipsp1 = &pcis->ipstack[pcis->ips_count];
103     int code = pfont->data.procs.subr_data(pfont, index, false,
104 					   &ipsp1->cs_data);
105 
106     if (code < 0)
107 	return_error(code);
108     pcis->ips_count++;
109     skip_iv(pcis);
110     return code;
111 }
112 
113 /* Add 1 or 3 stem hints. */
114 private int
type1_stem1(gs_type1_state * pcis,cv_stem_hint_table * psht,const fixed * pv,fixed lsb,byte * active_hints)115 type1_stem1(gs_type1_state *pcis, cv_stem_hint_table *psht, const fixed *pv,
116 	    fixed lsb, byte *active_hints)
117 {
118     fixed v0 = pv[0] + lsb, v1 = v0 + pv[1];
119     cv_stem_hint *bot = &psht->data[0];
120     cv_stem_hint *orig_top = bot + psht->count;
121     cv_stem_hint *top = orig_top;
122 
123     if (psht->count >= max_total_stem_hints)
124 	return_error(gs_error_limitcheck);
125     while (top > bot &&
126 	   (v0 < top[-1].v0 || (v0 == top[-1].v0 && v1 < top[-1].v1))
127 	   ) {
128 	*top = top[-1];
129 	top--;
130     }
131     if (top > bot && v0 == top[-1].v0 && v1 == top[-1].v1) {
132 	/* Duplicate hint, don't add it. */
133 	memmove(top, top + 1, (char *)orig_top - (char *)top);
134 	if (active_hints) {
135 	    uint index = top[-1].index;
136 
137 	    active_hints[index >> 3] |= 0x80 >> (index & 7);
138 	}
139 	return 0;
140     }
141     top->v0 = v0;
142     top->v1 = v1;
143     psht->count++;
144     return 0;
145 }
146 private void
type1_stem3(gs_type1_state * pcis,cv_stem_hint_table * psht,const fixed * pv3,fixed lsb,byte * active_hints)147 type1_stem3(gs_type1_state *pcis, cv_stem_hint_table *psht, const fixed *pv3,
148 	    fixed lsb, byte *active_hints)
149 {
150     type1_stem1(pcis, psht, pv3, lsb, active_hints);
151     type1_stem1(pcis, psht, pv3 + 2, lsb, active_hints);
152     type1_stem1(pcis, psht, pv3 + 4, lsb, active_hints);
153 }
154 
155 /*
156  * Get the next operator from a Type 1 Charstring.  This procedure handles
157  * numbers, div, blend, pop, and callsubr/return.
158  */
159 private int
type1_next(gs_type1_state * pcis)160 type1_next(gs_type1_state *pcis)
161 {
162     ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1];
163     const byte *cip, *cipe;
164     crypt_state state;
165 #define CLEAR (csp = pcis->ostack - 1)
166     fixed *csp = &pcis->ostack[pcis->os_count - 1];
167     const bool encrypted = pcis->pfont->data.lenIV >= 0;
168     int c, code, num_results, c0;
169 
170  load:
171     cip = ipsp->ip;
172     cipe = ipsp->cs_data.bits.data + ipsp->cs_data.bits.size;
173     state = ipsp->dstate;
174     for (;;) {
175         if (cip >= cipe)
176 	    return_error(gs_error_invalidfont);
177 	c0 = *cip++;
178 	charstring_next(c0, state, c, encrypted);
179 	if (c >= c_num1) {
180 	    /* This is a number, decode it and push it on the stack. */
181 	    if (c < c_pos2_0) {	/* 1-byte number */
182 		decode_push_num1(csp, pcis->ostack, c);
183 	    } else if (c < cx_num4) {	/* 2-byte number */
184 		decode_push_num2(csp, pcis->ostack, c, cip, state, encrypted);
185 	    } else if (c == cx_num4) {	/* 4-byte number */
186 		long lw;
187 
188 		decode_num4(lw, cip, state, encrypted);
189 		CS_CHECK_PUSH(csp, pcis->ostack);
190 		*++csp = int2fixed(lw);
191 	    } else		/* not possible */
192 		return_error(gs_error_invalidfont);
193 	    continue;
194 	}
195 #ifdef DEBUG
196 	if (gs_debug_c('1')) {
197 	    const fixed *p;
198 
199 	    for (p = pcis->ostack; p <= csp; ++p)
200 		dprintf1(" %g", fixed2float(*p));
201 	    if (c == cx_escape) {
202 		crypt_state cstate = state;
203 		int cn;
204 
205 		charstring_next(*cip, cstate, cn, encrypted);
206 		dprintf1(" [*%d]\n", cn);
207 	    } else
208 		dprintf1(" [%d]\n", c);
209 	}
210 #endif
211 	switch ((char_command) c) {
212 	default:
213 	    break;
214 	case c_undef0:
215 	case c_undef2:
216 	case c_undef17:
217 	    return_error(gs_error_invalidfont);
218 	case c_callsubr:
219 	    code = type1_callsubr(pcis, fixed2int_var(*csp) +
220 				  pcis->pfont->data.subroutineNumberBias);
221 	    if (code < 0)
222 		return_error(code);
223 	    ipsp->ip = cip, ipsp->dstate = state;
224 	    --csp;
225 	    ++ipsp;
226 	    goto load;
227 	case c_return:
228 	    gs_glyph_data_free(&ipsp->cs_data, "type1_next");
229 	    pcis->ips_count--;
230 	    --ipsp;
231 	    goto load;
232 	case c_undoc15:
233 	    /* See gstype1.h for information on this opcode. */
234 	    CLEAR;
235 	    continue;
236 	case cx_escape:
237 	    charstring_next(*cip, state, c, encrypted);
238 	    ++cip;
239 	    switch ((char1_extended_command) c) {
240 	    default:
241 		c += CE_OFFSET;
242 		break;
243 	    case ce1_div:
244 		csp[-1] = float2fixed((double)csp[-1] / (double)*csp);
245 		--csp;
246 		continue;
247 	    case ce1_undoc15:	/* see gstype1.h */
248 		CLEAR;
249 		continue;
250 	    case ce1_callothersubr:
251 		switch (fixed2int_var(*csp)) {
252 		case 0:
253 		    pcis->ignore_pops = 2;
254 		    break;	/* pass to caller */
255 		case 3:
256 		    pcis->ignore_pops = 1;
257 		    break;	/* pass to caller */
258 		case 14:
259 		    num_results = 1; goto blend;
260 		case 15:
261 		    num_results = 2; goto blend;
262 		case 16:
263 		    num_results = 3; goto blend;
264 		case 17:
265 		    num_results = 4; goto blend;
266 		case 18:
267 		    num_results = 6;
268 		blend:
269 		    code = gs_type1_blend(pcis, csp, num_results);
270 		    if (code < 0)
271 			return code;
272 		    csp -= code;
273 		    continue;
274 		default:
275 		    break;	/* pass to caller */
276 		}
277 		break;
278 	    case ce1_pop:
279 		if (pcis->ignore_pops != 0) {
280 		    pcis->ignore_pops--;
281 		    continue;
282 		}
283 		return_error(gs_error_rangecheck);
284 	    }
285 	    break;
286 	}
287 	break;
288     }
289     ipsp->ip = cip, ipsp->dstate = state;
290     pcis->ips_count = ipsp + 1 - &pcis->ipstack[0];
291     pcis->os_count = csp + 1 - &pcis->ostack[0];
292     return c;
293 }
294 
295 /* ------ Output ------ */
296 
297 /* Put 2 or 4 bytes on a stream (big-endian). */
298 private void
sputc2(stream * s,int i)299 sputc2(stream *s, int i)
300 {
301     sputc(s, (byte)(i >> 8));
302     sputc(s, (byte)i);
303 }
304 private void
sputc4(stream * s,int i)305 sputc4(stream *s, int i)
306 {
307     sputc2(s, i >> 16);
308     sputc2(s, i);
309 }
310 
311 /* Put a Type 2 operator on a stream. */
312 private void
type2_put_op(stream * s,int op)313 type2_put_op(stream *s, int op)
314 {
315     if (op >= CE_OFFSET) {
316 	spputc(s, cx_escape);
317 	spputc(s, (byte)(op - CE_OFFSET));
318     } else
319 	sputc(s, (byte)op);
320 }
321 
322 /* Put a Type 2 number on a stream. */
323 private void
type2_put_int(stream * s,int i)324 type2_put_int(stream *s, int i)
325 {
326     if (i >= -107 && i <= 107)
327 	sputc(s, (byte)(i + 139));
328     else if (i <= 1131 && i >= 0)
329 	sputc2(s, (c_pos2_0 << 8) + i - 108);
330     else if (i >= -1131 && i < 0)
331 	sputc2(s, (c_neg2_0 << 8) - i - 108);
332     else if (i >= -32768 && i <= 32767) {
333 	spputc(s, c2_shortint);
334 	sputc2(s, i);
335     } else {
336 	/*
337 	 * We can't represent this number directly: compute it.
338 	 * (This can be done much more efficiently in particular cases;
339 	 * we'll do this if it ever seems worthwhile.)
340 	 */
341 	type2_put_int(s, i >> 10);
342 	type2_put_int(s, 1024);
343 	type2_put_op(s, CE_OFFSET + ce2_mul);
344 	type2_put_int(s, i & 1023);
345 	type2_put_op(s, CE_OFFSET + ce2_add);
346     }
347 }
348 
349 /* Put a fixed value on a stream. */
350 private void
type2_put_fixed(stream * s,fixed v)351 type2_put_fixed(stream *s, fixed v)
352 {
353     if (fixed_is_int(v))
354 	type2_put_int(s, fixed2int_var(v));
355     else if (v >= int2fixed(-32768) && v < int2fixed(32768)) {
356 	/* We can represent this as a 16:16 number. */
357 	spputc(s, cx_num4);
358 	sputc4(s, v << (16 - _fixed_shift));
359     } else {
360 	type2_put_int(s, fixed2int_var(v));
361 	type2_put_fixed(s, fixed_fraction(v));
362 	type2_put_op(s, CE_OFFSET + ce2_add);
363     }
364 }
365 
366 /* Put a stem hint table on a stream. */
367 private void
type2_put_stems(stream * s,int os_count,const cv_stem_hint_table * psht,int op)368 type2_put_stems(stream *s, int os_count, const cv_stem_hint_table *psht, int op)
369 {
370     fixed prev = 0;
371     int pushed = os_count;
372     int i;
373 
374     for (i = 0; i < psht->count; ++i, pushed += 2) {
375 	fixed v0 = psht->data[i].v0;
376 	fixed v1 = psht->data[i].v1;
377 
378 	if (pushed > ostack_size - 2) {
379 	    type2_put_op(s, op);
380 	    pushed = 0;
381 	}
382 	type2_put_fixed(s, v0 - prev);
383 	type2_put_fixed(s, v1 - v0);
384 	prev = v1;
385     }
386     type2_put_op(s, op);
387 }
388 
389 /* Put out a hintmask command. */
390 private void
type2_put_hintmask(stream * s,const byte * mask,uint size)391 type2_put_hintmask(stream *s, const byte *mask, uint size)
392 {
393     uint ignore;
394 
395     type2_put_op(s, c2_hintmask);
396     sputs(s, mask, size, &ignore);
397 }
398 
399 /* ------ Main program ------ */
400 
401 
402 /*
403  * Convert a Type 1 Charstring to (unencrypted) Type 2.
404  * For simplicity, we expand all Subrs in-line.
405  * We still need to optimize the output using these patterns:
406  *	(vhcurveto hvcurveto)* (vhcurveto hrcurveto | vrcurveto) =>
407  *	  vhcurveto
408  *	(hvcurveto vhcurveto)* (hvcurveto vrcurveto | hrcurveto) =>
409  *	  hvcurveto
410  */
411 #define MAX_STACK ostack_size
412 int
psf_convert_type1_to_type2(stream * s,const gs_glyph_data_t * pgd,gs_font_type1 * pfont)413 psf_convert_type1_to_type2(stream *s, const gs_glyph_data_t *pgd,
414 			   gs_font_type1 *pfont)
415 {
416     gs_type1_state cis;
417     cv_stem_hint_table hstem_hints;	/* horizontal stem hints */
418     cv_stem_hint_table vstem_hints;	/* vertical stem hints */
419     bool first = true;
420     bool replace_hints = false;
421     bool hints_changed = false;
422     enum {
423 	dotsection_in = 0,
424 	dotsection_out = -1
425     } dotsection_flag = dotsection_out;
426     byte active_hints[(max_total_stem_hints + 7) / 8];
427     byte dot_save_hints[(max_total_stem_hints + 7) / 8];
428     uint hintmask_size;
429 #define HINTS_CHANGED()\
430   BEGIN\
431     hints_changed = replace_hints;\
432     if (hints_changed)\
433 	CHECK_OP();		/* see below */\
434   END
435 #define CHECK_HINTS_CHANGED()\
436   BEGIN\
437     if (hints_changed) {\
438 	type2_put_hintmask(s, active_hints, hintmask_size);\
439 	hints_changed = false;\
440     }\
441   END
442     /*
443      * In order to combine Type 1 operators, we usually delay writing
444      * out operators (but not their operands).  We must keep track of
445      * the stack depth so we don't exceed it when combining operators.
446      */
447     int depth;			/* of operands on stack */
448     int prev_op;		/* operator to write, -1 if none */
449 #define CLEAR_OP()\
450   (depth = 0, prev_op = -1)
451 #define CHECK_OP()\
452   BEGIN\
453     if (prev_op >= 0) {\
454 	type2_put_op(s, prev_op);\
455 	CLEAR_OP();\
456     }\
457   END
458     fixed mx0 = 0, my0 = 0; /* See ce1_setcurrentpoint. */
459 
460     /*
461      * Do a first pass to collect hints.  Note that we must also process
462      * [h]sbw, because the hint coordinates are relative to the lsb.
463      */
464     hstem_hints.count = hstem_hints.replaced_count = hstem_hints.current = 0;
465     vstem_hints.count = vstem_hints.replaced_count = vstem_hints.current = 0;
466     type1_next_init(&cis, pgd, pfont);
467     for (;;) {
468 	int c = type1_next(&cis);
469 	fixed *csp = &cis.ostack[cis.os_count - 1];
470 
471 	switch (c) {
472 	default:
473 	    if (c < 0)
474 		return c;
475 	    type1_clear(&cis);
476 	    continue;
477 	case c1_hsbw:
478 	    gs_type1_sbw(&cis, cis.ostack[0], fixed_0, cis.ostack[1], fixed_0);
479 	    goto clear;
480 	case cx_hstem:
481 	    type1_stem1(&cis, &hstem_hints, csp - 1, cis.lsb.y, NULL);
482 	    goto clear;
483 	case cx_vstem:
484 	    type1_stem1(&cis, &vstem_hints, csp - 1, cis.lsb.x, NULL);
485 	    goto clear;
486 	case CE_OFFSET + ce1_sbw:
487 	    gs_type1_sbw(&cis, cis.ostack[0], cis.ostack[1],
488 			 cis.ostack[2], cis.ostack[3]);
489 	    goto clear;
490 	case CE_OFFSET + ce1_vstem3:
491 	    type1_stem3(&cis, &vstem_hints, csp - 5, cis.lsb.x, NULL);
492 	    goto clear;
493 	case CE_OFFSET + ce1_hstem3:
494 	    type1_stem3(&cis, &hstem_hints, csp - 5, cis.lsb.y, NULL);
495 	clear:
496 	    type1_clear(&cis);
497 	    continue;
498 	case ce1_callothersubr:
499 	    if (*csp == int2fixed(3))
500 		replace_hints = true;
501 	    cis.os_count -= 2;
502 	    continue;
503 	case CE_OFFSET + ce1_dotsection:
504 	    replace_hints = true;
505 	    continue;
506 	case CE_OFFSET + ce1_seac:
507 	case cx_endchar:
508 	    break;
509 	}
510 	break;
511     }
512     /*
513      * Number the hints for hintmask.  We must do this even if we never
514      * replace hints, because type1_stem# uses the index to set bits in
515      * active_hints.
516      */
517     {
518 	int i;
519 
520 	for (i = 0; i < hstem_hints.count; ++i)
521 	    hstem_hints.data[i].index = i;
522 	for (i = 0; i < vstem_hints.count; ++i)
523 	    vstem_hints.data[i].index = i + hstem_hints.count;
524     }
525     if (replace_hints) {
526 	hintmask_size =
527 	    (hstem_hints.count + vstem_hints.count + 7) / 8;
528 	memset(active_hints, 0, hintmask_size);
529     } else
530 	hintmask_size = 0;
531 
532     /* Do a second pass to write the result. */
533     type1_next_init(&cis, pgd, pfont);
534     CLEAR_OP();
535     for (;;) {
536 	int c = type1_next(&cis);
537 	fixed *csp = &cis.ostack[cis.os_count - 1];
538 #define POP(n)\
539   (csp -= (n), cis.os_count -= (n))
540 	int i;
541 	fixed mx, my;
542 
543 	switch (c) {
544 	default:
545 	    if (c < 0)
546 		return c;
547 	    if (c >= CE_OFFSET)
548 		return_error(gs_error_rangecheck);
549 	    /* The Type 1 use of all other operators is the same in Type 2. */
550 	copy:
551 	    CHECK_OP();
552 	    CHECK_HINTS_CHANGED();
553 	put:
554 	    for (i = 0; i < cis.os_count; ++i)
555 		type2_put_fixed(s, cis.ostack[i]);
556 	    depth += cis.os_count;
557 	    prev_op = c;
558 	    type1_clear(&cis);
559 	    continue;
560 	case cx_hstem:
561 	    type1_stem1(&cis, &hstem_hints, csp - 1, cis.lsb.y, active_hints);
562 	hint:
563 	    HINTS_CHANGED();
564 	    type1_clear(&cis);
565 	    continue;
566 	case cx_vstem:
567 	    type1_stem1(&cis, &vstem_hints, csp - 1, cis.lsb.x, active_hints);
568 	    goto hint;
569 	case CE_OFFSET + ce1_vstem3:
570 	    type1_stem3(&cis, &vstem_hints, csp - 5, cis.lsb.x, active_hints);
571 	    goto hint;
572 	case CE_OFFSET + ce1_hstem3:
573 	    type1_stem3(&cis, &hstem_hints, csp - 5, cis.lsb.y, active_hints);
574 	    goto hint;
575 	case CE_OFFSET + ce1_dotsection:
576 	    if (dotsection_flag == dotsection_out) {
577 		memcpy(dot_save_hints, active_hints, hintmask_size);
578 		memset(active_hints, 0, hintmask_size);
579 		dotsection_flag = dotsection_in;
580 	    } else {
581 		memcpy(active_hints, dot_save_hints, hintmask_size);
582 		dotsection_flag = dotsection_out;
583 	    }
584 	    HINTS_CHANGED();
585 	    continue;
586 	case c1_closepath:
587 	    continue;
588 	case CE_OFFSET + ce1_setcurrentpoint:
589 	    if (first) {
590 		/*  A workaround for fonts which use ce1_setcurrentpoint
591 		    in an illegal way for shifting a path.
592 		    See t1_hinter__setcurrentpoint for more information. */
593 		mx0 = csp[-1], my0 = *csp;
594 	    }
595 	    continue;
596 	case cx_vmoveto:
597 	    mx = 0, my = *csp;
598 	    POP(1); goto move;
599 	case cx_hmoveto:
600 	    mx = *csp, my = 0;
601 	    POP(1); goto move;
602 	case cx_rmoveto:
603 	    mx = csp[-1], my = *csp;
604 	    POP(2);
605 	move:
606 	    CHECK_OP();
607 	    if (first) {
608 		if (cis.os_count)
609 		    type2_put_fixed(s, *csp); /* width */
610 		mx += cis.lsb.x + mx0, my += cis.lsb.y + my0;
611 		first = false;
612 	    }
613 	    if (cis.flex_count != flex_max) {
614 		/* We're accumulating points for a flex. */
615 		if (type1_next(&cis) != ce1_callothersubr)
616 		    return_error(gs_error_rangecheck);
617 		csp = &cis.ostack[cis.os_count - 1];
618 		if (*csp != int2fixed(2) || csp[-1] != fixed_0)
619 		    return_error(gs_error_rangecheck);
620 		cis.flex_count++;
621 		csp[-1] = mx, *csp = my;
622 		continue;
623 	    }
624 	    CHECK_HINTS_CHANGED();
625 	    if (mx == 0) {
626 		type2_put_fixed(s, my);
627 		depth = 1, prev_op = cx_vmoveto;
628 	    } else if (my == 0) {
629 		type2_put_fixed(s, mx);
630 		depth = 1, prev_op = cx_hmoveto;
631 	    } else {
632 		type2_put_fixed(s, mx);
633 		type2_put_fixed(s, my);
634 		depth = 2, prev_op = cx_rmoveto;
635 	    }
636 	    type1_clear(&cis);
637 	    continue;
638 	case c1_hsbw:
639 	    gs_type1_sbw(&cis, cis.ostack[0], fixed_0, cis.ostack[1], fixed_0);
640 	    /*
641 	     * Leave the l.s.b. on the operand stack for the initial hint,
642 	     * moveto, or endchar command.
643 	     */
644 	    cis.ostack[0] = cis.ostack[1];
645 	sbw:
646 	    if (cis.ostack[0] == pfont->data.defaultWidthX)
647 		cis.os_count = 0;
648 	    else {
649 		cis.ostack[0] -= pfont->data.nominalWidthX;
650 		cis.os_count = 1;
651 	    }
652 	    if (hstem_hints.count) {
653 		if (cis.os_count)
654 		    type2_put_fixed(s, cis.ostack[0]);
655 		type2_put_stems(s, cis.os_count, &hstem_hints,
656 				(replace_hints ? c2_hstemhm : cx_hstem));
657 		cis.os_count = 0;
658 	    }
659 	    if (vstem_hints.count) {
660 		if (cis.os_count)
661 		    type2_put_fixed(s, cis.ostack[0]);
662 		type2_put_stems(s, cis.os_count, &vstem_hints,
663 				(replace_hints ? c2_vstemhm : cx_vstem));
664 		cis.os_count = 0;
665 	    }
666 	    continue;
667 	case CE_OFFSET + ce1_seac:
668 	    /*
669 	     * It is an undocumented feature of the Type 2 CharString
670 	     * format that endchar + 4 or 5 operands is equivalent to
671 	     * seac with an implicit asb operand + endchar with 0 or 1
672 	     * operands.  Remove the asb argument from the stack, but
673 	     * adjust the adx argument to compensate for the fact that
674 	     * Type 2 CharStrings don't have any concept of l.s.b.
675 	     */
676 	    csp[-3] += cis.lsb.x - csp[-4];
677 	    memmove(csp - 4, csp - 3, sizeof(*csp) * 4);
678 	    POP(1);
679 	    /* (falls through) */
680 	case cx_endchar:
681 	    CHECK_OP();
682 	    for (i = 0; i < cis.os_count; ++i)
683 		type2_put_fixed(s, cis.ostack[i]);
684 	    type2_put_op(s, cx_endchar);
685 	    return 0;
686 	case CE_OFFSET + ce1_sbw:
687 	    gs_type1_sbw(&cis, cis.ostack[0], cis.ostack[1],
688 			 cis.ostack[2], cis.ostack[3]);
689 	    cis.ostack[0] = cis.ostack[2];
690 	    goto sbw;
691 	case ce1_callothersubr:
692 	    CHECK_OP();
693 	    switch (fixed2int_var(*csp)) {
694 	    default:
695 		return_error(gs_error_rangecheck);
696 	    case 0:
697 		/*
698 		 * The operand stack contains: delta to reference point,
699 		 * 6 deltas for the two curves, fd, final point, 3, 0.
700 		 */
701 		csp[-18] += csp[-16], csp[-17] += csp[-15];
702 		memmove(csp - 16, csp - 14, sizeof(*csp) * 11);
703 		cis.os_count -= 6, csp -= 6;
704 		/*
705 		 * We could optimize by using [h]flex[1],
706 		 * but it isn't worth the trouble.
707 		 */
708 		c = CE_OFFSET + ce2_flex;
709 		cis.flex_count = flex_max;	/* not inside flex */
710 		cis.ignore_pops = 2;
711 		goto copy;
712 	    case 1:
713 		cis.flex_count = 0;
714 		cis.os_count -= 2;
715 		continue;
716 	    /*case 2:*/		/* detected in *moveto */
717 	    case 3:
718 		memset(active_hints, 0, hintmask_size);
719 		HINTS_CHANGED();
720 		cis.ignore_pops = 1;
721 		cis.os_count -= 2;
722 		continue;
723 	    case 12:
724 	    case 13:
725 		/* Counter control is not implemented. */
726 		cis.os_count -= 2 + fixed2int(csp[-1]);
727 		continue;
728 	    }
729 	    /*
730 	     * The remaining cases are strictly for optimization.
731 	     */
732 	case cx_rlineto:
733 	    if (depth > MAX_STACK - 2)
734 		goto copy;
735 	    switch (prev_op) {
736 	    case cx_rlineto:	/* rlineto+ => rlineto */
737 		goto put;
738 	    case cx_rrcurveto:	/* rrcurveto+ rlineto => rcurveline */
739 		c = c2_rcurveline;
740 		goto put;
741 	    default:
742 		goto copy;
743 	    }
744 	case cx_hlineto:  /* hlineto (vlineto hlineto)* [vlineto] => hlineto */
745 	    if (depth > MAX_STACK - 1 ||
746 		prev_op != (depth & 1 ? cx_vlineto : cx_hlineto))
747 		goto copy;
748 	    c = prev_op;
749 	    goto put;
750 	case cx_vlineto:  /* vlineto (hlineto vlineto)* [hlineto] => vlineto */
751 	    if (depth > MAX_STACK - 1 ||
752 		prev_op != (depth & 1 ? cx_hlineto : cx_vlineto))
753 		goto copy;
754 	    c = prev_op;
755 	    goto put;
756 	case cx_hvcurveto: /* hvcurveto (vhcurveto hvcurveto)* => hvcurveto */
757 				/* (vhcurveto hvcurveto)+ => vhcurveto  */
758 	    /*
759 	     * We have to check (depth & 1) because the last curve might
760 	     * have 5 parameters rather than 4 (see rrcurveto below).
761 	     */
762 	    if ((depth & 1) || depth > MAX_STACK - 4 ||
763 		prev_op != (depth & 4 ? cx_vhcurveto : cx_hvcurveto))
764 		goto copy;
765 	    c = prev_op;
766 	    goto put;
767 	case cx_vhcurveto: /* vhcurveto (hvcurveto vhcurveto)* => vhcurveto */
768 				/* (hvcurveto vhcurveto)+ => hvcurveto  */
769 	    /* See above re the (depth & 1) check. */
770 	    if ((depth & 1) || depth > MAX_STACK - 4 ||
771 		prev_op != (depth & 4 ? cx_hvcurveto : cx_vhcurveto))
772 		goto copy;
773 	    c = prev_op;
774 	    goto put;
775 	case cx_rrcurveto:
776 	    if (depth == 0) {
777 		if (csp[-1] == 0) {
778 		    /* A|0 B C D 0 F rrcurveto => [A] B C D F vvcurveto */
779 		    c = c2_vvcurveto;
780 		    csp[-1] = csp[0];
781 		    if (csp[-5] == 0) {
782 			memmove(csp - 5, csp - 4, sizeof(*csp) * 4);
783 			POP(2);
784 		    } else
785 			POP(1);
786 		} else if (*csp == 0) {
787 		    /* A B|0 C D E 0 rrcurveto => [B] A C D E hhcurveto */
788 		    c = c2_hhcurveto;
789 		    if (csp[-4] == 0) {
790 			memmove(csp - 4, csp - 3, sizeof(*csp) * 3);
791 			POP(2);
792 		    } else {
793 			*csp = csp[-5], csp[-5] = csp[-4], csp[-4] = *csp;
794 			POP(1);
795 		    }
796 		}
797 		/*
798 		 * We could also optimize:
799 		 *   0 B C D E F|0 rrcurveto => B C D E [F] vhcurveto
800 		 *   A 0 C D E|0 F rrcurveto => A C D F [E] hvcurveto
801 		 * but this gets in the way of subsequent optimization
802 		 * of multiple rrcurvetos, so we don't do it.
803 		 */
804 		goto copy;
805 	    }
806 	    if (depth > MAX_STACK - 6)
807 		goto copy;
808 	    switch (prev_op) {
809 	    case c2_hhcurveto:	/* hrcurveto (x1 0 x2 y2 x3 0 rrcurveto)* => */
810 				/* hhcurveto */
811 		if (csp[-4] == 0 && *csp == 0) {
812 		    memmove(csp - 4, csp - 3, sizeof(*csp) * 3);
813 		    c = prev_op;
814 		    POP(2);
815 		    goto put;
816 		}
817 		goto copy;
818 	    case c2_vvcurveto:	/* rvcurveto (0 y1 x2 y2 0 y3 rrcurveto)* => */
819 				/* vvcurveto */
820 		if (csp[-5] == 0 && csp[-1] == 0) {
821 		    memmove(csp - 5, csp - 4, sizeof(*csp) * 3);
822 		    csp[-2] = *csp;
823 		    c = prev_op;
824 		    POP(2);
825 		    goto put;
826 		}
827 		goto copy;
828 	    case cx_hvcurveto:
829 		if (depth & 1)
830 		    goto copy;
831 		if (!(depth & 4))
832 		    goto hrc;
833 	    vrc:  /* (vhcurveto hvcurveto)+ vrcurveto => vhcurveto */
834 		/* hvcurveto (vhcurveto hvcurveto)* vrcurveto => hvcurveto */
835 		if (csp[-5] != 0)
836 		    goto copy;
837 		memmove(csp - 5, csp - 4, sizeof(*csp) * 5);
838 		c = prev_op;
839 		POP(1);
840 		goto put;
841 	    case cx_vhcurveto:
842 		if (depth & 1)
843 		    goto copy;
844 		if (!(depth & 4))
845 		    goto vrc;
846 	    hrc:  /* (hvcurveto vhcurveto)+ hrcurveto => hvcurveto */
847 		/* vhcurveto (hvcurveto vhcurveto)* hrcurveto => vhcurveto */
848 		if (csp[-4] != 0)
849 		    goto copy;
850 		/* A 0 C D E F => A C D F E */
851 		memmove(csp - 4, csp - 3, sizeof(*csp) * 2);
852 		csp[-2] = *csp;
853 		c = prev_op;
854 		POP(1);
855 		goto put;
856 	    case cx_rlineto:	/* rlineto+ rrcurveto => rlinecurve */
857 		c = c2_rlinecurve;
858 		goto put;
859 	    case cx_rrcurveto:	/* rrcurveto+ => rrcurveto */
860 		goto put;
861 	    default:
862 		goto copy;
863 	    }
864 	}
865     }
866 }
867