/* 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) { int ix = fixed2int_var(fx0); int iy = fixed2int_var(fy0); int itox = fixed2int_var(fx1); int itoy = fixed2int_var(fy1); return_if_interrupt(dev->memory); if (itoy == iy) { /* horizontal line */ return (ix <= itox ? gx_fill_rectangle_device_rop(ix, iy, itox - ix + 1, 1, pdevc, dev, lop) : gx_fill_rectangle_device_rop(itox, iy, ix - itox + 1, 1, pdevc, dev, lop) ); } if (itox == ix) { /* vertical line */ return (iy <= itoy ? gx_fill_rectangle_device_rop(ix, iy, 1, itoy - iy + 1, pdevc, dev, lop) : gx_fill_rectangle_device_rop(ix, itoy, 1, iy - itoy + 1, pdevc, dev, lop) ); } { 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)) { if (h < 0) SWAP(fx0, fx1, tf), SWAP(fy0, fy1, tf), h = -h; right.start.x = (left.start.x = fx0 - fixed_half) + fixed_1; right.end.x = (left.end.x = fx1 - fixed_half) + fixed_1; left.start.y = right.start.y = fy0; left.end.y = right.end.y = fy1; swap_axes = false; } else { if (w < 0) SWAP(fx0, fx1, tf), SWAP(fy0, fy1, tf), w = -w; right.start.x = (left.start.x = fy0 - fixed_half) + fixed_1; right.end.x = (left.end.x = fy1 - fixed_half) + 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); } }
/* We must be very careful to follow the center-of-pixel rule in all cases. */ int gx_default_fill_parallelogram(gx_device * dev, fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by, const gx_device_color * pdevc, gs_logical_operation_t lop) { fixed t; fixed qx, qy, ym; dev_proc_fill_trapezoid((*fill_trapezoid)); gs_fixed_edge left, right; int code; /* Make a special fast check for rectangles. */ if (PARALLELOGRAM_IS_RECT(ax, ay, bx, by)) { gs_int_rect r; INT_RECT_FROM_PARALLELOGRAM(&r, px, py, ax, ay, bx, by); vd_rect(int2fixed(r.p.x), int2fixed(r.p.y), int2fixed(r.q.x), int2fixed(r.q.y), 1, (int)pdevc->colors.pure); return gx_fill_rectangle_device_rop(r.p.x, r.p.y, r.q.x - r.p.x, r.q.y - r.p.y, pdevc, dev, lop); } /* * Not a rectangle. Ensure that the 'a' line is to the left of * the 'b' line. Testing ax <= bx is neither sufficient nor * necessary: in general, we need to compare the slopes. */ /* Ensure ay >= 0, by >= 0. */ if (ay < 0) px += ax, py += ay, ax = -ax, ay = -ay; if (by < 0) px += bx, py += by, bx = -bx, by = -by; qx = px + ax + bx; if ((ax ^ bx) < 0) { /* In this case, the test ax <= bx is sufficient. */ if (ax > bx) SWAP(ax, bx, t), SWAP(ay, by, t); } else { /* * Compare the slopes. We know that ay >= 0, by >= 0, * and ax and bx have the same sign; the lines are in the * correct order iff * ay/ax >= by/bx, or * ay*bx >= by*ax * Eventually we can probably find a better way to test this, * without using floating point. */ if ((double)ay * bx < (double)by * ax) SWAP(ax, bx, t), SWAP(ay, by, t); } fill_trapezoid = dev_proc(dev, fill_trapezoid); qy = py + ay + by; left.start.x = right.start.x = px; left.start.y = right.start.y = py; left.end.x = px + ax; left.end.y = py + ay; right.end.x = px + bx; right.end.y = py + by; #define ROUNDED_SAME(p1, p2)\ (fixed_pixround(p1) == fixed_pixround(p2)) if (ay < by) { if (!ROUNDED_SAME(py, left.end.y)) { code = (*fill_trapezoid) (dev, &left, &right, py, left.end.y, false, pdevc, lop); if (code < 0) return code; } left.start = left.end; left.end.x = qx, left.end.y = qy; ym = right.end.y; if (!ROUNDED_SAME(left.start.y, ym)) { code = (*fill_trapezoid) (dev, &left, &right, left.start.y, ym, false, pdevc, lop); if (code < 0) return code; } right.start = right.end; right.end.x = qx, right.end.y = qy; } else { if (!ROUNDED_SAME(py, right.end.y)) { code = (*fill_trapezoid) (dev, &left, &right, py, right.end.y, false, pdevc, lop); if (code < 0) return code; } right.start = right.end; right.end.x = qx, right.end.y = qy; ym = left.end.y; if (!ROUNDED_SAME(right.start.y, ym)) { code = (*fill_trapezoid) (dev, &left, &right, right.start.y, ym, false, pdevc, lop); if (code < 0) return code; } left.start = left.end; left.end.x = qx, left.end.y = qy; } if (!ROUNDED_SAME(ym, qy)) return (*fill_trapezoid) (dev, &left, &right, ym, qy, false, pdevc, lop); else return 0; #undef ROUNDED_SAME }
/* 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. * If we are drawing a non-axis aligned trap, then we check * for whether a triangular extension area on the end covers an * additional pixel centre; if so, we fill an extra pixel. * If we are drawing an axis aligned trap and fill adjust is 0, * then we shouldn't need to do this. * If we are drawing an axis aligned trap, and fill adjust is non * zero, then perform the check, but with a "butt cap" rather than * a "triangle cap" region. * See bug 687721 and bug 693212 for this history of this. */ if (w == 0 && adjusty) { int deltay; deltay = int2fixed(fixed2int_var(fy1)) + fixed_half -fy1; if ((deltay > 0) && (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; } deltay = int2fixed(fixed2int_var(fy0)) + fixed_half -fy0; if ((deltay < 0) && (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; } } else if (w != 0) { int deltax, deltay; deltay = int2fixed(fixed2int_var(fy1)) + fixed_half -fy1; 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; } deltay = int2fixed(fixed2int_var(fy0)) + fixed_half -fy0; 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. */ if (h == 0 && adjustx) { int deltax; deltax = int2fixed(fixed2int_var(fx1)) + fixed_half -fx1; if ((deltax > 0) && (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; } deltax = int2fixed(fixed2int_var(fx0)) + fixed_half -fx0; if ((deltax < 0) && (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; } } else if (h != 0) { int deltax, deltay; deltax = int2fixed(fixed2int_var(fx1)) + fixed_half -fx1; 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; } deltax = int2fixed(fixed2int_var(fx0)) + fixed_half -fx0; 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); } }