コード例 #1
0
int
charstring_execchar(i_ctx_t *i_ctx_p, int font_type_mask)
{
    gs_text_enum_t *penum = op_show_find(i_ctx_p);
    gs_font *pfont;
    os_ptr op = osp;
    int code = font_param(op - 3, &pfont);

    if (code < 0)
        return code;
    if (penum == 0 ||
        pfont->FontType >= sizeof(font_type_mask) * 8 ||
        !(font_type_mask & (1 << (int)pfont->FontType)))
        return_error(e_undefined);
    code = charstring_execchar_aux(i_ctx_p, penum, pfont);
    if (code < 0 && igs->in_cachedevice == CACHE_DEVICE_CACHING) {
        /* Perform the cache cleanup, when the cached character data
           has been allocated (gx_alloc_char_bits) but
           the character has not been added to the cache (gx_add_cached_char)
           due to a falure in the character renderer.
         */
        gs_show_enum *const penum_s = (gs_show_enum *)penum;

        if (penum_s->cc != NULL) {
            gx_free_cached_char(pfont->dir, penum_s->cc);
            penum_s->cc = NULL;
        }
    }
    return code;
}
コード例 #2
0
/* Get the calling operator for error reporting in %Type32BuildGlyph */
static int
zgetshowoperator(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    gs_text_enum_t *osenum = op_show_find(i_ctx_p);
  
    push(1);
    if (osenum == NULL)
        make_null(op);
    else {
        op_proc_t proc;
        *(void **)&proc = osenum->enum_client_data;
        make_oper(op, 0, proc);
    }
    return 0;
}
コード例 #3
0
ファイル: zchar.c プロジェクト: ststeiger/ghostsvg
/* <wx> <wy> setcharwidth - */
static int
zsetcharwidth(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    double width[2];
    gs_text_enum_t *penum = op_show_find(i_ctx_p);
    int code = num_params(op, 2, width);

    if (penum == 0)
	return_error(e_undefined);
    if (code < 0)
	return code;
    if (zchar_show_width_only(penum))
	return op_show_return_width(i_ctx_p, 2, &width[0]);
    code = gs_text_setcharwidth(penum, width);
    if (code < 0)
	return code;
    pop(2);
    return 0;
}
コード例 #4
0
ファイル: zchar.c プロジェクト: ststeiger/ghostsvg
/* <wx> <wy> <llx> <lly> <urx> <ury> setcachedevice - */
int
zsetcachedevice(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    double wbox[6];
    gs_text_enum_t *penum = op_show_find(i_ctx_p);
    int code = num_params(op, 6, wbox);

    if (penum == 0)
	return_error(e_undefined);
    if (code < 0)
	return code;
    if (zchar_show_width_only(penum))
	return op_show_return_width(i_ctx_p, 6, &wbox[0]);
    code = gs_text_setcachedevice(penum, wbox);
    if (code < 0)
	return code;
    pop(6);
    if (code == 1)
	clear_pagedevice(istate);
    return 0;
}
コード例 #5
0
ファイル: zchar.c プロジェクト: ststeiger/ghostsvg
/* <w0x> <w0y> <llx> <lly> <urx> <ury> <w1x> <w1y> <vx> <vy> setcachedevice2 - */
int
zsetcachedevice2(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    double wbox[10];
    gs_text_enum_t *penum = op_show_find(i_ctx_p);
    int code = num_params(op, 10, wbox);

    if (penum == 0)
	return_error(e_undefined);
    if (code < 0)
	return code;
    if (zchar_show_width_only(penum))
	return op_show_return_width(i_ctx_p, 10,
				    (gs_rootfont(igs)->WMode ?
				     &wbox[6] : &wbox[0]));
    code = gs_text_setcachedevice2(penum, wbox);
    if (code < 0)
	return code;
    pop(10);
    if (code == 1)
	clear_pagedevice(istate);
    return 0;
}
コード例 #6
0
ファイル: zchar.c プロジェクト: ststeiger/ghostsvg
/* Finish setting up a text operator. */
int
op_show_finish_setup(i_ctx_t *i_ctx_p, gs_text_enum_t * penum, int npop,
		     op_proc_t endproc /* end procedure */ )
{
    gs_text_enum_t *osenum = op_show_find(i_ctx_p);
    es_ptr ep = esp + snumpush;
    gs_glyph glyph;

    if (gs_currentcpsimode(igs->memory)) {
	/* CET 14-03.PS page 2 emits rangecheck before rendering a character.
	   Early check the text to font compatibility 
	   with decomposing the text into characters.*/
	int code = gs_text_count_chars(igs, gs_get_text_params(penum), imemory);

	if (code < 0)
	    return code;
    }
    /*
     * If we are in the procedure of a cshow for a CID font and this is
     * a show operator, do something special, per the Red Book.
     */
    if (osenum &&
	SHOW_IS_ALL_OF(osenum,
		       TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_INTERVENE) &&
	SHOW_IS_ALL_OF(penum, TEXT_FROM_STRING | TEXT_RETURN_WIDTH) &&
	(glyph = gs_text_current_glyph(osenum)) != gs_no_glyph &&
	glyph >= gs_min_cid_glyph &&

        /* According to PLRM, we don't need to raise a rangecheck error,
           if currentfont is changed in the proc of the operator 'cshow'. */
	gs_default_same_font (gs_text_current_font(osenum), 
			      gs_text_current_font(penum), true)
	) {
	gs_text_params_t text;

	if (!(penum->text.size == 1 &&
	      penum->text.data.bytes[0] ==
	        (gs_text_current_char(osenum) & 0xff))
	    )
	    return_error(e_rangecheck);
	text = penum->text;
	text.operation =
	    (text.operation &
	     ~(TEXT_FROM_STRING | TEXT_FROM_BYTES | TEXT_FROM_CHARS |
	       TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_CHAR)) |
	    TEXT_FROM_SINGLE_GLYPH;
	text.data.d_glyph = glyph;
	text.size = 1;
	gs_text_restart(penum, &text);
    }
    if (osenum && osenum->current_font->FontType == ft_user_defined &&
	osenum->orig_font->FontType == ft_composite &&
	((const gs_font_type0 *)osenum->orig_font)->data.FMapType == fmap_CMap) {
	/* A special behavior defined in PLRM3 section 5.11 page 389. */
	penum->outer_CID = osenum->returned.current_glyph;
    }
    if (osenum == NULL && !(penum->text.operation & (TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH))) {
        int ft = igs->root_font->FontType;
 
        if ((ft >= ft_CID_encrypted && ft <= ft_CID_TrueType) || ft == ft_CID_bitmap)
            return_error(e_typecheck);
    }
    make_mark_estack(ep - (snumpush - 1), es_show, op_show_cleanup);
    if (endproc == NULL)
	endproc = finish_show;
    make_null(&esslot(ep));
    make_int(&esodepth(ep), ref_stack_count_inline(&o_stack) - npop); /* Save stack depth for */
    make_int(&esddepth(ep), ref_stack_count_inline(&d_stack));        /* correct interrupt processing */
    make_int(&esgslevel(ep), igs->level);
    make_null(&essfont(ep));
    make_null(&esrfont(ep));
    make_op_estack(&eseproc(ep), endproc);
    make_istruct(ep, 0, penum);
    esp = ep;
    return 0;
}
コード例 #7
0
ファイル: zcharout.c プロジェクト: BorodaZizitopa/ghostscript
/*
 * Consult Metrics2 and CDevProc, and call setcachedevice[2].  Return
 * o_push_estack if we had to call a CDevProc, or if we are skipping the
 * rendering process (only getting the metrics).
 * Returns exec_cont - a function, which must be called by caller after this function.
 */
int
zchar_set_cache(i_ctx_t *i_ctx_p, const gs_font_base * pbfont,
                const ref * pcnref, const double psb[2],
                const double pwidth[2], const gs_rect * pbbox,
                op_proc_t cont, op_proc_t *exec_cont,
                const double Metrics2_sbw_default[4])
{
    os_ptr op = osp;
    ref *pcdevproc, *valueref;
    int have_cdevproc;
    ref rpop;
    ref cid, *cidptr;
    bool metrics2;
    bool metrics2_use_default = false;
    double w2[10];
    gs_text_enum_t *penum = op_show_find(i_ctx_p);

    w2[0] = pwidth[0], w2[1] = pwidth[1];

    /* Adjust the bounding box for stroking if needed. */

    w2[2] = pbbox->p.x, w2[3] = pbbox->p.y;
    w2[4] = pbbox->q.x, w2[5] = pbbox->q.y;
    if (pbfont->PaintType != 0) {
        double expand = max(1.415, gs_currentmiterlimit(igs)) *
        gs_currentlinewidth(igs) / 2;

        w2[2] -= expand, w2[3] -= expand;
        w2[4] += expand, w2[5] += expand;
    }

    /* Check for Metrics2. */

    {
        int code = zchar_get_metrics2(pbfont, pcnref, w2 + 6);

        if (code < 0)
            return code;
        metrics2 = code > 0;
    }

    /*
     * For FontType 9 and 11, if Metrics2 is missing, the caller provides
     * default Metrics2 values derived from the FontBBox.
     */
    if (!metrics2 && Metrics2_sbw_default != NULL) {
        w2[6] = Metrics2_sbw_default[2];
        w2[7] = Metrics2_sbw_default[3];
        w2[8] = Metrics2_sbw_default[0];
        w2[9] = Metrics2_sbw_default[1];
        metrics2 = true;
        metrics2_use_default = true;
    }

    /* Check for CDevProc or "short-circuiting". */

    have_cdevproc = zchar_get_CDevProc(pbfont, &pcdevproc);

    /* Obscure test. The CDevProc is supposed to be called with the original CID but what we get passed
     * here is the TT GID. So the CDevProc won't do the right thing. We need to extract the CID from the
     * enumerator, and use that instead.
     */
    cidptr = (ref *)pcnref;
    if (pbfont->FontType == ft_CID_TrueType && dict_find_string(&pfont_data(gs_font_parent(pbfont))->dict, "File", &valueref) > 0) {
        if (pbfont->key_name.size != pbfont->font_name.size ||
            strncmp((const char *)pbfont->key_name.chars, (const char *)pbfont->font_name.chars, pbfont->key_name.size)) {

            if (penum->returned.current_glyph >= GS_MIN_CID_GLYPH) {
                make_int(&cid, penum->returned.current_glyph - GS_MIN_CID_GLYPH);
            }
            else {
                make_int(&cid, penum->returned.current_glyph);
            }
            cidptr = &cid;
        }
    }
    if (have_cdevproc || zchar_show_width_only(penum)) {
        int i;
        op_proc_t zsetc;
        int nparams;

        if (have_cdevproc) {
            check_proc_only(*pcdevproc);
            zsetc = zsetcachedevice2;

            /* If we have cdevproc and the font type is CID type 0,
               we'll throw away Metrics2_sbw_default that is calculated
               from FontBBox. */
            if (!metrics2
                || (penum->current_font->FontType == ft_CID_encrypted
                    && metrics2_use_default)) {
                w2[6] = w2[0], w2[7] = w2[1];
                w2[8] = w2[9] = 0;
            }
            nparams = 10;
        } else {
            make_oper(&rpop, 0, zpop);
            pcdevproc = &rpop;
            if (metrics2)
                zsetc = zsetcachedevice2, nparams = 10;
            else
                zsetc = zsetcachedevice, nparams = 6;
        }
        check_estack(3);
        /* Push the l.s.b. for .type1addpath if necessary. */
        if (psb != 0) {
            push(nparams + 3);
            make_real(op - (nparams + 2), psb[0]);
            make_real(op - (nparams + 1), psb[1]);
        } else {
            push(nparams + 1);
        }
        for (i = 0; i < nparams; ++i)
            make_real(op - nparams + i, w2[i]);
        ref_assign(op, cidptr);
        push_op_estack(cont);
        push_op_estack(zsetc);
        ++esp;
        ref_assign(esp, pcdevproc);
        return o_push_estack;
    } {
        int code =
            (metrics2 ? gs_text_setcachedevice2(penum, w2) :
             gs_text_setcachedevice(penum, w2));

        if (code < 0)
            return code;
    }

    /* No metrics modification, do the stroke or fill now. */

    /* Push the l.s.b. for .type1addpath if necessary. */
    if (psb != 0) {
        push(2);
        make_real(op - 1, psb[0]);
        make_real(op, psb[1]);
    }
    *exec_cont = cont;
    return 0;
}
コード例 #8
0
ファイル: zcharout.c プロジェクト: BoxianLai/moxiedev
/*
 * Consult Metrics2 and CDevProc, and call setcachedevice[2].  Return
 * o_push_estack if we had to call a CDevProc, or if we are skipping the
 * rendering process (only getting the metrics).
 */
int
zchar_set_cache(os_ptr op, const gs_font_base *pbfont, const ref *pcnref,
  const float psb[2], const float pwidth[2], const gs_rect *pbbox,
  int (*cont_fill)(P1(os_ptr)), int (*cont_stroke)(P1(os_ptr)))
{	const ref *pfdict = &pfont_data(pbfont)->dict;
	ref *pmdict;
	ref *pcdevproc;
	int have_cdevproc;
	ref rpop;
	bool metrics2 = false;
	int (*cont)(P1(os_ptr));
	float w2[10];
	gs_show_enum *penum = op_show_find();

	w2[0] = pwidth[0], w2[1] = pwidth[1];

	/* Adjust the bounding box for stroking if needed. */

	w2[2] = pbbox->p.x, w2[3] = pbbox->p.y;
	w2[4] = pbbox->q.x, w2[5] = pbbox->q.y;
	if ( pbfont->PaintType == 0 )
		cont = cont_fill;
	else
	{	double expand = max(1.415, gs_currentmiterlimit(igs)) *
		  gs_currentlinewidth(igs) / 2;

		w2[2] -= expand, w2[3] -= expand;
		w2[4] += expand, w2[5] += expand;
		cont = cont_stroke;
	}

	/* Check for Metrics2. */

	if ( dict_find_string(pfdict, "Metrics2", &pmdict) > 0 )
	{	ref *pmvalue;
		check_type_only(*pmdict, t_dictionary);
		check_dict_read(*pmdict);
		if ( dict_find(pmdict, pcnref, &pmvalue) > 0 )
		{	check_read_type_only(*pmvalue, t_array);
			if ( r_size(pmvalue) == 4 )
			{	int code = num_params(pmvalue->value.refs + 3,
						      4, w2 + 6);
				if ( code < 0 )
				  return code;
				metrics2 = true;
			}
		}
	}

	/* Check for CDevProc or "short-circuiting". */

	have_cdevproc = dict_find_string(pfdict, "CDevProc", &pcdevproc) > 0;
	if ( have_cdevproc || gs_show_width_only(penum) )
	{	int i;
		int (*zsetc)(P1(os_ptr));
		int nparams;

		if ( have_cdevproc )
		  { check_proc_only(*pcdevproc);
		    zsetc = zsetcachedevice2;
		    if ( !metrics2 )
		      { w2[6] = w2[0], w2[7] = w2[1];
			w2[8] = w2[9] = 0;
		      }
		    nparams = 10;
		  }
		else
		  { make_oper(&rpop, 0, zpop);
		    pcdevproc = &rpop;
		    if ( metrics2 )
		      zsetc = zsetcachedevice2, nparams = 10;
		    else
		      zsetc = zsetcachedevice, nparams = 6;
		  }
		check_estack(3);
		/* Push the l.s.b. for .type1addpath if necessary. */
		if ( psb != 0 )
		  { push(nparams + 3);
		    make_real(op - (nparams + 2), psb[0]);
		    make_real(op - (nparams + 1), psb[1]);
		  }
		else
		  { push(nparams + 1);
		  }
		for ( i = 0; i < nparams; ++i )
		  make_real(op - nparams + i, w2[i]);
		ref_assign(op, pcnref);
		push_op_estack(cont);
		push_op_estack(zsetc);
		++esp;
		ref_assign(esp, pcdevproc);
		return o_push_estack;
	}
	{ int code =
		(metrics2 ? gs_setcachedevice2(penum, igs, w2) :
		 gs_setcachedevice(penum, igs, w2));
	  if ( code < 0 )
	    return code;
	}

	/* No metrics modification, do the stroke or fill now. */

	/* Push the l.s.b. for .type1addpath if necessary. */
	if ( psb != 0 )
	  { push(2);
	    make_real(op - 1, psb[0]);
	    make_real(op, psb[1]);
	  }
	return cont(op);
}
コード例 #9
0
/*
 * Check the path against FontBBox before drawing.  The original operands
 * of type1execchar are still on the o-stack.
 * Returns exec_cont - a function, which must be called by caller after this function.
 */
static int
bbox_draw(i_ctx_t *i_ctx_p, int (*draw)(gs_state *), op_proc_t *exec_cont)
{
    os_ptr op = osp;
    gs_rect bbox;
    gs_font *pfont;
    gs_text_enum_t *penum;
    gs_font_base * pbfont;
    gs_font_type1 * pfont1;
    gs_type1exec_state cxs;
    int code;

    if (igs->in_cachedevice < 2)	/* not caching */
        return nobbox_draw(i_ctx_p, draw);
    if ((code = font_param(op - 3, &pfont)) < 0)
        return code;
    penum = op_show_find(i_ctx_p);
    if (penum == 0 || !font_uses_charstrings(pfont))
        return_error(e_undefined);
    if ((code = gs_pathbbox(igs, &bbox)) < 0) {
        /*
         * If the matrix is singular, all user coordinates map onto a
         * straight line.  Don't bother rendering the character at all.
         */
        if (code == e_undefinedresult) {
            pop(4);
            gs_newpath(igs);
            return 0;
        }
        return code;
    }
    if (draw == gs_stroke) {
        /* Expand the bounding box by the line width. */
        float width = gs_currentlinewidth(igs) * 1.41422;

        bbox.p.x -= width, bbox.p.y -= width;
        bbox.q.x += width, bbox.q.y += width;
    }
    pbfont = (gs_font_base *)pfont;
    if (rect_within(bbox, pbfont->FontBBox))	/* within bounds */
        return nobbox_draw(i_ctx_p, draw);
    /* Enlarge the FontBBox to save work in the future. */
    rect_merge(pbfont->FontBBox, bbox);
    /* Dismantle everything we've done, and start over. */
    gs_text_retry(penum);
    pfont1 = (gs_font_type1 *) pfont;
    if ((penum->FontBBox_as_Metrics2.x == 0 &&
         penum->FontBBox_as_Metrics2.y == 0) ||
        gs_rootfont(igs)->WMode == 0 ) {
        code = zchar_get_metrics(pbfont, op - 1, cxs.sbw);
        if (code < 0)
            return code;
        cxs.present = code;
        cxs.use_FontBBox_as_Metrics2 = false;
    }  else {
        cxs.sbw[0] = penum->FontBBox_as_Metrics2.x / 2;
        cxs.sbw[1] = penum->FontBBox_as_Metrics2.y;
        cxs.sbw[2] = 0;
        cxs.sbw[3] = -penum->FontBBox_as_Metrics2.x; /* Sic! */
        cxs.use_FontBBox_as_Metrics2 = true;
        cxs.present = metricsSideBearingAndWidth;
    }
    code = type1_exec_init(&cxs.cis, penum, igs, pfont1);
    if (code < 0)
        return code;
    cxs.char_bbox = pfont1->FontBBox;
    code = type1exec_bbox(i_ctx_p, penum, &cxs, pfont, exec_cont);
    return code;
}
コード例 #10
0
static int
bbox_finish(i_ctx_t *i_ctx_p, op_proc_t cont, op_proc_t *exec_cont)
{   /* Returns exec_cont - a function, which must be called by caller after this function. */
    os_ptr op = osp;
    gs_font *pfont;
    int code;
    gs_text_enum_t *penum = op_show_find(i_ctx_p);
    gs_type1exec_state cxs;	/* stack allocate to avoid sandbars */
    gs_type1_state *const pcis = &cxs.cis;
    double sbxy[2];
    gs_point sbpt;
    gs_point *psbpt = 0;
    os_ptr opc = op;
    const ref *opstr;
    ref other_subr;

    if (!r_has_type(opc, t_string)) {
        check_op(3);
        code = num_params(op, 2, sbxy);
        if (code < 0)
            return code;
        sbpt.x = sbxy[0];
        sbpt.y = sbxy[1];
        psbpt = &sbpt;
        opc -= 2;
        check_type(*opc, t_string);
    }
    code = font_param(opc - 3, &pfont);
    if (code < 0)
        return code;
    if (penum == 0 || !font_uses_charstrings(pfont))
        return_error(e_undefined);
    {
        gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont;
        int lenIV = pfont1->data.lenIV;

        if (lenIV > 0 && r_size(opc) <= lenIV)
            return_error(e_invalidfont);
        check_estack(5);	/* in case we need to do a callout */
        code = type1_exec_init(pcis, penum, igs, pfont1);
        if (code < 0)
            return code;
        if (psbpt)
            gs_type1_set_lsb(pcis, psbpt);
    }
    opstr = opc;
  icont:
    code = type1_continue_dispatch(i_ctx_p, &cxs, opstr, &other_subr,
                                   (psbpt ? 6 : 4));
    op = osp;		/* OtherSubrs might have altered it */
    switch (code) {
        case 0:		/* all done */
            /* Call the continuation now. */
            if (psbpt)
                pop(2);
            *exec_cont = cont;
            return 0;
        case type1_result_callothersubr:	/* unknown OtherSubr */
            push_op_estack(cont);	/* call later */
            return type1_call_OtherSubr(i_ctx_p, &cxs, bbox_continue,
                                        &other_subr);
        case type1_result_sbw:	/* [h]sbw, just continue */
            opstr = 0;
            goto icont;
        default:		/* code < 0, error */
            return code;
    }
}
コード例 #11
0
ファイル: zcharout.c プロジェクト: 99years/plan9
/*
 * Consult Metrics2 and CDevProc, and call setcachedevice[2].  Return
 * o_push_estack if we had to call a CDevProc, or if we are skipping the
 * rendering process (only getting the metrics).
 * Returns exec_cont - a function, which must be called by caller after this function.
 */
int
zchar_set_cache(i_ctx_t *i_ctx_p, const gs_font_base * pbfont,
		const ref * pcnref, const double psb[2],
		const double pwidth[2], const gs_rect * pbbox,
		op_proc_t cont, op_proc_t *exec_cont,
		const double Metrics2_sbw_default[4])
{
    os_ptr op = osp;
    ref *pcdevproc;
    int have_cdevproc;
    ref rpop;
    bool metrics2;
    bool metrics2_use_default = false;
    double w2[10];
    gs_text_enum_t *penum = op_show_find(i_ctx_p);

    w2[0] = pwidth[0], w2[1] = pwidth[1];

    /* Adjust the bounding box for stroking if needed. */

    w2[2] = pbbox->p.x, w2[3] = pbbox->p.y;
    w2[4] = pbbox->q.x, w2[5] = pbbox->q.y;
    if (pbfont->PaintType != 0) {
	double expand = max(1.415, gs_currentmiterlimit(igs)) *
	gs_currentlinewidth(igs) / 2;

	w2[2] -= expand, w2[3] -= expand;
	w2[4] += expand, w2[5] += expand;
    }

    /* Check for Metrics2. */

    {
	int code = zchar_get_metrics2(pbfont, pcnref, w2 + 6);

	if (code < 0)
	    return code;
	metrics2 = code > 0;
    }

    /*
     * For FontType 9 and 11, if Metrics2 is missing, the caller provides
     * default Metrics2 values derived from the FontBBox.
     */
    if (!metrics2 && Metrics2_sbw_default != NULL) {
        w2[6] = Metrics2_sbw_default[2];
        w2[7] = Metrics2_sbw_default[3];
        w2[8] = Metrics2_sbw_default[0];
        w2[9] = Metrics2_sbw_default[1];
	metrics2 = true;
	metrics2_use_default = true;
    }

    /* Check for CDevProc or "short-circuiting". */

    have_cdevproc = zchar_get_CDevProc(pbfont, &pcdevproc);
    if (have_cdevproc || zchar_show_width_only(penum)) {
	int i;
	op_proc_t zsetc;
	int nparams;

	if (have_cdevproc) {
	    check_proc_only(*pcdevproc);
	    zsetc = zsetcachedevice2;
	    
	    /* If we have cdevproc and the font type is CID type 0,
	       we'll throw away Metrics2_sbw_default that is calculated 
	       from FontBBox. */
	    if (!metrics2 
		|| (penum->current_font->FontType == ft_CID_encrypted
		    && metrics2_use_default)) {
		w2[6] = w2[0], w2[7] = w2[1];
		w2[8] = w2[9] = 0;
	    }
	    nparams = 10;
	} else {
	    make_oper(&rpop, 0, zpop);
	    pcdevproc = &rpop;
	    if (metrics2)
		zsetc = zsetcachedevice2, nparams = 10;
	    else
		zsetc = zsetcachedevice, nparams = 6;
	}
	check_estack(3);
	/* Push the l.s.b. for .type1addpath if necessary. */
	if (psb != 0) {
	    push(nparams + 3);
	    make_real(op - (nparams + 2), psb[0]);
	    make_real(op - (nparams + 1), psb[1]);
	} else {
	    push(nparams + 1);
	}
	for (i = 0; i < nparams; ++i)
	    make_real(op - nparams + i, w2[i]);
	ref_assign(op, pcnref);
	push_op_estack(cont);
	push_op_estack(zsetc);
	++esp;
	ref_assign(esp, pcdevproc);
	return o_push_estack;
    } {
	int code =
	    (metrics2 ? gs_text_setcachedevice2(penum, w2) :
	     gs_text_setcachedevice(penum, w2));

	if (code < 0)
	    return code;
    }

    /* No metrics modification, do the stroke or fill now. */

    /* Push the l.s.b. for .type1addpath if necessary. */
    if (psb != 0) {
	push(2);
	make_real(op - 1, psb[0]);
	make_real(op, psb[1]);
    }
    *exec_cont = cont;
    return 0;
}