Exemplo n.º 1
0
/*
 * Continue interpreting a Type 1 charstring.  If str != 0, it is taken as
 * the byte string to interpret.  Return 0 on successful completion, <0 on
 * error, or >0 when client intervention is required (or allowed).  The int*
 * argument is where the othersubr # is stored for callothersubr.
 */
int
gs_type1_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd,
		   int *pindex)
{
    gs_font_type1 *pfont = pcis->pfont;
    gs_type1_data *pdata = &pfont->data;
    t1_hinter *h = &pcis->h;
    bool encrypted = pdata->lenIV >= 0;
    fixed cstack[ostack_size];

#define cs0 cstack[0]
#define ics0 fixed2int_var(cs0)
#define cs1 cstack[1]
#define ics1 fixed2int_var(cs1)
#define cs2 cstack[2]
#define ics2 fixed2int_var(cs2)
#define cs3 cstack[3]
#define ics3 fixed2int_var(cs3)
#define cs4 cstack[4]
#define ics4 fixed2int_var(cs4)
#define cs5 cstack[5]
#define ics5 fixed2int_var(cs5)
    cs_ptr csp;
#define clear CLEAR_CSTACK(cstack, csp)
    ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1];
    register const byte *cip;
    register crypt_state state;
    register int c;
    int code = 0;
    fixed ftx = pcis->origin.x, fty = pcis->origin.y;

    switch (pcis->init_done) {
	case -1:
	    t1_hinter__init(h, pcis->path);
	    break;
	case 0:
	    gs_type1_finish_init(pcis);	/* sets origin */
	    ftx = pcis->origin.x, fty = pcis->origin.y;
            code = t1_hinter__set_mapping(h, &pcis->pis->ctm,
			    &pfont->FontMatrix, &pfont->base->FontMatrix,
			    pcis->scale.x.log2_unit, pcis->scale.x.log2_unit,
			    pcis->scale.x.log2_unit - pcis->log2_subpixels.x,
			    pcis->scale.y.log2_unit - pcis->log2_subpixels.y,
			    pcis->origin.x, pcis->origin.y, 
			    gs_currentaligntopixels(pfont->dir));
	    if (code < 0)
	    	return code;
	    code = t1_hinter__set_font_data(h, 1, pdata, pcis->no_grid_fitting);
	    if (code < 0)
	    	return code;
	    break;
	default /*case 1 */ :
	    break;
    }
    INIT_CSTACK(cstack, csp, pcis);

    if (pgd == 0)
	goto cont;
    ipsp->cs_data = *pgd;
    cip = pgd->bits.data;
  call:state = crypt_charstring_seed;
    if (encrypted) {
	int skip = pdata->lenIV;

	/* Skip initial random bytes */
	for (; skip > 0; ++cip, --skip)
	    decrypt_skip_next(*cip, state);
    }
    goto top;
  cont:cip = ipsp->ip;
    state = ipsp->dstate;
  top:for (;;) {
	uint c0 = *cip++;

	charstring_next(c0, state, c, encrypted);
	if (c >= c_num1) {
	    /* This is a number, decode it and push it on the stack. */

	    if (c < c_pos2_0) {	/* 1-byte number */
		decode_push_num1(csp, cstack, c);
	    } else if (c < cx_num4) {	/* 2-byte number */
		decode_push_num2(csp, cstack, c, cip, state, encrypted);
	    } else if (c == cx_num4) {	/* 4-byte number */
		long lw;

		decode_num4(lw, cip, state, encrypted);
		CS_CHECK_PUSH(csp, cstack);
		*++csp = int2fixed(lw);
		if (lw != fixed2long(*csp)) {
		    /*
		     * We handle the only case we've ever seen that
		     * actually uses such large numbers specially.
		     */
		    long denom;

		    c0 = *cip++;
		    charstring_next(c0, state, c, encrypted);
		    if (c < c_num1)
			return_error(gs_error_rangecheck);
		    if (c < c_pos2_0)
			decode_num1(denom, c);
		    else if (c < cx_num4)
			decode_num2(denom, c, cip, state, encrypted);
		    else if (c == cx_num4)
			decode_num4(denom, cip, state, encrypted);
		    else
			return_error(gs_error_invalidfont);
		    c0 = *cip++;
		    charstring_next(c0, state, c, encrypted);
		    if (c != cx_escape)
			return_error(gs_error_rangecheck);
		    c0 = *cip++;
		    charstring_next(c0, state, c, encrypted);
		    if (c != ce1_div)
			return_error(gs_error_rangecheck);
		    *csp = float2fixed((double)lw / denom);
		}
	    } else		/* not possible */
		return_error(gs_error_invalidfont);
	  pushed:if_debug3('1', "[1]%d: (%d) %f\n",
		      (int)(csp - cstack), c, fixed2float(*csp));
	    continue;
	}
#ifdef DEBUG
	if (gs_debug['1']) {
	    static const char *const c1names[] =
	    {char1_command_names};

	    if (c1names[c] == 0)
		dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c);
	    else
		dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c,
			  c1names[c]);
	}
#endif
	switch ((char_command) c) {
#define cnext clear; goto top
#define inext goto top

		/* Commands with identical functions in Type 1 and Type 2, */
		/* except for 'escape'. */

	    case c_undef0:
	    case c_undef2:
	    case c_undef17:
		return_error(gs_error_invalidfont);
	    case c_callsubr:
		c = fixed2int_var(*csp) + pdata->subroutineNumberBias;
		code = pdata->procs.subr_data
		    (pfont, c, false, &ipsp[1].cs_data);
		if (code < 0)
		    return_error(code);
		--csp;
		ipsp->ip = cip, ipsp->dstate = state;
		++ipsp;
		cip = ipsp->cs_data.bits.data;
		goto call;
	    case c_return:
		gs_glyph_data_free(&ipsp->cs_data, "gs_type1_interpret");
		--ipsp;
		goto cont;
	    case c_undoc15:
		/* See gstype1.h for information on this opcode. */
		cnext;

		/* Commands with similar but not identical functions */
		/* in Type 1 and Type 2 charstrings. */

	    case cx_hstem:
                code = t1_hinter__hstem(h, cs0, cs1);
		if (code < 0)
		    return code;
		cnext;
	    case cx_vstem:
                code = t1_hinter__vstem(h, cs0, cs1);
		if (code < 0)
		    return code;
		cnext;
	    case cx_vmoveto:
		cs1 = cs0;
		cs0 = 0;
	      move:		/* cs0 = dx, cs1 = dy for hint checking. */
                code = t1_hinter__rmoveto(h, cs0, cs1);
		goto cc;
	    case cx_rlineto:
	      line:		/* cs0 = dx, cs1 = dy for hint checking. */
                code = t1_hinter__rlineto(h, cs0, cs1);
	      cc:if (code < 0)
		    return code;
		cnext;
	    case cx_hlineto:
		cs1 = 0;
		goto line;
	    case cx_vlineto:
		cs1 = cs0;
		cs0 = 0;
		goto line;
	    case cx_rrcurveto:
                code = t1_hinter__rcurveto(h, cs0, cs1, cs2, cs3, cs4, cs5);
		goto cc;
	    case cx_endchar:
                code = t1_hinter__endchar(h, (pcis->seac_accent >= 0));
		if (code < 0)
		    return code;
                if (pcis->seac_accent < 0) {
                    code = t1_hinter__endglyph(h);
		    if (code < 0)
			return code;
		    code = gx_setcurrentpoint_from_path(pcis->pis, pcis->path);
		    if (code < 0)
			return code;
		}
		code = gs_type1_endchar(pcis);
		if (code == 1) {
		    /* do accent of seac */
		    ipsp = &pcis->ipstack[pcis->ips_count - 1];
		    cip = ipsp->cs_data.bits.data;
		    goto call;
		}
		return code;
	    case cx_rmoveto:
		goto move;
	    case cx_hmoveto:
		cs1 = 0;
		goto move;
	    case cx_vhcurveto:
                code = t1_hinter__rcurveto(h, 0, cs0, cs1, cs2, cs3, 0);
		goto cc;
	    case cx_hvcurveto:
                code = t1_hinter__rcurveto(h, cs0, 0, cs1, cs2, 0, cs3);
		goto cc;

		/* Commands only recognized in Type 1 charstrings, */
		/* plus 'escape'. */

	    case c1_closepath:
                code = t1_hinter__closepath(h);
		goto cc;
	    case c1_hsbw:
                if (!h->seac_flag) {
		    fixed sbx = cs0, sby = fixed_0, wx = cs1, wy = fixed_0;

		    if (pcis->sb_set) {
			sbx = pcis->lsb.x;
			sby = pcis->lsb.y;
		    }
		    if (pcis->width_set) {
			wx = pcis->width.x;
			wy = pcis->width.y;
		    }
		    code = t1_hinter__sbw(h, sbx, sby, wx, wy);
                } else
                    code = t1_hinter__sbw_seac(h, pcis->adxy.x, pcis->adxy.y);
		if (code < 0)
		    return code;
		gs_type1_sbw(pcis, cs0, fixed_0, cs1, fixed_0);
		cs1 = fixed_0;
rsbw:		/* Give the caller the opportunity to intervene. */
		pcis->os_count = 0;	/* clear */
		ipsp->ip = cip, ipsp->dstate = state;
		pcis->ips_count = ipsp - &pcis->ipstack[0] + 1;
		/* If we aren't in a seac, do nothing else now; */
		/* finish_init will take care of the rest. */
		if (pcis->init_done < 0) {
		    /* Finish init when we return. */
		    pcis->init_done = 0;
		} else {
		    /*
		     * Accumulate the side bearing now, but don't do it
		     * a second time for the base character of a seac.
		     */
		    if (pcis->seac_accent >= 0) {
			/*
			 * As a special hack to work around a bug in
			 * Fontographer, we deal with the (illegal)
			 * situation in which the side bearing of the
			 * accented character (save_lsbx) is different from
			 * the side bearing of the base character (cs0/cs1).
			 */
			fixed dsbx = cs0 - pcis->save_lsb.x;
			fixed dsby = cs1 - pcis->save_lsb.y;

			if (dsbx | dsby) {
			    pcis->lsb.x += dsbx;
			    pcis->lsb.y += dsby;
			    pcis->save_adxy.x -= dsbx;
			    pcis->save_adxy.y -= dsby;
			}
		    }
		}
		return type1_result_sbw;
	    case cx_escape:
		charstring_next(*cip, state, c, encrypted);
		++cip;
#ifdef DEBUG
		if (gs_debug['1'] && c < char1_extended_command_count) {
		    static const char *const ce1names[] =
		    {char1_extended_command_names};

		    if (ce1names[c] == 0)
			dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c);
		    else
			dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c,
				  ce1names[c]);
		}
#endif
		switch ((char1_extended_command) c) {
		    case ce1_dotsection:
                        code = t1_hinter__dotsection(h);
			if (code < 0)
			    return code;
			cnext;
		    case ce1_vstem3:
                        code = t1_hinter__vstem3(h, cs0, cs1, cs2, cs3, cs4, cs5);
			if (code < 0)
			    return code;
			cnext;
		    case ce1_hstem3:
                        code = t1_hinter__hstem3(h, cs0, cs1, cs2, cs3, cs4, cs5);
			if (code < 0)
			    return code;
			cnext;
		    case ce1_seac:
			code = gs_type1_seac(pcis, cstack + 1, cstack[0],
					     ipsp);
			if (code != 0) {
			    *pindex = ics3;
			    return code;
			}
			clear;
			cip = ipsp->cs_data.bits.data;
			goto call;
		    case ce1_sbw:
                        if (!h->seac_flag)
                            code = t1_hinter__sbw(h, cs0, cs1, cs2, cs3);
                        else
                            code = t1_hinter__sbw_seac(h, cs0 + pcis->adxy.x , cs1 + pcis->adxy.y);
			if (code < 0)
			    return code;
			gs_type1_sbw(pcis, cs0, cs1, cs2, cs3);
			goto rsbw;
		    case ce1_div:
			csp[-1] = float2fixed((double)csp[-1] / (double)*csp);
			--csp;
			goto pushed;
		    case ce1_undoc15:
			/* See gstype1.h for information on this opcode. */
			cnext;
		    case ce1_callothersubr:
			{
			    int num_results;
			    /* We must remember to pop both the othersubr # */
			    /* and the argument count off the stack. */
			    switch (*pindex = fixed2int_var(*csp)) {
				case 0:
				    {	
					fixed fheight = csp[-4];
					/* Assume the next two opcodes */
					/* are `pop' `pop'.  Unfortunately, some */
					/* Monotype fonts put these in a Subr, */
					/* so we can't just look ahead in the */
					/* opcode stream. */
					pcis->ignore_pops = 2;
					csp[-4] = csp[-3] - pcis->asb_diff;
					csp[-3] = csp[-2];
					csp -= 3;
					code = t1_hinter__flex_end(h, fheight);
				    }
				    if (code < 0)
					return code;
				    pcis->flex_count = flex_max;	/* not inside flex */
				    inext;
				case 1:
				    code = t1_hinter__flex_beg(h);
				    if (code < 0)
					return code;
				    pcis->flex_count = 1;
				    csp -= 2;
				    inext;
				case 2:
				    if (pcis->flex_count >= flex_max)
					return_error(gs_error_invalidfont);
				    code = t1_hinter__flex_point(h);
				    if (code < 0)
					return code;
				    csp -= 2;
				    inext;
				case 3:
				    /* Assume the next opcode is a `pop'. */
				    /* See above as to why we don't just */
				    /* look ahead in the opcode stream. */
				    pcis->ignore_pops = 1;
                                    code = t1_hinter__drop_hints(h);
				    if (code < 0)
					return code;
				    csp -= 2;
				    inext;
				case 12:
				case 13:
				    /* Counter control isn't implemented. */
				    cnext;
				case 14:
				    num_results = 1;
				  blend:
				    code = gs_type1_blend(pcis, csp,
							  num_results);
				    if (code < 0)
					return code;
				    csp -= code;
				    inext;
				case 15:
				    num_results = 2;
				    goto blend;
				case 16:
				    num_results = 3;
				    goto blend;
				case 17:
				    num_results = 4;
				    goto blend;
				case 18:
				    num_results = 6;
				    goto blend;
			    }
			}
			/* Not a recognized othersubr, */
			/* let the client handle it. */
			{
			    int scount = csp - cstack;
			    int n;

			    /* Copy the arguments to the caller's stack. */
			    if (scount < 1 || csp[-1] < 0 ||
				csp[-1] > int2fixed(scount - 1)
				)
				return_error(gs_error_invalidfont);
			    n = fixed2int_var(csp[-1]);
			    code = (*pdata->procs.push_values)
				(pcis->callback_data, csp - (n + 1), n);
			    if (code < 0)
				return_error(code);
			    scount -= n + 1;
			    /* Exit to caller */
			    ipsp->ip = cip, ipsp->dstate = state;
			    pcis->os_count = scount;
			    pcis->ips_count = ipsp - &pcis->ipstack[0] + 1;
			    if (scount)
				memcpy(pcis->ostack, cstack, scount * sizeof(fixed));
			    return type1_result_callothersubr;
			}
		    case ce1_pop:
			/* Check whether we're ignoring the pops after */
			/* a known othersubr. */
			if (pcis->ignore_pops != 0) {
			    pcis->ignore_pops--;
			    inext;
			}
			CS_CHECK_PUSH(csp, cstack);
			++csp;
			code = (*pdata->procs.pop_value)
			    (pcis->callback_data, csp);
			if (code < 0)
			    return_error(code);
			goto pushed;
		    case ce1_setcurrentpoint:
			t1_hinter__setcurrentpoint(h, cs0, cs1);
			cs0 += pcis->adxy.x;
			cs1 += pcis->adxy.y;
			cnext;
		    default:
			return_error(gs_error_invalidfont);
		}
		/*NOTREACHED */

		/* Fill up the dispatch up to 32. */

	      case_c1_undefs:
	    default:		/* pacify compiler */
		return_error(gs_error_invalidfont);
	}
    }
}
Exemplo n.º 2
0
/* This performs a thresholding operation on a single plane of data and 
   performs a copy mono operation to the device */
int 
gxht_thresh_plane(gx_image_enum *penum, gx_ht_order *d_order,  
                  fixed xrun, int dest_width, int dest_height,
                  byte *thresh_align, byte *contone_align, int contone_stride, 
                  gx_device * dev) 
{
    int thresh_width, thresh_height, dx;
    int left_rem_end, left_width, vdi;
    int num_full_tiles, right_tile_width;
    int k, jj, dy;
    byte *thresh_tile;
    int position;
    bool replicate_tile;
    image_posture posture = penum->posture;
    const int y_pos = penum->yci;
    int width;
    byte *ptr_out, *row_ptr, *ptr_out_temp;
    byte *threshold = d_order->threshold;
    int init_tile, in_row_offset, ii, num_tiles, tile_remainder;
    int offset_bits = penum->ht_offset_bits;
    byte *halftone = penum->ht_buffer;
    int dithered_stride = penum->ht_stride;

    /* Go ahead and fill the threshold line buffer with tiled threshold values.
       First just grab the row or column that we are going to tile with and
       then do memcpy into the buffer */

    thresh_width = d_order->width;
    thresh_height = d_order->height;
    /* Figure out the tile steps.  Left offset, Number of tiles, Right offset. */
    switch (posture) {
        case image_portrait:
            vdi = penum->hci;
            /* Compute the tiling positions with dest_width */
            dx = fixed2int_var(xrun) % thresh_width;
            /* Left remainder part */
            left_rem_end = min(dx + dest_width, thresh_width);
            left_width = left_rem_end - dx;  /* The left width of our tile part */
            /* Now the middle part */
            num_full_tiles =
                (int)fastfloor((dest_width - left_width)/ (float) thresh_width);
            /* Now the right part */
            right_tile_width = dest_width -  num_full_tiles * thresh_width -
                               left_width;
            /* Those dimensions stay the same across the set of lines that
               we fill in our buffer.  Iterate over the vdi and fill up our
               threshold buffer */
            for (k = 0; k < vdi; k++) {
                /* Get a pointer to our tile row */
                dy = (penum->yci + k + penum->dev->band_offset_y) % thresh_height;
                thresh_tile = threshold + d_order->width * dy;
                /* Fill the buffer, can be multiple rows.  Make sure
                   to update with stride */
                position = contone_stride * k;
                /* Tile into the 128 bit aligned threshold strip */
                fill_threshhold_buffer(&(thresh_align[position]),
                                       thresh_tile, thresh_width, dx, left_width,
                                       num_full_tiles, right_tile_width);
            }
            /* Apply the threshold operation */
#if RAW_HT_DUMP
            gx_ht_threshold_row_byte(contone_align, thresh_align, contone_stride,
                              halftone, dithered_stride, dest_width, vdi);
            sprintf(file_name,"HT_Portrait_%d_%dx%dx%d.raw", penum->id, dest_width,
                    dest_height, spp_out);
            fid = fopen(file_name,"a+b");
            fwrite(halftone,1,dest_width * vdi,fid);
            fclose(fid);
#else
            if (offset_bits > dest_width)
                offset_bits = dest_width;
            gx_ht_threshold_row_bit(contone_align, thresh_align, contone_stride,
                              halftone, dithered_stride, dest_width, vdi,
                              offset_bits);
            /* FIXME: An improvement here would be to generate the initial
             * offset_bits at the correct offset within the byte so that they
             * align with the remainder of the line. This would mean not
             * always packing them into the first offset_bits (in MSB order)
             * of our 16 bit word, but rather into the last offset_bits
             * (in MSB order) (except when the entire run is small!).
             *
             * This would enable us to do just one aligned copy_mono call for
             * the entire scanline. */
            /* Now do the copy mono operation */
            /* First the left remainder bits */
            if (offset_bits > 0) {
                int x_pos = fixed2int_var(xrun);
                (*dev_proc(dev, copy_mono)) (dev, halftone, 0, dithered_stride,
                                             gx_no_bitmap_id, x_pos, y_pos,
                                             offset_bits, vdi,
                                             (gx_color_index) 0,
                                             (gx_color_index) 1);
            }
            if ((dest_width - offset_bits) > 0 ) {
                /* Now the primary aligned bytes */
                byte *curr_ptr = halftone;
                int curr_width = dest_width - offset_bits;
                int x_pos = fixed2int_var(xrun) + offset_bits;
                if (offset_bits > 0) {
                    curr_ptr += 2; /* If the first 2 bytes had the left part then increment */
                }
                (*dev_proc(dev, copy_mono)) (dev, curr_ptr, 0, dithered_stride,
                                             gx_no_bitmap_id, x_pos, y_pos,
                                             curr_width, vdi,
                                             (gx_color_index) 0, (gx_color_index) 1);
            }
#endif
            break;
        case image_landscape:
            /* Go ahead and paint the chunk if we have 16 values or a partial
               to get us in sync with the 1 bit devices 16 bit positions */
            vdi = penum->wci;
            while (penum->ht_landscape.count > 15 ||
                   ((penum->ht_landscape.count >= offset_bits) &&
                    penum->ht_landscape.offset_set)) {
                /* Go ahead and 2D tile in the threshold buffer at this time */
                /* Always work the tiling from the upper left corner of our
                   16 columns */
                if (penum->ht_landscape.offset_set) {
                    width = offset_bits;
                } else {
                    width = 16;
                }
                if (penum->y_extent.x < 0) {
                    dx = (penum->ht_landscape.xstart - width + 1) % thresh_width;
                } else {
                    dx = penum->ht_landscape.xstart % thresh_width;
                }
                dy = (penum->dev->band_offset_y + penum->ht_landscape.y_pos) % thresh_height;
                if (dy < 0)
                    dy += thresh_height;
                /* Left remainder part */
                left_rem_end = min(dx + 16, thresh_width);
                left_width = left_rem_end - dx;
                /* Now the middle part */
                num_full_tiles =
                    (int)fastfloor((float) (16 - left_width)/ (float) thresh_width);
                /* Now the right part */
                right_tile_width =
                    16 - num_full_tiles * thresh_width - left_width;
                /* Now loop over the y stuff */
                ptr_out = thresh_align;
                /* Do this in three parts.  We do a top part, followed by
                   larger mem copies followed by a bottom partial. After
                   a slower initial fill we are able to do larger faster
                   expansions */
                if (dest_height <= 2 * thresh_height) {
                    init_tile = dest_height;
                    replicate_tile = false;
                } else {
                    init_tile = thresh_height;
                    replicate_tile = true;
                }
                for (jj = 0; jj < init_tile; jj++) {
                    in_row_offset = (jj + dy) % thresh_height;
                    row_ptr = threshold + in_row_offset * thresh_width;
                    ptr_out_temp = ptr_out;
                    /* Left part */
                    memcpy(ptr_out_temp, row_ptr + dx, left_width);
                    ptr_out_temp += left_width;
                    /* Now the full tiles */
                    for (ii = 0; ii < num_full_tiles; ii++) {
                        memcpy(ptr_out_temp, row_ptr, thresh_width);
                        ptr_out_temp += thresh_width;
                    }
                    /* Now the remainder */
                    memcpy(ptr_out_temp, row_ptr, right_tile_width);
                    ptr_out += 16;
                }
                if (replicate_tile) {
                    /* Find out how many we need to copy */
                    num_tiles =
                        (int)fastfloor((float) (dest_height - thresh_height)/ (float) thresh_height);
                    tile_remainder = dest_height - (num_tiles + 1) * thresh_height;
                    for (jj = 0; jj < num_tiles; jj ++) {
                        memcpy(ptr_out, thresh_align, 16 * thresh_height);
                        ptr_out += 16 * thresh_height;
                    }
                    /* Now fill in the remainder */
                    memcpy(ptr_out, thresh_align, 16 * tile_remainder);
                }
                /* Apply the threshold operation */
                gx_ht_threshold_landscape(contone_align, thresh_align,
                                    penum->ht_landscape, halftone, dest_height);
                /* Perform the copy mono */
                penum->ht_landscape.offset_set = false;
                if (penum->ht_landscape.index < 0) {
                    (*dev_proc(dev, copy_mono)) (dev, halftone, 0, 2,
                                                 gx_no_bitmap_id,
                                                 penum->ht_landscape.xstart - width + 1,
                                                 penum->ht_landscape.y_pos,
                                                 width, dest_height,
                                                 (gx_color_index) 0,
                                                 (gx_color_index) 1);
                } else {
                    (*dev_proc(dev, copy_mono)) (dev, halftone, 0, 2,
                                                 gx_no_bitmap_id,
                                                 penum->ht_landscape.xstart,
                                                 penum->ht_landscape.y_pos,
                                                 width, dest_height,
                                                 (gx_color_index) 0,
                                                 (gx_color_index) 1);
                }
                /* Clean up and reset our buffer.  We may have a line left
                   over that has to be maintained due to line replication in the
                   resolution conversion */
                if (width != penum->ht_landscape.count) {
                    reset_landscape_buffer(&(penum->ht_landscape), contone_align,
                                           dest_height, width);
                } else {
                    /* Reset the whole buffer */
                    penum->ht_landscape.count = 0;
                    if (penum->ht_landscape.index < 0) {
                        /* Going right to left */
                        penum->ht_landscape.curr_pos = 15;
                    } else {
                        /* Going left to right */
                        penum->ht_landscape.curr_pos = 0;
                    }
                    penum->ht_landscape.num_contones = 0;
                    memset(&(penum->ht_landscape.widths[0]), 0, sizeof(int)*16);
                }
            }
            break;
        default:
            return gs_rethrow(-1, "Invalid orientation for thresholding");
    }
    return 0;
}
Exemplo n.º 3
0
/* Draw a one-pixel-wide line. */
int
gx_default_draw_thin_line(gx_device * dev,
                          fixed fx0, fixed fy0, fixed fx1, fixed fy1,
                    const gx_device_color * pdevc, gs_logical_operation_t lop,
                          fixed adjustx, fixed adjusty)
{
    int ix, iy, itox, itoy;
    int epsilon;

    return_if_interrupt(dev->memory);

    /* This function was updated in revision 10391 to fix problems with
     * mispositioned thin lines. This introduced a regression (see bug
     * 691030). The code was then reworked to behave in what we believe is
     * the correct manner, but this causes unacceptable problems with PCL
     * output. While the current PCL work is underway, we have therefore
     * amended this code to take note of the fill adjust values; if non-
     * zero (i.e. postscript) we do "the correct thing". If zero, we do
     * what we used to.
     *
     * The one case where this doesn't work is in the case where our PCL
     * implementation thickens lines slightly to try and approximate HP
     * printer behaviour. Here we do use a non-zero fill_adjust and hence
     * have differences; tests show that these are acceptable though.
     *
     * It is hoped that this difference in behaviour will be short lived.
     */

    epsilon = ((adjustx | adjusty) == 0 ? fixed_epsilon : 0);

    {
        fixed h = fy1 - fy0;
        fixed w = fx1 - fx0;
        fixed tf;
        bool swap_axes;
        gs_fixed_edge left, right;

        if ((w < 0 ? -w : w) <= (h < 0 ? -h : h)) {
            /* A "mostly-vertical" line */
            if (h < 0)
                SWAP(fx0, fx1, tf), SWAP(fy0, fy1, tf),
                    h = -h;
            /* So we are plotting a trapezoid with horizontal thin edges.
             * Check for whether a triangular extension area on the end
             * covers an additional pixel centre. */
            {
                int deltay = int2fixed(fixed2int_var(fy1)) + fixed_half -fy1;
                int deltax = int2fixed(fixed2int_var(fx1)) + fixed_half -fx1;

                if (deltax < 0) deltax=-deltax;
                if ((deltay > 0) && (deltay <= fixed_half) &&
                    (deltay+deltax <= fixed_half))
                {
                    int c = gx_fill_rectangle_device_rop(fixed2int_var(fx1),
                                                         fixed2int_var(fy1),
                                                         1,1,pdevc,dev,lop);
                    if (c < 0) return c;
                }
            }
            {
                int deltay = int2fixed(fixed2int_var(fy0)) + fixed_half -fy0;
                int deltax = int2fixed(fixed2int_var(fx0)) + fixed_half -fx0;

                if (deltax < 0) deltax=-deltax;
                if ((deltay < 0) && (deltay >= -fixed_half) &&
                    (-deltay+deltax <= fixed_half))
                {
                    int c = gx_fill_rectangle_device_rop(fixed2int_var(fx0),
                                                         fixed2int_var(fy0),
                                                         1,1,pdevc,dev,lop);
                    if (c < 0) return c;
                }
            }
            /* Can we treat it as a vertical rectangle? */
            ix   = fixed2int_var(fx0-epsilon);
            itox = fixed2int_var(fx1-epsilon);
            if (itox == ix) {
                /* Figure out the start/height, allowing for our "covers
                 * centre of pixel" rule. */
                iy   = fixed2int_var(fy0+fixed_half-fixed_epsilon);
                itoy = fixed2int_var(fy1+fixed_half-fixed_epsilon);
                itoy = itoy - iy;
                if (itoy <= 0) {
                    /* Zero height; drawing this as a trapezoid wouldn't
                     * fill any pixels, so just exit. */
                    return 0;
                }
                return gx_fill_rectangle_device_rop(ix, iy, 1, itoy,
                                                    pdevc, dev, lop);
            }
            left.start.x = fx0 - fixed_half + fixed_epsilon - epsilon;
            right.start.x = left.start.x + fixed_1;
            left.end.x = fx1 - fixed_half + fixed_epsilon - epsilon;
            right.end.x = left.end.x + fixed_1;
            left.start.y = right.start.y = fy0;
            left.end.y = right.end.y = fy1;
            swap_axes = false;
        } else {
            /* A "mostly-horizontal" line */
            if (w < 0)
                SWAP(fx0, fx1, tf), SWAP(fy0, fy1, tf),
                    w = -w;
            /* So we are plotting a trapezoid with vertical thin edges
             * Check for whether a triangular extension area on the end
             * covers an additional pixel centre. */
            {
                int deltax = int2fixed(fixed2int_var(fx1)) + fixed_half -fx1;
                int deltay = int2fixed(fixed2int_var(fy1)) + fixed_half -fy1;

                if (deltay < 0) deltay=-deltay;
                if ((deltax > 0) && (deltax <= fixed_half) &&
                    (deltax+deltay <= fixed_half))
                {
                    int c = gx_fill_rectangle_device_rop(fixed2int_var(fx1),
                                                         fixed2int_var(fy1),
                                                         1,1,pdevc,dev,lop);
                    if (c < 0) return c;
                }
            }
            {
                int deltax = int2fixed(fixed2int_var(fx0)) + fixed_half -fx0;
                int deltay = int2fixed(fixed2int_var(fy0)) + fixed_half -fy0;

                if (deltay < 0) deltay=-deltay;
                if ((deltax < 0) && (deltax >= -fixed_half) &&
                    (-deltax+deltay <= fixed_half))
                {
                    int c = gx_fill_rectangle_device_rop(fixed2int_var(fx0),
                                                         fixed2int_var(fy0),
                                                         1,1,pdevc,dev,lop);
                    if (c < 0) return c;
                }
            }
            /* Can we treat this as a horizontal rectangle? */
            iy   = fixed2int_var(fy0 - epsilon);
            itoy = fixed2int_var(fy1 - epsilon);
            if (itoy == iy) {
                /* Figure out the start/width, allowing for our "covers
                * centre of pixel" rule. */
                ix   = fixed2int_var(fx0+fixed_half-fixed_epsilon);
                itox = fixed2int_var(fx1+fixed_half-fixed_epsilon);
                itox = itox - ix;
                if (itox <= 0) {
                    /* Zero width; drawing this as a trapezoid wouldn't
                     * fill any pixels, so just exit. */
                    return 0;
                }
                return gx_fill_rectangle_device_rop(ix, iy, itox, 1,
                                                    pdevc, dev, lop);
            }
            left.start.x = fy0 - fixed_half + fixed_epsilon - epsilon;
            right.start.x = left.start.x + fixed_1;
            left.end.x = fy1 - fixed_half + fixed_epsilon - epsilon;
            right.end.x = left.end.x + fixed_1;
            left.start.y = right.start.y = fx0;
            left.end.y = right.end.y = fx1;
            swap_axes = true;
        }
        return (*dev_proc(dev, fill_trapezoid)) (dev, &left, &right,
                                                 left.start.y, left.end.y,
                                                 swap_axes, pdevc, lop);
    }
}
Exemplo n.º 4
0
/*
 * If a Type 1 character is defined with 'seac', store the character codes
 * in chars[0] and chars[1] and return 1; otherwise, return 0 or <0.
 * This is exported only for the benefit of font copying.
 */
int
gs_type1_piece_codes(/*const*/ gs_font_type1 *pfont,
		     const gs_glyph_data_t *pgd, gs_char *chars)
{
    gs_type1_data *const pdata = &pfont->data;
    /*
     * Decode the CharString looking for seac.  We have to process
     * callsubr, callothersubr, and return operators, but if we see
     * any other operators other than [h]sbw, pop, hint operators,
     * or endchar, we can return immediately.  We have to include
     * endchar because it is an (undocumented) equivalent for seac
     * in Type 2 CharStrings: see the cx_endchar case in
     * gs_type2_interpret in gstype2.c.
     *
     * It's really unfortunate that we have to duplicate so much parsing
     * code, but factoring out the parser from the interpreter would
     * involve more restructuring than we're prepared to do right now.
     */
    bool encrypted = pdata->lenIV >= 0;
    fixed cstack[ostack_size];
    fixed *csp;
    ip_state_t ipstack[ipstack_size + 1];
    ip_state_t *ipsp = &ipstack[0];
    const byte *cip;
    crypt_state state;
    int c;
    int code;
    
    CLEAR_CSTACK(cstack, csp);
    cip = pgd->bits.data;
 call:
    state = crypt_charstring_seed;
    if (encrypted) {
	int skip = pdata->lenIV;

	/* Skip initial random bytes */
	for (; skip > 0; ++cip, --skip)
	    decrypt_skip_next(*cip, state);
    }
 top:
    for (;;) {
	uint c0 = *cip++;

	charstring_next(c0, state, c, encrypted);
	if (c >= c_num1) {
	    /* This is a number, decode it and push it on the stack. */
	    if (c < c_pos2_0) {	/* 1-byte number */
		decode_push_num1(csp, cstack, c);
	    } else if (c < cx_num4) {	/* 2-byte number */
		decode_push_num2(csp, cstack, c, cip, state, encrypted);
	    } else if (c == cx_num4) {	/* 4-byte number */
		long lw;

		decode_num4(lw, cip, state, encrypted);
		CS_CHECK_PUSH(csp, cstack);
		*++csp = int2fixed(lw);
	    } else		/* not possible */
		return_error(gs_error_invalidfont);
	    continue;
	}
#define cnext CLEAR_CSTACK(cstack, csp); goto top
	switch ((char_command) c) {
	default:
	    goto out;
	case c_callsubr:
	    c = fixed2int_var(*csp) + pdata->subroutineNumberBias;
	    code = pdata->procs.subr_data
		(pfont, c, false, &ipsp[1].cs_data);
	    if (code < 0)
		return_error(code);
	    --csp;
	    ipsp->ip = cip, ipsp->dstate = state;
	    ++ipsp;
	    cip = ipsp->cs_data.bits.data;
	    goto call;
	case c_return:
	    gs_glyph_data_free(&ipsp->cs_data, "gs_type1_piece_codes");
	    --ipsp;
	    cip = ipsp->ip, state = ipsp->dstate;
	    goto top;
	case cx_hstem:
	case cx_vstem:
	case c1_hsbw:
	    cnext;
	case cx_endchar:
	    if (csp < cstack + 3)
		goto out;	/* not seac */
	do_seac:
	    /* This is the payoff for all this code! */
	    chars[0] = fixed2int(csp[-1]);
	    chars[1] = fixed2int(csp[0]);
	    return 1;
	case cx_escape:
	    charstring_next(*cip, state, c, encrypted);
	    ++cip;
	    switch ((char1_extended_command) c) {
	    default:
		goto out;
	    case ce1_vstem3:
	    case ce1_hstem3:
	    case ce1_sbw:
		cnext;
	    case ce1_pop:
		/*
		 * pop must do nothing, since it is used after
		 * subr# 1 3 callothersubr.
		 */
		goto top;
	    case ce1_seac:
		goto do_seac;
	    case ce1_callothersubr:
		switch (fixed2int_var(*csp)) {
		default:
		    goto out;
		case 3:
		    csp -= 2;
		    goto top;
		case 12:
		case 13:
		case 14:
		case 15:
		case 16:
		case 17:
		case 18:
		    cnext;
		}
	    }
	}
#undef cnext
    }
 out:
    return 0;
}
Exemplo n.º 5
0
/*
 * Define an implementation that uses trilinear interpolation.
 */
static void
interpolate_accum(const fixed * pi, const gx_color_lookup_table * pclt,
                  frac * pv, fixed factor)
{
    const int *pdim = pclt->dims;
    int m = pclt->m;

    if (pclt->n > 3) {
        /* Do two 3-D interpolations, interpolating between them. */
        gx_color_lookup_table clt3;
        int ix = fixed2int_var(pi[0]);
        fixed fx = fixed_fraction(pi[0]);

        clt3.n = 3;
        clt3.dims[0] = pdim[1];	/* needed only for range checking */
        clt3.dims[1] = pdim[2];
        clt3.dims[2] = pdim[3];
        clt3.m = m;
        clt3.table = pclt->table + ix * pdim[1];
        interpolate_accum(pi + 1, &clt3, pv, fixed_1);
        if (ix == pdim[0] - 1)
            return;
        clt3.table += pdim[1];
        interpolate_accum(pi + 1, &clt3, pv, fx);
    } else {
        int ic = fixed2int_var(pi[2]);
        fixed fc = fixed_fraction(pi[2]);
        uint dc1 = (ic == pdim[2] - 1 ? 0 : m);
        int ib = fixed2int_var(pi[1]);
        fixed fb = fixed_fraction(pi[1]);
        uint db1 = (ib == pdim[1] - 1 ? 0 : pdim[2] * m);
        uint dbc = (ib * pdim[2] + ic) * m;
        uint dbc1 = db1 + dc1;
        int ia = fixed2int_var(pi[0]);
        fixed fa = fixed_fraction(pi[0]);
        const byte *pa0 = pclt->table[ia].data + dbc;
        const byte *pa1 =
            (ia == pdim[0] - 1 ? pa0 : pclt->table[ia + 1].data + dbc);
        int j;

        /* The values to be interpolated are */
        /* pa{0,1}[{0,db1,dc1,dbc1}]. */
        for (j = 0; j < m; ++j, ++pa0, ++pa1) {
            frac v000 = byte2frac(pa0[0]);
            frac v001 = byte2frac(pa0[dc1]);
            frac v010 = byte2frac(pa0[db1]);
            frac v011 = byte2frac(pa0[dbc1]);
            frac v100 = byte2frac(pa1[0]);
            frac v101 = byte2frac(pa1[dc1]);
            frac v110 = byte2frac(pa1[db1]);
            frac v111 = byte2frac(pa1[dbc1]);
            frac rv;

            frac v00 = v000 +
                (frac) arith_rshift((long)fc * (v001 - v000),
                                    _fixed_shift);
            frac v01 = v010 +
                (frac) arith_rshift((long)fc * (v011 - v010),
                                    _fixed_shift);
            frac v10 = v100 +
                (frac) arith_rshift((long)fc * (v101 - v100),
                                    _fixed_shift);
            frac v11 = v110 +
                (frac) arith_rshift((long)fc * (v111 - v110),
                                    _fixed_shift);

            frac v0 = v00 +
                (frac) arith_rshift((long)fb * (v01 - v00),
                                    _fixed_shift);
            frac v1 = v10 +
                (frac) arith_rshift((long)fb * (v11 - v10),
                                    _fixed_shift);

            rv = v0 +
                (frac) arith_rshift((long)fa * (v1 - v0),
                                    _fixed_shift);
            if (factor == fixed_1)
                pv[j] = rv;
            else
                pv[j] += (frac) arith_rshift((long)factor * (rv - pv[j]),
                                             _fixed_shift);
        }
    }
}
Exemplo n.º 6
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);
        }
    }
}