forked from KolibriOS/kolibrios
385 lines
10 KiB
C
385 lines
10 KiB
C
|
/*
|
||
|
* 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
|