1 /* Copyright (C) 1996, 2000 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: gstype2.c,v 1.10.2.3.2.1 2003/01/17 00:49:03 giles Exp $ */
20 /* Adobe Type 2 charstring interpreter */
21 #include "math_.h"
22 #include "memory_.h"
23 #include "gx.h"
24 #include "gserrors.h"
25 #include "gsstruct.h"
26 #include "gxarith.h"
27 #include "gxfixed.h"
28 #include "gxmatrix.h"
29 #include "gxcoord.h"
30 #include "gxistate.h"
31 #include "gzpath.h"
32 #include "gxfont.h"
33 #include "gxfont1.h"
34 #include "gxtype1.h"
35 
36 /* NOTE: The following are not yet implemented:
37  *	Registry items other than 0
38  *	Counter masks (but they are parsed correctly)
39  *	'random' operator
40  */
41 
42 /* ------ Internal routines ------ */
43 
44 /*
45  * Set the character width.  This is provided as an optional extra operand
46  * on the stack for the first operator.  After setting the width, we remove
47  * the extra operand, and back up the interpreter pointer so we will
48  * re-execute the operator when control re-enters the interpreter.
49  */
50 #define check_first_operator(explicit_width)\
51   BEGIN\
52     if ( pcis->init_done < 0 )\
53       { ipsp->ip = cip, ipsp->dstate = state;\
54 	return type2_sbw(pcis, csp, cstack, ipsp, explicit_width);\
55       }\
56   END
57 private int
type2_sbw(gs_type1_state * pcis,cs_ptr csp,cs_ptr cstack,ip_state_t * ipsp,bool explicit_width)58 type2_sbw(gs_type1_state * pcis, cs_ptr csp, cs_ptr cstack, ip_state_t * ipsp,
59 	  bool explicit_width)
60 {
61     fixed wx;
62 
63     if (explicit_width) {
64 	wx = cstack[0] + pcis->pfont->data.nominalWidthX;
65 	memmove(cstack, cstack + 1, (csp - cstack) * sizeof(*cstack));
66 	--csp;
67     } else
68 	wx = pcis->pfont->data.defaultWidthX;
69     gs_type1_sbw(pcis, fixed_0, fixed_0, wx, fixed_0);
70     /* Back up the interpretation pointer. */
71     ipsp->ip--;
72     decrypt_skip_previous(*ipsp->ip, ipsp->dstate);
73     /* Save the interpreter state. */
74     pcis->os_count = csp + 1 - cstack;
75     pcis->ips_count = ipsp - &pcis->ipstack[0] + 1;
76     memcpy(pcis->ostack, cstack, pcis->os_count * sizeof(cstack[0]));
77     if (pcis->init_done < 0) {	/* Finish init when we return. */
78 	pcis->init_done = 0;
79     }
80     return type1_result_sbw;
81 }
82 private int
type2_vstem(gs_type1_state * pcis,cs_ptr csp,cs_ptr cstack)83 type2_vstem(gs_type1_state * pcis, cs_ptr csp, cs_ptr cstack)
84 {
85     fixed x = 0;
86     cs_ptr ap;
87 
88     apply_path_hints(pcis, false);
89     for (ap = cstack; ap + 1 <= csp; x += ap[1], ap += 2)
90 	type1_vstem(pcis, x += ap[0], ap[1]);
91     pcis->num_hints += (csp + 1 - cstack) >> 1;
92     return 0;
93 }
94 
95 /* Enable only the hints selected by a mask. */
96 private void
enable_hints(stem_hint_table * psht,const byte * mask)97 enable_hints(stem_hint_table * psht, const byte * mask)
98 {
99     stem_hint *table = &psht->data[0];
100     stem_hint *ph = table + psht->current;
101 
102     for (ph = &table[psht->count]; --ph >= table;) {
103 	ph->active = (mask[ph->index >> 3] & (0x80 >> (ph->index & 7))) != 0;
104 	if_debug6('1', "[1]  %s %u: %g(%g),%g(%g)\n",
105 		  (ph->active ? "enable" : "disable"), ph->index,
106 		  fixed2float(ph->v0), fixed2float(ph->dv0),
107 		  fixed2float(ph->v1), fixed2float(ph->dv1));
108     }
109 }
110 
111 /* ------ Main interpreter ------ */
112 
113 /*
114  * Continue interpreting a Type 2 charstring.  If str != 0, it is taken as
115  * the byte string to interpret.  Return 0 on successful completion, <0 on
116  * error, or >0 when client intervention is required (or allowed).  The int*
117  * argument is only for compatibility with the Type 1 charstring interpreter.
118  */
119 int
gs_type2_interpret(gs_type1_state * pcis,const gs_const_string * str,int * ignore_pindex)120 gs_type2_interpret(gs_type1_state * pcis, const gs_const_string * str,
121 		   int *ignore_pindex)
122 {
123     gs_font_type1 *pfont = pcis->pfont;
124     gs_type1_data *pdata = &pfont->data;
125     bool encrypted = pdata->lenIV >= 0;
126     gs_op1_state s;
127     fixed cstack[ostack_size];
128     cs_ptr csp;
129 #define clear CLEAR_CSTACK(cstack, csp)
130     ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1];
131     register const byte *cip;
132     register crypt_state state;
133     register int c;
134     cs_ptr ap;
135     bool vertical;
136     int code = 0;
137 
138 /****** FAKE THE REGISTRY ******/
139     struct {
140 	float *values;
141 	uint size;
142     } Registry[1];
143 
144     Registry[0].values = pcis->pfont->data.WeightVector.values;
145 
146     switch (pcis->init_done) {
147 	case -1:
148 	    break;
149 	case 0:
150 	    gs_type1_finish_init(pcis, &s);	/* sets sfc, ptx, pty, origin */
151 	    break;
152 	default /*case 1 */ :
153 	    ptx = pcis->position.x;
154 	    pty = pcis->position.y;
155 	    sfc = pcis->fc;
156     }
157     sppath = pcis->path;
158     s.pcis = pcis;
159     INIT_CSTACK(cstack, csp, pcis);
160 
161     if (str == 0)
162 	goto cont;
163     ipsp->char_string = *str;
164     ipsp->free_char_string = 0;	/* don't free caller-supplied strings */
165     cip = str->data;
166   call:state = crypt_charstring_seed;
167     if (encrypted) {
168 	int skip = pdata->lenIV;
169 
170 	/* Skip initial random bytes */
171 	for (; skip > 0; ++cip, --skip)
172 	    decrypt_skip_next(*cip, state);
173     }
174     goto top;
175   cont:cip = ipsp->ip;
176     state = ipsp->dstate;
177   top:for (;;) {
178 	uint c0 = *cip++;
179 
180 	charstring_next(c0, state, c, encrypted);
181 	if (c >= c_num1) {
182 	    /* This is a number, decode it and push it on the stack. */
183 
184 	    if (c < c_pos2_0) {	/* 1-byte number */
185 		decode_push_num1(csp, c);
186 	    } else if (c < cx_num4) {	/* 2-byte number */
187 		decode_push_num2(csp, c, cip, state, encrypted);
188 	    } else if (c == cx_num4) {	/* 4-byte number */
189 		long lw;
190 
191 		decode_num4(lw, cip, state, encrypted);
192 		/* 32-bit numbers are 16:16. */
193 		*++csp = arith_rshift(lw, 16 - _fixed_shift);
194 	    } else		/* not possible */
195 		return_error(gs_error_invalidfont);
196 	  pushed:if_debug3('1', "[1]%d: (%d) %f\n",
197 		      (int)(csp - cstack), c, fixed2float(*csp));
198 	    continue;
199 	}
200 #ifdef DEBUG
201 	if (gs_debug['1']) {
202 	    static const char *const c2names[] =
203 	    {char2_command_names};
204 
205 	    if (c2names[c] == 0)
206 		dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c);
207 	    else
208 		dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c,
209 			  c2names[c]);
210 	}
211 #endif
212 	switch ((char_command) c) {
213 #define cnext clear; goto top
214 
215 		/* Commands with identical functions in Type 1 and Type 2, */
216 		/* except for 'escape'. */
217 
218 	    case c_undef0:
219 	    case c_undef2:
220 	    case c_undef17:
221 		return_error(gs_error_invalidfont);
222 	    case c_callsubr:
223 		c = fixed2int_var(*csp) + pdata->subroutineNumberBias;
224 		code = pdata->procs.subr_data
225 		    (pfont, c, false, &ipsp[1].char_string);
226 	      subr:if (code < 0) {
227 	            /* Calling a Subr with an out-of-range index is clearly a error:
228 	             * the Adobe documentation says the results of doing this are
229 	             * undefined. However, we have seen a PDF file produced by Adobe
230 	             * PDF Library 4.16 that included a Type 2 font that called an
231 	             * out-of-range Subr, and Acrobat Reader did not signal an error.
232 	             * Therefore, we ignore such calls.
233 	             */
234                     cip++;
235                     goto top;
236                 }
237 		--csp;
238 		ipsp->ip = cip, ipsp->dstate = state;
239 		++ipsp;
240 		ipsp->free_char_string = code;
241 		cip = ipsp->char_string.data;
242 		goto call;
243 	    case c_return:
244 		if (ipsp->free_char_string > 0)
245 		    gs_free_const_string(pfont->memory,
246 					 ipsp->char_string.data,
247 					 ipsp->char_string.size,
248 					 "gs_type2_interpret");
249 		--ipsp;
250 		goto cont;
251 	    case c_undoc15:
252 		/* See gstype1.h for information on this opcode. */
253 		cnext;
254 
255 		/* Commands with similar but not identical functions */
256 		/* in Type 1 and Type 2 charstrings. */
257 
258 	    case cx_hstem:
259 		goto hstem;
260 	    case cx_vstem:
261 		goto vstem;
262 	    case cx_vmoveto:
263 		/*
264 		 * Type 2 CharStrings, unlike Type 1, insert an explicit
265 		 * closepath before a moveto rather than an implicit one.
266 		 * (This makes a difference for charpath.)  Note that if
267 		 * we are just getting the glyph info, sppath may be 0:
268 		 * this is OK, because check_first_operator will return.
269 		 */
270 		if (pfont->PaintType != 1 && sppath != 0) {
271 		    code = gx_path_close_subpath(sppath);
272 		    if (code < 0)
273 			return code;
274 		}
275 		check_first_operator(csp > cstack);
276 		accum_y(*csp);
277 	      move:if ((pcis->hint_next != 0 || path_is_drawing(sppath)))
278 		    apply_path_hints(pcis, true);
279 		code = gx_path_add_point(sppath, ptx, pty);
280 	      cc:if (code < 0)
281 		    return code;
282 		goto pp;
283 	    case cx_rlineto:
284 		for (ap = cstack; ap + 1 <= csp; ap += 2) {
285 		    accum_xy(ap[0], ap[1]);
286 		    code = gx_path_add_line(sppath, ptx, pty);
287 		    if (code < 0)
288 			return code;
289 		}
290 	      pp:if_debug2('1', "[1]pt=(%g,%g)\n",
291 			  fixed2float(ptx), fixed2float(pty));
292 		cnext;
293 	    case cx_hlineto:
294 		vertical = false;
295 		goto hvl;
296 	    case cx_vlineto:
297 		vertical = true;
298 	      hvl:for (ap = cstack; ap <= csp; vertical = !vertical, ++ap) {
299 		    if (vertical)
300 			accum_y(*ap);
301 		    else
302 			accum_x(*ap);
303 		    code = gx_path_add_line(sppath, ptx, pty);
304 		    if (code < 0)
305 			return code;
306 		}
307 		goto pp;
308 	    case cx_rrcurveto:
309 		for (ap = cstack; ap + 5 <= csp; ap += 6) {
310 		    code = gs_op1_rrcurveto(&s, ap[0], ap[1], ap[2],
311 					    ap[3], ap[4], ap[5]);
312 		    if (code < 0)
313 			return code;
314 		}
315 		goto pp;
316 	    case cx_endchar:
317 		/*
318 		 * See vmoveto above re closing the subpath.  Note that
319 		 * sppath may be 0 if we are just getting the glyph info.
320 		 */
321 		if (pfont->PaintType != 1 && sppath != 0) {
322 		    code = gx_path_close_subpath(sppath);
323 		    if (code < 0)
324 			return code;
325 		}
326 		/*
327 		 * It is an undocumented (!) feature of Type 2 CharStrings
328 		 * that if endchar is invoked with 4 or 5 operands, it is
329 		 * equivalent to the Type 1 seac operator!  In this case,
330 		 * the asb operand of seac is missing: we assume it is
331 		 * the same as the l.s.b. of the accented character.
332 		 */
333 		if (csp >= cstack + 3) {
334 		    check_first_operator(csp > cstack + 3);
335 		    code = gs_type1_seac(pcis, cstack, pcis->lsb.x, ipsp);
336 		    if (code < 0)
337 			return code;
338 		    clear;
339 		    cip = ipsp->char_string.data;
340 		    goto call;
341 		}
342 		/*
343 		 * This might be the only operator in the charstring.
344 		 * In this case, there might be a width on the stack.
345 		 */
346 		check_first_operator(csp >= cstack);
347 		code = gs_type1_endchar(pcis);
348 		if (code == 1) {
349 		    /*
350 		     * Reset the total hint count so that hintmask will
351 		     * parse its following data correctly.
352 		     * (gs_type1_endchar already reset the actual hint
353 		     * tables.)
354 		     */
355 		    pcis->num_hints = 0;
356 		    /* do accent of seac */
357 		    spt = pcis->position;
358 		    ipsp = &pcis->ipstack[pcis->ips_count - 1];
359 		    cip = ipsp->char_string.data;
360 		    goto call;
361 		}
362 		return code;
363 	    case cx_rmoveto:
364 		/* See vmoveto above re closing the subpath. */
365 		if (pfont->PaintType != 1 && sppath != 0) {
366 		    code = gx_path_close_subpath(sppath);
367 		    if (code < 0)
368 			return code;
369 		}
370 		check_first_operator(csp > cstack + 1);
371 		accum_xy(csp[-1], *csp);
372 		goto move;
373 	    case cx_hmoveto:
374 		/* See vmoveto above re closing the subpath. */
375 		if (pfont->PaintType != 1 && sppath != 0) {
376 		    code = gx_path_close_subpath(sppath);
377 		    if (code < 0)
378 			return code;
379 		}
380 		check_first_operator(csp > cstack);
381 		accum_x(*csp);
382 		goto move;
383 	    case cx_vhcurveto:
384 		vertical = true;
385 		goto hvc;
386 	    case cx_hvcurveto:
387 		vertical = false;
388 	      hvc:for (ap = cstack; ap + 3 <= csp; vertical = !vertical, ap += 4) {
389 		    gs_fixed_point pt1, pt2;
390 		    fixed ax0 = sppath->position.x - ptx;
391 		    fixed ay0 = sppath->position.y - pty;
392 
393 		    if (vertical)
394 			accum_y(ap[0]);
395 		    else
396 			accum_x(ap[0]);
397 		    pt1.x = ptx + ax0, pt1.y = pty + ay0;
398 		    accum_xy(ap[1], ap[2]);
399 		    pt2.x = ptx, pt2.y = pty;
400 		    if (vertical) {
401 			if (ap + 4 == csp)
402 			    accum_xy(ap[3], ap[4]);
403 			else
404 			    accum_x(ap[3]);
405 		    } else {
406 			if (ap + 4 == csp)
407 			    accum_xy(ap[4], ap[3]);
408 			else
409 			    accum_y(ap[3]);
410 		    }
411 		    code = gx_path_add_curve(sppath, pt1.x, pt1.y,
412 					     pt2.x, pt2.y, ptx, pty);
413 		    if (code < 0)
414 			return code;
415 		}
416 		goto pp;
417 
418 			/***********************
419 			 * New Type 2 commands *
420 			 ***********************/
421 
422 	    case c2_blend:
423 		{
424 		    int n = fixed2int_var(*csp);
425 		    int num_values = csp - cstack;
426 		    gs_font_type1 *pfont = pcis->pfont;
427 		    int k = pfont->data.WeightVector.count;
428 		    int i, j;
429 		    cs_ptr base, deltas;
430 
431 		    base = csp - 1 - num_values;
432 		    deltas = base + n - 1;
433 		    for (j = 0; j < n; j++, base++, deltas += k - 1)
434 			for (i = 1; i < k; i++)
435 			    *base += deltas[i] * pfont->data.WeightVector.values[i];
436 		}
437 		cnext;
438 	    case c2_hstemhm:
439 		pcis->have_hintmask = true;
440 	      hstem:check_first_operator(!((csp - cstack) & 1));
441 		apply_path_hints(pcis, false);
442 		{
443 		    fixed x = 0;
444 
445 		    for (ap = cstack; ap + 1 <= csp; x += ap[1], ap += 2)
446 			type1_hstem(pcis, x += ap[0], ap[1]);
447 		}
448 		pcis->num_hints += (csp + 1 - cstack) >> 1;
449 		cnext;
450 	    case c2_hintmask:
451 		/*
452 		 * A hintmask at the beginning of the CharString is
453 		 * equivalent to vstemhm + hintmask.  For simplicity, we use
454 		 * this interpretation everywhere.
455 		 *
456 		 * Even though the Adobe documentation doesn't say this,
457 		 * it appears that the same holds true for cntrmask.
458 		 */
459 	    case c2_cntrmask:
460 		pcis->have_hintmask = true;
461 		check_first_operator(!((csp - cstack) & 1));
462 		type2_vstem(pcis, csp, cstack);
463 		/*
464 		 * We should clear the stack here only if this is the
465 		 * initial mask operator that includes the implicit
466 		 * vstemhm, but currently this is too much trouble to
467 		 * detect.
468 		 */
469 		clear;
470 		{
471 		    byte mask[max_total_stem_hints / 8];
472 		    int i;
473 
474 		    if_debug3('1', "[1]mask[%d:%dh,%dv]", pcis->num_hints,
475 			  pcis->hstem_hints.count, pcis->vstem_hints.count);
476 		    for (i = 0; i < pcis->num_hints; ++cip, i += 8) {
477 			charstring_next(*cip, state, mask[i >> 3], encrypted);
478 			if_debug1('1', " 0x%02x", mask[i >> 3]);
479 		    }
480 		    if_debug0('1', "\n");
481 		    ipsp->ip = cip;
482 		    ipsp->dstate = state;
483 		    if (c == c2_cntrmask) {
484 			/****** NYI ******/
485 		    } else {	/* hintmask or equivalent */
486 			if_debug0('1', "[1]hstem hints:\n");
487 			enable_hints(&pcis->hstem_hints, mask);
488 			if_debug0('1', "[1]vstem hints:\n");
489 			enable_hints(&pcis->vstem_hints, mask);
490 		    }
491 		}
492 		break;
493 	    case c2_vstemhm:
494 		pcis->have_hintmask = true;
495 	      vstem:check_first_operator(!((csp - cstack) & 1));
496 		type2_vstem(pcis, csp, cstack);
497 		cnext;
498 	    case c2_rcurveline:
499 		for (ap = cstack; ap + 5 <= csp; ap += 6) {
500 		    code = gs_op1_rrcurveto(&s, ap[0], ap[1], ap[2], ap[3],
501 					    ap[4], ap[5]);
502 		    if (code < 0)
503 			return code;
504 		}
505 		accum_xy(ap[0], ap[1]);
506 		code = gx_path_add_line(sppath, ptx, pty);
507 		goto cc;
508 	    case c2_rlinecurve:
509 		for (ap = cstack; ap + 7 <= csp; ap += 2) {
510 		    accum_xy(ap[0], ap[1]);
511 		    code = gx_path_add_line(sppath, ptx, pty);
512 		    if (code < 0)
513 			return code;
514 		}
515 		code = gs_op1_rrcurveto(&s, ap[0], ap[1], ap[2], ap[3],
516 					ap[4], ap[5]);
517 		goto cc;
518 	    case c2_vvcurveto:
519 		ap = cstack;
520 		{
521 		    int n = csp + 1 - cstack;
522 		    fixed dxa = (n & 1 ? *ap++ : 0);
523 
524 		    for (; ap + 3 <= csp; ap += 4) {
525 			code = gs_op1_rrcurveto(&s, dxa, ap[0], ap[1], ap[2],
526 						fixed_0, ap[3]);
527 			if (code < 0)
528 			    return code;
529 			dxa = 0;
530 		    }
531 		}
532 		goto pp;
533 	    case c2_hhcurveto:
534 		ap = cstack;
535 		{
536 		    int n = csp + 1 - cstack;
537 		    fixed dya = (n & 1 ? *ap++ : 0);
538 
539 		    for (; ap + 3 <= csp; ap += 4) {
540 			code = gs_op1_rrcurveto(&s, ap[0], dya, ap[1], ap[2],
541 						ap[3], fixed_0);
542 			if (code < 0)
543 			    return code;
544 			dya = 0;
545 		    }
546 		}
547 		goto pp;
548 	    case c2_shortint:
549 		{
550 		    int c1, c2;
551 
552 		    charstring_next(*cip, state, c1, encrypted);
553 		    ++cip;
554 		    charstring_next(*cip, state, c2, encrypted);
555 		    ++cip;
556 		    *++csp = int2fixed((((c1 ^ 0x80) - 0x80) << 8) + c2);
557 		}
558 		goto pushed;
559 	    case c2_callgsubr:
560 		c = fixed2int_var(*csp) + pdata->gsubrNumberBias;
561 		code = pdata->procs.subr_data
562 		    (pfont, c, true, &ipsp[1].char_string);
563 		goto subr;
564 	    case cx_escape:
565 		charstring_next(*cip, state, c, encrypted);
566 		++cip;
567 #ifdef DEBUG
568 		if (gs_debug['1'] && c < char2_extended_command_count) {
569 		    static const char *const ce2names[] =
570 		    {char2_extended_command_names};
571 
572 		    if (ce2names[c] == 0)
573 			dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c);
574 		    else
575 			dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c,
576 				  ce2names[c]);
577 		}
578 #endif
579 		switch ((char2_extended_command) c) {
580 		    case ce2_and:
581 			csp[-1] = ((csp[-1] != 0) & (*csp != 0) ? fixed_1 : 0);
582 			--csp;
583 			break;
584 		    case ce2_or:
585 			csp[-1] = (csp[-1] | *csp ? fixed_1 : 0);
586 			--csp;
587 			break;
588 		    case ce2_not:
589 			*csp = (*csp ? 0 : fixed_1);
590 			break;
591 		    case ce2_store:
592 			{
593 			    int i, n = fixed2int_var(*csp);
594 			    float *to = Registry[fixed2int_var(csp[-3])].values +
595 			    fixed2int_var(csp[-2]);
596 			    const fixed *from =
597 			    pcis->transient_array + fixed2int_var(csp[-1]);
598 
599 			    for (i = 0; i < n; ++i)
600 				to[i] = fixed2float(from[i]);
601 			}
602 			csp -= 4;
603 			break;
604 		    case ce2_abs:
605 			if (*csp < 0)
606 			    *csp = -*csp;
607 			break;
608 		    case ce2_add:
609 			csp[-1] += *csp;
610 			--csp;
611 			break;
612 		    case ce2_sub:
613 			csp[-1] -= *csp;
614 			--csp;
615 			break;
616 		    case ce2_div:
617 			csp[-1] = float2fixed((double)csp[-1] / *csp);
618 			--csp;
619 			break;
620 		    case ce2_load:
621 			/* The specification says there is no j (starting index */
622 			/* in registry array) argument.... */
623 			{
624 			    int i, n = fixed2int_var(*csp);
625 			    const float *from = Registry[fixed2int_var(csp[-2])].values;
626 			    fixed *to =
627 			    pcis->transient_array + fixed2int_var(csp[-1]);
628 
629 			    for (i = 0; i < n; ++i)
630 				to[i] = float2fixed(from[i]);
631 			}
632 			csp -= 3;
633 			break;
634 		    case ce2_neg:
635 			*csp = -*csp;
636 			break;
637 		    case ce2_eq:
638 			csp[-1] = (csp[-1] == *csp ? fixed_1 : 0);
639 			--csp;
640 			break;
641 		    case ce2_drop:
642 			--csp;
643 			break;
644 		    case ce2_put:
645 			pcis->transient_array[fixed2int_var(*csp)] = csp[-1];
646 			csp -= 2;
647 			break;
648 		    case ce2_get:
649 			*csp = pcis->transient_array[fixed2int_var(*csp)];
650 			break;
651 		    case ce2_ifelse:
652 			if (csp[-1] > *csp)
653 			    csp[-3] = csp[-2];
654 			csp -= 3;
655 			break;
656 		    case ce2_random:
657 			++csp;
658 			/****** NYI ******/
659 			break;
660 		    case ce2_mul:
661 			{
662 			    double prod = fixed2float(csp[-1]) * *csp;
663 
664 			    csp[-1] =
665 				(prod > max_fixed ? max_fixed :
666 				 prod < min_fixed ? min_fixed : prod);
667 			}
668 			--csp;
669 			break;
670 		    case ce2_sqrt:
671 			if (*csp >= 0)
672 			    *csp = float2fixed(sqrt(fixed2float(*csp)));
673 			break;
674 		    case ce2_dup:
675 			csp[1] = *csp;
676 			++csp;
677 			break;
678 		    case ce2_exch:
679 			{
680 			    fixed top = *csp;
681 
682 			    *csp = csp[-1], csp[-1] = top;
683 			}
684 			break;
685 		    case ce2_index:
686 			*csp =
687 			    (*csp < 0 ? csp[-1] : csp[-1 - fixed2int_var(csp[-1])]);
688 			break;
689 		    case ce2_roll:
690 			{
691 			    int distance = fixed2int_var(*csp);
692 			    int count = fixed2int_var(csp[-1]);
693 			    cs_ptr bot;
694 
695 			    csp -= 2;
696 			    if (count < 0 || count > csp + 1 - cstack)
697 				return_error(gs_error_invalidfont);
698 			    if (count == 0)
699 				break;
700 			    if (distance < 0)
701 				distance = count - (-distance % count);
702 			    bot = csp + 1 - count;
703 			    while (--distance >= 0) {
704 				fixed top = *csp;
705 
706 				memmove(bot + 1, bot,
707 					(count - 1) * sizeof(fixed));
708 				*bot = top;
709 			    }
710 			}
711 			break;
712 		    case ce2_hflex:
713 			csp[6] = fixed_half;	/* fd/100 */
714 			csp[4] = *csp, csp[5] = 0;	/* dx6, dy6 */
715 			csp[2] = csp[-1], csp[3] = -csp[-4];	/* dx5, dy5 */
716 			*csp = csp[-2], csp[1] = 0;	/* dx4, dy4 */
717 			csp[-2] = csp[-3], csp[-1] = 0;		/* dx3, dy3 */
718 			csp[-3] = csp[-4], csp[-4] = csp[-5];	/* dx2, dy2 */
719 			csp[-5] = 0;	/* dy1 */
720 			csp += 6;
721 			goto flex;
722 		    case ce2_flex:
723 			*csp /= 100;	/* fd/100 */
724 flex:			{
725 			    fixed x_join = csp[-12] + csp[-10] + csp[-8];
726 			    fixed y_join = csp[-11] + csp[-9] + csp[-7];
727 			    fixed x_end = x_join + csp[-6] + csp[-4] + csp[-2];
728 			    fixed y_end = y_join + csp[-5] + csp[-3] + csp[-1];
729 			    gs_point join, end;
730 			    double flex_depth;
731 
732 			    if ((code =
733 				 gs_distance_transform(fixed2float(x_join),
734 						       fixed2float(y_join),
735 						       &ctm_only(pcis->pis),
736 						       &join)) < 0 ||
737 				(code =
738 				 gs_distance_transform(fixed2float(x_end),
739 						       fixed2float(y_end),
740 						       &ctm_only(pcis->pis),
741 						       &end)) < 0
742 				)
743 				return code;
744 			    /*
745 			     * Use the X or Y distance depending on whether
746 			     * the curve is more horizontal or more
747 			     * vertical.
748 			     */
749 			    if (any_abs(end.y) > any_abs(end.x))
750 				flex_depth = join.x;
751 			    else
752 				flex_depth = join.y;
753 			    if (fabs(flex_depth) < fixed2float(*csp)) {
754 				/* Do flex as line. */
755 				accum_xy(x_end, y_end);
756 				code = gx_path_add_line(sppath, ptx, pty);
757 			    } else {
758 				/*
759 				 * Do flex as curve.  We can't jump to rrc,
760 				 * because the flex operators don't clear
761 				 * the stack (!).
762 				 */
763 				code = gs_op1_rrcurveto(&s,
764 					csp[-12], csp[-11], csp[-10],
765 					csp[-9], csp[-8], csp[-7]);
766 				if (code < 0)
767 				    return code;
768 				code = gs_op1_rrcurveto(&s,
769 					csp[-6], csp[-5], csp[-4],
770 					csp[-3], csp[-2], csp[-1]);
771 			    }
772 			    if (code < 0)
773 				return code;
774 			    csp -= 13;
775 			}
776 			cnext;
777 		    case ce2_hflex1:
778 			csp[4] = fixed_half;	/* fd/100 */
779 			csp[2] = *csp;          /* dx6 */
780 			csp[3] = -(csp[-7] + csp[-5] + csp[-1]);	/* dy6 */
781 			*csp = csp[-2], csp[1] = csp[-1];	/* dx5, dy5 */
782 			csp[-2] = csp[-3], csp[-1] = 0;		/* dx4, dy4 */
783 			csp[-3] = 0;	/* dy3 */
784 			csp += 4;
785 			goto flex;
786 		    case ce2_flex1:
787 			{
788 			    fixed dx = csp[-10] + csp[-8] + csp[-6] + csp[-4] + csp[-2];
789 			    fixed dy = csp[-9] + csp[-7] + csp[-5] + csp[-3] + csp[-1];
790 
791 			    if (any_abs(dx) > any_abs(dy))
792 				csp[1] = -dy;	/* d6 is dx6 */
793 			    else
794 				csp[1] = *csp, *csp = -dx;	/* d6 is dy6 */
795 			}
796 			csp[2] = fixed_half;	/* fd/100 */
797 			csp += 2;
798 			goto flex;
799 		}
800 		break;
801 
802 		/* Fill up the dispatch up to 32. */
803 
804 	      case_c2_undefs:
805 	    default:		/* pacify compiler */
806 		return_error(gs_error_invalidfont);
807 	}
808     }
809 }
810