Exemple #1
0
/* Compute the derived values of a halftone tile. */
void
gx_compute_cell_values(gx_ht_cell_params_t * phcp)
{
    const int M = phcp->M, N = phcp->N, M1 = phcp->M1, N1 = phcp->N1;
    const uint m = any_abs(M), n = any_abs(N);
    const uint m1 = any_abs(M1), n1 = any_abs(N1);
    const ulong C = phcp->C = (ulong)m * m1 + (ulong)n * n1;
    const int D = phcp->D = igcd(m1, n);
    const int D1 = phcp->D1 = igcd(m, n1);

    phcp->W = C / D, phcp->W1 = C / D1;
    /* Compute the shift value. */
    /* If M1 or N is zero, the shift is zero. */
    if (M1 && N) {
        int h = 0, k = 0, dy = 0;
        int shift;

        /*
         * There may be a faster way to do this: see Knuth vol. 2,
         * section 4.5.2, Algorithm X (p. 302) and exercise 15
         * (p. 315, solution p. 523).
         */
        while (dy != D)
            if (dy > D) {
                if (M1 > 0)
                    ++k;
                else
                    --k;
                dy -= m1;
            } else {
                if (N > 0)
                    ++h;
                else
                    --h;
                dy += n;
            }
        shift = h * M + k * N1;
        /* We just computed what amounts to a right shift; */
        /* what we want is a left shift. */
        phcp->S = imod(-shift, phcp->W);
    } else
        phcp->S = 0;
    if_debug12('h', "[h]MNR=(%d,%d)/%d, M'N'R'=(%d,%d)/%d => C=%lu, D=%d, D'=%d, W=%u, W'=%u, S=%d\n",
               M, N, phcp->R, M1, N1, phcp->R1,
               C, D, D1, phcp->W, phcp->W1, phcp->S);
}
static inline void
choose_by_vector(fixed x0, fixed y0, fixed x1, fixed y1, const segment *s, 
	double *slope, double *len, const segment **store_segm, fixed *store_x, fixed *store_y)
{
    if (y0 != y1) {
	double t = (double)any_abs(x1 - x0) / any_abs(y1 - y0);
	double l = any_abs(y1 - y0); /* Don't want 'hypot'. */

	if (*slope > t || (*slope == t && l > *len)) {
	    *slope = t;
	    *len = l;
	    *store_segm = s;
	    *store_x = x1;
	    *store_y = y1;
	}
    }
}
static int
hint_by_trap(gx_device_spot_analyzer *padev, int side_mask,
    void *client_data, gx_san_trap *t0, gx_san_trap *t1, double ave_width,
    int (*handler)(void *client_data, gx_san_sect *ss))
{   gx_san_trap *t;
    double w, wd, best_width_diff = ave_width * 10;
    gx_san_trap *best_trap = NULL;
    bool at_top = false;
    gx_san_sect sect;
    int code;

    for (t = t0; ; t = t->upper->upper) {
	w = t->xrbot - t->xlbot;
	wd = any_abs(w - ave_width);
	if (w > 0 && wd < best_width_diff) {
	    best_width_diff = wd;
	    best_trap = t;
	}
	if (t == t1)
	    break;
    }
    w = t->xrtop - t->xltop;
    wd = any_abs(w - ave_width);
    if (w > 0 && wd < best_width_diff) {
	best_width_diff = wd;
	best_trap = t;
	at_top = true;
    }
    if (best_trap != NULL) {
	/* Make a stem section hint at_top of best_trap : */
	sect.yl = at_top ? best_trap->ytop : best_trap->ybot; 
	sect.yr = sect.yl;
	sect.xl = at_top ? best_trap->xltop : best_trap->xlbot; 
	sect.xr = at_top ? best_trap->xrtop : best_trap->xrbot;
	sect.l = best_trap->l; 
	sect.r = best_trap->r;
	vd_bar(sect.xl, sect.yl, sect.xr, sect.yr, 0, VD_HINT_COLOR);
	code = handler(client_data, &sect);
	if (code < 0)
	    return code;
    }
    return 0;
}
static inline bool
is_stem_boundaries(gx_san_trap *t, int side_mask)
{
    double dx, norm, cosine;
    const double cosine_threshold = 0.9; /* Arbitrary */
    double dy = t->ytop - t->ybot;

    if (side_mask & 1) {
	dx = t->xltop - t->xlbot;
	norm = hypot(dx, dy);
	cosine = dx / norm;
	if (any_abs(cosine) > cosine_threshold)
	    return false;
    }
    if (side_mask & 2) {
	dx = t->xrtop - t->xrbot;
	norm = hypot(dx, dy);
	cosine = dx / norm;
	if (any_abs(cosine) > cosine_threshold)
	    return false;
    }
    return true;
}
Exemple #5
0
static int
gx_remap_DeviceN(const gs_client_color * pcc, const gs_color_space * pcs,
        gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
                       gs_color_select_t select)
{
    frac conc[GS_CLIENT_COLOR_MAX_COMPONENTS];
    const gs_color_space *pconcs;
    int i = pcs->type->num_components(pcs),k;
    int code = 0;
    const gs_color_space *pacs = pcs->base_space;
    gs_client_color temp;
    bool mapped = false;

    if ( pcs->cmm_icc_profile_data != NULL && pis->color_component_map.use_alt_cspace) {
        /* This is the case where we have placed a N-CLR source profile for
           this color space */
        if (pcs->cmm_icc_profile_data->devicen_permute_needed) {
            for ( k = 0; k < i; k++) {
                temp.paint.values[k] = pcc->paint.values[pcs->cmm_icc_profile_data->devicen_permute[k]];
            }
            code = pacs->type->remap_color(&temp, pacs, pdc, pis, dev, select);
        } else {
            code = pacs->type->remap_color(pcc, pacs, pdc, pis, dev, select);
        }
        return(code);
    } else {
        /* Check if we are doing any named color management.  This check happens
           regardless if we are doing the alternate tint transform or not.  If
           desired, that check could be made in gsicc_transform_named_color and
           a decision made to return true or false */
        if (pis->icc_manager->device_named != NULL) {
            /* Try to apply the direct replacement */
            mapped = gx_remap_named_color(pcc, pcs, pdc, pis, dev, select);
        }
        if (!mapped) {
            code = (*pcs->type->concretize_color)(pcc, pcs, conc, pis, dev);
            if (code < 0)
                return code;
            pconcs = cs_concrete_space(pcs, pis);
            code = (*pconcs->type->remap_concrete_color)(conc, pconcs, pdc, pis, dev, select);
        }
        /* Save original color space and color info into dev color */
        i = any_abs(i);
        for (i--; i >= 0; i--)
            pdc->ccolor.paint.values[i] = pcc->paint.values[i];
        pdc->ccolor_valid = true;
        return code;
    }
}
Exemple #6
0
/* ICC color mapping linearity check, a 2-points case. Check only the 1/2 point */
static int
gx_icc_is_linear_in_line(const gs_color_space *cs, const gs_gstate * pgs,
                        gx_device *dev,
                        const gs_client_color *c0, const gs_client_color *c1,
                        float smoothness, gsicc_link_t *icclink)
{
    int nsrc = cs->type->num_components(cs);
    cmm_dev_profile_t *dev_profile;
    int ndes;
    int code;
    unsigned short src0[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short src1[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short src01[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short des0[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short des1[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short des01[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short interp_des;
    unsigned short max_diff = (unsigned short) max(1, 65535 * smoothness);
    int k;

    code = dev_proc(dev, get_profile)(dev, &(dev_profile));
    if (code < 0)
        return code;
    ndes = gsicc_get_device_profile_comps(dev_profile);

    /* Get us to ushort and get mid point */
    for (k = 0; k < nsrc; k++) {
        src0[k] = (unsigned short) (c0->paint.values[k]*65535);
        src1[k] = (unsigned short) (c1->paint.values[k]*65535);
        src01[k] = ((unsigned int) src0[k] + (unsigned int) src1[k]) >> 1;
    }
    /* Transform the end points and the interpolated point */
    gsicc_remap_fast(dev, &(src0[0]), &(des0[0]), icclink);
    gsicc_remap_fast(dev, &(src1[0]), &(des1[0]), icclink);
    gsicc_remap_fast(dev, &(src01[0]), &(des01[0]), icclink);
    /* Interpolate 1/2 value in des space and compare */
    for (k = 0; k < ndes; k++) {
        interp_des = (des0[k] + des1[k]) >> 1;
        if (any_abs((signed int) interp_des - (signed int) des01[k]) > max_diff)
            return false;
    }
    return 1;
}
Exemple #7
0
/*
 * Save the device color information including the color space id and
 * client color data (if available).
 *
 * More description in src/gxhldevc.h
 */
bool
gx_hld_save_color(const gs_imager_state * pis, const gx_device_color * pdevc,
		gx_hl_saved_color * psc)
{
    const gs_state * pgs = gx_hld_get_gstate_ptr(pis);
    memset(psc, 0, sizeof(*psc));	/* clear the entire structure */

    if (pdevc == NULL) {
        /* No device color given, should not happen */
        gx_hld_saved_color_init(psc);	/* revert to unknown color */
	return false;
    } else if (pgs == NULL) {
        /* No color space, simply save device color specific info */
        psc->color_space_id = psc->pattern_id = gs_no_id;
        pdevc->type->save_dc(pdevc, &(psc->saved_dev_color));
	return false;
    } else {
        /*
	 * Have color space, save id,  ccolor, & device color specific info.
	 * Also save the high level colors since two gx_color_index values
	 * may be the same but for differing high level colors (due to the
	 * usual lower resolution of the gx_color_index values.
	 */
        const gs_color_space * pcs = pgs->color_space;
        int i = gs_color_space_num_components(pcs);

        psc->color_space_id = pcs->id;
        pdevc->type->save_dc(pdevc, &(psc->saved_dev_color));
        i = any_abs(i);
        for (i--; i >= 0; i--)
	    psc->ccolor.paint.values[i] = pdevc->ccolor.paint.values[i];

	/* Save the pattern id - if present */
	if ((pdevc->type == gx_dc_type_pattern 
	   || pdevc->type == gx_dc_type_pattern2) && pdevc->ccolor_valid)
            psc->pattern_id = pdevc->ccolor.pattern->pattern_id;
	else
            psc->pattern_id = gs_no_id;
	return true;
    }
}
/*
 * According to "Adobe Type 1 Font Format", 
 * Section 6.2 "CharString Number Encoding", in particular the Note at 
 * the end of the section:
 * "Numbers with absolute values larger than 32,000 must be followed by a 
 * div operator such that the result of the div is less than 32,000."
 * 
 * This function looks ahead for the div operator
 * and applies it in the compile time, so that the big numbers
 * are not placed onto the stack.
 */
int gs_type1_check_float(crypt_state *state, bool encrypted, const byte **ci, cs_ptr csp, long lw)
{
    long denom;
    uint c0;
    int c;
    const byte *cip = *ci;

    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);
    /* Rather "Adobe Type 1 Font Format" restricts the div result with 32,000, 
       We don't want to check it here as a compatibility to the old code,
       and because Type 2 doesn't set this limitation.
       Instead that we're checking here just for 'fixed' overflow,
       which is a weaker limit.
     */
    if (any_abs(lw / denom) > max_int_in_fixed) {
	return_error(gs_error_rangecheck);
    }
    *csp = float2fixed((double)lw / denom);
    *ci = cip;
    return(0);
}
Exemple #9
0
static int
gx_remap_DeviceN(const gs_client_color * pcc, const gs_color_space * pcs,
        gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
                       gs_color_select_t select)
{
    frac conc[GS_CLIENT_COLOR_MAX_COMPONENTS];
    const gs_color_space *pconcs;
    int i = pcs->type->num_components(pcs),k;
    int code;
    const gs_color_space *pacs = pcs->base_space;
    gs_client_color temp;

    if ( pcs->cmm_icc_profile_data != NULL && pis->color_component_map.use_alt_cspace) {
        /* If needed, reorganize the data.  The ICC colorants tag drives the
           the laydown order */
        if (pcs->cmm_icc_profile_data->devicen_permute_needed) {
            for ( k = 0; k < i; k++) {
                temp.paint.values[k] = pcc->paint.values[pcs->cmm_icc_profile_data->devicen_permute[k]];
            }
            code = pacs->type->remap_color(&temp, pacs, pdc, pis, dev, select);
        } else {
            code = pacs->type->remap_color(pcc, pacs, pdc, pis, dev, select);
        }
        return(code);
    } else {
        code = (*pcs->type->concretize_color)(pcc, pcs, conc, pis, dev);
        if (code < 0)
            return code;
        pconcs = cs_concrete_space(pcs, pis);
        code = (*pconcs->type->remap_concrete_color)(conc, pconcs, pdc, pis, dev, select);
        /* Save original color space and color info into dev color */
        i = any_abs(i);
        for (i--; i >= 0; i--)
            pdc->ccolor.paint.values[i] = pcc->paint.values[i];
        pdc->ccolor_valid = true;
        return code;
    }
}
Exemple #10
0
irender_proc_t
gs_image_class_1_simple(gx_image_enum * penum)
{
    irender_proc_t rproc;
    fixed ox = dda_current(penum->dda.pixel0.x);
    fixed oy = dda_current(penum->dda.pixel0.y);

    if (penum->use_rop || penum->spp != 1 || penum->bps != 1)
        return 0;
    switch (penum->posture) {
        case image_portrait:
            {			/* Use fast portrait algorithm. */
                long dev_width =
                    fixed2long_pixround(ox + penum->x_extent.x) -
                    fixed2long_pixround(ox);

                if (dev_width != penum->rect.w) {
                    /*
                     * Add an extra align_bitmap_mod of padding so that
                     * we can align scaled rows with the device.
                     */
                    long line_size =
                        bitmap_raster(any_abs(dev_width)) + align_bitmap_mod;

                    if (penum->adjust != 0 || line_size > max_uint)
                        return 0;
                    /* Must buffer a scan line. */
                    penum->line_width = any_abs(dev_width);
                    penum->line_size = (uint) line_size;
                    penum->line = gs_alloc_bytes(penum->memory,
                                            penum->line_size, "image line");
                    if (penum->line == 0) {
                        gx_default_end_image(penum->dev,
                                             (gx_image_enum_common_t *)penum,
                                             false);
                        return 0;
                    }
                }
                if_debug2('b', "[b]render=simple, unpack=copy; rect.w=%d, dev_width=%ld\n",
                          penum->rect.w, dev_width);
                rproc = image_render_simple;
                break;
            }
        case image_landscape:
            {			/* Use fast landscape algorithm. */
                long dev_width =
                    fixed2long_pixround(oy + penum->x_extent.y) -
                    fixed2long_pixround(oy);
                long line_size =
                    (dev_width = any_abs(dev_width),
                     bitmap_raster(dev_width) * 8 +
                     ROUND_UP(dev_width, 8) * align_bitmap_mod);

                if ((dev_width != penum->rect.w && penum->adjust != 0) ||
                    line_size > max_uint
                    )
                    return 0;
                /* Must buffer a group of 8N scan lines. */
                penum->line_width = dev_width;
                penum->line_size = (uint) line_size;
                penum->line = gs_alloc_bytes(penum->memory,
                                             penum->line_size, "image line");
                if (penum->line == 0) {
                    gx_default_end_image(penum->dev,
                                         (gx_image_enum_common_t *) penum,
                                         false);
                    return 0;
                }
                penum->xi_next = penum->line_xy = fixed2int_var_rounded(ox);
                if_debug3('b', "[b]render=landscape, unpack=copy; rect.w=%d, dev_width=%ld, line_size=%ld\n",
                          penum->rect.w, dev_width, line_size);
                rproc = image_render_landscape;
                /* Precompute values needed for rasterizing. */
                penum->dxy =
                    float2fixed(penum->matrix.xy +
                                fixed2float(fixed_epsilon) / 2);
                break;
            }
        default:
            return 0;
    }
    /* Precompute values needed for rasterizing. */
    penum->dxx =
        float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2);
    /*
     * We don't want to spread the samples, but we have to reset unpack_bps
     * to prevent the buffer pointer from being incremented by 8 bytes per
     * input byte.
     */
    penum->unpack = sample_unpack_copy;
    penum->unpack_bps = 8;
    if (penum->use_mask_color) {
        /*
         * Set the masked color as 'no_color' to make it transparent
         *  according to the mask color range and the decoding.
         */
        penum->masked = true;
        if (penum->mask_color.values[0] == 1) {
            /* if v0 == 1, 1 is transparent since v1 must be == 1 to be a valid range */
            set_nonclient_dev_color(penum->map[0].inverted ? penum->icolor0 : penum->icolor1,
                        gx_no_color_index);
        } else if (penum->mask_color.values[1] == 0) {
            /* if v1 == 0, 0 is transparent since v0 must be == 0 to be a valid range */
            set_nonclient_dev_color(penum->map[0].inverted ? penum->icolor1 : penum->icolor0,
                        gx_no_color_index);
        } else {
            /*
             * The only other possible in-range value is v0 = 0, v1 = 1.
             * The image is completely transparent!
             */
            rproc = image_render_skip;
        }
        penum->map[0].decoding = sd_none;
    }
    return rproc;
}
Exemple #11
0
static int
subpath_expand_dashes(const subpath * psub, gx_path * ppath,
		   const gs_imager_state * pis, const gx_dash_params * dash)
{
    const float *pattern = dash->pattern;
    int count, index;
    bool ink_on;
    double elt_length;
    fixed x0 = psub->pt.x, y0 = psub->pt.y;
    fixed x, y;
    const segment *pseg;
    int wrap = (dash->init_ink_on && psub->is_closed ? -1 : 0);
    int drawing = wrap;
    segment_notes notes = ~sn_not_first;
    const gx_line_params *pgs_lp = gs_currentlineparams_inline(pis);
    bool zero_length = true;
    int code;

    if ((code = gx_path_add_point(ppath, x0, y0)) < 0)
	return code;
    /*
     * To do the right thing at the beginning of a closed path, we have
     * to skip any initial line, and then redo it at the end of the
     * path.  Drawing = -1 while skipping, 0 while drawing normally, and
     * 1 on the second round.  Note that drawing != 0 implies ink_on.
     */
  top:count = dash->pattern_size;
    ink_on = dash->init_ink_on;
    index = dash->init_index;
    elt_length = dash->init_dist_left;
    x = x0, y = y0;
    pseg = (const segment *)psub;
    while ((pseg = pseg->next) != 0 && pseg->type != s_start) {
	fixed sx = pseg->pt.x, sy = pseg->pt.y;
	fixed udx = sx - x, udy = sy - y;
	double length, dx, dy;
	double scale = 1;
	double left;

	if (!(udx | udy)) {	/* degenerate */
	    if (pgs_lp->dot_length == 0 &&
		pgs_lp->cap != gs_cap_round) {
		/* From PLRM, stroke operator :
		   If a subpath is degenerate (consists of a single-point closed path 
		   or of two or more points at the same coordinates), 
		   stroke paints it only if round line caps have been specified */
		if (zero_length || pseg->type != s_line_close)
		    continue;
	    }
	    dx = 0, dy = 0, length = 0;
	} else {
  	    gs_point d;

	    zero_length = false;
	    dx = udx, dy = udy;	/* scaled as fixed */
	    gs_imager_idtransform(pis, dx, dy, &d);
	    length = hypot(d.x, d.y) * (1.0 / fixed_1);
	    if (gs_imager_currentdashadapt(pis)) {
		double reps = length / dash->pattern_length;

		scale = reps / ceil(reps);
		/* Ensure we're starting at the start of a */
		/* repetition.  (This shouldn't be necessary, */
		/* but it is.) */
		count = dash->pattern_size;
		ink_on = dash->init_ink_on;
		index = dash->init_index;
		elt_length = dash->init_dist_left * scale;
	    }
	}
	left = length;
	while (left > elt_length) {	/* We are using up the line segment. */
	    double fraction = elt_length / length;
	    fixed fx = (fixed) (dx * fraction);
	    fixed fy = (fixed) (dy * fraction);
	    fixed nx = x + fx;
	    fixed ny = y + fy;

	    if (ink_on) {
		if (drawing >= 0) {
		    if (left >= elt_length && any_abs(fx) + any_abs(fy) < fixed_half)
			code = gx_path_add_dash_notes(ppath, nx, ny, udx, udy, 
				notes & pseg->notes);
		    else
			code = gx_path_add_line_notes(ppath, nx, ny,
						  notes & pseg->notes);
		}
		notes |= sn_not_first;
	    } else {
		if (drawing > 0)	/* done */
		    return 0;
		code = gx_path_add_point(ppath, nx, ny);
		notes &= ~sn_not_first;
		drawing = 0;
	    }
	    if (code < 0)
		return code;
	    left -= elt_length;
	    ink_on = !ink_on;
	    if (++index == count)
		index = 0;
	    elt_length = pattern[index] * scale;
	    x = nx, y = ny;
	}
	elt_length -= left;
	/* Handle the last dash of a segment. */
      on:if (ink_on) {
	    if (drawing >= 0) {
		if (pseg->type == s_line_close && drawing > 0)
		    code = gx_path_close_subpath_notes(ppath,
						 notes & pseg->notes);
		else if (any_abs(sx - x) + any_abs(sy - y) < fixed_half)
		    code = gx_path_add_dash_notes(ppath, sx, sy, udx, udy, 
			    notes & pseg->notes);
		else
		    code = gx_path_add_line_notes(ppath, sx, sy,
					notes & pseg->notes);
		notes |= sn_not_first;
	    }
	} else {
	    code = gx_path_add_point(ppath, sx, sy);
	    notes &= ~sn_not_first;
	    if (elt_length < fixed2float(fixed_epsilon) &&
		(pseg->next == 0 || pseg->next->type == s_start || elt_length == 0)) {		
				/*
				 * Ink is off, but we're within epsilon of the end
				 * of the dash element.  
				 * "Stretch" a little so we get a dot.
				 * Also if the next dash pattern is zero length,
				 * use the last segment orientation.
				 */
		double elt_length1;

		if (code < 0)
		    return code;
		if (++index == count)
		    index = 0;
		elt_length1 = pattern[index] * scale;
		if (pseg->next == 0 || pseg->next->type == s_start) {
		    elt_length = elt_length1;
		    left = 0;
		    ink_on = true;
		    goto on;
		}
		/* Looking ahead one dash pattern element.
		   If it is zero length, apply to the current segment 
		   (at its end). */
		if (elt_length1 == 0) {
		    left = 0;
		    code = gx_path_add_dash_notes(ppath, sx, sy, udx, udy,
				    notes & pseg->notes);
		    if (++index == count)
			index = 0;
		    elt_length = pattern[index] * scale;
		    ink_on = false;
		} else if (--index == 0) {
		    /* Revert lookahead. */
		    index = count - 1;
		}
	    }
	    if (drawing > 0)	/* done */
		return code;
	    drawing = 0;
	}
	if (code < 0)
	    return code;
	x = sx, y = sy;
    }
    /* Check for wraparound. */
    if (wrap && drawing <= 0) {	/* We skipped some initial lines. */
	/* Go back and do them now. */
	drawing = 1;
	goto top;
    }
    return 0;
}
Exemple #12
0
/* Default icc color mapping linearity check, a triangle case. */
static int
gx_icc_is_linear_in_triangle(const gs_color_space *cs, const gs_gstate * pgs,
                gx_device *dev,
                const gs_client_color *c0, const gs_client_color *c1,
                const gs_client_color *c2, float smoothness, gsicc_link_t *icclink)
{
    /* Check 4 points middle points of 3 sides and middle of one side with
       other point.  We avoid divisions this way. */
    unsigned short src0[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short src1[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short src2[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short des0[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short des1[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short des2[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short src01[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short src12[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short src02[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short src012[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short des01[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short des12[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short des02[GS_CLIENT_COLOR_MAX_COMPONENTS];
    unsigned short des012[GS_CLIENT_COLOR_MAX_COMPONENTS];
    int nsrc = cs->type->num_components(cs);
    int ndes, code;
    unsigned short max_diff = (unsigned short) max(1, 65535 * smoothness);
    unsigned int interp_des;
    int k;
    cmm_dev_profile_t *dev_profile;

    code = dev_proc(dev, get_profile)(dev, &(dev_profile));
    if (code < 0)
        return code;
    ndes = gsicc_get_device_profile_comps(dev_profile);

    /* This needs to be optimized. And range corrected */
    for (k = 0; k < nsrc; k++){
        src0[k] = (unsigned short) (c0->paint.values[k]*65535);
        src1[k] = (unsigned short) (c1->paint.values[k]*65535);
        src2[k] = (unsigned short) (c2->paint.values[k]*65535);
        src01[k] = (src0[k] + src1[k]) >> 1;
        src02[k] = (src0[k] + src2[k]) >> 1;
        src12[k] = (src1[k] + src2[k]) >> 1;
        src012[k] = (src12[k] + src0[k]) >> 1;
    }
    /* Map the points */
    gsicc_remap_fast(dev, &(src0[0]), &(des0[0]), icclink);
    gsicc_remap_fast(dev, &(src1[0]), &(des1[0]), icclink);
    gsicc_remap_fast(dev, &(src2[0]), &(des2[0]), icclink);
    gsicc_remap_fast(dev, &(src01[0]), &(des01[0]), icclink);
    gsicc_remap_fast(dev, &(src12[0]), &(des12[0]), icclink);
    gsicc_remap_fast(dev, &(src02[0]), &(des02[0]), icclink);
    gsicc_remap_fast(dev, &(src012[0]), &(des012[0]), icclink);
    /* Interpolate in des space and check it */
    for (k = 0; k < ndes; k++){
        interp_des = (des0[k] + des1[k]) >> 1;
        if (any_abs((signed int) interp_des - (signed int) des01[k]) > max_diff)
            return false;
        interp_des = (des0[k] + des2[k]) >> 1;
        if (any_abs((signed int) interp_des - (signed int) des02[k]) > max_diff)
            return false;
        interp_des = (des1[k] + des2[k]) >> 1;
        if (any_abs((signed int) interp_des - (signed int) des12[k]) > max_diff)
            return false;
        /* 12 with 0 */
        interp_des = (des0[k] + interp_des) >> 1;
        if (any_abs((signed int) interp_des - (signed int) des012[k]) > max_diff)
            return false;
    }
    return 1;
}
Exemple #13
0
int
gxht_thresh_image_init(gx_image_enum *penum)
{
    int code = 0;
    fixed ox, oy;
    int temp;
    int dev_width, max_height;
    int spp_out;
    int k;
    gx_ht_order *d_order;

    if (gx_device_must_halftone(penum->dev)) {
        if (penum->pis != NULL && penum->pis->dev_ht != NULL) {
            for (k = 0; k < penum->pis->dev_ht->num_comp; k++) {
                d_order = &(penum->pis->dev_ht->components[k].corder);
                code = gx_ht_construct_threshold(d_order, penum->dev, 
                                                 penum->pis, k);
                if (code < 0 ) {
                    return gs_rethrow(code, "threshold creation failed");
                }
            }
        } else {
            return -1;
        }
    }
    spp_out = penum->dev->color_info.num_components;
    /* If the image is landscaped then we want to maintain a buffer
       that is sufficiently large so that we can hold a byte
       of halftoned data along the column.  This way we avoid doing
       multiple writes into the same position over and over.
       The size of the buffer we need depends upon the bitdepth of
       the output device, the number of device coloranants and the
       number of  colorants in the source space.  Note we will
       need to eventually  consider  multi-level halftone case
       here too.  For now, to make use of the SSE2 stuff, we would
       like to have 16 bytes of data to process at a time.  So we
       will collect the columns of data in a buffer that is 16 wide.
       We will also keep track of the widths of each column.  When
       the total width count reaches 16, we will create our
       threshold array and apply it.  We may have one column that is
       buffered between calls in this case.  Also if a call is made
       with h=0 we will flush the buffer as we are at the end of the
       data.  */
    if (penum->posture == image_landscape) {
        int col_length = 
            fixed2int_var_rounded(any_abs(penum->x_extent.y)) * spp_out;
        ox = dda_current(penum->dda.pixel0.x);
        oy = dda_current(penum->dda.pixel0.y);
        temp = (int) ceil((float) col_length/16.0);
        penum->line_size = temp * 16;  /* The stride */
        /* Now we need at most 16 of these */
        penum->line = gs_alloc_bytes(penum->memory,
                                     16 * penum->line_size + 16,
                                     "gxht_thresh");
        /* Same with this */
        penum->thresh_buffer = gs_alloc_bytes(penum->memory,
                                   penum->line_size * 16  + 16,
                                   "gxht_thresh");
        /* That maps into 2 bytes of Halftone data */
        penum->ht_buffer = gs_alloc_bytes(penum->memory,
                                       penum->line_size * 2,
                                       "gxht_thresh");
        penum->ht_stride = penum->line_size;
        if (penum->line == NULL || penum->thresh_buffer == NULL
                    || penum->ht_buffer == NULL)
            return -1;
        penum->ht_landscape.count = 0;
        penum->ht_landscape.num_contones = 0;
        if (penum->y_extent.x < 0) {
            /* Going right to left */
            penum->ht_landscape.curr_pos = 15;
            penum->ht_landscape.index = -1;
        } else {
            /* Going left to right */
            penum->ht_landscape.curr_pos = 0;
            penum->ht_landscape.index = 1;
        }
        if (penum->x_extent.y < 0) {
            penum->ht_landscape.flipy = true;
            penum->ht_landscape.y_pos =
                fixed2int_pixround_perfect(dda_current(penum->dda.pixel0.y) + penum->x_extent.y);
        } else {
            penum->ht_landscape.flipy = false;
            penum->ht_landscape.y_pos =
                fixed2int_pixround_perfect(dda_current(penum->dda.pixel0.y));
        }
        memset(&(penum->ht_landscape.widths[0]), 0, sizeof(int)*16);
        penum->ht_landscape.offset_set = false;
        penum->ht_offset_bits = 0; /* Will get set in call to render */
        if (code >= 0) {
#if defined(DEBUG) || defined(PACIFY_VALGRIND)
            memset(penum->line, 0, 16 * penum->line_size + 16);
            memset(penum->ht_buffer, 0, penum->line_size * 2);
            memset(penum->thresh_buffer, 0, 16 * penum->line_size + 16);
#endif
        }
    } else {
        /* In the portrait case we allocate a single line buffer
           in device width, a threshold buffer of the same size
           and possibly wider and the buffer for the halftoned
           bits. We have to do a bit of work to enable 16 byte
           boundary after an offset to ensure that we can make use
           of  the SSE2 operations for thresholding.  We do the
           allocations now to avoid doing them with every line */
        /* Initialize the ht_landscape stuff to zero */
        memset(&(penum->ht_landscape), 0, sizeof(ht_landscape_info_t));
        ox = dda_current(penum->dda.pixel0.x);
        oy = dda_current(penum->dda.pixel0.y);
        dev_width =
           (int) fabs((long) fixed2long_pixround(ox + penum->x_extent.x) -
                    fixed2long_pixround(ox));
        /* Get the bit position so that we can do a copy_mono for
           the left remainder and then 16 bit aligned copies for the
           rest.  The right remainder will be OK as it will land in
           the MSBit positions. Note the #define chunk bits16 in
           gdevm1.c.  Allow also for a 15 sample over run.
        */
        penum->ht_offset_bits = (-fixed2int_var_pixround(ox)) & 15;
        if (penum->ht_offset_bits > 0) {
            penum->ht_stride = ((7 + (dev_width + 4)) / 8) +
                                ARCH_SIZEOF_LONG;
        } else {
            penum->ht_stride = ((7 + (dev_width + 2)) / 8) +
                            ARCH_SIZEOF_LONG;
        }
        /* We want to figure out the maximum height that we may
           have in taking a single source row and going to device
           space */
        max_height = (int) ceil(fixed2float(any_abs(penum->dst_height)) /
                                            (float) penum->Height);
        penum->ht_buffer = gs_alloc_bytes(penum->memory,
                                          penum->ht_stride * max_height * spp_out,
                                          "gxht_thresh");
        /* We want to have 128 bit alignement for our contone and
           threshold strips so that we can use SSE operations
           in the threshold operation.  Add in a minor buffer and offset
           to ensure this.  If gs_alloc_bytes provides at least 16
           bit alignment so we may need to move 14 bytes.  However, the
           HT process is split in two operations.  One that involves
           the HT of a left remainder and the rest which ensures that
           we pack in the HT data in the bits with no skew for a fast
           copy into the gdevm1 device (16 bit copies).  So, we
           need to account for those pixels which occur first and which
           are NOT aligned for the contone buffer.  After we offset
           by this remainder portion we should be 128 bit aligned.
           Also allow a 15 sample over run during the execution.  */
        temp = (int) ceil((float) ((dev_width + 15.0) + 15.0)/16.0);
        penum->line_size = temp * 16;  /* The stride */
        penum->line = gs_alloc_bytes(penum->memory, penum->line_size * spp_out, 
                                     "gxht_thresh");
        penum->thresh_buffer = gs_alloc_bytes(penum->memory, 
                                              penum->line_size * max_height * spp_out,
                                              "gxht_thresh");
        if (penum->line == NULL || penum->thresh_buffer == NULL || 
            penum->ht_buffer == NULL) {
            return -1;
        } else {
#if defined(DEBUG) || defined(PACIFY_VALGRIND)
            memset(penum->line, 0, penum->line_size * spp_out);
            memset(penum->ht_buffer, 0,
                   penum->ht_stride * max_height * spp_out);
            memset(penum->thresh_buffer, 0,
                   penum->line_size * max_height * spp_out);
#endif
        }
    }
    /* Precompute values needed for rasterizing. */
    penum->dxx = float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2);
    return code;
}
Exemple #14
0
/* Test whether a 1-Input Stitching function is monotonic. */
static int
fn_1ItSg_is_monotonic(const gs_function_t * pfn_common,
		      const float *lower, const float *upper, uint *mask)
{
    const gs_function_1ItSg_t *const pfn =
	(const gs_function_1ItSg_t *)pfn_common;
    float v0 = lower[0], v1 = upper[0];
    float d0 = pfn->params.Domain[0], d1 = pfn->params.Domain[1];
    int k = pfn->params.k;
    int i;

    *mask = 0;
    if (v0 > v1) {
	v0 = v1; v1 = lower[0];
    }
    if (v0 > d1 || v1 < d0)
	return_error(gs_error_rangecheck);
    if (v0 < d0)
	v0 = d0;
    if (v1 > d1)
	v1 = d1;
    for (i = 0; i < pfn->params.k; ++i) {
	float b0 = (i == 0 ? d0 : pfn->params.Bounds[i - 1]);
	float b1 = (i == k - 1 ? d1 : pfn->params.Bounds[i]);
	const float bsmall = (float)1e-6 * (b1 - b0);
	float esmall;
	float e0, e1;
	float w0, w1;
	float vv0, vv1;
	double vb0, vb1;

	if (v0 >= b1)
	    continue;
	if (v0 >= b1 - bsmall)
	    continue; /* Ignore a small noise */
	vv0 = max(b0, v0);
	vv1 = v1;
	if (vv1 > b1 && v1 < b1 + bsmall)
	    vv1 = b1; /* Ignore a small noise */
	if (vv0 == vv1)
	    return 1;
	if (vv0 < b1 && vv1 > b1) {
	    *mask = 1;
	    return 0; /* Consider stitches as monotonity breaks. */
	}
	e0 = pfn->params.Encode[2 * i];
	e1 = pfn->params.Encode[2 * i + 1];
	esmall = (float)1e-6 * any_abs(e1 - e0);
	vb0 = max(vv0, b0);
	vb1 = min(vv1, b1);
	w0 = (float)(vb0 - b0) * (e1 - e0) / (b1 - b0) + e0;
	w1 = (float)(vb1 - b0) * (e1 - e0) / (b1 - b0) + e0;
	/* Note that w0 > w1 is now possible if e0 > e1. */
	if (e0 > e1) {
	    if (w0 > e0 && w0 - esmall <= e0)
		w0 = e0; /* Suppress a small noise */
	    if (w1 < e1 && w1 + esmall >= e1)
		w1 = e1; /* Suppress a small noise */
	} else {
	    if (w0 < e0 && w0 + esmall >= e0)
		w0 = e0; /* Suppress a small noise */
	    if (w1 > e1 && w1 - esmall <= e1)
		w1 = e1; /* Suppress a small noise */
	}
	if (w0 > w1)
	    return gs_function_is_monotonic(pfn->params.Functions[i],
					    &w1, &w0, mask);
	else
	    return gs_function_is_monotonic(pfn->params.Functions[i],
					    &w0, &w1, mask);
    }
    /* v0 is equal to the range end. */
    *mask = 0;
    return 1; 
}
Exemple #15
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);
        }
    }
}