Example #1
0
/* <num> setlinewidth - */
static int
zsetlinewidth(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
	/*
	 * The Red Book doesn't say anything about this, but Adobe
	 * interpreters return (or perhaps store) the absolute value
	 * of the width.
	 */
    double width;
    int code = real_param(op, &width);

    if (code < 0)
	return_op_typecheck(op);
    code = gs_setlinewidth(igs, fabs(width));
    if (code >= 0)
	pop(1);
    return code;
}
Example #2
0
static int
charstring_execchar_aux(i_ctx_t *i_ctx_p, gs_text_enum_t *penum, gs_font *pfont)
{
    os_ptr op = osp;
    gs_font_base *const pbfont = (gs_font_base *) pfont;
    gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont;
    const gs_type1_data *pdata;
    gs_type1exec_state cxs;
    gs_type1_state *const pcis = &cxs.cis;
    gs_rect FontBBox = pfont1->FontBBox;
    int code;

    if (penum->current_font->FontType == ft_CID_encrypted) {
        if (FontBBox.q.x <= FontBBox.p.x && FontBBox.q.y <= FontBBox.p.y) {
            gs_font_cid0 *pfcid0 = (gs_font_cid0 *)penum->current_font;

            FontBBox = pfcid0->FontBBox;
        }
    }

    pdata = &pfont1->data;
    /*
     * Any reasonable implementation would execute something like
     *    1 setmiterlimit 0 setlinejoin 0 setlinecap
     * here, but the Adobe implementations don't.
     *
     * If this is a stroked font, set the stroke width.
     */
    if (pfont->PaintType)
        gs_setlinewidth(igs, pfont->StrokeWidth);
    check_estack(3);		/* for continuations */
    /*
     * Execute the definition of the character.
     */
    if (r_is_proc(op))
        return zchar_exec_char_proc(i_ctx_p);
    /*
     * The definition must be a Type 1 CharString.
     * Note that we do not require read access: this is deliberate.
     */
    check_type(*op, t_string);
    if (r_size(op) <= max(pdata->lenIV, 0))
        return_error(e_invalidfont);
    /*
     * In order to make character oversampling work, we must
     * set up the cache before calling .type1addpath.
     * To do this, we must get the bounding box from the FontBBox,
     * and the width from the CharString or the Metrics.
     * If the FontBBox isn't valid, we can't do any of this.
     */

    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 {  /* pass here if FontType==9,11 && WMode==1*/
        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 = metricsNone;
    }
    /* Establish a current point. */
    code = gs_moveto(igs, 0.0, 0.0);
    if (code < 0)
        return code;
    code = type1_exec_init(pcis, penum, igs, pfont1);
    if (code < 0)
        return code;
    gs_type1_set_callback_data(pcis, &cxs);
    if (FontBBox.q.x > FontBBox.p.x &&
        FontBBox.q.y > FontBBox.p.y
        ) {
        /* The FontBBox appears to be valid. */
        op_proc_t exec_cont = 0;

        cxs.char_bbox = pfont1->FontBBox;
        code = type1exec_bbox(i_ctx_p, penum, &cxs, pfont, &exec_cont);
        if (code >= 0 && exec_cont != 0)
            code = (*exec_cont)(i_ctx_p);
        return code;
    } else {
        /* The FontBBox is not valid */
        const ref *opstr = op;
        ref other_subr;
        const gs_matrix * pctm = &ctm_only(igs);

        /* First, check for singular CTM */
        if (pctm->xx * pctm->yy == pctm->xy * pctm->yx) {
           /* The code below won't be able to find the FontBBox but we
            * don't need it anyway. Set an empty box and consider it valid.
            */
            op_proc_t exec_cont = 0;

            cxs.char_bbox.p.x = 0;
            cxs.char_bbox.p.y = 0;
            cxs.char_bbox.q.x = 0;
            cxs.char_bbox.q.y = 0;
            code = type1exec_bbox(i_ctx_p, penum, &cxs, pfont, &exec_cont);
            if (code >= 0 && exec_cont != 0)
                code = (*exec_cont)(i_ctx_p);
            return code;
        }
        /* Now we create the path first, then do the setcachedevice.
         * If we are oversampling (in this case, only for anti-
         * aliasing, not just to improve quality), we have to
         * create the path twice, since we can't know the
         * oversampling factor until after setcachedevice.
         */
        switch (cxs.present) {
            case metricsSideBearingAndWidth: {
                gs_point pt;

                pt.x = cxs.sbw[0], pt.y = cxs.sbw[1];
                gs_type1_set_lsb(pcis, &pt);
            }
            /* fall through */
            case metricsWidthOnly: {
                gs_point pt;

                pt.x = cxs.sbw[2], pt.y = cxs.sbw[3];
                gs_type1_set_width(pcis, &pt);
            }
        }

        /* Continue interpreting. */
      icont:
        code = type1_continue_dispatch(i_ctx_p, &cxs, opstr, &other_subr, 4);
        op = osp;		/* OtherSubrs might change it */
        switch (code) {
            case 0:		/* all done */
                return nobbox_finish(i_ctx_p, &cxs);
            default:		/* code < 0, error */
                return code;
            case type1_result_callothersubr:	/* unknown OtherSubr */
                return type1_call_OtherSubr(i_ctx_p, &cxs, nobbox_continue,
                                            &other_subr);
            case type1_result_sbw:	/* [h]sbw, just continue */
                switch (cxs.present) {
                    case metricsNone:
                        cxs.sbw[0] = fixed2float(pcis->lsb.x);
                        cxs.sbw[1] = fixed2float(pcis->lsb.y);
                    /* fall through */
                    case metricsWidthOnly:
                        cxs.sbw[2] = fixed2float(pcis->width.x);
                        cxs.sbw[3] = fixed2float(pcis->width.y);
                }
                opstr = 0;
                goto icont;
        }
    }
}
Example #3
0
/* Stroke the current path */
int
gs_stroke(gs_state * pgs)
{
    int code;

    /*
     * If we're inside a charpath, just merge the current path
     * into the parent's path.
     */
    if (pgs->in_charpath) {
	if (pgs->in_charpath == cpm_true_charpath) {
	    /*
	     * A stroke inside a true charpath should do the
	     * equivalent of strokepath.
	     */
	    code = gs_strokepath(pgs);
	    if (code < 0)
		return code;
	}
	code = gx_path_add_char_path(pgs->show_gstate->path, pgs->path,
				     pgs->in_charpath);
    }
    if (gs_is_null_device(pgs->device)) {
	/* Handle separately to prevent gs_state_color_load. */
	gs_newpath(pgs);
	code = 0;
    } else {
	int abits, acode, rcode = 0;

        /* to distinguish text from vectors we hackly look at the
           target device 1 bit per component is a cache and this is
           text else it is a path */
        if (gx_device_has_color(gs_currentdevice(pgs)))
            gs_set_object_tag(pgs, GS_PATH_TAG);
        else
            gs_set_object_tag(pgs, GS_TEXT_TAG);

	/* Here we need to distinguish text from vectors to compute the object tag.
	   Actually we need to know whether this function is called to rasterize a character,
	   or to rasterize a vector graphics to the output device.
	   Currently we assume it works for the bitrgbtags device only,
	   which is a low level device with a 4-component color model.
	   We use the fact that with printers a character is usually being rendered 
	   to a 1bpp cache device rather than to the output device.
	   Therefore we hackly look whether the target device
	   "has a color" : either it's a multicomponent color model,
	   or it is not gray (such as a yellow separation).

	   This check has several limitations :
	   1. It doesn't work with -dNOCACHE.
	   2. It doesn't work with large characters,
	      which cannot fit into a cache cell and thus they
	      render directly to the output device.
	   3. It doesn't work for TextAlphaBits=2 or 4.
	      We don't care of this case because
	      text antialiasing usually usn't applied to printers.
	   4. It doesn't work for things like with "(xyz) true charpath stroke".
	      That's unfortunate, we'd like to improve someday.
	   5. It doesn't work for high level devices when a Type 3 character is being constructed.
	      This case is not important for low level devices
	      (which a printer is), because low level device doesn't accept
	      Type 3 charproc streams immediately.
	 */
        if (gx_device_has_color(gs_currentdevice(pgs))) {
            gs_set_object_tag(pgs, GS_PATH_TAG);
	}
	else {
            gs_set_object_tag(pgs, GS_TEXT_TAG);
	}
	gx_set_dev_color(pgs);
	code = gs_state_color_load(pgs);
	if (code < 0)
	    return code;
	abits = alpha_buffer_bits(pgs);
	if (abits > 1) {
	    /*
	     * Expand the bounding box by the line width.
	     * This is expensive to compute, so we only do it
	     * if we know we're going to buffer.
	     */
	    float xxyy = fabs(pgs->ctm.xx) + fabs(pgs->ctm.yy);
	    float xyyx = fabs(pgs->ctm.xy) + fabs(pgs->ctm.yx);
	    float scale = (float)(1 << (abits / 2));
	    float orig_width = gs_currentlinewidth(pgs);
	    float new_width = orig_width * scale;
	    fixed extra_adjust =
		float2fixed(max(xxyy, xyyx) * new_width / 2);
	    float orig_flatness = gs_currentflat(pgs);
	    gx_path spath;

	    /* Scale up the line width, dash pattern, and flatness. */
	    if (extra_adjust < fixed_1)
		extra_adjust = fixed_1;
	    acode = alpha_buffer_init(pgs,
				      pgs->fill_adjust.x + extra_adjust,
				      pgs->fill_adjust.y + extra_adjust,
				      abits);
	    if (acode < 0)
		return acode;
	    gs_setlinewidth(pgs, new_width);
	    scale_dash_pattern(pgs, scale);
	    gs_setflat(pgs, orig_flatness * scale);
	    /*
	     * The alpha-buffer device requires that we fill the
	     * entire path as a single unit.
	     */
	    gx_path_init_local(&spath, pgs->memory);
	    code = gx_stroke_add(pgs->path, &spath, pgs);
	    gs_setlinewidth(pgs, orig_width);
	    scale_dash_pattern(pgs, 1.0 / scale);
	    if (code >= 0)
		code = gx_fill_path(&spath, pgs->dev_color, pgs,
				    gx_rule_winding_number,
				    pgs->fill_adjust.x,
				    pgs->fill_adjust.y);
	    gs_setflat(pgs, orig_flatness);
	    gx_path_free(&spath, "gs_stroke");
	    if (acode > 0)
		rcode = alpha_buffer_release(pgs, code >= 0);
	} else
	    code = gx_stroke_fill(pgs->path, pgs);
	if (code >= 0)
	    gs_newpath(pgs);
	if (code >= 0 && rcode < 0)
	    code = rcode;
    }
    return code;
}
Example #4
0
int
pxSetPenWidth(px_args_t *par, px_state_t *pxs)
{	return gs_setlinewidth(pxs->pgs, real_value(par->pv[0], 0));
}