int gs_idtransform(gs_state * pgs, floatp dx, floatp dy, gs_point * pt) { /* If the matrix isn't skewed, we get more accurate results */ /* by using transform_inverse than by using the inverse matrix. */ if (!is_skewed(&pgs->ctm)) { return gs_distance_transform_inverse(dx, dy, &ctm_only(pgs), pt); } else { ensure_inverse_valid(pgs); return gs_distance_transform(dx, dy, &pgs->ctm_inverse, pt); } }
/* Report current point for sampling */ int gs_screen_currentpoint(gs_screen_enum * penum, gs_point * ppt) { gs_point pt; int code; double sx, sy; /* spot center in spot coords (integers) */ gs_point spot_center; /* device coords */ if (penum->order.wse) { int code; code = gs_wts_screen_enum_currentpoint(penum->order.wse, ppt); return code; } if (penum->y >= penum->strip) { /* all done */ gx_ht_construct_spot_order(&penum->order); return 1; } /* We displace the sampled coordinates very slightly */ /* in order to reduce the likely number of points */ /* for which the spot function returns the same value. */ if ((code = gs_point_transform(penum->x + 0.501, penum->y + 0.498, &penum->mat, &pt)) < 0) return code; /* find the spot center in device coords : */ sx = ceil( pt.x / 2 ) * 2; sy = ceil( pt.y / 2 ) * 2; if ((code = gs_point_transform(sx, sy, &penum->mat_inv, &spot_center)) < 0) return code; /* shift the spot center to nearest pixel center : */ spot_center.x = floor(spot_center.x) + 0.5; spot_center.y = floor(spot_center.y) + 0.5; /* compute the spot function arguments for the shifted spot : */ if ((code = gs_distance_transform(penum->x - spot_center.x + 0.501, penum->y - spot_center.y + 0.498, &penum->mat, &pt)) < 0) return code; pt.x += 1; pt.y += 1; if (pt.x < -1.0) pt.x += ((int)(-ceil(pt.x)) + 1) & ~1; else if (pt.x >= 1.0) pt.x -= ((int)pt.x + 1) & ~1; if (pt.y < -1.0) pt.y += ((int)(-ceil(pt.y)) + 1) & ~1; else if (pt.y >= 1.0) pt.y -= ((int)pt.y + 1) & ~1; *ppt = pt; return 0; }
/* Translate a matrix, possibly in place. */ int gs_matrix_translate(const gs_matrix *pm, floatp dx, floatp dy, gs_matrix *pmr) { gs_point trans; int code = gs_distance_transform(dx, dy, pm, &trans); if ( code < 0 ) return code; if ( pmr != pm ) *pmr = *pm; pmr->tx += trans.x; pmr->ty += trans.y; return 0; }
static inline int gs_distance_transform_compat(floatp x, floatp y, const gs_matrix_fixed *m, gs_point *pt) { #if !PRECISE_CURRENTPOINT gs_fixed_point p; int code = gs_distance_transform2fixed(m, x, y, &p); if (code < 0) return code; pt->x = fixed2float(p.x); pt->y = fixed2float(p.y); return 0; #else return gs_distance_transform(x, y, (const gs_matrix *)m, pt); #endif }
int gs_translate(gs_state * pgs, floatp dx, floatp dy) { gs_point pt; int code; if ((code = gs_distance_transform(dx, dy, &ctm_only(pgs), &pt)) < 0) return code; pt.x = (float)pt.x + pgs->ctm.tx; pt.y = (float)pt.y + pgs->ctm.ty; update_ctm(pgs, pt.x, pt.y); #ifdef DEBUG if (gs_debug_c('x')) dlprintf4("[x]translate: %f %f -> %f %f\n", dx, dy, pt.x, pt.y), trace_ctm(pgs); #endif return 0; }
/* the routine sets ph->actual_frequency and ph->actual_angle. */ static int pick_cell_size(gs_screen_halftone * ph, const gs_matrix * pmat, ulong max_size, uint min_levels, bool accurate, gx_ht_cell_params_t * phcp) { const bool landscape = (pmat->xy != 0.0 || pmat->yx != 0.0); /* Account for a possibly reflected coordinate system. */ /* See gxstroke.c for the algorithm. */ const bool reflected = pmat->xy * pmat->yx > pmat->xx * pmat->yy; const int reflection = (reflected ? -1 : 1); const int rotation = (landscape ? (pmat->yx < 0 ? 90 : -90) : pmat->xx < 0 ? 180 : 0); const double f0 = ph->frequency, a0 = ph->angle; const double T = fabs((landscape ? pmat->yx / pmat->xy : pmat->xx / pmat->yy)); gs_point uv0; #define u0 uv0.x #define v0 uv0.y int rt = 1; double f = 0, a = 0; double e_best = 1000; bool better; /* * We need to find a vector in device space whose length is * 1 inch / ph->frequency and whose angle is ph->angle. * Because device pixels may not be square, we can't simply * map the length to device space and then rotate it; * instead, since we know that user space is uniform in X and Y, * we calculate the correct angle in user space before rotation. */ /* Compute trial values of u and v. */ { gs_matrix rmat; gs_make_rotation(a0 * reflection + rotation, &rmat); gs_distance_transform(72.0 / f0, 0.0, &rmat, &uv0); gs_distance_transform(u0, v0, pmat, &uv0); if_debug10('h', "[h]Requested: f=%g a=%g mat=[%g %g %g %g] max_size=%lu min_levels=%u =>\n u=%g v=%g\n", ph->frequency, ph->angle, pmat->xx, pmat->xy, pmat->yx, pmat->yy, max_size, min_levels, u0, v0); } /* Adjust u and v to reasonable values. */ if (u0 == 0 && v0 == 0) return_error(gs_error_rangecheck); while ((fabs(u0) + fabs(v0)) * rt < 4) ++rt; try_size: better = false; { double fm0 = u0 * rt; double fn0 = v0 * rt; int m0 = (int)floor(u0 * rt + 0.0001); int n0 = (int)floor(v0 * rt + 0.0001); gx_ht_cell_params_t p; p.R = p.R1 = rt; for (p.M = m0 + 1; p.M >= m0; p.M--) for (p.N = n0 + 1; p.N >= n0; p.N--) { long raster, wt, wt_size; double fr, ar, ft, at, f_diff, a_diff, f_err, a_err; p.M1 = (int)floor(p.M / T + 0.5); p.N1 = (int)floor(p.N * T + 0.5); gx_compute_cell_values(&p); if_debug3('h', "[h]trying m=%d, n=%d, r=%d\n", p.M, p.N, rt); wt = p.W; if (wt >= max_short) continue; /* Check the strip size, not the full tile size, */ /* against max_size. */ raster = bitmap_raster(wt); if (raster > max_size / p.D || raster > max_long / wt) continue; wt_size = raster * wt; /* Compute the corresponding values of F and A. */ if (landscape) ar = atan2(p.M * pmat->xy, p.N * pmat->yx), fr = 72.0 * (p.M == 0 ? pmat->xy / p.N * cos(ar) : pmat->yx / p.M * sin(ar)); else ar = atan2(p.N * pmat->xx, p.M * pmat->yy), fr = 72.0 * (p.M == 0 ? pmat->yy / p.N * sin(ar) : pmat->xx / p.M * cos(ar)); ft = fabs(fr) * rt; /* Normalize the angle to the requested quadrant. */ at = (ar * radians_to_degrees - rotation) * reflection; at -= floor(at / 180.0) * 180.0; at += floor(a0 / 180.0) * 180.0; f_diff = fabs(ft - f0); a_diff = fabs(at - a0); f_err = f_diff / fabs(f0); /* * We used to compute the percentage difference here: * a_err = (a0 == 0 ? a_diff : a_diff / fabs(a0)); * but using the angle difference makes more sense: */ a_err = a_diff; if_debug5('h', " ==> d=%d, wt=%ld, wt_size=%ld, f=%g, a=%g\n", p.D, wt, bitmap_raster(wt) * wt, ft, at); { /* * Compute the error in position between ideal location. * and the current integer location. */ double error = (fn0 - p.N) * (fn0 - p.N) + (fm0 - p.M) * (fm0 - p.M); /* * Adjust the error by the length of the vector. This gives * a slight bias toward larger cell sizzes. */ error /= p.N * p.N + p.M * p.M; error = sqrt(error); /* The previous calcs. gave value squared */ if (error > e_best) continue; e_best = error; } *phcp = p; f = ft, a = at; better = true; if_debug3('h', "*** best wt_size=%ld, f_diff=%g, a_diff=%g\n", wt_size, f_diff, a_diff); /* * We want a maximum relative frequency error of 1% and a * maximum angle error of 1% (of 90 degrees). */ if (f_err <= 0.01 && a_err <= 0.9 /*degrees*/) goto done; } } if (phcp->C < min_levels) { /* We don't have enough levels yet. Keep going. */ ++rt; goto try_size; } if (better) { /* If we want accurate screens, continue till we fail. */ if (accurate) { ++rt; goto try_size; } } else { /* * We couldn't find an acceptable M and N. If R > 1, * take what we've got; if R = 1, give up. */ if (rt == 1) return_error(gs_error_rangecheck); } /* Deliver the results. */ done: if_debug5('h', "[h]Chosen: f=%g a=%g M=%d N=%d R=%d\n", f, a, phcp->M, phcp->N, phcp->R); ph->actual_frequency = f; ph->actual_angle = a; return 0; #undef u0 #undef v0 }
/* * Transform a distance from unscaled text space (text space ignoring the * scaling implied by the font size) to device space. */ int pdf_text_distance_transform(floatp wx, floatp wy, const pdf_text_state_t *pts, gs_point *ppt) { return gs_distance_transform(wx, wy, &pts->in.matrix, ppt); }
int gs_dtransform(gs_state * pgs, floatp dx, floatp dy, gs_point * pt) { return gs_distance_transform(dx, dy, &ctm_only(pgs), pt); }
/* [CTM before Form Matrix applied] <<Form dictionary>> .beginform - */ static int zbeginform(i_ctx_t *i_ctx_p) { os_ptr op = osp; gx_device *cdev = gs_currentdevice_inline(igs); int code; float BBox[4], Matrix[6]; gs_form_template_t tmplate; gs_point ll, ur; gs_fixed_rect box; check_type(*op, t_dictionary); check_dict_read(*op); code = read_matrix(imemory, op - 1, &tmplate.CTM); if (code < 0) return code; code = dict_floats_param(imemory, op, "BBox", 4, BBox, NULL); if (code < 0) return code; if (code == 0) return_error(gs_error_undefined); tmplate.FormID = -1; tmplate.BBox.p.x = BBox[0]; tmplate.BBox.p.y = BBox[1]; tmplate.BBox.q.x = BBox[2]; tmplate.BBox.q.y = BBox[3]; code = dict_floats_param(imemory, op, "Matrix", 6, Matrix, NULL); if (code < 0) return code; if (code == 0) return_error(gs_error_undefined); tmplate.form_matrix.xx = Matrix[0]; tmplate.form_matrix.xy = Matrix[1]; tmplate.form_matrix.yx = Matrix[2]; tmplate.form_matrix.yy = Matrix[3]; tmplate.form_matrix.tx = Matrix[4]; tmplate.form_matrix.ty = Matrix[5]; tmplate.pcpath = igs->clip_path; code = dev_proc(cdev, dev_spec_op)(cdev, gxdso_form_begin, &tmplate, 0); /* return value > 0 means the device sent us back a matrix * and wants the CTM set to that. */ if (code > 0) { gs_setmatrix(igs, &tmplate.CTM); gs_distance_transform(tmplate.BBox.p.x, tmplate.BBox.p.y, &tmplate.CTM, &ll); gs_distance_transform(tmplate.BBox.q.x, tmplate.BBox.q.y, &tmplate.CTM, &ur); /* A form can legitimately have negative co-ordinates in paths * because it can be translated. But we always clip paths to the * page which (clearly) can't have negative co-ordinates. NB this * wouldn't be a problem if we didn't reset the CTM, but that would * break the form capture. * So here we temporarily set the clip to permit negative values, * fortunately this works..... */ /* We choose to permit negative values of the same magnitude as the * positive ones. */ box.p.x = float2fixed(ll.x); box.p.y = float2fixed(ll.y); box.q.x = float2fixed(ur.x); box.q.y = float2fixed(ur.y); if (box.p.x < 0) { if(box.p.x * -1 > box.q.x) box.q.x = box.p.x * -1; } else { if (fabs(ur.x) > fabs(ll.x)) box.p.x = box.q.x * -1; else { box.p.x = float2fixed(ll.x * -1); box.q.x = float2fixed(ll.x); } } if (box.p.y < 0) { if(box.p.y * -1 > box.q.y) box.q.y = box.p.y * -1; } else { if (fabs(ur.y) > fabs(ll.y)) box.p.y = box.q.y * -1; else { box.p.y = float2fixed(ll.y * -1); box.q.y = float2fixed(ll.y); } } /* This gets undone when we grestore after the form is executed */ code = gx_clip_to_rectangle(igs, &box); } pop(2); 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); } } }