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