Blame pixman/pixman-edge.c

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