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