示例#1
0
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);
    }
}
示例#2
0
/* 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;
}
示例#3
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;
}
示例#4
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
}
示例#5
0
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;
}
示例#6
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
}
示例#7
0
/*
 * 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);
}
示例#8
0
int
gs_dtransform(gs_state * pgs, floatp dx, floatp dy, gs_point * pt)
{
    return gs_distance_transform(dx, dy, &ctm_only(pgs), pt);
}
示例#9
0
/* [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;
}
示例#10
0
/*
 * 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);
        }
    }
}