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