| /* |
| * Copyright © 2004 Keith Packard |
| * |
| * Permission to use, copy, modify, distribute, and sell this software and its |
| * documentation for any purpose is hereby granted without fee, provided that |
| * the above copyright notice appear in all copies and that both that |
| * copyright notice and this permission notice appear in supporting |
| * documentation, and that the name of Keith Packard not be used in |
| * advertising or publicity pertaining to distribution of the software without |
| * specific, written prior permission. Keith Packard makes no |
| * representations about the suitability of this software for any purpose. It |
| * is provided "as is" without express or implied warranty. |
| * |
| * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
| * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
| * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
| * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
| * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| * PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <string.h> |
| |
| #include "pixman-private.h" |
| #include "pixman-accessor.h" |
| |
| /* |
| * Step across a small sample grid gap |
| */ |
| #define RENDER_EDGE_STEP_SMALL(edge) \ |
| { \ |
| edge->x += edge->stepx_small; \ |
| edge->e += edge->dx_small; \ |
| if (edge->e > 0) \ |
| { \ |
| edge->e -= edge->dy; \ |
| edge->x += edge->signdx; \ |
| } \ |
| } |
| |
| /* |
| * Step across a large sample grid gap |
| */ |
| #define RENDER_EDGE_STEP_BIG(edge) \ |
| { \ |
| edge->x += edge->stepx_big; \ |
| edge->e += edge->dx_big; \ |
| if (edge->e > 0) \ |
| { \ |
| edge->e -= edge->dy; \ |
| edge->x += edge->signdx; \ |
| } \ |
| } |
| |
| #ifdef PIXMAN_FB_ACCESSORS |
| #define PIXMAN_RASTERIZE_EDGES pixman_rasterize_edges_accessors |
| #else |
| #define PIXMAN_RASTERIZE_EDGES pixman_rasterize_edges_no_accessors |
| #endif |
| |
| /* |
| * 4 bit alpha |
| */ |
| |
| #define N_BITS 4 |
| #define RASTERIZE_EDGES rasterize_edges_4 |
| |
| #ifndef WORDS_BIGENDIAN |
| #define SHIFT_4(o) ((o) << 2) |
| #else |
| #define SHIFT_4(o) ((1 - (o)) << 2) |
| #endif |
| |
| #define GET_4(x, o) (((x) >> SHIFT_4 (o)) & 0xf) |
| #define PUT_4(x, o, v) \ |
| (((x) & ~(0xf << SHIFT_4 (o))) | (((v) & 0xf) << SHIFT_4 (o))) |
| |
| #define DEFINE_ALPHA(line, x) \ |
| uint8_t *__ap = (uint8_t *) line + ((x) >> 1); \ |
| int __ao = (x) & 1 |
| |
| #define STEP_ALPHA ((__ap += __ao), (__ao ^= 1)) |
| |
| #define ADD_ALPHA(a) \ |
| { \ |
| uint8_t __o = READ (image, __ap); \ |
| uint8_t __a = (a) + GET_4 (__o, __ao); \ |
| WRITE (image, __ap, PUT_4 (__o, __ao, __a | (0 - ((__a) >> 4)))); \ |
| } |
| |
| #include "pixman-edge-imp.h" |
| |
| #undef ADD_ALPHA |
| #undef STEP_ALPHA |
| #undef DEFINE_ALPHA |
| #undef RASTERIZE_EDGES |
| #undef N_BITS |
| |
| |
| /* |
| * 1 bit alpha |
| */ |
| |
| #define N_BITS 1 |
| #define RASTERIZE_EDGES rasterize_edges_1 |
| |
| #include "pixman-edge-imp.h" |
| |
| #undef RASTERIZE_EDGES |
| #undef N_BITS |
| |
| /* |
| * 8 bit alpha |
| */ |
| |
| static force_inline uint8_t |
| clip255 (int x) |
| { |
| if (x > 255) |
| return 255; |
| |
| return x; |
| } |
| |
| #define ADD_SATURATE_8(buf, val, length) \ |
| do \ |
| { \ |
| int i__ = (length); \ |
| uint8_t *buf__ = (buf); \ |
| int val__ = (val); \ |
| \ |
| while (i__--) \ |
| { \ |
| WRITE (image, (buf__), clip255 (READ (image, (buf__)) + (val__))); \ |
| (buf__)++; \ |
| } \ |
| } while (0) |
| |
| /* |
| * We want to detect the case where we add the same value to a long |
| * span of pixels. The triangles on the end are filled in while we |
| * count how many sub-pixel scanlines contribute to the middle section. |
| * |
| * +--------------------------+ |
| * fill_height =| \ / |
| * +------------------+ |
| * |================| |
| * fill_start fill_end |
| */ |
| static void |
| rasterize_edges_8 (pixman_image_t *image, |
| pixman_edge_t * l, |
| pixman_edge_t * r, |
| pixman_fixed_t t, |
| pixman_fixed_t b) |
| { |
| pixman_fixed_t y = t; |
| uint32_t *line; |
| int fill_start = -1, fill_end = -1; |
| int fill_size = 0; |
| uint32_t *buf = (image)->bits.bits; |
| int stride = (image)->bits.rowstride; |
| int width = (image)->bits.width; |
| |
| line = buf + pixman_fixed_to_int (y) * stride; |
| |
| for (;;) |
| { |
| uint8_t *ap = (uint8_t *) line; |
| pixman_fixed_t lx, rx; |
| int lxi, rxi; |
| |
| /* clip X */ |
| lx = l->x; |
| if (lx < 0) |
| lx = 0; |
| |
| rx = r->x; |
| |
| if (pixman_fixed_to_int (rx) >= width) |
| { |
| /* Use the last pixel of the scanline, covered 100%. |
| * We can't use the first pixel following the scanline, |
| * because accessing it could result in a buffer overrun. |
| */ |
| rx = pixman_int_to_fixed (width) - 1; |
| } |
| |
| /* Skip empty (or backwards) sections */ |
| if (rx > lx) |
| { |
| int lxs, rxs; |
| |
| /* Find pixel bounds for span. */ |
| lxi = pixman_fixed_to_int (lx); |
| rxi = pixman_fixed_to_int (rx); |
| |
| /* Sample coverage for edge pixels */ |
| lxs = RENDER_SAMPLES_X (lx, 8); |
| rxs = RENDER_SAMPLES_X (rx, 8); |
| |
| /* Add coverage across row */ |
| if (lxi == rxi) |
| { |
| WRITE (image, ap + lxi, |
| clip255 (READ (image, ap + lxi) + rxs - lxs)); |
| } |
| else |
| { |
| WRITE (image, ap + lxi, |
| clip255 (READ (image, ap + lxi) + N_X_FRAC (8) - lxs)); |
| |
| /* Move forward so that lxi/rxi is the pixel span */ |
| lxi++; |
| |
| /* Don't bother trying to optimize the fill unless |
| * the span is longer than 4 pixels. */ |
| if (rxi - lxi > 4) |
| { |
| if (fill_start < 0) |
| { |
| fill_start = lxi; |
| fill_end = rxi; |
| fill_size++; |
| } |
| else |
| { |
| if (lxi >= fill_end || rxi < fill_start) |
| { |
| /* We're beyond what we saved, just fill it */ |
| ADD_SATURATE_8 (ap + fill_start, |
| fill_size * N_X_FRAC (8), |
| fill_end - fill_start); |
| fill_start = lxi; |
| fill_end = rxi; |
| fill_size = 1; |
| } |
| else |
| { |
| /* Update fill_start */ |
| if (lxi > fill_start) |
| { |
| ADD_SATURATE_8 (ap + fill_start, |
| fill_size * N_X_FRAC (8), |
| lxi - fill_start); |
| fill_start = lxi; |
| } |
| else if (lxi < fill_start) |
| { |
| ADD_SATURATE_8 (ap + lxi, N_X_FRAC (8), |
| fill_start - lxi); |
| } |
| |
| /* Update fill_end */ |
| if (rxi < fill_end) |
| { |
| ADD_SATURATE_8 (ap + rxi, |
| fill_size * N_X_FRAC (8), |
| fill_end - rxi); |
| fill_end = rxi; |
| } |
| else if (fill_end < rxi) |
| { |
| ADD_SATURATE_8 (ap + fill_end, |
| N_X_FRAC (8), |
| rxi - fill_end); |
| } |
| fill_size++; |
| } |
| } |
| } |
| else |
| { |
| ADD_SATURATE_8 (ap + lxi, N_X_FRAC (8), rxi - lxi); |
| } |
| |
| WRITE (image, ap + rxi, clip255 (READ (image, ap + rxi) + rxs)); |
| } |
| } |
| |
| if (y == b) |
| { |
| /* We're done, make sure we clean up any remaining fill. */ |
| if (fill_start != fill_end) |
| { |
| if (fill_size == N_Y_FRAC (8)) |
| { |
| MEMSET_WRAPPED (image, ap + fill_start, |
| 0xff, fill_end - fill_start); |
| } |
| else |
| { |
| ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8), |
| fill_end - fill_start); |
| } |
| } |
| break; |
| } |
| |
| if (pixman_fixed_frac (y) != Y_FRAC_LAST (8)) |
| { |
| RENDER_EDGE_STEP_SMALL (l); |
| RENDER_EDGE_STEP_SMALL (r); |
| y += STEP_Y_SMALL (8); |
| } |
| else |
| { |
| RENDER_EDGE_STEP_BIG (l); |
| RENDER_EDGE_STEP_BIG (r); |
| y += STEP_Y_BIG (8); |
| if (fill_start != fill_end) |
| { |
| if (fill_size == N_Y_FRAC (8)) |
| { |
| MEMSET_WRAPPED (image, ap + fill_start, |
| 0xff, fill_end - fill_start); |
| } |
| else |
| { |
| ADD_SATURATE_8 (ap + fill_start, fill_size * N_X_FRAC (8), |
| fill_end - fill_start); |
| } |
| |
| fill_start = fill_end = -1; |
| fill_size = 0; |
| } |
| |
| line += stride; |
| } |
| } |
| } |
| |
| #ifndef PIXMAN_FB_ACCESSORS |
| static |
| #endif |
| void |
| PIXMAN_RASTERIZE_EDGES (pixman_image_t *image, |
| pixman_edge_t * l, |
| pixman_edge_t * r, |
| pixman_fixed_t t, |
| pixman_fixed_t b) |
| { |
| switch (PIXMAN_FORMAT_BPP (image->bits.format)) |
| { |
| case 1: |
| rasterize_edges_1 (image, l, r, t, b); |
| break; |
| |
| case 4: |
| rasterize_edges_4 (image, l, r, t, b); |
| break; |
| |
| case 8: |
| rasterize_edges_8 (image, l, r, t, b); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| #ifndef PIXMAN_FB_ACCESSORS |
| |
| PIXMAN_EXPORT void |
| pixman_rasterize_edges (pixman_image_t *image, |
| pixman_edge_t * l, |
| pixman_edge_t * r, |
| pixman_fixed_t t, |
| pixman_fixed_t b) |
| { |
| return_if_fail (image->type == BITS); |
| |
| if (image->bits.read_func || image->bits.write_func) |
| pixman_rasterize_edges_accessors (image, l, r, t, b); |
| else |
| pixman_rasterize_edges_no_accessors (image, l, r, t, b); |
| } |
| |
| #endif |