Пример #1
0
/*
 * Return the effective clipping path of a graphics state.  Sometimes this
 * is the intersection of the clip path and the view clip path; sometimes it
 * is just the clip path.  We aren't sure what the correct algorithm is for
 * this: for now, we use view clipping unless the current device is a memory
 * device.  This takes care of the most important case, where the current
 * device is a cache device.
 */
int
gx_effective_clip_path(gs_state * pgs, gx_clip_path ** ppcpath)
{
    gs_id view_clip_id =
	(pgs->view_clip == 0 || pgs->view_clip->rule == 0 ? gs_no_id :
	 pgs->view_clip->id);

    if (gs_device_is_memory(pgs->device)) {
	*ppcpath = pgs->clip_path;
	return 0;
    }
    if (pgs->effective_clip_id == pgs->clip_path->id &&
	pgs->effective_view_clip_id == view_clip_id
	) {
	*ppcpath = pgs->effective_clip_path;
	return 0;
    }
    /* Update the cache. */
    if (view_clip_id == gs_no_id) {
	if (!pgs->effective_clip_shared)
	    gx_cpath_free(pgs->effective_clip_path, "gx_effective_clip_path");
	pgs->effective_clip_path = pgs->clip_path;
	pgs->effective_clip_shared = true;
    } else {
	gs_fixed_rect cbox, vcbox;

	gx_cpath_inner_box(pgs->clip_path, &cbox);
	gx_cpath_outer_box(pgs->view_clip, &vcbox);
	if (rect_within(vcbox, cbox)) {
	    if (!pgs->effective_clip_shared)
		gx_cpath_free(pgs->effective_clip_path,
			      "gx_effective_clip_path");
	    pgs->effective_clip_path = pgs->view_clip;
	    pgs->effective_clip_shared = true;
	} else {
	    /* Construct the intersection of the two clip paths. */
	    int code;
	    gx_clip_path ipath;
	    gx_path vpath;
	    gx_clip_path *npath = pgs->effective_clip_path;

	    if (pgs->effective_clip_shared) {
		npath = gx_cpath_alloc(pgs->memory, "gx_effective_clip_path");
		if (npath == 0)
		    return_error(gs_error_VMerror);
	    }
	    gx_cpath_init_local(&ipath, pgs->memory);
	    code = gx_cpath_assign_preserve(&ipath, pgs->clip_path);
	    if (code < 0)
		return code;
	    gx_path_init_local(&vpath, pgs->memory);
	    code = gx_cpath_to_path(pgs->view_clip, &vpath);
	    if (code < 0 ||
		(code = gx_cpath_clip(pgs, &ipath, &vpath,
				      gx_rule_winding_number)) < 0 ||
		(code = gx_cpath_assign_free(npath, &ipath)) < 0
		)
		DO_NOTHING;
	    gx_path_free(&vpath, "gx_effective_clip_path");
	    gx_cpath_free(&ipath, "gx_effective_clip_path");
	    if (code < 0)
		return code;
	    pgs->effective_clip_path = npath;
	    pgs->effective_clip_shared = false;
	}
    }
    pgs->effective_clip_id = pgs->effective_clip_path->id;
    pgs->effective_view_clip_id = view_clip_id;
    *ppcpath = pgs->effective_clip_path;
    return 0;
}
Пример #2
0
/* We take the trouble to do this efficiently in the simple cases. */
int
gs_rectfill(gs_state * pgs, const gs_rect * pr, uint count)
{
    const gs_rect *rlist = pr;
    gx_clip_path *pcpath;
    uint rcount = count;
    int code;
    gx_device * pdev = pgs->device;
    gx_device_color *pdc = gs_currentdevicecolor_inline(pgs);
    const gs_imager_state *pis = (const gs_imager_state *)pgs;
    bool hl_color_available = gx_hld_is_hl_color_available(pis, pdc);
    bool hl_color = (hl_color_available &&
                dev_proc(pdev, dev_spec_op)(pdev, gxdso_supports_hlcolor, 
                                  NULL, 0));
    bool center_of_pixel = (pgs->fill_adjust.x == 0 && pgs->fill_adjust.y == 0);

    /* Processing a fill object operation */
    dev_proc(pgs->device, set_graphics_type_tag)(pgs->device, GS_PATH_TAG);

    code = gx_set_dev_color(pgs);
    if (code != 0)
        return code;
    if ((is_fzero2(pgs->ctm.xy, pgs->ctm.yx) ||
         is_fzero2(pgs->ctm.xx, pgs->ctm.yy)) &&
        gx_effective_clip_path(pgs, &pcpath) >= 0 &&
        clip_list_is_rectangle(gx_cpath_list(pcpath)) &&
        (hl_color ||
         pdc->type == gx_dc_type_pure ||
         pdc->type == gx_dc_type_ht_binary ||
         pdc->type == gx_dc_type_ht_colored) &&
        gs_state_color_load(pgs) >= 0 &&
        (*dev_proc(pdev, get_alpha_bits)) (pdev, go_graphics)
        <= 1 &&
        (!pgs->overprint || !pgs->effective_overprint_mode)
        ) {
        uint i;
        gs_fixed_rect clip_rect;

        gx_cpath_inner_box(pcpath, &clip_rect);
        /* We should never plot anything for an empty clip rectangle */
        if ((clip_rect.p.x >= clip_rect.q.x) &&
            (clip_rect.p.y >= clip_rect.q.y))
            return 0;
        for (i = 0; i < count; ++i) {
            gs_fixed_point p, q;
            gs_fixed_rect draw_rect;

            if (gs_point_transform2fixed(&pgs->ctm, pr[i].p.x, pr[i].p.y, &p) < 0 ||
                gs_point_transform2fixed(&pgs->ctm, pr[i].q.x, pr[i].q.y, &q) < 0
                ) {		/* Switch to the slow algorithm. */
                goto slow;
            }
            draw_rect.p.x = min(p.x, q.x);
            draw_rect.p.y = min(p.y, q.y);
            draw_rect.q.x = max(p.x, q.x);
            draw_rect.q.y = max(p.y, q.y);
            if (hl_color) {
                rect_intersect(draw_rect, clip_rect);
                /* We do pass on 0 extant rectangles to high level
                   devices.  It isn't clear how a client and an output
                   device should interact if one uses a center of
                   pixel algorithm and the other uses any part of
                   pixel.  For now we punt and just pass the high
                   level rectangle on without adjustment. */
                if (draw_rect.p.x <= draw_rect.q.x &&
                    draw_rect.p.y <= draw_rect.q.y) {
                    code = dev_proc(pdev, fill_rectangle_hl_color)(pdev,
                             &draw_rect, pis, pdc, pcpath);
                    if (code < 0)
                        return code;
                }
            } else {
                int x, y, w, h;

                rect_intersect(draw_rect, clip_rect);
                if (center_of_pixel) {
                    draw_rect.p.x = fixed_rounded(draw_rect.p.x);
                    draw_rect.p.y = fixed_rounded(draw_rect.p.y);
                    draw_rect.q.x = fixed_rounded(draw_rect.q.x);
                    draw_rect.q.y = fixed_rounded(draw_rect.q.y);
                } else { /* any part of pixel rule - touched */
                    draw_rect.p.x = fixed_floor(draw_rect.p.x);
                    draw_rect.p.y = fixed_floor(draw_rect.p.y);
                    draw_rect.q.x = fixed_ceiling(draw_rect.q.x);
                    draw_rect.q.y = fixed_ceiling(draw_rect.q.y);
                }
                x = fixed2int(draw_rect.p.x);
                y = fixed2int(draw_rect.p.y);
                w = fixed2int(draw_rect.q.x) - x;
                h = fixed2int(draw_rect.q.y) - y;
                /* clients that use the "any part of pixel" rule also
                   fill 0 areas.  This is true of current graphics
                   library clients but not a general rule.  */
                if (!center_of_pixel) {
                    if (w == 0)
                        w = 1;
                    /* yes Adobe Acrobat 8, seems to back up the y
                       coordinate when the width is 0, sigh. */
                    if (h == 0) {
                        y--;
                        h = 1;
                    }
                }
                if (gx_fill_rectangle(x, y, w, h, pdc, pgs) < 0)
                    goto slow;
            }
        }
        return 0;
      slow:rlist = pr + i;
        rcount = count - i;
    } {
        bool do_save = !gx_path_is_null(pgs->path);

        if (do_save) {
            if ((code = gs_gsave(pgs)) < 0)
                return code;
            gs_newpath(pgs);
        }
        if ((code = gs_rectappend(pgs, rlist, rcount)) < 0 ||
            (code = gs_fill(pgs)) < 0
            )
            DO_NOTHING;
        if (do_save)
            gs_grestore(pgs);
        else if (code < 0)
            gs_newpath(pgs);
    }
    return code;
}
Пример #3
0
static int
bbox_fill_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath,
	       const gx_fill_params * params, const gx_device_color * pdevc,
	       const gx_clip_path * pcpath)
{
    gx_device_bbox *const bdev = (gx_device_bbox *) dev;
    gx_device *tdev = bdev->target;
    dev_proc_fill_path((*fill_path)) =
	(tdev == 0 ? dev_proc(&gs_null_device, fill_path) :
	 dev_proc(tdev, fill_path));
    int code;

    if (ppath == NULL) {
	/* A special handling of shfill with no path. */
	gs_fixed_rect ibox;
	gs_fixed_point adjust;

	if (pcpath == NULL)
	    return 0;
	gx_cpath_inner_box(pcpath, &ibox);
	adjust = params->adjust;
	adjust_box(&ibox, adjust);
	BBOX_ADD_RECT(bdev, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y);
	return 0;
    } else if (!GX_DC_IS_TRANSPARENT(pdevc, bdev) && !gx_path_is_void(ppath)) {
	gs_fixed_rect ibox;
	gs_fixed_point adjust;

	if (gx_path_bbox(ppath, &ibox) < 0)
	    return 0;
	adjust = params->adjust;
	adjust_box(&ibox, adjust);
	/*
	 * If the path lies within the already accumulated box, just draw
	 * on the target.
	 */
	if (BBOX_IN_RECT(bdev, &ibox))
	    return fill_path(tdev, pis, ppath, params, pdevc, pcpath);
	/*
	 * If the target uses the default algorithm, just draw on the
	 * bbox device.
	 */
	if (tdev != 0 && fill_path == gx_default_fill_path)
	    return fill_path(dev, pis, ppath, params, pdevc, pcpath);
	/* Draw on the target now. */
	code = fill_path(tdev, pis, ppath, params, pdevc, pcpath);
	if (code < 0)
	    return code;
	if (pcpath != NULL &&
	    !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
					 ibox.q.x, ibox.q.y)
	    ) {
	    /*
	     * Let the target do the drawing, but break down the
	     * fill path into pieces for computing the bounding box.
	     */
	    gx_drawing_color devc;

	    set_nonclient_dev_color(&devc, bdev->black);  /* any non-white color will do */
	    bdev->target = NULL;
	    code = gx_default_fill_path(dev, pis, ppath, params, &devc, pcpath);
	    bdev->target = tdev;
	} else {		/* Just use the path bounding box. */
	    BBOX_ADD_RECT(bdev, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y);
	}
	return code;
    } else
	return fill_path(tdev, pis, ppath, params, pdevc, pcpath);
}
Пример #4
0
/* We take the trouble to do this efficiently in the simple cases. */
int
gs_rectfill(gs_state * pgs, const gs_rect * pr, uint count)
{
    const gs_rect *rlist = pr;
    gx_clip_path *pcpath;
    uint rcount = count;
    int code;
    gx_device * pdev = pgs->device;
    gx_device_color *pdc = pgs->dev_color;
    const gs_imager_state *pis = (const gs_imager_state *)pgs;
    bool hl_color_available = gx_hld_is_hl_color_available(pis, pdc);
    gs_fixed_rect empty = {{0, 0}, {0, 0}};
    bool hl_color = (hl_color_available && 
		dev_proc(pdev, fill_rectangle_hl_color)(pdev, 
		    	    &empty, pis, pdc, NULL) == 0);

    gx_set_dev_color(pgs);
    if ((is_fzero2(pgs->ctm.xy, pgs->ctm.yx) ||
	 is_fzero2(pgs->ctm.xx, pgs->ctm.yy)) &&
	gx_effective_clip_path(pgs, &pcpath) >= 0 &&
	clip_list_is_rectangle(gx_cpath_list(pcpath)) &&
	(hl_color ||
	 pdc->type == gx_dc_type_pure ||
	 pdc->type == gx_dc_type_ht_binary ||
	 pdc->type == gx_dc_type_ht_colored
	 /* DeviceN todo: add wts case */) &&
	gs_state_color_load(pgs) >= 0 &&
	(*dev_proc(pdev, get_alpha_bits)) (pdev, go_graphics)
	<= 1 &&
        (!pgs->overprint || !pgs->effective_overprint_mode)
	) {
	uint i;
	gs_fixed_rect clip_rect;

	gx_cpath_inner_box(pcpath, &clip_rect);
	for (i = 0; i < count; ++i) {
	    gs_fixed_point p, q;
	    gs_fixed_rect draw_rect;
	    
	    if (gs_point_transform2fixed(&pgs->ctm, pr[i].p.x, pr[i].p.y, &p) < 0 ||
		gs_point_transform2fixed(&pgs->ctm, pr[i].q.x, pr[i].q.y, &q) < 0
		) {		/* Switch to the slow algorithm. */
		goto slow;
	    }
	    draw_rect.p.x = min(p.x, q.x);
	    draw_rect.p.y = min(p.y, q.y);
	    draw_rect.q.x = max(p.x, q.x);
	    draw_rect.q.y = max(p.y, q.y);
	    if (hl_color) {
		rect_intersect(draw_rect, clip_rect);
		if (draw_rect.p.x < draw_rect.q.x &&
		    draw_rect.p.y < draw_rect.q.y) {
		    code = dev_proc(pdev, fill_rectangle_hl_color)(pdev,
			     &draw_rect, pis, pdc, pcpath);
		    if (code < 0)
			return code;
		}
	    } else {
		int x, y, w, h;

		draw_rect.p.x -= pgs->fill_adjust.x;
		draw_rect.p.y -= pgs->fill_adjust.x;
		draw_rect.q.x += pgs->fill_adjust.x;
		draw_rect.q.y += pgs->fill_adjust.x;
		rect_intersect(draw_rect, clip_rect);
		x = fixed2int_pixround(draw_rect.p.x);
		y = fixed2int_pixround(draw_rect.p.y);
		w = fixed2int_pixround(draw_rect.q.x) - x;
		h = fixed2int_pixround(draw_rect.q.y) - y;
		if (w > 0 && h > 0)
    		    if (gx_fill_rectangle(x, y, w, h, pdc, pgs) < 0)
			goto slow;
	    }
	}
	return 0;
      slow:rlist = pr + i;
	rcount = count - i;
    } {
	bool do_save = !gx_path_is_null(pgs->path);

	if (do_save) {
	    if ((code = gs_gsave(pgs)) < 0)
		return code;
	    gs_newpath(pgs);
	}
	if ((code = gs_rectappend(pgs, rlist, rcount)) < 0 ||
	    (code = gs_fill(pgs)) < 0
	    )
	    DO_NOTHING;
	if (do_save)
	    gs_grestore(pgs);
	else if (code < 0)
	    gs_newpath(pgs);
    }
    return code;
}