/* 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 }
int gx_default_fill_linear_color_scanline(gx_device *dev, const gs_fill_attributes *fa, int i0, int j, int w, const frac31 *c0, const int32_t *c0f, const int32_t *cg_num, int32_t cg_den) { /* This default implementation decomposes the area into constant color rectangles. Devices may supply optimized implementations with the inversed nesting of the i,k cicles, i.e. with enumerating planes first, with a direct writing to the raster, and with a fixed bits per component. */ frac31 c[GX_DEVICE_COLOR_MAX_COMPONENTS]; ulong f[GX_DEVICE_COLOR_MAX_COMPONENTS]; int i, i1 = i0 + w, bi = i0, k; gx_color_index ci0 = 0, ci1; const gx_device_color_info *cinfo = &dev->color_info; int n = cinfo->num_components; int si, ei, code; if (j < fixed2int(fa->clip->p.y) || j > fixed2int_ceiling(fa->clip->q.y)) /* Must be compatible to the clipping logic. */ return 0; for (k = 0; k < n; k++) { int shift = cinfo->comp_shift[k]; int bits = cinfo->comp_bits[k]; c[k] = c0[k]; f[k] = c0f[k]; ci0 |= (gx_color_index)(c[k] >> (sizeof(c[k]) * 8 - 1 - bits)) << shift; } for (i = i0 + 1; i < i1; i++) { ci1 = 0; for (k = 0; k < n; k++) { int shift = cinfo->comp_shift[k]; int bits = cinfo->comp_bits[k]; int32_t m = f[k] + cg_num[k]; c[k] += m / cg_den; m -= m / cg_den * cg_den; if (m < 0) { c[k]--; m += cg_den; } f[k] = m; ci1 |= (gx_color_index)(c[k] >> (sizeof(c[k]) * 8 - 1 - bits)) << shift; } if (ci1 != ci0) { si = max(bi, fixed2int(fa->clip->p.x)); /* Must be compatible to the clipping logic. */ ei = min(i, fixed2int_ceiling(fa->clip->q.x)); /* Must be compatible to the clipping logic. */ if (si < ei) { if (fa->swap_axes) { vd_rect(int2fixed(j), int2fixed(si), int2fixed(j + 1), int2fixed(ei), 1, (ulong)ci0); code = dev_proc(dev, fill_rectangle)(dev, j, si, 1, ei - si, ci0); } else { vd_rect(int2fixed(si), int2fixed(j), int2fixed(ei), int2fixed(j + 1), 1, (ulong)ci0); code = dev_proc(dev, fill_rectangle)(dev, si, j, ei - si, 1, ci0); } if (code < 0) return code; } bi = i; ci0 = ci1; } } si = max(bi, fixed2int(fa->clip->p.x)); /* Must be compatible to the clipping logic. */ ei = min(i, fixed2int_ceiling(fa->clip->q.x)); /* Must be compatible to the clipping logic. */ if (si < ei) { if (fa->swap_axes) { vd_rect(int2fixed(j), int2fixed(si), int2fixed(j + 1), int2fixed(ei), 1, (ulong)ci0); return dev_proc(dev, fill_rectangle)(dev, j, si, 1, ei - si, ci0); } else { vd_rect(int2fixed(si), int2fixed(j), int2fixed(ei), int2fixed(j + 1), 1, (ulong)ci0); return dev_proc(dev, fill_rectangle)(dev, si, j, ei - si, 1, ci0); } } return 0; }