static inline int gs_arc_add_inline(gs_state *pgs, bool cw, floatp xc, floatp yc, floatp rad, floatp a1, floatp a2, bool add) { gs_point p3; int code = gs_imager_arc_add(pgs->path, (gs_imager_state *)pgs, cw, xc, yc, rad, a1, a2, add, &p3); if (code < 0) return code; #if !PRECISE_CURRENTPOINT return gx_setcurrentpoint_from_path((gs_imager_state *)pgs, pgs->path); #else pgs->current_point_valid = true; return gs_point_transform(p3.x, p3.y, &ctm_only(pgs), &pgs->current_point); #endif }
/* * Continue interpreting a Type 1 charstring. If str != 0, it is taken as * the byte string to interpret. Return 0 on successful completion, <0 on * error, or >0 when client intervention is required (or allowed). The int* * argument is where the othersubr # is stored for callothersubr. */ int gs_type1_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd, int *pindex) { gs_font_type1 *pfont = pcis->pfont; gs_type1_data *pdata = &pfont->data; t1_hinter *h = &pcis->h; bool encrypted = pdata->lenIV >= 0; fixed cstack[ostack_size]; #define cs0 cstack[0] #define ics0 fixed2int_var(cs0) #define cs1 cstack[1] #define ics1 fixed2int_var(cs1) #define cs2 cstack[2] #define ics2 fixed2int_var(cs2) #define cs3 cstack[3] #define ics3 fixed2int_var(cs3) #define cs4 cstack[4] #define ics4 fixed2int_var(cs4) #define cs5 cstack[5] #define ics5 fixed2int_var(cs5) cs_ptr csp; #define clear CLEAR_CSTACK(cstack, csp) ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1]; register const byte *cip; register crypt_state state; register int c; int code = 0; fixed ftx = pcis->origin.x, fty = pcis->origin.y; switch (pcis->init_done) { case -1: t1_hinter__init(h, pcis->path); break; case 0: gs_type1_finish_init(pcis); /* sets origin */ ftx = pcis->origin.x, fty = pcis->origin.y; code = t1_hinter__set_mapping(h, &pcis->pis->ctm, &pfont->FontMatrix, &pfont->base->FontMatrix, pcis->scale.x.log2_unit, pcis->scale.x.log2_unit, pcis->scale.x.log2_unit - pcis->log2_subpixels.x, pcis->scale.y.log2_unit - pcis->log2_subpixels.y, pcis->origin.x, pcis->origin.y, gs_currentaligntopixels(pfont->dir)); if (code < 0) return code; code = t1_hinter__set_font_data(h, 1, pdata, pcis->no_grid_fitting); if (code < 0) return code; break; default /*case 1 */ : break; } INIT_CSTACK(cstack, csp, pcis); if (pgd == 0) goto cont; ipsp->cs_data = *pgd; cip = pgd->bits.data; call:state = crypt_charstring_seed; if (encrypted) { int skip = pdata->lenIV; /* Skip initial random bytes */ for (; skip > 0; ++cip, --skip) decrypt_skip_next(*cip, state); } goto top; cont:cip = ipsp->ip; state = ipsp->dstate; top:for (;;) { uint c0 = *cip++; charstring_next(c0, state, c, encrypted); if (c >= c_num1) { /* This is a number, decode it and push it on the stack. */ if (c < c_pos2_0) { /* 1-byte number */ decode_push_num1(csp, cstack, c); } else if (c < cx_num4) { /* 2-byte number */ decode_push_num2(csp, cstack, c, cip, state, encrypted); } else if (c == cx_num4) { /* 4-byte number */ long lw; decode_num4(lw, cip, state, encrypted); CS_CHECK_PUSH(csp, cstack); *++csp = int2fixed(lw); if (lw != fixed2long(*csp)) { /* * We handle the only case we've ever seen that * actually uses such large numbers specially. */ long denom; c0 = *cip++; charstring_next(c0, state, c, encrypted); if (c < c_num1) return_error(gs_error_rangecheck); if (c < c_pos2_0) decode_num1(denom, c); else if (c < cx_num4) decode_num2(denom, c, cip, state, encrypted); else if (c == cx_num4) decode_num4(denom, cip, state, encrypted); else return_error(gs_error_invalidfont); c0 = *cip++; charstring_next(c0, state, c, encrypted); if (c != cx_escape) return_error(gs_error_rangecheck); c0 = *cip++; charstring_next(c0, state, c, encrypted); if (c != ce1_div) return_error(gs_error_rangecheck); *csp = float2fixed((double)lw / denom); } } else /* not possible */ return_error(gs_error_invalidfont); pushed:if_debug3('1', "[1]%d: (%d) %f\n", (int)(csp - cstack), c, fixed2float(*csp)); continue; } #ifdef DEBUG if (gs_debug['1']) { static const char *const c1names[] = {char1_command_names}; if (c1names[c] == 0) dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c); else dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c, c1names[c]); } #endif switch ((char_command) c) { #define cnext clear; goto top #define inext goto top /* Commands with identical functions in Type 1 and Type 2, */ /* except for 'escape'. */ case c_undef0: case c_undef2: case c_undef17: return_error(gs_error_invalidfont); case c_callsubr: c = fixed2int_var(*csp) + pdata->subroutineNumberBias; code = pdata->procs.subr_data (pfont, c, false, &ipsp[1].cs_data); if (code < 0) return_error(code); --csp; ipsp->ip = cip, ipsp->dstate = state; ++ipsp; cip = ipsp->cs_data.bits.data; goto call; case c_return: gs_glyph_data_free(&ipsp->cs_data, "gs_type1_interpret"); --ipsp; goto cont; case c_undoc15: /* See gstype1.h for information on this opcode. */ cnext; /* Commands with similar but not identical functions */ /* in Type 1 and Type 2 charstrings. */ case cx_hstem: code = t1_hinter__hstem(h, cs0, cs1); if (code < 0) return code; cnext; case cx_vstem: code = t1_hinter__vstem(h, cs0, cs1); if (code < 0) return code; cnext; case cx_vmoveto: cs1 = cs0; cs0 = 0; move: /* cs0 = dx, cs1 = dy for hint checking. */ code = t1_hinter__rmoveto(h, cs0, cs1); goto cc; case cx_rlineto: line: /* cs0 = dx, cs1 = dy for hint checking. */ code = t1_hinter__rlineto(h, cs0, cs1); cc:if (code < 0) return code; cnext; case cx_hlineto: cs1 = 0; goto line; case cx_vlineto: cs1 = cs0; cs0 = 0; goto line; case cx_rrcurveto: code = t1_hinter__rcurveto(h, cs0, cs1, cs2, cs3, cs4, cs5); goto cc; case cx_endchar: code = t1_hinter__endchar(h, (pcis->seac_accent >= 0)); if (code < 0) return code; if (pcis->seac_accent < 0) { code = t1_hinter__endglyph(h); if (code < 0) return code; code = gx_setcurrentpoint_from_path(pcis->pis, pcis->path); if (code < 0) return code; } code = gs_type1_endchar(pcis); if (code == 1) { /* do accent of seac */ ipsp = &pcis->ipstack[pcis->ips_count - 1]; cip = ipsp->cs_data.bits.data; goto call; } return code; case cx_rmoveto: goto move; case cx_hmoveto: cs1 = 0; goto move; case cx_vhcurveto: code = t1_hinter__rcurveto(h, 0, cs0, cs1, cs2, cs3, 0); goto cc; case cx_hvcurveto: code = t1_hinter__rcurveto(h, cs0, 0, cs1, cs2, 0, cs3); goto cc; /* Commands only recognized in Type 1 charstrings, */ /* plus 'escape'. */ case c1_closepath: code = t1_hinter__closepath(h); goto cc; case c1_hsbw: if (!h->seac_flag) { fixed sbx = cs0, sby = fixed_0, wx = cs1, wy = fixed_0; if (pcis->sb_set) { sbx = pcis->lsb.x; sby = pcis->lsb.y; } if (pcis->width_set) { wx = pcis->width.x; wy = pcis->width.y; } code = t1_hinter__sbw(h, sbx, sby, wx, wy); } else code = t1_hinter__sbw_seac(h, pcis->adxy.x, pcis->adxy.y); if (code < 0) return code; gs_type1_sbw(pcis, cs0, fixed_0, cs1, fixed_0); cs1 = fixed_0; rsbw: /* Give the caller the opportunity to intervene. */ pcis->os_count = 0; /* clear */ ipsp->ip = cip, ipsp->dstate = state; pcis->ips_count = ipsp - &pcis->ipstack[0] + 1; /* If we aren't in a seac, do nothing else now; */ /* finish_init will take care of the rest. */ if (pcis->init_done < 0) { /* Finish init when we return. */ pcis->init_done = 0; } else { /* * Accumulate the side bearing now, but don't do it * a second time for the base character of a seac. */ if (pcis->seac_accent >= 0) { /* * As a special hack to work around a bug in * Fontographer, we deal with the (illegal) * situation in which the side bearing of the * accented character (save_lsbx) is different from * the side bearing of the base character (cs0/cs1). */ fixed dsbx = cs0 - pcis->save_lsb.x; fixed dsby = cs1 - pcis->save_lsb.y; if (dsbx | dsby) { pcis->lsb.x += dsbx; pcis->lsb.y += dsby; pcis->save_adxy.x -= dsbx; pcis->save_adxy.y -= dsby; } } } return type1_result_sbw; case cx_escape: charstring_next(*cip, state, c, encrypted); ++cip; #ifdef DEBUG if (gs_debug['1'] && c < char1_extended_command_count) { static const char *const ce1names[] = {char1_extended_command_names}; if (ce1names[c] == 0) dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c); else dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c, ce1names[c]); } #endif switch ((char1_extended_command) c) { case ce1_dotsection: code = t1_hinter__dotsection(h); if (code < 0) return code; cnext; case ce1_vstem3: code = t1_hinter__vstem3(h, cs0, cs1, cs2, cs3, cs4, cs5); if (code < 0) return code; cnext; case ce1_hstem3: code = t1_hinter__hstem3(h, cs0, cs1, cs2, cs3, cs4, cs5); if (code < 0) return code; cnext; case ce1_seac: code = gs_type1_seac(pcis, cstack + 1, cstack[0], ipsp); if (code != 0) { *pindex = ics3; return code; } clear; cip = ipsp->cs_data.bits.data; goto call; case ce1_sbw: if (!h->seac_flag) code = t1_hinter__sbw(h, cs0, cs1, cs2, cs3); else code = t1_hinter__sbw_seac(h, cs0 + pcis->adxy.x , cs1 + pcis->adxy.y); if (code < 0) return code; gs_type1_sbw(pcis, cs0, cs1, cs2, cs3); goto rsbw; case ce1_div: csp[-1] = float2fixed((double)csp[-1] / (double)*csp); --csp; goto pushed; case ce1_undoc15: /* See gstype1.h for information on this opcode. */ cnext; case ce1_callothersubr: { int num_results; /* We must remember to pop both the othersubr # */ /* and the argument count off the stack. */ switch (*pindex = fixed2int_var(*csp)) { case 0: { fixed fheight = csp[-4]; /* Assume the next two opcodes */ /* are `pop' `pop'. Unfortunately, some */ /* Monotype fonts put these in a Subr, */ /* so we can't just look ahead in the */ /* opcode stream. */ pcis->ignore_pops = 2; csp[-4] = csp[-3] - pcis->asb_diff; csp[-3] = csp[-2]; csp -= 3; code = t1_hinter__flex_end(h, fheight); } if (code < 0) return code; pcis->flex_count = flex_max; /* not inside flex */ inext; case 1: code = t1_hinter__flex_beg(h); if (code < 0) return code; pcis->flex_count = 1; csp -= 2; inext; case 2: if (pcis->flex_count >= flex_max) return_error(gs_error_invalidfont); code = t1_hinter__flex_point(h); if (code < 0) return code; csp -= 2; inext; case 3: /* Assume the next opcode is a `pop'. */ /* See above as to why we don't just */ /* look ahead in the opcode stream. */ pcis->ignore_pops = 1; code = t1_hinter__drop_hints(h); if (code < 0) return code; csp -= 2; inext; case 12: case 13: /* Counter control isn't implemented. */ cnext; case 14: num_results = 1; blend: code = gs_type1_blend(pcis, csp, num_results); if (code < 0) return code; csp -= code; inext; case 15: num_results = 2; goto blend; case 16: num_results = 3; goto blend; case 17: num_results = 4; goto blend; case 18: num_results = 6; goto blend; } } /* Not a recognized othersubr, */ /* let the client handle it. */ { int scount = csp - cstack; int n; /* Copy the arguments to the caller's stack. */ if (scount < 1 || csp[-1] < 0 || csp[-1] > int2fixed(scount - 1) ) return_error(gs_error_invalidfont); n = fixed2int_var(csp[-1]); code = (*pdata->procs.push_values) (pcis->callback_data, csp - (n + 1), n); if (code < 0) return_error(code); scount -= n + 1; /* Exit to caller */ ipsp->ip = cip, ipsp->dstate = state; pcis->os_count = scount; pcis->ips_count = ipsp - &pcis->ipstack[0] + 1; if (scount) memcpy(pcis->ostack, cstack, scount * sizeof(fixed)); return type1_result_callothersubr; } case ce1_pop: /* Check whether we're ignoring the pops after */ /* a known othersubr. */ if (pcis->ignore_pops != 0) { pcis->ignore_pops--; inext; } CS_CHECK_PUSH(csp, cstack); ++csp; code = (*pdata->procs.pop_value) (pcis->callback_data, csp); if (code < 0) return_error(code); goto pushed; case ce1_setcurrentpoint: t1_hinter__setcurrentpoint(h, cs0, cs1); cs0 += pcis->adxy.x; cs1 += pcis->adxy.y; cnext; default: return_error(gs_error_invalidfont); } /*NOTREACHED */ /* Fill up the dispatch up to 32. */ case_c1_undefs: default: /* pacify compiler */ return_error(gs_error_invalidfont); } } }
int gs_arcto(gs_state * pgs, floatp ax1, floatp ay1, floatp ax2, floatp ay2, floatp arad, float retxy[4]) { double xt0, yt0, xt2, yt2; gs_point up0; #define ax0 up0.x #define ay0 up0.y /* Transform the current point back into user coordinates. */ int code = gs_currentpoint(pgs, &up0); if (code < 0) return code; { double dx0, dy0, dx2, dy2, sql0, sql2; /* Now we have to compute the tangent points. */ /* Basically, the idea is to compute the tangent */ /* of the bisector by using tan(x+y) and tan(z/2) */ /* formulas, without ever using any trig. */ dx0 = ax0 - ax1; dy0 = ay0 - ay1; dx2 = ax2 - ax1; dy2 = ay2 - ay1; /* Compute the squared lengths from p1 to p0 and p2. */ sql0 = dx0 * dx0 + dy0 * dy0; sql2 = dx2 * dx2 + dy2 * dy2; if (sql0 == 0. || sql2 == 0.) return_error(gs_error_undefinedresult); /* for CET 11-04 */ /* Check for collinear points. */ if (dx0*dy2 == dy0*dx2) { code = gs_lineto(pgs, ax1, ay1); xt0 = xt2 = ax1; yt0 = yt2 = ay1; } else { /* not collinear */ /* Compute the distance from p1 to the tangent points. */ /* This is the only messy part. */ double num = dy0 * dx2 - dy2 * dx0; double denom = sqrt(sql0 * sql2) - (dx0 * dx2 + dy0 * dy2); double dist = fabs(arad * num / denom); double l0 = dist / sqrt(sql0), l2 = dist / sqrt(sql2); arc_curve_params_t arc; arc.ppath = pgs->path; arc.pis = (gs_imager_state *) pgs; arc.radius = arad; arc.action = arc_lineto; arc.notes = sn_none; if (arad < 0) l0 = -l0, l2 = -l2; arc.p0.x = xt0 = ax1 + dx0 * l0; arc.p0.y = yt0 = ay1 + dy0 * l0; arc.p3.x = xt2 = ax1 + dx2 * l2; arc.p3.y = yt2 = ay1 + dy2 * l2; arc.pt.x = ax1; arc.pt.y = ay1; code = arc_add(&arc, false); if (code == 0) code = gx_setcurrentpoint_from_path((gs_imager_state *)pgs, pgs->path); } } if (retxy != 0) { retxy[0] = xt0; retxy[1] = yt0; retxy[2] = xt2; retxy[3] = yt2; } return code; }
/* * Continue interpreting a Type 2 charstring. If str != 0, it is taken as * the byte string to interpret. Return 0 on successful completion, <0 on * error, or >0 when client intervention is required (or allowed). The int* * argument is only for compatibility with the Type 1 charstring interpreter. */ int gs_type2_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd, int *ignore_pindex) { gs_font_type1 *pfont = pcis->pfont; gs_type1_data *pdata = &pfont->data; t1_hinter *h = &pcis->h; bool encrypted = pdata->lenIV >= 0; fixed cstack[ostack_size]; cs_ptr csp; #define clear CLEAR_CSTACK(cstack, csp) ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1]; register const byte *cip; register crypt_state state; register int c; cs_ptr ap; bool vertical; int code = 0; /****** FAKE THE REGISTRY ******/ struct { float *values; uint size; } Registry[1]; Registry[0].values = pcis->pfont->data.WeightVector.values; switch (pcis->init_done) { case -1: t1_hinter__init(h, pcis->path); break; case 0: gs_type1_finish_init(pcis); /* sets origin */ code = t1_hinter__set_mapping(h, &pcis->pis->ctm, &pfont->FontMatrix, &pfont->base->FontMatrix, pcis->scale.x.log2_unit, pcis->scale.x.log2_unit, pcis->scale.x.log2_unit - pcis->log2_subpixels.x, pcis->scale.y.log2_unit - pcis->log2_subpixels.y, pcis->origin.x, pcis->origin.y, gs_currentaligntopixels(pfont->dir)); if (code < 0) return code; code = t1_hinter__set_font_data(h, 2, pdata, pcis->no_grid_fitting, pcis->pfont->is_resource); if (code < 0) return code; break; default /*case 1 */ : break; } INIT_CSTACK(cstack, csp, pcis); if (pgd == 0) goto cont; ipsp->cs_data = *pgd; cip = pgd->bits.data; if (cip == 0) return (gs_note_error(gs_error_invalidfont)); call:state = crypt_charstring_seed; if (encrypted) { int skip = pdata->lenIV; /* Skip initial random bytes */ for (; skip > 0; ++cip, --skip) decrypt_skip_next(*cip, state); } goto top; cont:if (ipsp < pcis->ipstack || ipsp->ip == 0) return (gs_note_error(gs_error_invalidfont)); cip = ipsp->ip; state = ipsp->dstate; top:for (;;) { uint c0 = *cip++; charstring_next(c0, state, c, encrypted); if (c >= c_num1) { /* This is a number, decode it and push it on the stack. */ if (c < c_pos2_0) { /* 1-byte number */ decode_push_num1(csp, cstack, c); } else if (c < cx_num4) { /* 2-byte number */ decode_push_num2(csp, cstack, c, cip, state, encrypted); } else if (c == cx_num4) { /* 4-byte number */ long lw; decode_num4(lw, cip, state, encrypted); /* 32-bit numbers are 16:16. */ CS_CHECK_PUSH(csp, cstack); *++csp = arith_rshift(lw, 16 - _fixed_shift); } else /* not possible */ return_error(gs_error_invalidfont); pushed:if_debug3('1', "[1]%d: (%d) %f\n", (int)(csp - cstack), c, fixed2float(*csp)); continue; } #ifdef DEBUG if (gs_debug['1']) { static const char *const c2names[] = {char2_command_names}; if (c2names[c] == 0) dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c); else dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c, c2names[c]); } #endif switch ((char_command) c) { #define cnext clear; goto top /* Commands with identical functions in Type 1 and Type 2, */ /* except for 'escape'. */ case c_undef0: case c_undef2: case c_undef17: return_error(gs_error_invalidfont); case c_callsubr: c = fixed2int_var(*csp) + pdata->subroutineNumberBias; code = pdata->procs.subr_data (pfont, c, false, &ipsp[1].cs_data); subr:if (code < 0) { /* Calling a Subr with an out-of-range index is clearly a error: * the Adobe documentation says the results of doing this are * undefined. However, we have seen a PDF file produced by Adobe * PDF Library 4.16 that included a Type 2 font that called an * out-of-range Subr, and Acrobat Reader did not signal an error. * Therefore, we ignore such calls. */ cip++; goto top; } --csp; ipsp->ip = cip, ipsp->dstate = state; ++ipsp; cip = ipsp->cs_data.bits.data; goto call; case c_return: gs_glyph_data_free(&ipsp->cs_data, "gs_type2_interpret"); --ipsp; goto cont; case c_undoc15: /* See gstype1.h for information on this opcode. */ cnext; /* Commands with similar but not identical functions */ /* in Type 1 and Type 2 charstrings. */ case cx_hstem: goto hstem; case cx_vstem: goto vstem; case cx_vmoveto: check_first_operator(csp > cstack); code = t1_hinter__rmoveto(h, 0, *csp); move: cc: if (code < 0) return code; goto pp; case cx_rlineto: for (ap = cstack; ap + 1 <= csp; ap += 2) { code = t1_hinter__rlineto(h, ap[0], ap[1]); if (code < 0) return code; } pp: cnext; case cx_hlineto: vertical = false; goto hvl; case cx_vlineto: vertical = true; hvl:for (ap = cstack; ap <= csp; vertical = !vertical, ++ap) { if (vertical) { code = t1_hinter__rlineto(h, 0, ap[0]); } else { code = t1_hinter__rlineto(h, ap[0], 0); } if (code < 0) return code; } goto pp; case cx_rrcurveto: for (ap = cstack; ap + 5 <= csp; ap += 6) { code = t1_hinter__rcurveto(h, ap[0], ap[1], ap[2], ap[3], ap[4], ap[5]); if (code < 0) return code; } goto pp; case cx_endchar: /* * It is a feature of Type 2 CharStrings that if endchar is * invoked with 4 or 5 operands, it is equivalent to the * Type 1 seac operator. In this case, the asb operand of * seac is missing: we assume it is the same as the * l.s.b. of the accented character. This feature was * undocumented until the 16 March 2000 version of the Type * 2 Charstring Format specification, but, thankfully, is * described in that revision. */ if (csp >= cstack + 3) { check_first_operator(csp > cstack + 3); code = gs_type1_seac(pcis, cstack, 0, ipsp); if (code < 0) return code; clear; cip = ipsp->cs_data.bits.data; goto call; } /* * This might be the only operator in the charstring. * In this case, there might be a width on the stack. */ check_first_operator(csp >= cstack); if (pcis->seac_accent < 0) { code = t1_hinter__endglyph(h); if (code < 0) return code; code = gx_setcurrentpoint_from_path(pcis->pis, pcis->path); if (code < 0) return code; } else { t1_hinter__setcurrentpoint(h, pcis->save_adxy.x + pcis->origin_offset.x, pcis->save_adxy.y + pcis->origin_offset.y); code = t1_hinter__end_subglyph(h); if (code < 0) return code; } code = gs_type1_endchar(pcis); if (code == 1) { /* * Reset the total hint count so that hintmask will * parse its following data correctly. * (gs_type1_endchar already reset the actual hint * tables.) */ pcis->num_hints = 0; /* do accent of seac */ ipsp = &pcis->ipstack[pcis->ips_count - 1]; cip = ipsp->cs_data.bits.data; goto call; } return code; case cx_rmoveto: /* See vmoveto above re closing the subpath. */ check_first_operator(!((csp - cstack) & 1)); if (csp > cstack + 1) { /* Some Type 2 charstrings omit the vstemhm operator before rmoveto, even though this is only allowed before hintmask and cntrmask. Thanks to Felix Pahl. */ type2_vstem(pcis, csp - 2, cstack); cstack [0] = csp [-1]; cstack [1] = csp [ 0]; csp = cstack + 1; } code = t1_hinter__rmoveto(h, csp[-1], *csp); goto move; case cx_hmoveto: /* See vmoveto above re closing the subpath. */ check_first_operator(csp > cstack); code = t1_hinter__rmoveto(h, *csp, 0); goto move; case cx_vhcurveto: vertical = true; goto hvc; case cx_hvcurveto: vertical = false; hvc:for (ap = cstack; ap + 3 <= csp; vertical = !vertical, ap += 4) { gs_fixed_point pt[2] = {{0, 0}, {0, 0}}; if (vertical) { pt[0].y = ap[0]; pt[1].x = ap[3]; if (ap + 4 == csp) pt[1].y = ap[4]; } else { pt[0].x = ap[0]; if (ap + 4 == csp) pt[1].x = ap[4]; pt[1].y = ap[3]; } code = t1_hinter__rcurveto(h, pt[0].x, pt[0].y, ap[1], ap[2], pt[1].x, pt[1].y); if (code < 0) return code; } goto pp; /*********************** * New Type 2 commands * ***********************/ case c2_blend: { int n = fixed2int_var(*csp); int num_values = csp - cstack; gs_font_type1 *pfont = pcis->pfont; int k = pfont->data.WeightVector.count; int i, j; cs_ptr base, deltas; base = csp - 1 - num_values; deltas = base + n - 1; for (j = 0; j < n; j++, base++, deltas += k - 1) for (i = 1; i < k; i++) *base += (fixed)(deltas[i] * pfont->data.WeightVector.values[i]); } cnext; case c2_hstemhm: hstem:check_first_operator(!((csp - cstack) & 1)); { fixed x = 0; for (ap = cstack; ap + 1 <= csp; x += ap[1], ap += 2) { code = t1_hinter__hstem(h, x += ap[0], ap[1]); if (code < 0) return code; } } pcis->num_hints += (csp + 1 - cstack) >> 1; cnext; case c2_hintmask: /* * A hintmask at the beginning of the CharString is * equivalent to vstemhm + hintmask. For simplicity, we use * this interpretation everywhere. */ case c2_cntrmask: check_first_operator(!((csp - cstack) & 1)); type2_vstem(pcis, csp, cstack); /* * We should clear the stack here only if this is the * initial mask operator that includes the implicit * vstemhm, but currently this is too much trouble to * detect. */ clear; { byte mask[max_total_stem_hints / 8]; int i; for (i = 0; i < pcis->num_hints; ++cip, i += 8) { charstring_next(*cip, state, mask[i >> 3], encrypted); if_debug1('1', " 0x%02x", mask[i >> 3]); } if_debug0('1', "\n"); ipsp->ip = cip; ipsp->dstate = state; if (c == c2_cntrmask) { /****** NYI ******/ } else { /* hintmask or equivalent */ if_debug0('1', "[1]hstem hints:\n"); if_debug0('1', "[1]vstem hints:\n"); code = t1_hinter__hint_mask(h, mask); if (code < 0) return code; } } break; case c2_vstemhm: vstem:check_first_operator(!((csp - cstack) & 1)); type2_vstem(pcis, csp, cstack); cnext; case c2_rcurveline: for (ap = cstack; ap + 5 <= csp; ap += 6) { code = t1_hinter__rcurveto(h, ap[0], ap[1], ap[2], ap[3], ap[4], ap[5]); if (code < 0) return code; } code = t1_hinter__rlineto(h, ap[0], ap[1]); goto cc; case c2_rlinecurve: for (ap = cstack; ap + 7 <= csp; ap += 2) { code = t1_hinter__rlineto(h, ap[0], ap[1]); if (code < 0) return code; } code = t1_hinter__rcurveto(h, ap[0], ap[1], ap[2], ap[3], ap[4], ap[5]); goto cc; case c2_vvcurveto: ap = cstack; { int n = csp + 1 - cstack; fixed dxa = (n & 1 ? *ap++ : 0); for (; ap + 3 <= csp; ap += 4) { code = t1_hinter__rcurveto(h, dxa, ap[0], ap[1], ap[2], fixed_0, ap[3]); if (code < 0) return code; dxa = 0; } } goto pp; case c2_hhcurveto: ap = cstack; { int n = csp + 1 - cstack; fixed dya = (n & 1 ? *ap++ : 0); for (; ap + 3 <= csp; ap += 4) { code = t1_hinter__rcurveto(h, ap[0], dya, ap[1], ap[2], ap[3], fixed_0); if (code < 0) return code; dya = 0; } } goto pp; case c2_shortint: { int c1, c2; charstring_next(*cip, state, c1, encrypted); ++cip; charstring_next(*cip, state, c2, encrypted); ++cip; CS_CHECK_PUSH(csp, cstack); *++csp = int2fixed((((c1 ^ 0x80) - 0x80) << 8) + c2); } goto pushed; case c2_callgsubr: c = fixed2int_var(*csp) + pdata->gsubrNumberBias; code = pdata->procs.subr_data (pfont, c, true, &ipsp[1].cs_data); goto subr; case cx_escape: charstring_next(*cip, state, c, encrypted); ++cip; #ifdef DEBUG if (gs_debug['1'] && c < char2_extended_command_count) { static const char *const ce2names[] = {char2_extended_command_names}; if (ce2names[c] == 0) dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c); else dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c, ce2names[c]); } #endif switch ((char2_extended_command) c) { case ce2_and: csp[-1] = ((csp[-1] != 0) & (*csp != 0) ? fixed_1 : 0); --csp; break; case ce2_or: csp[-1] = (csp[-1] | *csp ? fixed_1 : 0); --csp; break; case ce2_not: *csp = (*csp ? 0 : fixed_1); break; case ce2_store: { int i, n = fixed2int_var(*csp); float *to = Registry[fixed2int_var(csp[-3])].values + fixed2int_var(csp[-2]); const fixed *from = pcis->transient_array + fixed2int_var(csp[-1]); for (i = 0; i < n; ++i) to[i] = fixed2float(from[i]); } csp -= 4; break; case ce2_abs: if (*csp < 0) *csp = -*csp; break; case ce2_add: csp[-1] += *csp; --csp; break; case ce2_sub: csp[-1] -= *csp; --csp; break; case ce2_div: csp[-1] = float2fixed((double)csp[-1] / *csp); --csp; break; case ce2_load: /* The specification says there is no j (starting index */ /* in registry array) argument.... */ { int i, n = fixed2int_var(*csp); const float *from = Registry[fixed2int_var(csp[-2])].values; fixed *to = pcis->transient_array + fixed2int_var(csp[-1]); for (i = 0; i < n; ++i) to[i] = float2fixed(from[i]); } csp -= 3; break; case ce2_neg: *csp = -*csp; break; case ce2_eq: csp[-1] = (csp[-1] == *csp ? fixed_1 : 0); --csp; break; case ce2_drop: --csp; break; case ce2_put: pcis->transient_array[fixed2int_var(*csp)] = csp[-1]; csp -= 2; break; case ce2_get: *csp = pcis->transient_array[fixed2int_var(*csp)]; break; case ce2_ifelse: if (csp[-1] > *csp) csp[-3] = csp[-2]; csp -= 3; break; case ce2_random: CS_CHECK_PUSH(csp, cstack); ++csp; /****** NYI ******/ break; case ce2_mul: { double prod = fixed2float(csp[-1]) * *csp; csp[-1] = (prod > max_fixed ? max_fixed : prod < min_fixed ? min_fixed : (fixed)prod); } --csp; break; case ce2_sqrt: if (*csp >= 0) *csp = float2fixed(sqrt(fixed2float(*csp))); break; case ce2_dup: CS_CHECK_PUSH(csp, cstack); csp[1] = *csp; ++csp; break; case ce2_exch: { fixed top = *csp; *csp = csp[-1], csp[-1] = top; } break; case ce2_index: *csp = (*csp < 0 ? csp[-1] : csp[-1 - fixed2int_var(csp[-1])]); break; case ce2_roll: { int distance = fixed2int_var(*csp); int count = fixed2int_var(csp[-1]); cs_ptr bot; csp -= 2; if (count < 0 || count > csp + 1 - cstack) return_error(gs_error_invalidfont); if (count == 0) break; if (distance < 0) distance = count - (-distance % count); bot = csp + 1 - count; while (--distance >= 0) { fixed top = *csp; memmove(bot + 1, bot, (count - 1) * sizeof(fixed)); *bot = top; } } break; case ce2_hflex: csp[6] = fixed_half; /* fd/100 */ csp[4] = *csp, csp[5] = 0; /* dx6, dy6 */ csp[2] = csp[-1], csp[3] = -csp[-4]; /* dx5, dy5 */ *csp = csp[-2], csp[1] = 0; /* dx4, dy4 */ csp[-2] = csp[-3], csp[-1] = 0; /* dx3, dy3 */ csp[-3] = csp[-4], csp[-4] = csp[-5]; /* dx2, dy2 */ csp[-5] = 0; /* dy1 */ csp += 6; goto flex; case ce2_flex: *csp /= 100; /* fd/100 */ flex: { fixed x_join = csp[-12] + csp[-10] + csp[-8]; fixed y_join = csp[-11] + csp[-9] + csp[-7]; fixed x_end = x_join + csp[-6] + csp[-4] + csp[-2]; fixed y_end = y_join + csp[-5] + csp[-3] + csp[-1]; gs_point join, end; double flex_depth; if ((code = gs_distance_transform(fixed2float(x_join), fixed2float(y_join), &ctm_only(pcis->pis), &join)) < 0 || (code = gs_distance_transform(fixed2float(x_end), fixed2float(y_end), &ctm_only(pcis->pis), &end)) < 0 ) return code; /* * Use the X or Y distance depending on whether * the curve is more horizontal or more * vertical. */ if (any_abs(end.y) > any_abs(end.x)) flex_depth = join.x; else flex_depth = join.y; if (fabs(flex_depth) < fixed2float(*csp)) { /* Do flex as line. */ code = t1_hinter__rlineto(h, x_end, y_end); } else { /* * Do flex as curve. We can't jump to rrc, * because the flex operators don't clear * the stack (!). */ code = t1_hinter__rcurveto(h, csp[-12], csp[-11], csp[-10], csp[-9], csp[-8], csp[-7]); if (code < 0) return code; code = t1_hinter__rcurveto(h, csp[-6], csp[-5], csp[-4], csp[-3], csp[-2], csp[-1]); } if (code < 0) return code; csp -= 13; } cnext; case ce2_hflex1: csp[4] = fixed_half; /* fd/100 */ csp[2] = *csp; /* dx6 */ csp[3] = -(csp[-7] + csp[-5] + csp[-1]); /* dy6 */ *csp = csp[-2], csp[1] = csp[-1]; /* dx5, dy5 */ csp[-2] = csp[-3], csp[-1] = 0; /* dx4, dy4 */ csp[-3] = 0; /* dy3 */ csp += 4; goto flex; case ce2_flex1: { fixed dx = csp[-10] + csp[-8] + csp[-6] + csp[-4] + csp[-2]; fixed dy = csp[-9] + csp[-7] + csp[-5] + csp[-3] + csp[-1]; if (any_abs(dx) > any_abs(dy)) csp[1] = -dy; /* d6 is dx6 */ else csp[1] = *csp, *csp = -dx; /* d6 is dy6 */ } csp[2] = fixed_half; /* fd/100 */ csp += 2; goto flex; } break; /* Fill up the dispatch up to 32. */ case_c2_undefs: default: /* pacify compiler */ return_error(gs_error_invalidfont); } } }