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 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 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 92 type1_clear(gs_type1_state *pcis) 93 { 94 pcis->os_count = 0; 95 } 96 97 /* Execute a callsubr. */ 98 private int 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 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 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 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 299 sputc2(stream *s, int i) 300 { 301 sputc(s, (byte)(i >> 8)); 302 sputc(s, (byte)i); 303 } 304 private void 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 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 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 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 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 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 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