Blame pixman/pixman-trap.c

Packit 030a23
/*
Packit 030a23
 * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
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 <stdio.h>
Packit 030a23
#include <stdlib.h>
Packit 030a23
#include "pixman-private.h"
Packit 030a23
Packit 030a23
/*
Packit 030a23
 * Compute the smallest value greater than or equal to y which is on a
Packit 030a23
 * grid row.
Packit 030a23
 */
Packit 030a23
Packit 030a23
PIXMAN_EXPORT pixman_fixed_t
Packit 030a23
pixman_sample_ceil_y (pixman_fixed_t y, int n)
Packit 030a23
{
Packit 030a23
    pixman_fixed_t f = pixman_fixed_frac (y);
Packit 030a23
    pixman_fixed_t i = pixman_fixed_floor (y);
Packit 030a23
Packit 030a23
    f = DIV (f - Y_FRAC_FIRST (n) + (STEP_Y_SMALL (n) - pixman_fixed_e), STEP_Y_SMALL (n)) * STEP_Y_SMALL (n) +
Packit 030a23
	Y_FRAC_FIRST (n);
Packit 030a23
    
Packit 030a23
    if (f > Y_FRAC_LAST (n))
Packit 030a23
    {
Packit 030a23
	if (pixman_fixed_to_int (i) == 0x7fff)
Packit 030a23
	{
Packit 030a23
	    f = 0xffff; /* saturate */
Packit 030a23
	}
Packit 030a23
	else
Packit 030a23
	{
Packit 030a23
	    f = Y_FRAC_FIRST (n);
Packit 030a23
	    i += pixman_fixed_1;
Packit 030a23
	}
Packit 030a23
    }
Packit 030a23
    return (i | f);
Packit 030a23
}
Packit 030a23
Packit 030a23
/*
Packit 030a23
 * Compute the largest value strictly less than y which is on a
Packit 030a23
 * grid row.
Packit 030a23
 */
Packit 030a23
PIXMAN_EXPORT pixman_fixed_t
Packit 030a23
pixman_sample_floor_y (pixman_fixed_t y,
Packit 030a23
                       int            n)
Packit 030a23
{
Packit 030a23
    pixman_fixed_t f = pixman_fixed_frac (y);
Packit 030a23
    pixman_fixed_t i = pixman_fixed_floor (y);
Packit 030a23
Packit 030a23
    f = DIV (f - pixman_fixed_e - Y_FRAC_FIRST (n), STEP_Y_SMALL (n)) * STEP_Y_SMALL (n) +
Packit 030a23
	Y_FRAC_FIRST (n);
Packit 030a23
Packit 030a23
    if (f < Y_FRAC_FIRST (n))
Packit 030a23
    {
Packit 030a23
	if (pixman_fixed_to_int (i) == 0x8000)
Packit 030a23
	{
Packit 030a23
	    f = 0; /* saturate */
Packit 030a23
	}
Packit 030a23
	else
Packit 030a23
	{
Packit 030a23
	    f = Y_FRAC_LAST (n);
Packit 030a23
	    i -= pixman_fixed_1;
Packit 030a23
	}
Packit 030a23
    }
Packit 030a23
    return (i | f);
Packit 030a23
}
Packit 030a23
Packit 030a23
/*
Packit 030a23
 * Step an edge by any amount (including negative values)
Packit 030a23
 */
Packit 030a23
PIXMAN_EXPORT void
Packit 030a23
pixman_edge_step (pixman_edge_t *e,
Packit 030a23
                  int            n)
Packit 030a23
{
Packit 030a23
    pixman_fixed_48_16_t ne;
Packit 030a23
Packit 030a23
    e->x += n * e->stepx;
Packit 030a23
Packit 030a23
    ne = e->e + n * (pixman_fixed_48_16_t) e->dx;
Packit 030a23
Packit 030a23
    if (n >= 0)
Packit 030a23
    {
Packit 030a23
	if (ne > 0)
Packit 030a23
	{
Packit 030a23
	    int nx = (ne + e->dy - 1) / e->dy;
Packit 030a23
	    e->e = ne - nx * (pixman_fixed_48_16_t) e->dy;
Packit 030a23
	    e->x += nx * e->signdx;
Packit 030a23
	}
Packit 030a23
    }
Packit 030a23
    else
Packit 030a23
    {
Packit 030a23
	if (ne <= -e->dy)
Packit 030a23
	{
Packit 030a23
	    int nx = (-ne) / e->dy;
Packit 030a23
	    e->e = ne + nx * (pixman_fixed_48_16_t) e->dy;
Packit 030a23
	    e->x -= nx * e->signdx;
Packit 030a23
	}
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
/*
Packit 030a23
 * A private routine to initialize the multi-step
Packit 030a23
 * elements of an edge structure
Packit 030a23
 */
Packit 030a23
static void
Packit 030a23
_pixman_edge_multi_init (pixman_edge_t * e,
Packit 030a23
                         int             n,
Packit 030a23
                         pixman_fixed_t *stepx_p,
Packit 030a23
                         pixman_fixed_t *dx_p)
Packit 030a23
{
Packit 030a23
    pixman_fixed_t stepx;
Packit 030a23
    pixman_fixed_48_16_t ne;
Packit 030a23
Packit 030a23
    ne = n * (pixman_fixed_48_16_t) e->dx;
Packit 030a23
    stepx = n * e->stepx;
Packit 030a23
Packit 030a23
    if (ne > 0)
Packit 030a23
    {
Packit 030a23
	int nx = ne / e->dy;
Packit 030a23
	ne -= nx * (pixman_fixed_48_16_t)e->dy;
Packit 030a23
	stepx += nx * e->signdx;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    *dx_p = ne;
Packit 030a23
    *stepx_p = stepx;
Packit 030a23
}
Packit 030a23
Packit 030a23
/*
Packit 030a23
 * Initialize one edge structure given the line endpoints and a
Packit 030a23
 * starting y value
Packit 030a23
 */
Packit 030a23
PIXMAN_EXPORT void
Packit 030a23
pixman_edge_init (pixman_edge_t *e,
Packit 030a23
                  int            n,
Packit 030a23
                  pixman_fixed_t y_start,
Packit 030a23
                  pixman_fixed_t x_top,
Packit 030a23
                  pixman_fixed_t y_top,
Packit 030a23
                  pixman_fixed_t x_bot,
Packit 030a23
                  pixman_fixed_t y_bot)
Packit 030a23
{
Packit 030a23
    pixman_fixed_t dx, dy;
Packit 030a23
Packit 030a23
    e->x = x_top;
Packit 030a23
    e->e = 0;
Packit 030a23
    dx = x_bot - x_top;
Packit 030a23
    dy = y_bot - y_top;
Packit 030a23
    e->dy = dy;
Packit 030a23
    e->dx = 0;
Packit 030a23
Packit 030a23
    if (dy)
Packit 030a23
    {
Packit 030a23
	if (dx >= 0)
Packit 030a23
	{
Packit 030a23
	    e->signdx = 1;
Packit 030a23
	    e->stepx = dx / dy;
Packit 030a23
	    e->dx = dx % dy;
Packit 030a23
	    e->e = -dy;
Packit 030a23
	}
Packit 030a23
	else
Packit 030a23
	{
Packit 030a23
	    e->signdx = -1;
Packit 030a23
	    e->stepx = -(-dx / dy);
Packit 030a23
	    e->dx = -dx % dy;
Packit 030a23
	    e->e = 0;
Packit 030a23
	}
Packit 030a23
Packit 030a23
	_pixman_edge_multi_init (e, STEP_Y_SMALL (n),
Packit 030a23
				 &e->stepx_small, &e->dx_small);
Packit 030a23
Packit 030a23
	_pixman_edge_multi_init (e, STEP_Y_BIG (n),
Packit 030a23
				 &e->stepx_big, &e->dx_big);
Packit 030a23
    }
Packit 030a23
    pixman_edge_step (e, y_start - y_top);
Packit 030a23
}
Packit 030a23
Packit 030a23
/*
Packit 030a23
 * Initialize one edge structure given a line, starting y value
Packit 030a23
 * and a pixel offset for the line
Packit 030a23
 */
Packit 030a23
PIXMAN_EXPORT void
Packit 030a23
pixman_line_fixed_edge_init (pixman_edge_t *            e,
Packit 030a23
                             int                        n,
Packit 030a23
                             pixman_fixed_t             y,
Packit 030a23
                             const pixman_line_fixed_t *line,
Packit 030a23
                             int                        x_off,
Packit 030a23
                             int                        y_off)
Packit 030a23
{
Packit 030a23
    pixman_fixed_t x_off_fixed = pixman_int_to_fixed (x_off);
Packit 030a23
    pixman_fixed_t y_off_fixed = pixman_int_to_fixed (y_off);
Packit 030a23
    const pixman_point_fixed_t *top, *bot;
Packit 030a23
Packit 030a23
    if (line->p1.y <= line->p2.y)
Packit 030a23
    {
Packit 030a23
	top = &line->p1;
Packit 030a23
	bot = &line->p2;
Packit 030a23
    }
Packit 030a23
    else
Packit 030a23
    {
Packit 030a23
	top = &line->p2;
Packit 030a23
	bot = &line->p1;
Packit 030a23
    }
Packit 030a23
    
Packit 030a23
    pixman_edge_init (e, n, y,
Packit 030a23
                      top->x + x_off_fixed,
Packit 030a23
                      top->y + y_off_fixed,
Packit 030a23
                      bot->x + x_off_fixed,
Packit 030a23
                      bot->y + y_off_fixed);
Packit 030a23
}
Packit 030a23
Packit 030a23
PIXMAN_EXPORT void
Packit 030a23
pixman_add_traps (pixman_image_t *     image,
Packit 030a23
                  int16_t              x_off,
Packit 030a23
                  int16_t              y_off,
Packit 030a23
                  int                  ntrap,
Packit 030a23
                  const pixman_trap_t *traps)
Packit 030a23
{
Packit 030a23
    int bpp;
Packit 030a23
    int height;
Packit 030a23
Packit 030a23
    pixman_fixed_t x_off_fixed;
Packit 030a23
    pixman_fixed_t y_off_fixed;
Packit 030a23
    pixman_edge_t l, r;
Packit 030a23
    pixman_fixed_t t, b;
Packit 030a23
Packit 030a23
    _pixman_image_validate (image);
Packit 030a23
    
Packit 030a23
    height = image->bits.height;
Packit 030a23
    bpp = PIXMAN_FORMAT_BPP (image->bits.format);
Packit 030a23
Packit 030a23
    x_off_fixed = pixman_int_to_fixed (x_off);
Packit 030a23
    y_off_fixed = pixman_int_to_fixed (y_off);
Packit 030a23
Packit 030a23
    while (ntrap--)
Packit 030a23
    {
Packit 030a23
	t = traps->top.y + y_off_fixed;
Packit 030a23
	if (t < 0)
Packit 030a23
	    t = 0;
Packit 030a23
	t = pixman_sample_ceil_y (t, bpp);
Packit 030a23
Packit 030a23
	b = traps->bot.y + y_off_fixed;
Packit 030a23
	if (pixman_fixed_to_int (b) >= height)
Packit 030a23
	    b = pixman_int_to_fixed (height) - 1;
Packit 030a23
	b = pixman_sample_floor_y (b, bpp);
Packit 030a23
Packit 030a23
	if (b >= t)
Packit 030a23
	{
Packit 030a23
	    /* initialize edge walkers */
Packit 030a23
	    pixman_edge_init (&l, bpp, t,
Packit 030a23
	                      traps->top.l + x_off_fixed,
Packit 030a23
	                      traps->top.y + y_off_fixed,
Packit 030a23
	                      traps->bot.l + x_off_fixed,
Packit 030a23
	                      traps->bot.y + y_off_fixed);
Packit 030a23
Packit 030a23
	    pixman_edge_init (&r, bpp, t,
Packit 030a23
	                      traps->top.r + x_off_fixed,
Packit 030a23
	                      traps->top.y + y_off_fixed,
Packit 030a23
	                      traps->bot.r + x_off_fixed,
Packit 030a23
	                      traps->bot.y + y_off_fixed);
Packit 030a23
Packit 030a23
	    pixman_rasterize_edges (image, &l, &r, t, b);
Packit 030a23
	}
Packit 030a23
Packit 030a23
	traps++;
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
#if 0
Packit 030a23
static void
Packit 030a23
dump_image (pixman_image_t *image,
Packit 030a23
            const char *    title)
Packit 030a23
{
Packit 030a23
    int i, j;
Packit 030a23
Packit 030a23
    if (!image->type == BITS)
Packit 030a23
	printf ("%s is not a regular image\n", title);
Packit 030a23
Packit 030a23
    if (!image->bits.format == PIXMAN_a8)
Packit 030a23
	printf ("%s is not an alpha mask\n", title);
Packit 030a23
Packit 030a23
    printf ("\n\n\n%s: \n", title);
Packit 030a23
Packit 030a23
    for (i = 0; i < image->bits.height; ++i)
Packit 030a23
    {
Packit 030a23
	uint8_t *line =
Packit 030a23
	    (uint8_t *)&(image->bits.bits[i * image->bits.rowstride]);
Packit 030a23
Packit 030a23
	for (j = 0; j < image->bits.width; ++j)
Packit 030a23
	    printf ("%c", line[j] ? '#' : ' ');
Packit 030a23
Packit 030a23
	printf ("\n");
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
#endif
Packit 030a23
Packit 030a23
PIXMAN_EXPORT void
Packit 030a23
pixman_add_trapezoids (pixman_image_t *          image,
Packit 030a23
                       int16_t                   x_off,
Packit 030a23
                       int                       y_off,
Packit 030a23
                       int                       ntraps,
Packit 030a23
                       const pixman_trapezoid_t *traps)
Packit 030a23
{
Packit 030a23
    int i;
Packit 030a23
Packit 030a23
#if 0
Packit 030a23
    dump_image (image, "before");
Packit 030a23
#endif
Packit 030a23
Packit 030a23
    for (i = 0; i < ntraps; ++i)
Packit 030a23
    {
Packit 030a23
	const pixman_trapezoid_t *trap = &(traps[i]);
Packit 030a23
Packit 030a23
	if (!pixman_trapezoid_valid (trap))
Packit 030a23
	    continue;
Packit 030a23
Packit 030a23
	pixman_rasterize_trapezoid (image, trap, x_off, y_off);
Packit 030a23
    }
Packit 030a23
Packit 030a23
#if 0
Packit 030a23
    dump_image (image, "after");
Packit 030a23
#endif
Packit 030a23
}
Packit 030a23
Packit 030a23
PIXMAN_EXPORT void
Packit 030a23
pixman_rasterize_trapezoid (pixman_image_t *          image,
Packit 030a23
                            const pixman_trapezoid_t *trap,
Packit 030a23
                            int                       x_off,
Packit 030a23
                            int                       y_off)
Packit 030a23
{
Packit 030a23
    int bpp;
Packit 030a23
    int height;
Packit 030a23
Packit 030a23
    pixman_fixed_t y_off_fixed;
Packit 030a23
    pixman_edge_t l, r;
Packit 030a23
    pixman_fixed_t t, b;
Packit 030a23
Packit 030a23
    return_if_fail (image->type == BITS);
Packit 030a23
Packit 030a23
    _pixman_image_validate (image);
Packit 030a23
    
Packit 030a23
    if (!pixman_trapezoid_valid (trap))
Packit 030a23
	return;
Packit 030a23
Packit 030a23
    height = image->bits.height;
Packit 030a23
    bpp = PIXMAN_FORMAT_BPP (image->bits.format);
Packit 030a23
Packit 030a23
    y_off_fixed = pixman_int_to_fixed (y_off);
Packit 030a23
Packit 030a23
    t = trap->top + y_off_fixed;
Packit 030a23
    if (t < 0)
Packit 030a23
	t = 0;
Packit 030a23
    t = pixman_sample_ceil_y (t, bpp);
Packit 030a23
Packit 030a23
    b = trap->bottom + y_off_fixed;
Packit 030a23
    if (pixman_fixed_to_int (b) >= height)
Packit 030a23
	b = pixman_int_to_fixed (height) - 1;
Packit 030a23
    b = pixman_sample_floor_y (b, bpp);
Packit 030a23
    
Packit 030a23
    if (b >= t)
Packit 030a23
    {
Packit 030a23
	/* initialize edge walkers */
Packit 030a23
	pixman_line_fixed_edge_init (&l, bpp, t, &trap->left, x_off, y_off);
Packit 030a23
	pixman_line_fixed_edge_init (&r, bpp, t, &trap->right, x_off, y_off);
Packit 030a23
Packit 030a23
	pixman_rasterize_edges (image, &l, &r, t, b);
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
static const pixman_bool_t zero_src_has_no_effect[PIXMAN_N_OPERATORS] =
Packit 030a23
{
Packit 030a23
    FALSE,	/* Clear		0			0    */
Packit 030a23
    FALSE,	/* Src			1			0    */
Packit 030a23
    TRUE,	/* Dst			0			1    */
Packit 030a23
    TRUE,	/* Over			1			1-Aa */
Packit 030a23
    TRUE,	/* OverReverse		1-Ab			1    */
Packit 030a23
    FALSE,	/* In			Ab			0    */
Packit 030a23
    FALSE,	/* InReverse		0			Aa   */
Packit 030a23
    FALSE,	/* Out			1-Ab			0    */
Packit 030a23
    TRUE,	/* OutReverse		0			1-Aa */
Packit 030a23
    TRUE,	/* Atop			Ab			1-Aa */
Packit 030a23
    FALSE,	/* AtopReverse		1-Ab			Aa   */
Packit 030a23
    TRUE,	/* Xor			1-Ab			1-Aa */
Packit 030a23
    TRUE,	/* Add			1			1    */
Packit 030a23
};
Packit 030a23
Packit 030a23
static pixman_bool_t
Packit 030a23
get_trap_extents (pixman_op_t op, pixman_image_t *dest,
Packit 030a23
		  const pixman_trapezoid_t *traps, int n_traps,
Packit 030a23
		  pixman_box32_t *box)
Packit 030a23
{
Packit 030a23
    int i;
Packit 030a23
Packit 030a23
    /* When the operator is such that a zero source has an
Packit 030a23
     * effect on the underlying image, we have to
Packit 030a23
     * composite across the entire destination
Packit 030a23
     */
Packit 030a23
    if (!zero_src_has_no_effect [op])
Packit 030a23
    {
Packit 030a23
	box->x1 = 0;
Packit 030a23
	box->y1 = 0;
Packit 030a23
	box->x2 = dest->bits.width;
Packit 030a23
	box->y2 = dest->bits.height;
Packit 030a23
	return TRUE;
Packit 030a23
    }
Packit 030a23
    
Packit 030a23
    box->x1 = INT32_MAX;
Packit 030a23
    box->y1 = INT32_MAX;
Packit 030a23
    box->x2 = INT32_MIN;
Packit 030a23
    box->y2 = INT32_MIN;
Packit 030a23
	
Packit 030a23
    for (i = 0; i < n_traps; ++i)
Packit 030a23
    {
Packit 030a23
	const pixman_trapezoid_t *trap = &(traps[i]);
Packit 030a23
	int y1, y2;
Packit 030a23
	    
Packit 030a23
	if (!pixman_trapezoid_valid (trap))
Packit 030a23
	    continue;
Packit 030a23
	    
Packit 030a23
	y1 = pixman_fixed_to_int (trap->top);
Packit 030a23
	if (y1 < box->y1)
Packit 030a23
	    box->y1 = y1;
Packit 030a23
	    
Packit 030a23
	y2 = pixman_fixed_to_int (pixman_fixed_ceil (trap->bottom));
Packit 030a23
	if (y2 > box->y2)
Packit 030a23
	    box->y2 = y2;
Packit 030a23
	    
Packit 030a23
#define EXTEND_MIN(x)							\
Packit 030a23
	if (pixman_fixed_to_int ((x)) < box->x1)			\
Packit 030a23
	    box->x1 = pixman_fixed_to_int ((x));
Packit 030a23
#define EXTEND_MAX(x)							\
Packit 030a23
	if (pixman_fixed_to_int (pixman_fixed_ceil ((x))) > box->x2)	\
Packit 030a23
	    box->x2 = pixman_fixed_to_int (pixman_fixed_ceil ((x)));
Packit 030a23
	    
Packit 030a23
#define EXTEND(x)							\
Packit 030a23
	EXTEND_MIN(x);							\
Packit 030a23
	EXTEND_MAX(x);
Packit 030a23
	    
Packit 030a23
	EXTEND(trap->left.p1.x);
Packit 030a23
	EXTEND(trap->left.p2.x);
Packit 030a23
	EXTEND(trap->right.p1.x);
Packit 030a23
	EXTEND(trap->right.p2.x);
Packit 030a23
    }
Packit 030a23
	
Packit 030a23
    if (box->x1 >= box->x2 || box->y1 >= box->y2)
Packit 030a23
	return FALSE;
Packit 030a23
Packit 030a23
    return TRUE;
Packit 030a23
}
Packit 030a23
Packit 030a23
/*
Packit 030a23
 * pixman_composite_trapezoids()
Packit 030a23
 *
Packit 030a23
 * All the trapezoids are conceptually rendered to an infinitely big image.
Packit 030a23
 * The (0, 0) coordinates of this image are then aligned with the (x, y)
Packit 030a23
 * coordinates of the source image, and then both images are aligned with
Packit 030a23
 * the (x, y) coordinates of the destination. Then these three images are
Packit 030a23
 * composited across the entire destination.
Packit 030a23
 */
Packit 030a23
PIXMAN_EXPORT void
Packit 030a23
pixman_composite_trapezoids (pixman_op_t		op,
Packit 030a23
			     pixman_image_t *		src,
Packit 030a23
			     pixman_image_t *		dst,
Packit 030a23
			     pixman_format_code_t	mask_format,
Packit 030a23
			     int			x_src,
Packit 030a23
			     int			y_src,
Packit 030a23
			     int			x_dst,
Packit 030a23
			     int			y_dst,
Packit 030a23
			     int			n_traps,
Packit 030a23
			     const pixman_trapezoid_t *	traps)
Packit 030a23
{
Packit 030a23
    int i;
Packit 030a23
Packit 030a23
    return_if_fail (PIXMAN_FORMAT_TYPE (mask_format) == PIXMAN_TYPE_A);
Packit 030a23
    
Packit 030a23
    if (n_traps <= 0)
Packit 030a23
	return;
Packit 030a23
Packit 030a23
    _pixman_image_validate (src);
Packit 030a23
    _pixman_image_validate (dst);
Packit 030a23
Packit 030a23
    if (op == PIXMAN_OP_ADD &&
Packit 030a23
	(src->common.flags & FAST_PATH_IS_OPAQUE)		&&
Packit 030a23
	(mask_format == dst->common.extended_format_code)	&&
Packit 030a23
	!(dst->common.have_clip_region))
Packit 030a23
    {
Packit 030a23
	for (i = 0; i < n_traps; ++i)
Packit 030a23
	{
Packit 030a23
	    const pixman_trapezoid_t *trap = &(traps[i]);
Packit 030a23
	    
Packit 030a23
	    if (!pixman_trapezoid_valid (trap))
Packit 030a23
		continue;
Packit 030a23
	    
Packit 030a23
	    pixman_rasterize_trapezoid (dst, trap, x_dst, y_dst);
Packit 030a23
	}
Packit 030a23
    }
Packit 030a23
    else
Packit 030a23
    {
Packit 030a23
	pixman_image_t *tmp;
Packit 030a23
	pixman_box32_t box;
Packit 030a23
	int i;
Packit 030a23
Packit 030a23
	if (!get_trap_extents (op, dst, traps, n_traps, &box))
Packit 030a23
	    return;
Packit 030a23
	
Packit 030a23
	if (!(tmp = pixman_image_create_bits (
Packit 030a23
		  mask_format, box.x2 - box.x1, box.y2 - box.y1, NULL, -1)))
Packit 030a23
	    return;
Packit 030a23
	
Packit 030a23
	for (i = 0; i < n_traps; ++i)
Packit 030a23
	{
Packit 030a23
	    const pixman_trapezoid_t *trap = &(traps[i]);
Packit 030a23
	    
Packit 030a23
	    if (!pixman_trapezoid_valid (trap))
Packit 030a23
		continue;
Packit 030a23
	    
Packit 030a23
	    pixman_rasterize_trapezoid (tmp, trap, - box.x1, - box.y1);
Packit 030a23
	}
Packit 030a23
	
Packit 030a23
	pixman_image_composite (op, src, tmp, dst,
Packit 030a23
				x_src + box.x1, y_src + box.y1,
Packit 030a23
				0, 0,
Packit 030a23
				x_dst + box.x1, y_dst + box.y1,
Packit 030a23
				box.x2 - box.x1, box.y2 - box.y1);
Packit 030a23
	
Packit 030a23
	pixman_image_unref (tmp);
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
static int
Packit 030a23
greater_y (const pixman_point_fixed_t *a, const pixman_point_fixed_t *b)
Packit 030a23
{
Packit 030a23
    if (a->y == b->y)
Packit 030a23
	return a->x > b->x;
Packit 030a23
    return a->y > b->y;
Packit 030a23
}
Packit 030a23
Packit 030a23
/*
Packit 030a23
 * Note that the definition of this function is a bit odd because
Packit 030a23
 * of the X coordinate space (y increasing downwards).
Packit 030a23
 */
Packit 030a23
static int
Packit 030a23
clockwise (const pixman_point_fixed_t *ref,
Packit 030a23
	   const pixman_point_fixed_t *a,
Packit 030a23
	   const pixman_point_fixed_t *b)
Packit 030a23
{
Packit 030a23
    pixman_point_fixed_t	ad, bd;
Packit 030a23
Packit 030a23
    ad.x = a->x - ref->x;
Packit 030a23
    ad.y = a->y - ref->y;
Packit 030a23
    bd.x = b->x - ref->x;
Packit 030a23
    bd.y = b->y - ref->y;
Packit 030a23
Packit 030a23
    return ((pixman_fixed_32_32_t) bd.y * ad.x -
Packit 030a23
	    (pixman_fixed_32_32_t) ad.y * bd.x) < 0;
Packit 030a23
}
Packit 030a23
Packit 030a23
static void
Packit 030a23
triangle_to_trapezoids (const pixman_triangle_t *tri, pixman_trapezoid_t *traps)
Packit 030a23
{
Packit 030a23
    const pixman_point_fixed_t *top, *left, *right, *tmp;
Packit 030a23
Packit 030a23
    top = &tri->p1;
Packit 030a23
    left = &tri->p2;
Packit 030a23
    right = &tri->p3;
Packit 030a23
Packit 030a23
    if (greater_y (top, left))
Packit 030a23
    {
Packit 030a23
	tmp = left;
Packit 030a23
	left = top;
Packit 030a23
	top = tmp;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    if (greater_y (top, right))
Packit 030a23
    {
Packit 030a23
	tmp = right;
Packit 030a23
	right = top;
Packit 030a23
	top = tmp;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    if (clockwise (top, right, left))
Packit 030a23
    {
Packit 030a23
	tmp = right;
Packit 030a23
	right = left;
Packit 030a23
	left = tmp;
Packit 030a23
    }
Packit 030a23
    
Packit 030a23
    /*
Packit 030a23
     * Two cases:
Packit 030a23
     *
Packit 030a23
     *		+		+
Packit 030a23
     *	       / \             / \
Packit 030a23
     *	      /   \           /	  \
Packit 030a23
     *	     /     +         +	   \
Packit 030a23
     *      /    --           --    \
Packit 030a23
     *     /   --               --   \
Packit 030a23
     *    / ---                   --- \
Packit 030a23
     *	 +--                         --+
Packit 030a23
     */
Packit 030a23
Packit 030a23
    traps->top = top->y;
Packit 030a23
    traps->left.p1 = *top;
Packit 030a23
    traps->left.p2 = *left;
Packit 030a23
    traps->right.p1 = *top;
Packit 030a23
    traps->right.p2 = *right;
Packit 030a23
Packit 030a23
    if (right->y < left->y)
Packit 030a23
	traps->bottom = right->y;
Packit 030a23
    else
Packit 030a23
	traps->bottom = left->y;
Packit 030a23
Packit 030a23
    traps++;
Packit 030a23
Packit 030a23
    *traps = *(traps - 1);
Packit 030a23
    
Packit 030a23
    if (right->y < left->y)
Packit 030a23
    {
Packit 030a23
	traps->top = right->y;
Packit 030a23
	traps->bottom = left->y;
Packit 030a23
	traps->right.p1 = *right;
Packit 030a23
	traps->right.p2 = *left;
Packit 030a23
    }
Packit 030a23
    else
Packit 030a23
    {
Packit 030a23
	traps->top = left->y;
Packit 030a23
	traps->bottom = right->y;
Packit 030a23
	traps->left.p1 = *left;
Packit 030a23
	traps->left.p2 = *right;
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
static pixman_trapezoid_t *
Packit 030a23
convert_triangles (int n_tris, const pixman_triangle_t *tris)
Packit 030a23
{
Packit 030a23
    pixman_trapezoid_t *traps;
Packit 030a23
    int i;
Packit 030a23
Packit 030a23
    if (n_tris <= 0)
Packit 030a23
	return NULL;
Packit 030a23
    
Packit 030a23
    traps = pixman_malloc_ab (n_tris, 2 * sizeof (pixman_trapezoid_t));
Packit 030a23
    if (!traps)
Packit 030a23
	return NULL;
Packit 030a23
Packit 030a23
    for (i = 0; i < n_tris; ++i)
Packit 030a23
	triangle_to_trapezoids (&(tris[i]), traps + 2 * i);
Packit 030a23
Packit 030a23
    return traps;
Packit 030a23
}
Packit 030a23
Packit 030a23
PIXMAN_EXPORT void
Packit 030a23
pixman_composite_triangles (pixman_op_t			op,
Packit 030a23
			    pixman_image_t *		src,
Packit 030a23
			    pixman_image_t *		dst,
Packit 030a23
			    pixman_format_code_t	mask_format,
Packit 030a23
			    int				x_src,
Packit 030a23
			    int				y_src,
Packit 030a23
			    int				x_dst,
Packit 030a23
			    int				y_dst,
Packit 030a23
			    int				n_tris,
Packit 030a23
			    const pixman_triangle_t *	tris)
Packit 030a23
{
Packit 030a23
    pixman_trapezoid_t *traps;
Packit 030a23
Packit 030a23
    if ((traps = convert_triangles (n_tris, tris)))
Packit 030a23
    {
Packit 030a23
	pixman_composite_trapezoids (op, src, dst, mask_format,
Packit 030a23
				     x_src, y_src, x_dst, y_dst,
Packit 030a23
				     n_tris * 2, traps);
Packit 030a23
	
Packit 030a23
	free (traps);
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
PIXMAN_EXPORT void
Packit 030a23
pixman_add_triangles (pixman_image_t          *image,
Packit 030a23
		      int32_t	               x_off,
Packit 030a23
		      int32_t	               y_off,
Packit 030a23
		      int	               n_tris,
Packit 030a23
		      const pixman_triangle_t *tris)
Packit 030a23
{
Packit 030a23
    pixman_trapezoid_t *traps;
Packit 030a23
Packit 030a23
    if ((traps = convert_triangles (n_tris, tris)))
Packit 030a23
    {
Packit 030a23
	pixman_add_trapezoids (image, x_off, y_off,
Packit 030a23
			       n_tris * 2, traps);
Packit 030a23
Packit 030a23
	free (traps);
Packit 030a23
    }
Packit 030a23
}