Beispiel #1
0
/* Get the default clipping box. */
int
gx_default_clip_box(const gs_state * pgs, gs_fixed_rect * pbox)
{
    register gx_device *dev = gs_currentdevice(pgs);
    gs_rect bbox;
    gs_matrix imat;
    int code;

    if (dev->ImagingBBox_set) {	/* Use the ImagingBBox, relative to default user space. */
	gs_defaultmatrix(pgs, &imat);
	bbox.p.x = dev->ImagingBBox[0];
	bbox.p.y = dev->ImagingBBox[1];
	bbox.q.x = dev->ImagingBBox[2];
	bbox.q.y = dev->ImagingBBox[3];
    } else {			/* Use the MediaSize indented by the HWMargins, */
	/* relative to unrotated user space adjusted by */
	/* the Margins.  (We suspect this isn't quite right, */
	/* but the whole issue of "margins" is such a mess that */
	/* we don't think we can do any better.) */
	(*dev_proc(dev, get_initial_matrix)) (dev, &imat);
	/* Adjust for the Margins. */
	imat.tx += dev->Margins[0] * dev->HWResolution[0] /
	    dev->MarginsHWResolution[0];
	imat.ty += dev->Margins[1] * dev->HWResolution[1] /
	    dev->MarginsHWResolution[1];
	bbox.p.x = dev->HWMargins[0];
	bbox.p.y = dev->HWMargins[1];
	bbox.q.x = dev->MediaSize[0] - dev->HWMargins[2];
	bbox.q.y = dev->MediaSize[1] - dev->HWMargins[3];
    }
    code = gs_bbox_transform(&bbox, &imat, &bbox);
    if (code < 0)
	return code;
    /* Round the clipping box so that it doesn't get ceilinged. */
    pbox->p.x = fixed_rounded(float2fixed(bbox.p.x));
    pbox->p.y = fixed_rounded(float2fixed(bbox.p.y));
    pbox->q.x = fixed_rounded(float2fixed(bbox.q.x));
    pbox->q.y = fixed_rounded(float2fixed(bbox.q.y));
    return 0;
}
Beispiel #2
0
/* We should swap axes to get best accuracy, but we don't. */
int
gz_fill_pgram_fixed(fixed px, fixed py, fixed ax, fixed ay,
  fixed bx, fixed by, const gx_device_color *pdevc, gs_state *pgs)
{	fixed t;
	fixed qx, dx, wx, pax, qax;
	int code;
#define swap(r, s) (t = r, r = s, s = t)
	/* Reorder the points so that 0 <= ay <= by. */
	if ( ay < 0 ) px += ax, py += ay, ax = -ax, ay = -ay;
	if ( by < 0 ) px += bx, py += by, bx = -bx, by = -by;
	if ( ay > by ) swap(ax, bx), swap(ay, by);
	if ( by == 0 ) return 0;	/* degenerate (line) */
	qx = px + ax + bx;
	/* Compute the distance from p to the point on the line (p, p+b) */
	/* whose Y coordinate is equal to ay. */
	dx = (fixed)((double)bx * ay / by);
	if ( dx < ax ) pax = px + dx, qax = qx - ax, wx = ax - dx;
	else pax = px + ax, qax = qx - dx, wx = dx - ax;
	if ( ay >= fixed_1 ||
	    fixed_rounded(py) != fixed_rounded(py + ay)
	   )
	   {	code = gz_fill_trapezoid_fixed(px, fixed_0, py, pax, wx, ay,
					       0, pdevc, pgs);
		if ( code < 0 ) return code;
	   }
	code = gz_fill_trapezoid_fixed(pax, wx, py + ay, qax, wx, by - ay,
				       0, pdevc, pgs);
	if ( code < 0 ) return code;
	py += by;
	if ( ay >= fixed_1 ||
	    fixed_rounded(py) != fixed_rounded(py + ay)
	   )
		return gz_fill_trapezoid_fixed(qax, wx, py, qx, fixed_0, ay,
					       0, pdevc, pgs);
#undef swap
	return 0;
}
Beispiel #3
0
int
gz_fill_trapezoid_fixed(fixed fx0, fixed fw0, fixed fy0,
  fixed fx1, fixed fw1, fixed fh, int swap_axes,
  const gx_device_color *pdevc, gs_state *pgs)
{	const fixed ymin = fixed_rounded(fy0) + fixed_half;
	const fixed ymax = fixed_rounded(fy0 + fh);
	int iy = fixed2int_var(ymin);
	const int iy1 = fixed2int_var(ymax);
	if ( iy >= iy1 ) return 0;	/* no scan lines to sample */
   {	trap_line l, r;
	int rxl, rxr, ry;
	const fixed dxl = fx1 - fx0;
	const fixed dxr = dxl + fw1 - fw0;
	const fixed yline = ymin - fy0;	/* partial pixel offset to */
					/* first line to sample */
	int fill_direct = color_is_pure(pdevc);
	gx_color_index cindex;
	gx_device *dev;
	dev_proc_fill_rectangle((*fill_rect));
	int code;
	
	if_debug2('z', "[z]y=[%d,%d]\n", iy, iy1);

	if ( fill_direct )
	  cindex = pdevc->color1,
	  dev = pgs->device->info,
	  fill_rect = dev->procs->fill_rectangle;
	gp_check_interrupts();
	r.x = (l.x = fx0 + fixed_half) + fw0;
	ry = iy;

	/* If the rounded X values are the same on both sides, */
	/* we can save ourselves a *lot* of work. */
	if ( fixed_truncated(l.x) == fixed_rounded(fx1) &&
	     fixed_truncated(r.x) == fixed_rounded(fx1 + fw1)
	   )
	{	rxl = fixed2int_var(l.x);
		rxr = fixed2int_var(r.x);
		iy = iy1;
		if_debug2('z', "[z]rectangle, x=[%d,%d]\n", rxl, rxr);
		goto last;
	}

#define fill_trap_rect(x,y,w,h)\
  (fill_direct ?\
    (swap_axes ? (*fill_rect)(dev, y, x, h, w, cindex) :\
     (*fill_rect)(dev, x, y, w, h, cindex)) :\
   swap_axes ? gz_fill_rectangle(y, x, h, w, pdevc, pgs) :\
   gz_fill_rectangle(x, y, w, h, pdevc, pgs))

	/* Compute the dx/dy ratios. */
	/* dx# = dx#i + (dx#f / fh). */
#define compute_dx(tl, d)\
  if ( d >= 0 )\
   { if ( d < fh ) tl.di = 0, tl.df = d;\
     else tl.di = (int)(d / fh), tl.df = d - tl.di * fh, tl.x += yline * tl.di;\
   }\
  else\
   { if ( (tl.df = d + fh) >= 0 /* d >= -fh */ ) tl.di = -1, tl.x -= yline;\
     else tl.di = (int)-((fh - 1 - d) / fh), tl.df = d - tl.di * fh, tl.x += yline * tl.di;\
   }

	/* Compute the x offsets at the first scan line to sample. */
	/* We need to be careful in computing yline * dx#f {/,%} fh */
	/* because the multiplication may overflow.  We know that */
	/* all the quantities involved are non-negative, and that */
	/* yline is less than 1 (as a fixed, of course); this gives us */
	/* a cheap conservative check for overflow in the multiplication. */
#define ymult_limit (max_fixed / fixed_1)
#define ymult_quo(yl, dxxf)\
  (dxxf < ymult_limit ? yl * dxxf / fh : fixed_mult_quo(yl, dxxf, fh))
#define ymult_rem(yl, dxxf)\
  (dxxf < ymult_limit ? yl * dxxf % fh : fixed_mult_rem(yl, dxxf, fh))

	/* It's worth checking for dxl == dxr, since this is the case */
	/* for parallelograms (including stroked lines). */
	compute_dx(l, dxl);
	if ( dxr == dxl )
	   {	fixed fx = ymult_quo(yline, l.df);
		l.x += fx;
		if ( l.di == 0 )
			r.di = 0, r.df = l.df;
		else			/* too hard to do adjustments right */
			compute_dx(r, dxr);
		r.x += fx;
	   }
	else
	   {	l.x += ymult_quo(yline, l.df);
		compute_dx(r, dxr);
		r.x += ymult_quo(yline, r.df);
	   }
	rxl = fixed2int_var(l.x);
	rxr = fixed2int_var(r.x);

	/* Compute one line's worth of dx/dy. */
	/* dx# * fixed_1 = ld#i + (ld#f / fh). */
	/* We don't have to bother with this if */
	/* we're only sampling a single scan line. */
	if ( iy1 - iy == 1 )
	   {	iy++;
		goto last;
	   }
#define compute_ldx(tl)\
  if ( tl.df < ymult_limit )\
    tl.ldi = int2fixed(tl.di) + int2fixed(tl.df) / fh,\
    tl.ldf = int2fixed(tl.df) % fh,\
    tl.xf = yline * tl.df % fh - fh;\
  else\
    tl.ldi = int2fixed(tl.di) + fixed_mult_quo(fixed_1, tl.df, fh),\
    tl.ldf = fixed_mult_rem(fixed_1, tl.df, fh),\
    tl.xf = fixed_mult_rem(yline, tl.df, fh) - fh
	compute_ldx(l);
	if ( dxr == dxl )
		r.ldi = l.ldi, r.ldf = l.ldf, r.xf = l.xf;
	else
	   {	compute_ldx(r);
	   }
#undef compute_ldx

	while ( ++iy != iy1 )
	   {	int ixl, ixr;
#define step_line(tl)\
  tl.x += tl.ldi;\
  if ( (tl.xf += tl.ldf) >= 0 ) tl.xf -= fh, tl.x++;
		step_line(l);
		step_line(r);
#undef step_line
		ixl = fixed2int_var(l.x);
		ixr = fixed2int_var(r.x);
		if ( ixl != rxl || ixr != rxr )
		   {	code = fill_trap_rect(rxl, ry, rxr - rxl, iy - ry);
			if ( code < 0 ) goto xit;
			rxl = ixl, rxr = ixr, ry = iy;
		   }	
	   }
last:	code = fill_trap_rect(rxl, ry, rxr - rxl, iy - ry);
xit:	gp_check_interrupts();
	if ( code < 0 && fill_direct ) return_error(code);
	return code;
   }
}
Beispiel #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 = 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;
}