int gx_forward_fill_trapezoid(gx_device * dev, const gs_fixed_edge * left, const gs_fixed_edge * right, fixed ybot, fixed ytop, bool swap_axes, const gx_drawing_color * pdcolor, gs_logical_operation_t lop) { gx_device_forward * const fdev = (gx_device_forward *)dev; gx_device *tdev = fdev->target; dev_proc_fill_trapezoid((*proc)) = (tdev == 0 ? (tdev = dev, gx_default_fill_trapezoid) : dev_proc(tdev, fill_trapezoid)); return proc(tdev, left, right, ybot, ytop, swap_axes, pdcolor, lop); }
/* We should swap axes to get best accuracy, but we don't. */ int gx_default_fill_triangle(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 ym; dev_proc_fill_trapezoid((*fill_trapezoid)) = dev_proc(dev, fill_trapezoid); gs_fixed_edge left, right; int code; /* Ensure ay >= 0, by >= 0. */ if (ay < 0) px += ax, py += ay, bx -= ax, by -= ay, ax = -ax, ay = -ay; if (by < 0) px += bx, py += by, ax -= bx, ay -= by, bx = -bx, by = -by; /* Ensure ay <= by. */ if (ay > by) SWAP(ax, bx, t), SWAP(ay, by, t); /* * Make a special check for a flat bottom or top, * which we can handle with a single call on fill_trapezoid. */ left.start.x = right.start.x = px; left.start.y = right.start.y = py; if (ay == 0) { /* Flat top */ if (ax < 0) left.start.x = px + ax; else right.start.x = px + ax; left.end.x = right.end.x = px + bx; left.end.y = right.end.y = py + by; ym = py; } else if (ay == by) { /* Flat bottom */ if (ax < bx) left.end.x = px + ax, right.end.x = px + bx; else left.end.x = px + bx, right.end.x = px + ax; left.end.y = right.end.y = py + by; ym = py; } else { ym = py + ay; if (fixed_mult_quo(bx, ay, by) < ax) { /* The 'b' line is to the left of the 'a' line. */ left.end.x = px + bx, left.end.y = py + by; right.end.x = px + ax, right.end.y = py + ay; code = (*fill_trapezoid) (dev, &left, &right, py, ym, false, pdevc, lop); right.start = right.end; right.end = left.end; } else { /* The 'a' line is to the left of the 'b' line. */ left.end.x = px + ax, left.end.y = py + ay; right.end.x = px + bx, right.end.y = py + by; code = (*fill_trapezoid) (dev, &left, &right, py, ym, false, pdevc, lop); left.start = left.end; left.end = right.end; } if (code < 0) return code; } return (*fill_trapezoid) (dev, &left, &right, ym, right.end.y, false, 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 }