Blame test/utils.c

Packit 030a23
#define _GNU_SOURCE
Packit 030a23
Packit 030a23
#include "utils.h"
Packit 030a23
#include <math.h>
Packit 030a23
#include <signal.h>
Packit 030a23
#include <stdlib.h>
Packit 030a23
#include <float.h>
Packit 030a23
#include <ctype.h>
Packit 030a23
#include <limits.h>
Packit 030a23
Packit 030a23
#ifdef HAVE_GETTIMEOFDAY
Packit 030a23
#include <sys/time.h>
Packit 030a23
#else
Packit 030a23
#include <time.h>
Packit 030a23
#endif
Packit 030a23
Packit 030a23
#ifdef HAVE_UNISTD_H
Packit 030a23
#include <unistd.h>
Packit 030a23
#endif
Packit 030a23
Packit 030a23
#ifdef HAVE_SYS_MMAN_H
Packit 030a23
#include <sys/mman.h>
Packit 030a23
#endif
Packit 030a23
Packit 030a23
#ifdef HAVE_FENV_H
Packit 030a23
#include <fenv.h>
Packit 030a23
#endif
Packit 030a23
Packit 030a23
#ifdef HAVE_LIBPNG
Packit 030a23
#include <png.h>
Packit 030a23
#endif
Packit 030a23
Packit 030a23
#define ROUND_UP(x, mult) (((x) + (mult) - 1) / (mult) * (mult))
Packit 030a23
Packit 030a23
/* Random number generator state
Packit 030a23
 */
Packit 030a23
Packit 030a23
prng_t prng_state_data;
Packit 030a23
prng_t *prng_state;
Packit 030a23
Packit 030a23
/*----------------------------------------------------------------------------*\
Packit 030a23
 *  CRC-32 version 2.0.0 by Craig Bruce, 2006-04-29.
Packit 030a23
 *
Packit 030a23
 *  This program generates the CRC-32 values for the files named in the
Packit 030a23
 *  command-line arguments.  These are the same CRC-32 values used by GZIP,
Packit 030a23
 *  PKZIP, and ZMODEM.  The Crc32_ComputeBuf () can also be detached and
Packit 030a23
 *  used independently.
Packit 030a23
 *
Packit 030a23
 *  THIS PROGRAM IS PUBLIC-DOMAIN SOFTWARE.
Packit 030a23
 *
Packit 030a23
 *  Based on the byte-oriented implementation "File Verification Using CRC"
Packit 030a23
 *  by Mark R. Nelson in Dr. Dobb's Journal, May 1992, pp. 64-67.
Packit 030a23
 *
Packit 030a23
 *  v1.0.0: original release.
Packit 030a23
 *  v1.0.1: fixed printf formats.
Packit 030a23
 *  v1.0.2: fixed something else.
Packit 030a23
 *  v1.0.3: replaced CRC constant table by generator function.
Packit 030a23
 *  v1.0.4: reformatted code, made ANSI C.  1994-12-05.
Packit 030a23
 *  v2.0.0: rewrote to use memory buffer & static table, 2006-04-29.
Packit 030a23
\*----------------------------------------------------------------------------*/
Packit 030a23
Packit 030a23
/*----------------------------------------------------------------------------*\
Packit 030a23
 *  NAME:
Packit 030a23
 *     Crc32_ComputeBuf () - computes the CRC-32 value of a memory buffer
Packit 030a23
 *  DESCRIPTION:
Packit 030a23
 *     Computes or accumulates the CRC-32 value for a memory buffer.
Packit 030a23
 *     The 'inCrc32' gives a previously accumulated CRC-32 value to allow
Packit 030a23
 *     a CRC to be generated for multiple sequential buffer-fuls of data.
Packit 030a23
 *     The 'inCrc32' for the first buffer must be zero.
Packit 030a23
 *  ARGUMENTS:
Packit 030a23
 *     inCrc32 - accumulated CRC-32 value, must be 0 on first call
Packit 030a23
 *     buf     - buffer to compute CRC-32 value for
Packit 030a23
 *     bufLen  - number of bytes in buffer
Packit 030a23
 *  RETURNS:
Packit 030a23
 *     crc32 - computed CRC-32 value
Packit 030a23
 *  ERRORS:
Packit 030a23
 *     (no errors are possible)
Packit 030a23
\*----------------------------------------------------------------------------*/
Packit 030a23
Packit 030a23
uint32_t
Packit 030a23
compute_crc32 (uint32_t    in_crc32,
Packit 030a23
	       const void *buf,
Packit 030a23
	       size_t      buf_len)
Packit 030a23
{
Packit 030a23
    static const uint32_t crc_table[256] = {
Packit 030a23
	0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
Packit 030a23
	0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
Packit 030a23
	0x09B64C2B, 0x7EB17CBD,	0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
Packit 030a23
	0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
Packit 030a23
	0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,	0x14015C4F, 0x63066CD9,
Packit 030a23
	0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
Packit 030a23
	0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
Packit 030a23
	0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
Packit 030a23
	0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
Packit 030a23
	0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
Packit 030a23
	0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
Packit 030a23
	0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
Packit 030a23
	0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
Packit 030a23
	0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
Packit 030a23
	0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
Packit 030a23
	0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
Packit 030a23
	0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
Packit 030a23
	0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
Packit 030a23
	0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
Packit 030a23
	0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
Packit 030a23
	0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
Packit 030a23
	0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
Packit 030a23
	0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
Packit 030a23
	0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
Packit 030a23
	0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
Packit 030a23
	0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
Packit 030a23
	0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
Packit 030a23
	0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
Packit 030a23
	0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
Packit 030a23
	0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
Packit 030a23
	0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
Packit 030a23
	0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
Packit 030a23
	0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
Packit 030a23
	0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
Packit 030a23
	0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
Packit 030a23
	0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
Packit 030a23
	0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
Packit 030a23
	0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
Packit 030a23
	0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
Packit 030a23
	0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
Packit 030a23
	0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
Packit 030a23
	0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
Packit 030a23
	0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
Packit 030a23
    };
Packit 030a23
Packit 030a23
    uint32_t              crc32;
Packit 030a23
    unsigned char *       byte_buf;
Packit 030a23
    size_t                i;
Packit 030a23
Packit 030a23
    /* accumulate crc32 for buffer */
Packit 030a23
    crc32 = in_crc32 ^ 0xFFFFFFFF;
Packit 030a23
    byte_buf = (unsigned char*) buf;
Packit 030a23
Packit 030a23
    for (i = 0; i < buf_len; i++)
Packit 030a23
	crc32 = (crc32 >> 8) ^ crc_table[(crc32 ^ byte_buf[i]) & 0xFF];
Packit 030a23
Packit 030a23
    return (crc32 ^ 0xFFFFFFFF);
Packit 030a23
}
Packit 030a23
Packit 030a23
static uint32_t
Packit 030a23
compute_crc32_for_image_internal (uint32_t        crc32,
Packit 030a23
				  pixman_image_t *img,
Packit 030a23
				  pixman_bool_t	  remove_alpha,
Packit 030a23
				  pixman_bool_t	  remove_rgb)
Packit 030a23
{
Packit 030a23
    pixman_format_code_t fmt = pixman_image_get_format (img);
Packit 030a23
    uint32_t *data = pixman_image_get_data (img);
Packit 030a23
    int stride = pixman_image_get_stride (img);
Packit 030a23
    int height = pixman_image_get_height (img);
Packit 030a23
    uint32_t mask = 0xffffffff;
Packit 030a23
    int i;
Packit 030a23
Packit 030a23
    if (stride < 0)
Packit 030a23
    {
Packit 030a23
	data += (stride / 4) * (height - 1);
Packit 030a23
	stride = - stride;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    /* mask unused 'x' part */
Packit 030a23
    if (PIXMAN_FORMAT_BPP (fmt) - PIXMAN_FORMAT_DEPTH (fmt) &&
Packit 030a23
	PIXMAN_FORMAT_DEPTH (fmt) != 0)
Packit 030a23
    {
Packit 030a23
	uint32_t m = (1 << PIXMAN_FORMAT_DEPTH (fmt)) - 1;
Packit 030a23
Packit 030a23
	if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_BGRA ||
Packit 030a23
	    PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_RGBA)
Packit 030a23
	{
Packit 030a23
	    m <<= (PIXMAN_FORMAT_BPP (fmt) - PIXMAN_FORMAT_DEPTH (fmt));
Packit 030a23
	}
Packit 030a23
Packit 030a23
	mask &= m;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    /* mask alpha channel */
Packit 030a23
    if (remove_alpha && PIXMAN_FORMAT_A (fmt))
Packit 030a23
    {
Packit 030a23
	uint32_t m;
Packit 030a23
Packit 030a23
	if (PIXMAN_FORMAT_BPP (fmt) == 32)
Packit 030a23
	    m = 0xffffffff;
Packit 030a23
	else
Packit 030a23
	    m = (1 << PIXMAN_FORMAT_BPP (fmt)) - 1;
Packit 030a23
Packit 030a23
	m >>= PIXMAN_FORMAT_A (fmt);
Packit 030a23
Packit 030a23
	if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_BGRA ||
Packit 030a23
	    PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_RGBA ||
Packit 030a23
	    PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_A)
Packit 030a23
	{
Packit 030a23
	    /* Alpha is at the bottom of the pixel */
Packit 030a23
	    m <<= PIXMAN_FORMAT_A (fmt);
Packit 030a23
	}
Packit 030a23
Packit 030a23
	mask &= m;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    /* mask rgb channels */
Packit 030a23
    if (remove_rgb && PIXMAN_FORMAT_RGB (fmt))
Packit 030a23
    {
Packit 030a23
	uint32_t m = ((uint32_t)~0) >> (32 - PIXMAN_FORMAT_BPP (fmt));
Packit 030a23
	uint32_t size = PIXMAN_FORMAT_R (fmt) + PIXMAN_FORMAT_G (fmt) + PIXMAN_FORMAT_B (fmt);
Packit 030a23
Packit 030a23
	m &= ~((1 << size) - 1);
Packit 030a23
Packit 030a23
	if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_BGRA ||
Packit 030a23
	    PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_RGBA)
Packit 030a23
	{
Packit 030a23
	    /* RGB channels are at the top of the pixel */
Packit 030a23
	    m >>= size;
Packit 030a23
	}
Packit 030a23
Packit 030a23
	mask &= m;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    for (i = 0; i * PIXMAN_FORMAT_BPP (fmt) < 32; i++)
Packit 030a23
	mask |= mask << (i * PIXMAN_FORMAT_BPP (fmt));
Packit 030a23
Packit 030a23
    for (i = 0; i < stride * height / 4; i++)
Packit 030a23
	data[i] &= mask;
Packit 030a23
Packit 030a23
    /* swap endiannes in order to provide identical results on both big
Packit 030a23
     * and litte endian systems
Packit 030a23
     */
Packit 030a23
    image_endian_swap (img);
Packit 030a23
Packit 030a23
    return compute_crc32 (crc32, data, stride * height);
Packit 030a23
}
Packit 030a23
Packit 030a23
uint32_t
Packit 030a23
compute_crc32_for_image (uint32_t        crc32,
Packit 030a23
			 pixman_image_t *img)
Packit 030a23
{
Packit 030a23
    if (img->common.alpha_map)
Packit 030a23
    {
Packit 030a23
	crc32 = compute_crc32_for_image_internal (crc32, img, TRUE, FALSE);
Packit 030a23
	crc32 = compute_crc32_for_image_internal (
Packit 030a23
	    crc32, (pixman_image_t *)img->common.alpha_map, FALSE, TRUE);
Packit 030a23
    }
Packit 030a23
    else
Packit 030a23
    {
Packit 030a23
	crc32 = compute_crc32_for_image_internal (crc32, img, FALSE, FALSE);
Packit 030a23
    }
Packit 030a23
Packit 030a23
    return crc32;
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
print_image (pixman_image_t *image)
Packit 030a23
{
Packit 030a23
    int i, j;
Packit 030a23
    int width, height, stride;
Packit 030a23
    pixman_format_code_t format;
Packit 030a23
    uint8_t *buffer;
Packit 030a23
    int s;
Packit 030a23
Packit 030a23
    width = pixman_image_get_width (image);
Packit 030a23
    height = pixman_image_get_height (image);
Packit 030a23
    stride = pixman_image_get_stride (image);
Packit 030a23
    format = pixman_image_get_format (image);
Packit 030a23
    buffer = (uint8_t *)pixman_image_get_data (image);
Packit 030a23
Packit 030a23
    s = (stride >= 0)? stride : - stride;
Packit 030a23
    
Packit 030a23
    printf ("---\n");
Packit 030a23
    for (i = 0; i < height; i++)
Packit 030a23
    {
Packit 030a23
	for (j = 0; j < s; j++)
Packit 030a23
	{
Packit 030a23
	    if (j == (width * PIXMAN_FORMAT_BPP (format) + 7) / 8)
Packit 030a23
		printf ("| ");
Packit 030a23
Packit 030a23
	    printf ("%02X ", *((uint8_t *)buffer + i * stride + j));
Packit 030a23
	}
Packit 030a23
	printf ("\n");
Packit 030a23
    }
Packit 030a23
    printf ("---\n");
Packit 030a23
}
Packit 030a23
Packit 030a23
/* perform endian conversion of pixel data
Packit 030a23
 */
Packit 030a23
void
Packit 030a23
image_endian_swap (pixman_image_t *img)
Packit 030a23
{
Packit 030a23
    int stride = pixman_image_get_stride (img);
Packit 030a23
    uint32_t *data = pixman_image_get_data (img);
Packit 030a23
    int height = pixman_image_get_height (img);
Packit 030a23
    int bpp = PIXMAN_FORMAT_BPP (pixman_image_get_format (img));
Packit 030a23
    int i, j;
Packit 030a23
Packit 030a23
    /* swap bytes only on big endian systems */
Packit 030a23
    if (is_little_endian())
Packit 030a23
	return;
Packit 030a23
Packit 030a23
    if (bpp == 8)
Packit 030a23
	return;
Packit 030a23
Packit 030a23
    for (i = 0; i < height; i++)
Packit 030a23
    {
Packit 030a23
	uint8_t *line_data = (uint8_t *)data + stride * i;
Packit 030a23
	int s = (stride >= 0)? stride : - stride;
Packit 030a23
    	
Packit 030a23
	switch (bpp)
Packit 030a23
	{
Packit 030a23
	case 1:
Packit 030a23
	    for (j = 0; j < s; j++)
Packit 030a23
	    {
Packit 030a23
		line_data[j] =
Packit 030a23
		    ((line_data[j] & 0x80) >> 7) |
Packit 030a23
		    ((line_data[j] & 0x40) >> 5) |
Packit 030a23
		    ((line_data[j] & 0x20) >> 3) |
Packit 030a23
		    ((line_data[j] & 0x10) >> 1) |
Packit 030a23
		    ((line_data[j] & 0x08) << 1) |
Packit 030a23
		    ((line_data[j] & 0x04) << 3) |
Packit 030a23
		    ((line_data[j] & 0x02) << 5) |
Packit 030a23
		    ((line_data[j] & 0x01) << 7);
Packit 030a23
	    }
Packit 030a23
	    break;
Packit 030a23
	case 4:
Packit 030a23
	    for (j = 0; j < s; j++)
Packit 030a23
	    {
Packit 030a23
		line_data[j] = (line_data[j] >> 4) | (line_data[j] << 4);
Packit 030a23
	    }
Packit 030a23
	    break;
Packit 030a23
	case 16:
Packit 030a23
	    for (j = 0; j + 2 <= s; j += 2)
Packit 030a23
	    {
Packit 030a23
		char t1 = line_data[j + 0];
Packit 030a23
		char t2 = line_data[j + 1];
Packit 030a23
Packit 030a23
		line_data[j + 1] = t1;
Packit 030a23
		line_data[j + 0] = t2;
Packit 030a23
	    }
Packit 030a23
	    break;
Packit 030a23
	case 24:
Packit 030a23
	    for (j = 0; j + 3 <= s; j += 3)
Packit 030a23
	    {
Packit 030a23
		char t1 = line_data[j + 0];
Packit 030a23
		char t2 = line_data[j + 1];
Packit 030a23
		char t3 = line_data[j + 2];
Packit 030a23
Packit 030a23
		line_data[j + 2] = t1;
Packit 030a23
		line_data[j + 1] = t2;
Packit 030a23
		line_data[j + 0] = t3;
Packit 030a23
	    }
Packit 030a23
	    break;
Packit 030a23
	case 32:
Packit 030a23
	    for (j = 0; j + 4 <= s; j += 4)
Packit 030a23
	    {
Packit 030a23
		char t1 = line_data[j + 0];
Packit 030a23
		char t2 = line_data[j + 1];
Packit 030a23
		char t3 = line_data[j + 2];
Packit 030a23
		char t4 = line_data[j + 3];
Packit 030a23
Packit 030a23
		line_data[j + 3] = t1;
Packit 030a23
		line_data[j + 2] = t2;
Packit 030a23
		line_data[j + 1] = t3;
Packit 030a23
		line_data[j + 0] = t4;
Packit 030a23
	    }
Packit 030a23
	    break;
Packit 030a23
	default:
Packit 030a23
	    assert (FALSE);
Packit 030a23
	    break;
Packit 030a23
	}
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
#define N_LEADING_PROTECTED	10
Packit 030a23
#define N_TRAILING_PROTECTED	10
Packit 030a23
Packit 030a23
typedef struct
Packit 030a23
{
Packit 030a23
    void *addr;
Packit 030a23
    uint32_t len;
Packit 030a23
    uint8_t *trailing;
Packit 030a23
    int n_bytes;
Packit 030a23
} info_t;
Packit 030a23
Packit 030a23
#if FENCE_MALLOC_ACTIVE
Packit 030a23
Packit 030a23
unsigned long
Packit 030a23
fence_get_page_size ()
Packit 030a23
{
Packit 030a23
    /* You can fake a page size here, if you want to test e.g. 64 kB
Packit 030a23
     * pages on a 4 kB page system. Just put a multiplier below.
Packit 030a23
     */
Packit 030a23
    return getpagesize ();
Packit 030a23
}
Packit 030a23
Packit 030a23
/* This is apparently necessary on at least OS X */
Packit 030a23
#ifndef MAP_ANONYMOUS
Packit 030a23
#define MAP_ANONYMOUS MAP_ANON
Packit 030a23
#endif
Packit 030a23
Packit 030a23
void *
Packit 030a23
fence_malloc (int64_t len)
Packit 030a23
{
Packit 030a23
    unsigned long page_size = fence_get_page_size ();
Packit 030a23
    unsigned long page_mask = page_size - 1;
Packit 030a23
    uint32_t n_payload_bytes = (len + page_mask) & ~page_mask;
Packit 030a23
    uint32_t n_bytes =
Packit 030a23
	(page_size * (N_LEADING_PROTECTED + N_TRAILING_PROTECTED + 2) +
Packit 030a23
	 n_payload_bytes) & ~page_mask;
Packit 030a23
    uint8_t *initial_page;
Packit 030a23
    uint8_t *leading_protected;
Packit 030a23
    uint8_t *trailing_protected;
Packit 030a23
    uint8_t *payload;
Packit 030a23
    uint8_t *addr;
Packit 030a23
Packit 030a23
    if (len < 0)
Packit 030a23
	abort();
Packit 030a23
    
Packit 030a23
    addr = mmap (NULL, n_bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
Packit 030a23
		 -1, 0);
Packit 030a23
Packit 030a23
    if (addr == MAP_FAILED)
Packit 030a23
    {
Packit 030a23
	printf ("mmap failed on %lld %u\n", (long long int)len, n_bytes);
Packit 030a23
	return NULL;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    initial_page = (uint8_t *)(((uintptr_t)addr + page_mask) & ~page_mask);
Packit 030a23
    leading_protected = initial_page + page_size;
Packit 030a23
    payload = leading_protected + N_LEADING_PROTECTED * page_size;
Packit 030a23
    trailing_protected = payload + n_payload_bytes;
Packit 030a23
Packit 030a23
    ((info_t *)initial_page)->addr = addr;
Packit 030a23
    ((info_t *)initial_page)->len = len;
Packit 030a23
    ((info_t *)initial_page)->trailing = trailing_protected;
Packit 030a23
    ((info_t *)initial_page)->n_bytes = n_bytes;
Packit 030a23
Packit 030a23
    if ((mprotect (leading_protected, N_LEADING_PROTECTED * page_size,
Packit 030a23
		  PROT_NONE) == -1) ||
Packit 030a23
	(mprotect (trailing_protected, N_TRAILING_PROTECTED * page_size,
Packit 030a23
		  PROT_NONE) == -1))
Packit 030a23
    {
Packit 030a23
	munmap (addr, n_bytes);
Packit 030a23
	return NULL;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    return payload;
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
fence_free (void *data)
Packit 030a23
{
Packit 030a23
    uint32_t page_size = fence_get_page_size ();
Packit 030a23
    uint8_t *payload = data;
Packit 030a23
    uint8_t *leading_protected = payload - N_LEADING_PROTECTED * page_size;
Packit 030a23
    uint8_t *initial_page = leading_protected - page_size;
Packit 030a23
    info_t *info = (info_t *)initial_page;
Packit 030a23
Packit 030a23
    munmap (info->addr, info->n_bytes);
Packit 030a23
}
Packit 030a23
Packit 030a23
static void
Packit 030a23
fence_image_destroy (pixman_image_t *image, void *data)
Packit 030a23
{
Packit 030a23
    fence_free (data);
Packit 030a23
}
Packit 030a23
Packit 030a23
/* Create an image with fence pages.
Packit 030a23
 *
Packit 030a23
 * Creates an image, where the data area is allocated with fence_malloc ().
Packit 030a23
 * Each row has an additional page in the stride.
Packit 030a23
 *
Packit 030a23
 * min_width is only a minimum width for the image. The width is aligned up
Packit 030a23
 * for the row size to be divisible by both page size and pixel size.
Packit 030a23
 *
Packit 030a23
 * If stride_fence is true, the additional page on each row will be
Packit 030a23
 * armed to cause SIGSEGV or SIGBUS on all accesses. This should catch
Packit 030a23
 * all accesses outside the valid row pixels.
Packit 030a23
 */
Packit 030a23
pixman_image_t *
Packit 030a23
fence_image_create_bits (pixman_format_code_t format,
Packit 030a23
                         int min_width,
Packit 030a23
                         int height,
Packit 030a23
                         pixman_bool_t stride_fence)
Packit 030a23
{
Packit 030a23
    unsigned page_size = fence_get_page_size ();
Packit 030a23
    unsigned page_mask = page_size - 1;
Packit 030a23
    unsigned bitspp = PIXMAN_FORMAT_BPP (format);
Packit 030a23
    unsigned bits_boundary;
Packit 030a23
    unsigned row_bits;
Packit 030a23
    int width;       /* pixels */
Packit 030a23
    unsigned stride; /* bytes */
Packit 030a23
    void *pixels;
Packit 030a23
    pixman_image_t *image;
Packit 030a23
    int i;
Packit 030a23
Packit 030a23
    /* must be power of two */
Packit 030a23
    assert (page_size && (page_size & page_mask) == 0);
Packit 030a23
Packit 030a23
    if (bitspp < 1 || min_width < 1 || height < 1)
Packit 030a23
        abort ();
Packit 030a23
Packit 030a23
    /* least common multiple between page size * 8 and bitspp */
Packit 030a23
    bits_boundary = bitspp;
Packit 030a23
    while (! (bits_boundary & 1))
Packit 030a23
        bits_boundary >>= 1;
Packit 030a23
    bits_boundary *= page_size * 8;
Packit 030a23
Packit 030a23
    /* round up to bits_boundary */
Packit 030a23
    row_bits = ROUND_UP ( (unsigned)min_width * bitspp, bits_boundary);
Packit 030a23
    width = row_bits / bitspp;
Packit 030a23
Packit 030a23
    stride = row_bits / 8;
Packit 030a23
    if (stride_fence)
Packit 030a23
        stride += page_size; /* add fence page */
Packit 030a23
Packit 030a23
    if (UINT_MAX / stride < (unsigned)height)
Packit 030a23
        abort ();
Packit 030a23
Packit 030a23
    pixels = fence_malloc (stride * (unsigned)height);
Packit 030a23
    if (!pixels)
Packit 030a23
        return NULL;
Packit 030a23
Packit 030a23
    if (stride_fence)
Packit 030a23
    {
Packit 030a23
        uint8_t *guard = (uint8_t *)pixels + stride - page_size;
Packit 030a23
Packit 030a23
        /* arm row end fence pages */
Packit 030a23
        for (i = 0; i < height; i++)
Packit 030a23
        {
Packit 030a23
            if (mprotect (guard + i * stride, page_size, PROT_NONE) == -1)
Packit 030a23
                goto out_fail;
Packit 030a23
        }
Packit 030a23
    }
Packit 030a23
Packit 030a23
    assert (width >= min_width);
Packit 030a23
Packit 030a23
    image = pixman_image_create_bits_no_clear (format, width, height,
Packit 030a23
                                               pixels, stride);
Packit 030a23
    if (!image)
Packit 030a23
        goto out_fail;
Packit 030a23
Packit 030a23
    pixman_image_set_destroy_function (image, fence_image_destroy, pixels);
Packit 030a23
Packit 030a23
    return image;
Packit 030a23
Packit 030a23
out_fail:
Packit 030a23
    fence_free (pixels);
Packit 030a23
Packit 030a23
    return NULL;
Packit 030a23
}
Packit 030a23
Packit 030a23
#else /* FENCE_MALLOC_ACTIVE */
Packit 030a23
Packit 030a23
void *
Packit 030a23
fence_malloc (int64_t len)
Packit 030a23
{
Packit 030a23
    return malloc (len);
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
fence_free (void *data)
Packit 030a23
{
Packit 030a23
    free (data);
Packit 030a23
}
Packit 030a23
Packit 030a23
pixman_image_t *
Packit 030a23
fence_image_create_bits (pixman_format_code_t format,
Packit 030a23
                         int min_width,
Packit 030a23
                         int height,
Packit 030a23
                         pixman_bool_t stride_fence)
Packit 030a23
{
Packit 030a23
    return pixman_image_create_bits (format, min_width, height, NULL, 0);
Packit 030a23
    /* Implicitly allocated storage does not need a destroy function
Packit 030a23
     * to get freed on refcount hitting zero.
Packit 030a23
     */
Packit 030a23
}
Packit 030a23
Packit 030a23
unsigned long
Packit 030a23
fence_get_page_size ()
Packit 030a23
{
Packit 030a23
    return 0;
Packit 030a23
}
Packit 030a23
Packit 030a23
#endif /* FENCE_MALLOC_ACTIVE */
Packit 030a23
Packit 030a23
uint8_t *
Packit 030a23
make_random_bytes (int n_bytes)
Packit 030a23
{
Packit 030a23
    uint8_t *bytes = fence_malloc (n_bytes);
Packit 030a23
Packit 030a23
    if (!bytes)
Packit 030a23
	return NULL;
Packit 030a23
Packit 030a23
    prng_randmemset (bytes, n_bytes, 0);
Packit 030a23
Packit 030a23
    return bytes;
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
a8r8g8b8_to_rgba_np (uint32_t *dst, uint32_t *src, int n_pixels)
Packit 030a23
{
Packit 030a23
    uint8_t *dst8 = (uint8_t *)dst;
Packit 030a23
    int i;
Packit 030a23
Packit 030a23
    for (i = 0; i < n_pixels; ++i)
Packit 030a23
    {
Packit 030a23
	uint32_t p = src[i];
Packit 030a23
	uint8_t a, r, g, b;
Packit 030a23
Packit 030a23
	a = (p & 0xff000000) >> 24;
Packit 030a23
	r = (p & 0x00ff0000) >> 16;
Packit 030a23
	g = (p & 0x0000ff00) >> 8;
Packit 030a23
	b = (p & 0x000000ff) >> 0;
Packit 030a23
Packit 030a23
	if (a != 0)
Packit 030a23
	{
Packit 030a23
#define DIVIDE(c, a)							\
Packit 030a23
	    do								\
Packit 030a23
	    {								\
Packit 030a23
		int t = ((c) * 255) / a;				\
Packit 030a23
		(c) = t < 0? 0 : t > 255? 255 : t;			\
Packit 030a23
	    } while (0)
Packit 030a23
Packit 030a23
	    DIVIDE (r, a);
Packit 030a23
	    DIVIDE (g, a);
Packit 030a23
	    DIVIDE (b, a);
Packit 030a23
	}
Packit 030a23
Packit 030a23
	*dst8++ = r;
Packit 030a23
	*dst8++ = g;
Packit 030a23
	*dst8++ = b;
Packit 030a23
	*dst8++ = a;
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
#ifdef HAVE_LIBPNG
Packit 030a23
Packit 030a23
pixman_bool_t
Packit 030a23
write_png (pixman_image_t *image, const char *filename)
Packit 030a23
{
Packit 030a23
    int width = pixman_image_get_width (image);
Packit 030a23
    int height = pixman_image_get_height (image);
Packit 030a23
    int stride = width * 4;
Packit 030a23
    uint32_t *data = malloc (height * stride);
Packit 030a23
    pixman_image_t *copy;
Packit 030a23
    png_struct *write_struct;
Packit 030a23
    png_info *info_struct;
Packit 030a23
    pixman_bool_t result = FALSE;
Packit 030a23
    FILE *f = fopen (filename, "wb");
Packit 030a23
    png_bytep *row_pointers;
Packit 030a23
    int i;
Packit 030a23
Packit 030a23
    if (!f)
Packit 030a23
	return FALSE;
Packit 030a23
Packit 030a23
    row_pointers = malloc (height * sizeof (png_bytep));
Packit 030a23
Packit 030a23
    copy = pixman_image_create_bits (
Packit 030a23
	PIXMAN_a8r8g8b8, width, height, data, stride);
Packit 030a23
Packit 030a23
    pixman_image_composite32 (
Packit 030a23
	PIXMAN_OP_SRC, image, NULL, copy, 0, 0, 0, 0, 0, 0, width, height);
Packit 030a23
Packit 030a23
    a8r8g8b8_to_rgba_np (data, data, height * width);
Packit 030a23
Packit 030a23
    for (i = 0; i < height; ++i)
Packit 030a23
	row_pointers[i] = (png_bytep)(data + i * width);
Packit 030a23
Packit 030a23
    if (!(write_struct = png_create_write_struct (
Packit 030a23
	      PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)))
Packit 030a23
	goto out1;
Packit 030a23
Packit 030a23
    if (!(info_struct = png_create_info_struct (write_struct)))
Packit 030a23
	goto out2;
Packit 030a23
Packit 030a23
    png_init_io (write_struct, f);
Packit 030a23
Packit 030a23
    png_set_IHDR (write_struct, info_struct, width, height,
Packit 030a23
		  8, PNG_COLOR_TYPE_RGB_ALPHA,
Packit 030a23
		  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
Packit 030a23
		  PNG_FILTER_TYPE_BASE);
Packit 030a23
Packit 030a23
    png_write_info (write_struct, info_struct);
Packit 030a23
Packit 030a23
    png_write_image (write_struct, row_pointers);
Packit 030a23
Packit 030a23
    png_write_end (write_struct, NULL);
Packit 030a23
Packit 030a23
    result = TRUE;
Packit 030a23
Packit 030a23
out2:
Packit 030a23
    png_destroy_write_struct (&write_struct, &info_struct);
Packit 030a23
Packit 030a23
out1:
Packit 030a23
    if (fclose (f) != 0)
Packit 030a23
	result = FALSE;
Packit 030a23
Packit 030a23
    pixman_image_unref (copy);
Packit 030a23
    free (row_pointers);
Packit 030a23
    free (data);
Packit 030a23
    return result;
Packit 030a23
}
Packit 030a23
Packit 030a23
#else /* no libpng */
Packit 030a23
Packit 030a23
pixman_bool_t
Packit 030a23
write_png (pixman_image_t *image, const char *filename)
Packit 030a23
{
Packit 030a23
    return FALSE;
Packit 030a23
}
Packit 030a23
Packit 030a23
#endif
Packit 030a23
Packit 030a23
static void
Packit 030a23
color8_to_color16 (uint32_t color8, pixman_color_t *color16)
Packit 030a23
{
Packit 030a23
    color16->alpha = ((color8 & 0xff000000) >> 24);
Packit 030a23
    color16->red =   ((color8 & 0x00ff0000) >> 16);
Packit 030a23
    color16->green = ((color8 & 0x0000ff00) >> 8);
Packit 030a23
    color16->blue =  ((color8 & 0x000000ff) >> 0);
Packit 030a23
Packit 030a23
    color16->alpha |= color16->alpha << 8;
Packit 030a23
    color16->red   |= color16->red << 8;
Packit 030a23
    color16->blue  |= color16->blue << 8;
Packit 030a23
    color16->green |= color16->green << 8;
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
draw_checkerboard (pixman_image_t *image,
Packit 030a23
		   int check_size,
Packit 030a23
		   uint32_t color1, uint32_t color2)
Packit 030a23
{
Packit 030a23
    pixman_color_t check1, check2;
Packit 030a23
    pixman_image_t *c1, *c2;
Packit 030a23
    int n_checks_x, n_checks_y;
Packit 030a23
    int i, j;
Packit 030a23
Packit 030a23
    color8_to_color16 (color1, &check1;;
Packit 030a23
    color8_to_color16 (color2, &check2;;
Packit 030a23
    
Packit 030a23
    c1 = pixman_image_create_solid_fill (&check1;;
Packit 030a23
    c2 = pixman_image_create_solid_fill (&check2;;
Packit 030a23
Packit 030a23
    n_checks_x = (
Packit 030a23
	pixman_image_get_width (image) + check_size - 1) / check_size;
Packit 030a23
    n_checks_y = (
Packit 030a23
	pixman_image_get_height (image) + check_size - 1) / check_size;
Packit 030a23
Packit 030a23
    for (j = 0; j < n_checks_y; j++)
Packit 030a23
    {
Packit 030a23
	for (i = 0; i < n_checks_x; i++)
Packit 030a23
	{
Packit 030a23
	    pixman_image_t *src;
Packit 030a23
Packit 030a23
	    if (((i ^ j) & 1))
Packit 030a23
		src = c1;
Packit 030a23
	    else
Packit 030a23
		src = c2;
Packit 030a23
Packit 030a23
	    pixman_image_composite32 (PIXMAN_OP_SRC, src, NULL, image,
Packit 030a23
				      0, 0, 0, 0,
Packit 030a23
				      i * check_size, j * check_size,
Packit 030a23
				      check_size, check_size);
Packit 030a23
	}
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
static uint32_t
Packit 030a23
call_test_function (uint32_t    (*test_function)(int testnum, int verbose),
Packit 030a23
		    int		testnum,
Packit 030a23
		    int		verbose)
Packit 030a23
{
Packit 030a23
    uint32_t retval;
Packit 030a23
Packit 030a23
#if defined (__GNUC__) && defined (_WIN32) && (defined (__i386) || defined (__i386__))
Packit 030a23
    __asm__ (
Packit 030a23
	/* Deliberately avoid aligning the stack to 16 bytes */
Packit 030a23
	"pushl	%1\n\t"
Packit 030a23
	"pushl	%2\n\t"
Packit 030a23
	"call	*%3\n\t"
Packit 030a23
	"addl	$8, %%esp\n\t"
Packit 030a23
	: "=a" (retval)
Packit 030a23
	: "r" (verbose),
Packit 030a23
	  "r" (testnum),
Packit 030a23
	  "r" (test_function)
Packit 030a23
	: "edx", "ecx"); /* caller save registers */
Packit 030a23
#else
Packit 030a23
    retval = test_function (testnum, verbose);
Packit 030a23
#endif
Packit 030a23
Packit 030a23
    return retval;
Packit 030a23
}
Packit 030a23
Packit 030a23
/*
Packit 030a23
 * A function, which can be used as a core part of the test programs,
Packit 030a23
 * intended to detect various problems with the help of fuzzing input
Packit 030a23
 * to pixman API (according to some templates, aka "smart" fuzzing).
Packit 030a23
 * Some general information about such testing can be found here:
Packit 030a23
 * http://en.wikipedia.org/wiki/Fuzz_testing
Packit 030a23
 *
Packit 030a23
 * It may help detecting:
Packit 030a23
 *  - crashes on bad handling of valid or reasonably invalid input to
Packit 030a23
 *    pixman API.
Packit 030a23
 *  - deviations from the behavior of older pixman releases.
Packit 030a23
 *  - deviations from the behavior of the same pixman release, but
Packit 030a23
 *    configured in a different way (for example with SIMD optimizations
Packit 030a23
 *    disabled), or running on a different OS or hardware.
Packit 030a23
 *
Packit 030a23
 * The test is performed by calling a callback function a huge number
Packit 030a23
 * of times. The callback function is expected to run some snippet of
Packit 030a23
 * pixman code with pseudorandom variations to the data feeded to
Packit 030a23
 * pixman API. A result of running each callback function should be
Packit 030a23
 * some deterministic value which depends on test number (test number
Packit 030a23
 * can be used as a seed for PRNG). When 'verbose' argument is nonzero,
Packit 030a23
 * callback function is expected to print to stdout some information
Packit 030a23
 * about what it does.
Packit 030a23
 *
Packit 030a23
 * Return values from many small tests are accumulated together and
Packit 030a23
 * used as final checksum, which can be compared to some expected
Packit 030a23
 * value. Running the tests not individually, but in a batch helps
Packit 030a23
 * to reduce process start overhead and also allows to parallelize
Packit 030a23
 * testing and utilize multiple CPU cores.
Packit 030a23
 *
Packit 030a23
 * The resulting executable can be run without any arguments. In
Packit 030a23
 * this case it runs a batch of tests starting from 1 and up to
Packit 030a23
 * 'default_number_of_iterations'. The resulting checksum is
Packit 030a23
 * compared with 'expected_checksum' and FAIL or PASS verdict
Packit 030a23
 * depends on the result of this comparison.
Packit 030a23
 *
Packit 030a23
 * If the executable is run with 2 numbers provided as command line
Packit 030a23
 * arguments, they specify the starting and ending numbers for a test
Packit 030a23
 * batch.
Packit 030a23
 *
Packit 030a23
 * If the executable is run with only one number provided as a command
Packit 030a23
 * line argument, then this number is used to call the callback function
Packit 030a23
 * once, and also with verbose flag set.
Packit 030a23
 */
Packit 030a23
int
Packit 030a23
fuzzer_test_main (const char *test_name,
Packit 030a23
		  int         default_number_of_iterations,
Packit 030a23
		  uint32_t    expected_checksum,
Packit 030a23
		  uint32_t    (*test_function)(int testnum, int verbose),
Packit 030a23
		  int         argc,
Packit 030a23
		  const char *argv[])
Packit 030a23
{
Packit 030a23
    int i, n1 = 1, n2 = 0;
Packit 030a23
    uint32_t checksum = 0;
Packit 030a23
    int verbose = getenv ("VERBOSE") != NULL;
Packit 030a23
Packit 030a23
    if (argc >= 3)
Packit 030a23
    {
Packit 030a23
	n1 = atoi (argv[1]);
Packit 030a23
	n2 = atoi (argv[2]);
Packit 030a23
	if (n2 < n1)
Packit 030a23
	{
Packit 030a23
	    printf ("invalid test range\n");
Packit 030a23
	    return 1;
Packit 030a23
	}
Packit 030a23
    }
Packit 030a23
    else if (argc >= 2)
Packit 030a23
    {
Packit 030a23
	n2 = atoi (argv[1]);
Packit 030a23
Packit 030a23
	checksum = call_test_function (test_function, n2, 1);
Packit 030a23
Packit 030a23
	printf ("%d: checksum=%08X\n", n2, checksum);
Packit 030a23
	return 0;
Packit 030a23
    }
Packit 030a23
    else
Packit 030a23
    {
Packit 030a23
	n1 = 1;
Packit 030a23
	n2 = default_number_of_iterations;
Packit 030a23
    }
Packit 030a23
Packit 030a23
#ifdef USE_OPENMP
Packit 030a23
    #pragma omp parallel for reduction(+:checksum) default(none) \
Packit 030a23
					shared(n1, n2, test_function, verbose)
Packit 030a23
#endif
Packit 030a23
    for (i = n1; i <= n2; i++)
Packit 030a23
    {
Packit 030a23
	uint32_t crc = call_test_function (test_function, i, 0);
Packit 030a23
	if (verbose)
Packit 030a23
	    printf ("%d: %08X\n", i, crc);
Packit 030a23
	checksum += crc;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    if (n1 == 1 && n2 == default_number_of_iterations)
Packit 030a23
    {
Packit 030a23
	if (checksum == expected_checksum)
Packit 030a23
	{
Packit 030a23
	    printf ("%s test passed (checksum=%08X)\n",
Packit 030a23
		    test_name, checksum);
Packit 030a23
	}
Packit 030a23
	else
Packit 030a23
	{
Packit 030a23
	    printf ("%s test failed! (checksum=%08X, expected %08X)\n",
Packit 030a23
		    test_name, checksum, expected_checksum);
Packit 030a23
	    return 1;
Packit 030a23
	}
Packit 030a23
    }
Packit 030a23
    else
Packit 030a23
    {
Packit 030a23
	printf ("%d-%d: checksum=%08X\n", n1, n2, checksum);
Packit 030a23
    }
Packit 030a23
Packit 030a23
    return 0;
Packit 030a23
}
Packit 030a23
Packit 030a23
/* Try to obtain current time in seconds */
Packit 030a23
double
Packit 030a23
gettime (void)
Packit 030a23
{
Packit 030a23
#ifdef HAVE_GETTIMEOFDAY
Packit 030a23
    struct timeval tv;
Packit 030a23
Packit 030a23
    gettimeofday (&tv, NULL);
Packit 030a23
    return (double)((int64_t)tv.tv_sec * 1000000 + tv.tv_usec) / 1000000.;
Packit 030a23
#else
Packit 030a23
    return (double)clock() / (double)CLOCKS_PER_SEC;
Packit 030a23
#endif
Packit 030a23
}
Packit 030a23
Packit 030a23
uint32_t
Packit 030a23
get_random_seed (void)
Packit 030a23
{
Packit 030a23
    union { double d; uint32_t u32; } t;
Packit 030a23
    t.d = gettime();
Packit 030a23
    prng_srand (t.u32);
Packit 030a23
Packit 030a23
    return prng_rand ();
Packit 030a23
}
Packit 030a23
Packit 030a23
#ifdef HAVE_SIGACTION
Packit 030a23
#ifdef HAVE_ALARM
Packit 030a23
static const char *global_msg;
Packit 030a23
Packit 030a23
static void
Packit 030a23
on_alarm (int signo)
Packit 030a23
{
Packit 030a23
    printf ("%s\n", global_msg);
Packit 030a23
    exit (1);
Packit 030a23
}
Packit 030a23
#endif
Packit 030a23
#endif
Packit 030a23
Packit 030a23
void
Packit 030a23
fail_after (int seconds, const char *msg)
Packit 030a23
{
Packit 030a23
#ifdef HAVE_SIGACTION
Packit 030a23
#ifdef HAVE_ALARM
Packit 030a23
    struct sigaction action;
Packit 030a23
Packit 030a23
    global_msg = msg;
Packit 030a23
Packit 030a23
    memset (&action, 0, sizeof (action));
Packit 030a23
    action.sa_handler = on_alarm;
Packit 030a23
Packit 030a23
    alarm (seconds);
Packit 030a23
Packit 030a23
    sigaction (SIGALRM, &action, NULL);
Packit 030a23
#endif
Packit 030a23
#endif
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
enable_divbyzero_exceptions (void)
Packit 030a23
{
Packit 030a23
#ifdef HAVE_FENV_H
Packit 030a23
#ifdef HAVE_FEENABLEEXCEPT
Packit 030a23
#ifdef HAVE_FEDIVBYZERO
Packit 030a23
    feenableexcept (FE_DIVBYZERO);
Packit 030a23
#endif
Packit 030a23
#endif
Packit 030a23
#endif
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
enable_invalid_exceptions (void)
Packit 030a23
{
Packit 030a23
#ifdef HAVE_FENV_H
Packit 030a23
#ifdef HAVE_FEENABLEEXCEPT
Packit 030a23
    feenableexcept (FE_INVALID);
Packit 030a23
#endif
Packit 030a23
#endif
Packit 030a23
}
Packit 030a23
Packit 030a23
void *
Packit 030a23
aligned_malloc (size_t align, size_t size)
Packit 030a23
{
Packit 030a23
    void *result;
Packit 030a23
Packit 030a23
#ifdef HAVE_POSIX_MEMALIGN
Packit 030a23
    if (posix_memalign (&result, align, size) != 0)
Packit 030a23
      result = NULL;
Packit 030a23
#else
Packit 030a23
    result = malloc (size);
Packit 030a23
#endif
Packit 030a23
Packit 030a23
    return result;
Packit 030a23
}
Packit 030a23
Packit 030a23
#define CONVERT_15(c, is_rgb)						\
Packit 030a23
    (is_rgb?								\
Packit 030a23
     ((((c) >> 3) & 0x001f) |						\
Packit 030a23
      (((c) >> 6) & 0x03e0) |						\
Packit 030a23
      (((c) >> 9) & 0x7c00)) :						\
Packit 030a23
     (((((c) >> 16) & 0xff) * 153 +					\
Packit 030a23
       (((c) >>  8) & 0xff) * 301 +					\
Packit 030a23
       (((c)      ) & 0xff) * 58) >> 2))
Packit 030a23
Packit 030a23
double
Packit 030a23
convert_srgb_to_linear (double c)
Packit 030a23
{
Packit 030a23
    if (c <= 0.04045)
Packit 030a23
        return c / 12.92;
Packit 030a23
    else
Packit 030a23
        return pow ((c + 0.055) / 1.055, 2.4);
Packit 030a23
}
Packit 030a23
Packit 030a23
double
Packit 030a23
convert_linear_to_srgb (double c)
Packit 030a23
{
Packit 030a23
    if (c <= 0.0031308)
Packit 030a23
        return c * 12.92;
Packit 030a23
    else
Packit 030a23
        return 1.055 * pow (c, 1.0/2.4) - 0.055;
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
initialize_palette (pixman_indexed_t *palette, uint32_t depth, int is_rgb)
Packit 030a23
{
Packit 030a23
    int i;
Packit 030a23
    uint32_t mask = (1 << depth) - 1;
Packit 030a23
Packit 030a23
    for (i = 0; i < 32768; ++i)
Packit 030a23
	palette->ent[i] = prng_rand() & mask;
Packit 030a23
Packit 030a23
    memset (palette->rgba, 0, sizeof (palette->rgba));
Packit 030a23
Packit 030a23
    for (i = 0; i < mask + 1; ++i)
Packit 030a23
    {
Packit 030a23
	uint32_t rgba24;
Packit 030a23
 	pixman_bool_t retry;
Packit 030a23
	uint32_t i15;
Packit 030a23
Packit 030a23
	/* We filled the rgb->index map with random numbers, but we
Packit 030a23
	 * do need the ability to round trip, that is if some indexed
Packit 030a23
	 * color expands to an argb24, then the 15 bit version of that
Packit 030a23
	 * color must map back to the index. Anything else, we don't
Packit 030a23
	 * care about too much.
Packit 030a23
	 */
Packit 030a23
	do
Packit 030a23
	{
Packit 030a23
	    uint32_t old_idx;
Packit 030a23
Packit 030a23
	    rgba24 = prng_rand();
Packit 030a23
	    i15 = CONVERT_15 (rgba24, is_rgb);
Packit 030a23
Packit 030a23
	    old_idx = palette->ent[i15];
Packit 030a23
	    if (CONVERT_15 (palette->rgba[old_idx], is_rgb) == i15)
Packit 030a23
		retry = 1;
Packit 030a23
	    else
Packit 030a23
		retry = 0;
Packit 030a23
	} while (retry);
Packit 030a23
Packit 030a23
	palette->rgba[i] = rgba24;
Packit 030a23
	palette->ent[i15] = i;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    for (i = 0; i < mask + 1; ++i)
Packit 030a23
    {
Packit 030a23
	assert (palette->ent[CONVERT_15 (palette->rgba[i], is_rgb)] == i);
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
struct operator_entry {
Packit 030a23
    pixman_op_t		 op;
Packit 030a23
    const char		*name;
Packit 030a23
    pixman_bool_t	 is_alias;
Packit 030a23
};
Packit 030a23
Packit 030a23
typedef struct operator_entry operator_entry_t;
Packit 030a23
Packit 030a23
static const operator_entry_t op_list[] =
Packit 030a23
{
Packit 030a23
#define ENTRY(op)							\
Packit 030a23
    { PIXMAN_OP_##op, "PIXMAN_OP_" #op, FALSE }
Packit 030a23
#define ALIAS(op, nam)							\
Packit 030a23
    { PIXMAN_OP_##op, nam, TRUE }
Packit 030a23
Packit 030a23
    /* operator_name () will return the first hit in this table,
Packit 030a23
     * so keep the list properly ordered between entries and aliases.
Packit 030a23
     * Aliases are not listed by list_operators ().
Packit 030a23
     */
Packit 030a23
Packit 030a23
    ENTRY (CLEAR),
Packit 030a23
    ENTRY (SRC),
Packit 030a23
    ENTRY (DST),
Packit 030a23
    ENTRY (OVER),
Packit 030a23
    ENTRY (OVER_REVERSE),
Packit 030a23
    ALIAS (OVER_REVERSE,		"overrev"),
Packit 030a23
    ENTRY (IN),
Packit 030a23
    ENTRY (IN_REVERSE),
Packit 030a23
    ALIAS (IN_REVERSE,			"inrev"),
Packit 030a23
    ENTRY (OUT),
Packit 030a23
    ENTRY (OUT_REVERSE),
Packit 030a23
    ALIAS (OUT_REVERSE,			"outrev"),
Packit 030a23
    ENTRY (ATOP),
Packit 030a23
    ENTRY (ATOP_REVERSE),
Packit 030a23
    ALIAS (ATOP_REVERSE,		"atoprev"),
Packit 030a23
    ENTRY (XOR),
Packit 030a23
    ENTRY (ADD),
Packit 030a23
    ENTRY (SATURATE),
Packit 030a23
Packit 030a23
    ENTRY (DISJOINT_CLEAR),
Packit 030a23
    ENTRY (DISJOINT_SRC),
Packit 030a23
    ENTRY (DISJOINT_DST),
Packit 030a23
    ENTRY (DISJOINT_OVER),
Packit 030a23
    ENTRY (DISJOINT_OVER_REVERSE),
Packit 030a23
    ENTRY (DISJOINT_IN),
Packit 030a23
    ENTRY (DISJOINT_IN_REVERSE),
Packit 030a23
    ENTRY (DISJOINT_OUT),
Packit 030a23
    ENTRY (DISJOINT_OUT_REVERSE),
Packit 030a23
    ENTRY (DISJOINT_ATOP),
Packit 030a23
    ENTRY (DISJOINT_ATOP_REVERSE),
Packit 030a23
    ENTRY (DISJOINT_XOR),
Packit 030a23
Packit 030a23
    ENTRY (CONJOINT_CLEAR),
Packit 030a23
    ENTRY (CONJOINT_SRC),
Packit 030a23
    ENTRY (CONJOINT_DST),
Packit 030a23
    ENTRY (CONJOINT_OVER),
Packit 030a23
    ENTRY (CONJOINT_OVER_REVERSE),
Packit 030a23
    ENTRY (CONJOINT_IN),
Packit 030a23
    ENTRY (CONJOINT_IN_REVERSE),
Packit 030a23
    ENTRY (CONJOINT_OUT),
Packit 030a23
    ENTRY (CONJOINT_OUT_REVERSE),
Packit 030a23
    ENTRY (CONJOINT_ATOP),
Packit 030a23
    ENTRY (CONJOINT_ATOP_REVERSE),
Packit 030a23
    ENTRY (CONJOINT_XOR),
Packit 030a23
Packit 030a23
    ENTRY (MULTIPLY),
Packit 030a23
    ENTRY (SCREEN),
Packit 030a23
    ENTRY (OVERLAY),
Packit 030a23
    ENTRY (DARKEN),
Packit 030a23
    ENTRY (LIGHTEN),
Packit 030a23
    ENTRY (COLOR_DODGE),
Packit 030a23
    ENTRY (COLOR_BURN),
Packit 030a23
    ENTRY (HARD_LIGHT),
Packit 030a23
    ENTRY (SOFT_LIGHT),
Packit 030a23
    ENTRY (DIFFERENCE),
Packit 030a23
    ENTRY (EXCLUSION),
Packit 030a23
    ENTRY (HSL_HUE),
Packit 030a23
    ENTRY (HSL_SATURATION),
Packit 030a23
    ENTRY (HSL_COLOR),
Packit 030a23
    ENTRY (HSL_LUMINOSITY),
Packit 030a23
Packit 030a23
    ALIAS (NONE, "<invalid operator 'none'>")
Packit 030a23
Packit 030a23
#undef ENTRY
Packit 030a23
#undef ALIAS
Packit 030a23
};
Packit 030a23
Packit 030a23
struct format_entry
Packit 030a23
{
Packit 030a23
    pixman_format_code_t format;
Packit 030a23
    const char		*name;
Packit 030a23
    pixman_bool_t	 is_alias;
Packit 030a23
};
Packit 030a23
Packit 030a23
typedef struct format_entry format_entry_t;
Packit 030a23
Packit 030a23
static const format_entry_t format_list[] =
Packit 030a23
{
Packit 030a23
#define ENTRY(f)							\
Packit 030a23
    { PIXMAN_##f, #f, FALSE }
Packit 030a23
#define ALIAS(f, nam)							\
Packit 030a23
    { PIXMAN_##f, nam, TRUE }
Packit 030a23
Packit 030a23
    /* format_name () will return the first hit in this table,
Packit 030a23
     * so keep the list properly ordered between entries and aliases.
Packit 030a23
     * Aliases are not listed by list_formats ().
Packit 030a23
     */
Packit 030a23
Packit 030a23
/* 32bpp formats */
Packit 030a23
    ENTRY (a8r8g8b8),
Packit 030a23
    ALIAS (a8r8g8b8,		"8888"),
Packit 030a23
    ENTRY (x8r8g8b8),
Packit 030a23
    ALIAS (x8r8g8b8,		"x888"),
Packit 030a23
    ENTRY (a8b8g8r8),
Packit 030a23
    ENTRY (x8b8g8r8),
Packit 030a23
    ENTRY (b8g8r8a8),
Packit 030a23
    ENTRY (b8g8r8x8),
Packit 030a23
    ENTRY (r8g8b8a8),
Packit 030a23
    ENTRY (r8g8b8x8),
Packit 030a23
    ENTRY (x14r6g6b6),
Packit 030a23
    ENTRY (x2r10g10b10),
Packit 030a23
    ALIAS (x2r10g10b10,		"2x10"),
Packit 030a23
    ENTRY (a2r10g10b10),
Packit 030a23
    ALIAS (a2r10g10b10,		"2a10"),
Packit 030a23
    ENTRY (x2b10g10r10),
Packit 030a23
    ENTRY (a2b10g10r10),
Packit 030a23
Packit 030a23
/* sRGB formats */
Packit 030a23
    ENTRY (a8r8g8b8_sRGB),
Packit 030a23
Packit 030a23
/* 24bpp formats */
Packit 030a23
    ENTRY (r8g8b8),
Packit 030a23
    ALIAS (r8g8b8,		"0888"),
Packit 030a23
    ENTRY (b8g8r8),
Packit 030a23
Packit 030a23
/* 16 bpp formats */
Packit 030a23
    ENTRY (r5g6b5),
Packit 030a23
    ALIAS (r5g6b5,		"0565"),
Packit 030a23
    ENTRY (b5g6r5),
Packit 030a23
Packit 030a23
    ENTRY (a1r5g5b5),
Packit 030a23
    ALIAS (a1r5g5b5,		"1555"),
Packit 030a23
    ENTRY (x1r5g5b5),
Packit 030a23
    ENTRY (a1b5g5r5),
Packit 030a23
    ENTRY (x1b5g5r5),
Packit 030a23
    ENTRY (a4r4g4b4),
Packit 030a23
    ALIAS (a4r4g4b4,		"4444"),
Packit 030a23
    ENTRY (x4r4g4b4),
Packit 030a23
    ENTRY (a4b4g4r4),
Packit 030a23
    ENTRY (x4b4g4r4),
Packit 030a23
Packit 030a23
/* 8bpp formats */
Packit 030a23
    ENTRY (a8),
Packit 030a23
    ALIAS (a8,			"8"),
Packit 030a23
    ENTRY (r3g3b2),
Packit 030a23
    ENTRY (b2g3r3),
Packit 030a23
    ENTRY (a2r2g2b2),
Packit 030a23
    ALIAS (a2r2g2b2,		"2222"),
Packit 030a23
    ENTRY (a2b2g2r2),
Packit 030a23
Packit 030a23
    ALIAS (c8,			"x4c4 / c8"),
Packit 030a23
    /* ENTRY (c8), */
Packit 030a23
    ALIAS (g8,			"x4g4 / g8"),
Packit 030a23
    /* ENTRY (g8), */
Packit 030a23
Packit 030a23
    ENTRY (x4a4),
Packit 030a23
Packit 030a23
    /* These format codes are identical to c8 and g8, respectively. */
Packit 030a23
    /* ENTRY (x4c4), */
Packit 030a23
    /* ENTRY (x4g4), */
Packit 030a23
Packit 030a23
/* 4 bpp formats */
Packit 030a23
    ENTRY (a4),
Packit 030a23
    ENTRY (r1g2b1),
Packit 030a23
    ENTRY (b1g2r1),
Packit 030a23
    ENTRY (a1r1g1b1),
Packit 030a23
    ENTRY (a1b1g1r1),
Packit 030a23
Packit 030a23
    ALIAS (c4,			"c4"),
Packit 030a23
    /* ENTRY (c4), */
Packit 030a23
    ALIAS (g4,			"g4"),
Packit 030a23
    /* ENTRY (g4), */
Packit 030a23
Packit 030a23
/* 1bpp formats */
Packit 030a23
    ENTRY (a1),
Packit 030a23
Packit 030a23
    ALIAS (g1,			"g1"),
Packit 030a23
    /* ENTRY (g1), */
Packit 030a23
Packit 030a23
/* YUV formats */
Packit 030a23
    ALIAS (yuy2,		"yuy2"),
Packit 030a23
    /* ENTRY (yuy2), */
Packit 030a23
    ALIAS (yv12,		"yv12"),
Packit 030a23
    /* ENTRY (yv12), */
Packit 030a23
Packit 030a23
/* Fake formats, not in pixman_format_code_t enum */
Packit 030a23
    ALIAS (null,		"null"),
Packit 030a23
    ALIAS (solid,		"solid"),
Packit 030a23
    ALIAS (solid,		"n"),
Packit 030a23
    ALIAS (pixbuf,		"pixbuf"),
Packit 030a23
    ALIAS (rpixbuf,		"rpixbuf"),
Packit 030a23
    ALIAS (unknown,		"unknown"),
Packit 030a23
Packit 030a23
#undef ENTRY
Packit 030a23
#undef ALIAS
Packit 030a23
};
Packit 030a23
Packit 030a23
pixman_format_code_t
Packit 030a23
format_from_string (const char *s)
Packit 030a23
{
Packit 030a23
    int i;
Packit 030a23
Packit 030a23
    for (i = 0; i < ARRAY_LENGTH (format_list); ++i)
Packit 030a23
    {
Packit 030a23
        const format_entry_t *ent = &format_list[i];
Packit 030a23
Packit 030a23
        if (strcasecmp (ent->name, s) == 0)
Packit 030a23
            return ent->format;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    return PIXMAN_null;
Packit 030a23
}
Packit 030a23
Packit 030a23
static void
Packit 030a23
emit (const char *s, int *n_chars)
Packit 030a23
{
Packit 030a23
    *n_chars += printf ("%s,", s);
Packit 030a23
    if (*n_chars > 60)
Packit 030a23
    {
Packit 030a23
        printf ("\n    ");
Packit 030a23
        *n_chars = 0;
Packit 030a23
    }
Packit 030a23
    else
Packit 030a23
    {
Packit 030a23
        printf (" ");
Packit 030a23
        (*n_chars)++;
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
list_formats (void)
Packit 030a23
{
Packit 030a23
    int n_chars;
Packit 030a23
    int i;
Packit 030a23
Packit 030a23
    printf ("Formats:\n    ");
Packit 030a23
Packit 030a23
    n_chars = 0;
Packit 030a23
    for (i = 0; i < ARRAY_LENGTH (format_list); ++i)
Packit 030a23
    {
Packit 030a23
        const format_entry_t *ent = &format_list[i];
Packit 030a23
Packit 030a23
        if (ent->is_alias)
Packit 030a23
            continue;
Packit 030a23
Packit 030a23
        emit (ent->name, &n_chars);
Packit 030a23
    }
Packit 030a23
Packit 030a23
    printf ("\n\n");
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
list_operators (void)
Packit 030a23
{
Packit 030a23
    char short_name [128] = { 0 };
Packit 030a23
    int i, n_chars;
Packit 030a23
Packit 030a23
    printf ("Operators:\n    ");
Packit 030a23
Packit 030a23
    n_chars = 0;
Packit 030a23
    for (i = 0; i < ARRAY_LENGTH (op_list); ++i)
Packit 030a23
    {
Packit 030a23
        const operator_entry_t *ent = &op_list[i];
Packit 030a23
        int j;
Packit 030a23
Packit 030a23
        if (ent->is_alias)
Packit 030a23
            continue;
Packit 030a23
Packit 030a23
        snprintf (short_name, sizeof (short_name) - 1, "%s",
Packit 030a23
                  ent->name + strlen ("PIXMAN_OP_"));
Packit 030a23
Packit 030a23
        for (j = 0; short_name[j] != '\0'; ++j)
Packit 030a23
            short_name[j] = tolower (short_name[j]);
Packit 030a23
Packit 030a23
        emit (short_name, &n_chars);
Packit 030a23
    }
Packit 030a23
Packit 030a23
    printf ("\n\n");
Packit 030a23
}
Packit 030a23
Packit 030a23
pixman_op_t
Packit 030a23
operator_from_string (const char *s)
Packit 030a23
{
Packit 030a23
    int i;
Packit 030a23
Packit 030a23
    for (i = 0; i < ARRAY_LENGTH (op_list); ++i)
Packit 030a23
    {
Packit 030a23
        const operator_entry_t *ent = &op_list[i];
Packit 030a23
Packit 030a23
        if (ent->is_alias)
Packit 030a23
        {
Packit 030a23
            if (strcasecmp (ent->name, s) == 0)
Packit 030a23
                return ent->op;
Packit 030a23
        }
Packit 030a23
        else
Packit 030a23
        {
Packit 030a23
            if (strcasecmp (ent->name + strlen ("PIXMAN_OP_"), s) == 0)
Packit 030a23
                return ent->op;
Packit 030a23
        }
Packit 030a23
    }
Packit 030a23
Packit 030a23
    return PIXMAN_OP_NONE;
Packit 030a23
}
Packit 030a23
Packit 030a23
const char *
Packit 030a23
operator_name (pixman_op_t op)
Packit 030a23
{
Packit 030a23
    int i;
Packit 030a23
Packit 030a23
    for (i = 0; i < ARRAY_LENGTH (op_list); ++i)
Packit 030a23
    {
Packit 030a23
        const operator_entry_t *ent = &op_list[i];
Packit 030a23
Packit 030a23
        if (ent->op == op)
Packit 030a23
            return ent->name;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    return "<unknown operator>";
Packit 030a23
}
Packit 030a23
Packit 030a23
const char *
Packit 030a23
format_name (pixman_format_code_t format)
Packit 030a23
{
Packit 030a23
    int i;
Packit 030a23
Packit 030a23
    for (i = 0; i < ARRAY_LENGTH (format_list); ++i)
Packit 030a23
    {
Packit 030a23
        const format_entry_t *ent = &format_list[i];
Packit 030a23
Packit 030a23
        if (ent->format == format)
Packit 030a23
            return ent->name;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    return "<unknown format>";
Packit 030a23
};
Packit 030a23
Packit 030a23
#define IS_ZERO(f)     (-DBL_MIN < (f) && (f) < DBL_MIN)
Packit 030a23
Packit 030a23
typedef double (* blend_func_t) (double as, double s, double ad, double d);
Packit 030a23
Packit 030a23
static force_inline double
Packit 030a23
blend_multiply (double sa, double s, double da, double d)
Packit 030a23
{
Packit 030a23
    return d * s;
Packit 030a23
}
Packit 030a23
Packit 030a23
static force_inline double
Packit 030a23
blend_screen (double sa, double s, double da, double d)
Packit 030a23
{
Packit 030a23
    return d * sa + s * da - s * d;
Packit 030a23
}
Packit 030a23
Packit 030a23
static force_inline double
Packit 030a23
blend_overlay (double sa, double s, double da, double d)
Packit 030a23
{
Packit 030a23
    if (2 * d < da)
Packit 030a23
        return 2 * s * d;
Packit 030a23
    else
Packit 030a23
        return sa * da - 2 * (da - d) * (sa - s);
Packit 030a23
}
Packit 030a23
Packit 030a23
static force_inline double
Packit 030a23
blend_darken (double sa, double s, double da, double d)
Packit 030a23
{
Packit 030a23
    s = s * da;
Packit 030a23
    d = d * sa;
Packit 030a23
Packit 030a23
    if (s > d)
Packit 030a23
        return d;
Packit 030a23
    else
Packit 030a23
        return s;
Packit 030a23
}
Packit 030a23
Packit 030a23
static force_inline double
Packit 030a23
blend_lighten (double sa, double s, double da, double d)
Packit 030a23
{
Packit 030a23
    s = s * da;
Packit 030a23
    d = d * sa;
Packit 030a23
Packit 030a23
    if (s > d)
Packit 030a23
        return s;
Packit 030a23
    else
Packit 030a23
        return d;
Packit 030a23
}
Packit 030a23
Packit 030a23
static force_inline double
Packit 030a23
blend_color_dodge (double sa, double s, double da, double d)
Packit 030a23
{
Packit 030a23
    if (IS_ZERO (d))
Packit 030a23
        return 0.0f;
Packit 030a23
    else if (d * sa >= sa * da - s * da)
Packit 030a23
        return sa * da;
Packit 030a23
    else if (IS_ZERO (sa - s))
Packit 030a23
        return sa * da;
Packit 030a23
    else
Packit 030a23
        return sa * sa * d / (sa - s);
Packit 030a23
}
Packit 030a23
Packit 030a23
static force_inline double
Packit 030a23
blend_color_burn (double sa, double s, double da, double d)
Packit 030a23
{
Packit 030a23
    if (d >= da)
Packit 030a23
        return sa * da;
Packit 030a23
    else if (sa * (da - d) >= s * da)
Packit 030a23
        return 0.0f;
Packit 030a23
    else if (IS_ZERO (s))
Packit 030a23
        return 0.0f;
Packit 030a23
    else
Packit 030a23
        return sa * (da - sa * (da - d) / s);
Packit 030a23
}
Packit 030a23
Packit 030a23
static force_inline double
Packit 030a23
blend_hard_light (double sa, double s, double da, double d)
Packit 030a23
{
Packit 030a23
    if (2 * s < sa)
Packit 030a23
        return 2 * s * d;
Packit 030a23
    else
Packit 030a23
        return sa * da - 2 * (da - d) * (sa - s);
Packit 030a23
}
Packit 030a23
Packit 030a23
static force_inline double
Packit 030a23
blend_soft_light (double sa, double s, double da, double d)
Packit 030a23
{
Packit 030a23
    if (2 * s <= sa)
Packit 030a23
    {
Packit 030a23
        if (IS_ZERO (da))
Packit 030a23
            return d * sa;
Packit 030a23
        else
Packit 030a23
            return d * sa - d * (da - d) * (sa - 2 * s) / da;
Packit 030a23
    }
Packit 030a23
    else
Packit 030a23
    {
Packit 030a23
        if (IS_ZERO (da))
Packit 030a23
        {
Packit 030a23
	    return d * sa;
Packit 030a23
        }
Packit 030a23
        else
Packit 030a23
        {
Packit 030a23
            if (4 * d <= da)
Packit 030a23
                return d * sa + (2 * s - sa) * d * ((16 * d / da - 12) * d / da + 3);
Packit 030a23
            else
Packit 030a23
                return d * sa + (sqrt (d * da) - d) * (2 * s - sa);
Packit 030a23
        }
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
static force_inline double
Packit 030a23
blend_difference (double sa, double s, double da, double d)
Packit 030a23
{
Packit 030a23
    double dsa = d * sa;
Packit 030a23
    double sda = s * da;
Packit 030a23
Packit 030a23
    if (sda < dsa)
Packit 030a23
        return dsa - sda;
Packit 030a23
    else
Packit 030a23
        return sda - dsa;
Packit 030a23
}
Packit 030a23
Packit 030a23
static force_inline double
Packit 030a23
blend_exclusion (double sa, double s, double da, double d)
Packit 030a23
{
Packit 030a23
    return s * da + d * sa - 2 * d * s;
Packit 030a23
}
Packit 030a23
Packit 030a23
static double
Packit 030a23
clamp (double d)
Packit 030a23
{
Packit 030a23
    if (d > 1.0)
Packit 030a23
	return 1.0;
Packit 030a23
    else if (d < 0.0)
Packit 030a23
	return 0.0;
Packit 030a23
    else
Packit 030a23
	return d;
Packit 030a23
}
Packit 030a23
Packit 030a23
static double
Packit 030a23
blend_channel (double as, double s, double ad, double d,
Packit 030a23
                   blend_func_t blend)
Packit 030a23
{
Packit 030a23
    return clamp ((1 - ad) * s + (1 - as) * d + blend (as, s, ad, d));
Packit 030a23
}
Packit 030a23
Packit 030a23
static double
Packit 030a23
calc_op (pixman_op_t op, double src, double dst, double srca, double dsta)
Packit 030a23
{
Packit 030a23
#define mult_chan(src, dst, Fa, Fb) MIN ((src) * (Fa) + (dst) * (Fb), 1.0)
Packit 030a23
Packit 030a23
    double Fa, Fb;
Packit 030a23
Packit 030a23
    switch (op)
Packit 030a23
    {
Packit 030a23
    case PIXMAN_OP_CLEAR:
Packit 030a23
    case PIXMAN_OP_DISJOINT_CLEAR:
Packit 030a23
    case PIXMAN_OP_CONJOINT_CLEAR:
Packit 030a23
	return mult_chan (src, dst, 0.0, 0.0);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_SRC:
Packit 030a23
    case PIXMAN_OP_DISJOINT_SRC:
Packit 030a23
    case PIXMAN_OP_CONJOINT_SRC:
Packit 030a23
	return mult_chan (src, dst, 1.0, 0.0);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_DST:
Packit 030a23
    case PIXMAN_OP_DISJOINT_DST:
Packit 030a23
    case PIXMAN_OP_CONJOINT_DST:
Packit 030a23
	return mult_chan (src, dst, 0.0, 1.0);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_OVER:
Packit 030a23
	return mult_chan (src, dst, 1.0, 1.0 - srca);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_OVER_REVERSE:
Packit 030a23
	return mult_chan (src, dst, 1.0 - dsta, 1.0);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_IN:
Packit 030a23
	return mult_chan (src, dst, dsta, 0.0);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_IN_REVERSE:
Packit 030a23
	return mult_chan (src, dst, 0.0, srca);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_OUT:
Packit 030a23
	return mult_chan (src, dst, 1.0 - dsta, 0.0);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_OUT_REVERSE:
Packit 030a23
	return mult_chan (src, dst, 0.0, 1.0 - srca);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_ATOP:
Packit 030a23
	return mult_chan (src, dst, dsta, 1.0 - srca);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_ATOP_REVERSE:
Packit 030a23
	return mult_chan (src, dst, 1.0 - dsta,  srca);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_XOR:
Packit 030a23
	return mult_chan (src, dst, 1.0 - dsta, 1.0 - srca);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_ADD:
Packit 030a23
	return mult_chan (src, dst, 1.0, 1.0);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_SATURATE:
Packit 030a23
    case PIXMAN_OP_DISJOINT_OVER_REVERSE:
Packit 030a23
	if (srca == 0.0)
Packit 030a23
	    Fa = 1.0;
Packit 030a23
	else
Packit 030a23
	    Fa = MIN (1.0, (1.0 - dsta) / srca);
Packit 030a23
	return mult_chan (src, dst, Fa, 1.0);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_DISJOINT_OVER:
Packit 030a23
	if (dsta == 0.0)
Packit 030a23
	    Fb = 1.0;
Packit 030a23
	else
Packit 030a23
	    Fb = MIN (1.0, (1.0 - srca) / dsta);
Packit 030a23
	return mult_chan (src, dst, 1.0, Fb);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_DISJOINT_IN:
Packit 030a23
	if (srca == 0.0)
Packit 030a23
	    Fa = 0.0;
Packit 030a23
	else
Packit 030a23
	    Fa = MAX (0.0, 1.0 - (1.0 - dsta) / srca);
Packit 030a23
	return mult_chan (src, dst, Fa, 0.0);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_DISJOINT_IN_REVERSE:
Packit 030a23
	if (dsta == 0.0)
Packit 030a23
	    Fb = 0.0;
Packit 030a23
	else
Packit 030a23
	    Fb = MAX (0.0, 1.0 - (1.0 - srca) / dsta);
Packit 030a23
	return mult_chan (src, dst, 0.0, Fb);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_DISJOINT_OUT:
Packit 030a23
	if (srca == 0.0)
Packit 030a23
	    Fa = 1.0;
Packit 030a23
	else
Packit 030a23
	    Fa = MIN (1.0, (1.0 - dsta) / srca);
Packit 030a23
	return mult_chan (src, dst, Fa, 0.0);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_DISJOINT_OUT_REVERSE:
Packit 030a23
	if (dsta == 0.0)
Packit 030a23
	    Fb = 1.0;
Packit 030a23
	else
Packit 030a23
	    Fb = MIN (1.0, (1.0 - srca) / dsta);
Packit 030a23
	return mult_chan (src, dst, 0.0, Fb);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_DISJOINT_ATOP:
Packit 030a23
	if (srca == 0.0)
Packit 030a23
	    Fa = 0.0;
Packit 030a23
	else
Packit 030a23
	    Fa = MAX (0.0, 1.0 - (1.0 - dsta) / srca);
Packit 030a23
	if (dsta == 0.0)
Packit 030a23
	    Fb = 1.0;
Packit 030a23
	else
Packit 030a23
	    Fb = MIN (1.0, (1.0 - srca) / dsta);
Packit 030a23
	return mult_chan (src, dst, Fa, Fb);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_DISJOINT_ATOP_REVERSE:
Packit 030a23
	if (srca == 0.0)
Packit 030a23
	    Fa = 1.0;
Packit 030a23
	else
Packit 030a23
	    Fa = MIN (1.0, (1.0 - dsta) / srca);
Packit 030a23
	if (dsta == 0.0)
Packit 030a23
	    Fb = 0.0;
Packit 030a23
	else
Packit 030a23
	    Fb = MAX (0.0, 1.0 - (1.0 - srca) / dsta);
Packit 030a23
	return mult_chan (src, dst, Fa, Fb);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_DISJOINT_XOR:
Packit 030a23
	if (srca == 0.0)
Packit 030a23
	    Fa = 1.0;
Packit 030a23
	else
Packit 030a23
	    Fa = MIN (1.0, (1.0 - dsta) / srca);
Packit 030a23
	if (dsta == 0.0)
Packit 030a23
	    Fb = 1.0;
Packit 030a23
	else
Packit 030a23
	    Fb = MIN (1.0, (1.0 - srca) / dsta);
Packit 030a23
	return mult_chan (src, dst, Fa, Fb);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_CONJOINT_OVER:
Packit 030a23
	if (dsta == 0.0)
Packit 030a23
	    Fb = 0.0;
Packit 030a23
	else
Packit 030a23
	    Fb = MAX (0.0, 1.0 - srca / dsta);
Packit 030a23
	return mult_chan (src, dst, 1.0, Fb);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_CONJOINT_OVER_REVERSE:
Packit 030a23
	if (srca == 0.0)
Packit 030a23
	    Fa = 0.0;
Packit 030a23
	else
Packit 030a23
	    Fa = MAX (0.0, 1.0 - dsta / srca);
Packit 030a23
	return mult_chan (src, dst, Fa, 1.0);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_CONJOINT_IN:
Packit 030a23
	if (srca == 0.0)
Packit 030a23
	    Fa = 1.0;
Packit 030a23
	else
Packit 030a23
	    Fa = MIN (1.0, dsta / srca);
Packit 030a23
	return mult_chan (src, dst, Fa, 0.0);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_CONJOINT_IN_REVERSE:
Packit 030a23
	if (dsta == 0.0)
Packit 030a23
	    Fb = 1.0;
Packit 030a23
	else
Packit 030a23
	    Fb = MIN (1.0, srca / dsta);
Packit 030a23
	return mult_chan (src, dst, 0.0, Fb);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_CONJOINT_OUT:
Packit 030a23
	if (srca == 0.0)
Packit 030a23
	    Fa = 0.0;
Packit 030a23
	else
Packit 030a23
	    Fa = MAX (0.0, 1.0 - dsta / srca);
Packit 030a23
	return mult_chan (src, dst, Fa, 0.0);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_CONJOINT_OUT_REVERSE:
Packit 030a23
	if (dsta == 0.0)
Packit 030a23
	    Fb = 0.0;
Packit 030a23
	else
Packit 030a23
	    Fb = MAX (0.0, 1.0 - srca / dsta);
Packit 030a23
	return mult_chan (src, dst, 0.0, Fb);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_CONJOINT_ATOP:
Packit 030a23
	if (srca == 0.0)
Packit 030a23
	    Fa = 1.0;
Packit 030a23
	else
Packit 030a23
	    Fa = MIN (1.0, dsta / srca);
Packit 030a23
	if (dsta == 0.0)
Packit 030a23
	    Fb = 0.0;
Packit 030a23
	else
Packit 030a23
	    Fb = MAX (0.0, 1.0 - srca / dsta);
Packit 030a23
	return mult_chan (src, dst, Fa, Fb);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_CONJOINT_ATOP_REVERSE:
Packit 030a23
	if (srca == 0.0)
Packit 030a23
	    Fa = 0.0;
Packit 030a23
	else
Packit 030a23
	    Fa = MAX (0.0, 1.0 - dsta / srca);
Packit 030a23
	if (dsta == 0.0)
Packit 030a23
	    Fb = 1.0;
Packit 030a23
	else
Packit 030a23
	    Fb = MIN (1.0, srca / dsta);
Packit 030a23
	return mult_chan (src, dst, Fa, Fb);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_CONJOINT_XOR:
Packit 030a23
	if (srca == 0.0)
Packit 030a23
	    Fa = 0.0;
Packit 030a23
	else
Packit 030a23
	    Fa = MAX (0.0, 1.0 - dsta / srca);
Packit 030a23
	if (dsta == 0.0)
Packit 030a23
	    Fb = 0.0;
Packit 030a23
	else
Packit 030a23
	    Fb = MAX (0.0, 1.0 - srca / dsta);
Packit 030a23
	return mult_chan (src, dst, Fa, Fb);
Packit 030a23
Packit 030a23
    case PIXMAN_OP_MULTIPLY:
Packit 030a23
    case PIXMAN_OP_SCREEN:
Packit 030a23
    case PIXMAN_OP_OVERLAY:
Packit 030a23
    case PIXMAN_OP_DARKEN:
Packit 030a23
    case PIXMAN_OP_LIGHTEN:
Packit 030a23
    case PIXMAN_OP_COLOR_DODGE:
Packit 030a23
    case PIXMAN_OP_COLOR_BURN:
Packit 030a23
    case PIXMAN_OP_HARD_LIGHT:
Packit 030a23
    case PIXMAN_OP_SOFT_LIGHT:
Packit 030a23
    case PIXMAN_OP_DIFFERENCE:
Packit 030a23
    case PIXMAN_OP_EXCLUSION:
Packit 030a23
    case PIXMAN_OP_HSL_HUE:
Packit 030a23
    case PIXMAN_OP_HSL_SATURATION:
Packit 030a23
    case PIXMAN_OP_HSL_COLOR:
Packit 030a23
    case PIXMAN_OP_HSL_LUMINOSITY:
Packit 030a23
    default:
Packit 030a23
	abort();
Packit 030a23
	return 0; /* silence MSVC */
Packit 030a23
    }
Packit 030a23
#undef mult_chan
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
do_composite (pixman_op_t op,
Packit 030a23
	      const color_t *src,
Packit 030a23
	      const color_t *mask,
Packit 030a23
	      const color_t *dst,
Packit 030a23
	      color_t *result,
Packit 030a23
	      pixman_bool_t component_alpha)
Packit 030a23
{
Packit 030a23
    color_t srcval, srcalpha;
Packit 030a23
Packit 030a23
    static const blend_func_t blend_funcs[] =
Packit 030a23
    {
Packit 030a23
        blend_multiply,
Packit 030a23
        blend_screen,
Packit 030a23
        blend_overlay,
Packit 030a23
        blend_darken,
Packit 030a23
        blend_lighten,
Packit 030a23
        blend_color_dodge,
Packit 030a23
        blend_color_burn,
Packit 030a23
        blend_hard_light,
Packit 030a23
        blend_soft_light,
Packit 030a23
        blend_difference,
Packit 030a23
        blend_exclusion,
Packit 030a23
    };
Packit 030a23
Packit 030a23
    if (mask == NULL)
Packit 030a23
    {
Packit 030a23
	srcval = *src;
Packit 030a23
Packit 030a23
	srcalpha.r = src->a;
Packit 030a23
	srcalpha.g = src->a;
Packit 030a23
	srcalpha.b = src->a;
Packit 030a23
	srcalpha.a = src->a;
Packit 030a23
    }
Packit 030a23
    else if (component_alpha)
Packit 030a23
    {
Packit 030a23
	srcval.r = src->r * mask->r;
Packit 030a23
	srcval.g = src->g * mask->g;
Packit 030a23
	srcval.b = src->b * mask->b;
Packit 030a23
	srcval.a = src->a * mask->a;
Packit 030a23
Packit 030a23
	srcalpha.r = src->a * mask->r;
Packit 030a23
	srcalpha.g = src->a * mask->g;
Packit 030a23
	srcalpha.b = src->a * mask->b;
Packit 030a23
	srcalpha.a = src->a * mask->a;
Packit 030a23
    }
Packit 030a23
    else
Packit 030a23
    {
Packit 030a23
	srcval.r = src->r * mask->a;
Packit 030a23
	srcval.g = src->g * mask->a;
Packit 030a23
	srcval.b = src->b * mask->a;
Packit 030a23
	srcval.a = src->a * mask->a;
Packit 030a23
Packit 030a23
	srcalpha.r = src->a * mask->a;
Packit 030a23
	srcalpha.g = src->a * mask->a;
Packit 030a23
	srcalpha.b = src->a * mask->a;
Packit 030a23
	srcalpha.a = src->a * mask->a;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    if (op >= PIXMAN_OP_MULTIPLY)
Packit 030a23
    {
Packit 030a23
        blend_func_t func = blend_funcs[op - PIXMAN_OP_MULTIPLY];
Packit 030a23
Packit 030a23
	result->a = srcalpha.a + dst->a - srcalpha.a * dst->a;
Packit 030a23
	result->r = blend_channel (srcalpha.r, srcval.r, dst->a, dst->r, func);
Packit 030a23
	result->g = blend_channel (srcalpha.g, srcval.g, dst->a, dst->g, func);
Packit 030a23
	result->b = blend_channel (srcalpha.b, srcval.b, dst->a, dst->b, func);
Packit 030a23
    }
Packit 030a23
    else
Packit 030a23
    {
Packit 030a23
        result->r = calc_op (op, srcval.r, dst->r, srcalpha.r, dst->a);
Packit 030a23
        result->g = calc_op (op, srcval.g, dst->g, srcalpha.g, dst->a);
Packit 030a23
        result->b = calc_op (op, srcval.b, dst->b, srcalpha.b, dst->a);
Packit 030a23
        result->a = calc_op (op, srcval.a, dst->a, srcalpha.a, dst->a);
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
static double
Packit 030a23
round_channel (double p, int m)
Packit 030a23
{
Packit 030a23
    int t;
Packit 030a23
    double r;
Packit 030a23
Packit 030a23
    t = p * ((1 << m));
Packit 030a23
    t -= t >> m;
Packit 030a23
Packit 030a23
    r = t / (double)((1 << m) - 1);
Packit 030a23
Packit 030a23
    return r;
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
round_color (pixman_format_code_t format, color_t *color)
Packit 030a23
{
Packit 030a23
    if (PIXMAN_FORMAT_R (format) == 0)
Packit 030a23
    {
Packit 030a23
	color->r = 0.0;
Packit 030a23
	color->g = 0.0;
Packit 030a23
	color->b = 0.0;
Packit 030a23
    }
Packit 030a23
    else
Packit 030a23
    {
Packit 030a23
	color->r = round_channel (color->r, PIXMAN_FORMAT_R (format));
Packit 030a23
	color->g = round_channel (color->g, PIXMAN_FORMAT_G (format));
Packit 030a23
	color->b = round_channel (color->b, PIXMAN_FORMAT_B (format));
Packit 030a23
    }
Packit 030a23
Packit 030a23
    if (PIXMAN_FORMAT_A (format) == 0)
Packit 030a23
	color->a = 1;
Packit 030a23
    else
Packit 030a23
	color->a = round_channel (color->a, PIXMAN_FORMAT_A (format));
Packit 030a23
}
Packit 030a23
Packit 030a23
/* Check whether @pixel is a valid quantization of the a, r, g, b
Packit 030a23
 * parameters. Some slack is permitted.
Packit 030a23
 */
Packit 030a23
void
Packit 030a23
pixel_checker_init (pixel_checker_t *checker, pixman_format_code_t format)
Packit 030a23
{
Packit 030a23
    assert (PIXMAN_FORMAT_VIS (format));
Packit 030a23
Packit 030a23
    checker->format = format;
Packit 030a23
Packit 030a23
    switch (PIXMAN_FORMAT_TYPE (format))
Packit 030a23
    {
Packit 030a23
    case PIXMAN_TYPE_A:
Packit 030a23
	checker->bs = 0;
Packit 030a23
	checker->gs = 0;
Packit 030a23
	checker->rs = 0;
Packit 030a23
	checker->as = 0;
Packit 030a23
	break;
Packit 030a23
Packit 030a23
    case PIXMAN_TYPE_ARGB:
Packit 030a23
    case PIXMAN_TYPE_ARGB_SRGB:
Packit 030a23
	checker->bs = 0;
Packit 030a23
	checker->gs = checker->bs + PIXMAN_FORMAT_B (format);
Packit 030a23
	checker->rs = checker->gs + PIXMAN_FORMAT_G (format);
Packit 030a23
	checker->as = checker->rs + PIXMAN_FORMAT_R (format);
Packit 030a23
	break;
Packit 030a23
Packit 030a23
    case PIXMAN_TYPE_ABGR:
Packit 030a23
	checker->rs = 0;
Packit 030a23
	checker->gs = checker->rs + PIXMAN_FORMAT_R (format);
Packit 030a23
	checker->bs = checker->gs + PIXMAN_FORMAT_G (format);
Packit 030a23
	checker->as = checker->bs + PIXMAN_FORMAT_B (format);
Packit 030a23
	break;
Packit 030a23
Packit 030a23
    case PIXMAN_TYPE_BGRA:
Packit 030a23
	/* With BGRA formats we start counting at the high end of the pixel */
Packit 030a23
	checker->bs = PIXMAN_FORMAT_BPP (format) - PIXMAN_FORMAT_B (format);
Packit 030a23
	checker->gs = checker->bs - PIXMAN_FORMAT_B (format);
Packit 030a23
	checker->rs = checker->gs - PIXMAN_FORMAT_G (format);
Packit 030a23
	checker->as = checker->rs - PIXMAN_FORMAT_R (format);
Packit 030a23
	break;
Packit 030a23
Packit 030a23
    case PIXMAN_TYPE_RGBA:
Packit 030a23
	/* With BGRA formats we start counting at the high end of the pixel */
Packit 030a23
	checker->rs = PIXMAN_FORMAT_BPP (format) - PIXMAN_FORMAT_R (format);
Packit 030a23
	checker->gs = checker->rs - PIXMAN_FORMAT_R (format);
Packit 030a23
	checker->bs = checker->gs - PIXMAN_FORMAT_G (format);
Packit 030a23
	checker->as = checker->bs - PIXMAN_FORMAT_B (format);
Packit 030a23
	break;
Packit 030a23
Packit 030a23
    default:
Packit 030a23
	assert (0);
Packit 030a23
	break;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    checker->am = ((1 << PIXMAN_FORMAT_A (format)) - 1) << checker->as;
Packit 030a23
    checker->rm = ((1 << PIXMAN_FORMAT_R (format)) - 1) << checker->rs;
Packit 030a23
    checker->gm = ((1 << PIXMAN_FORMAT_G (format)) - 1) << checker->gs;
Packit 030a23
    checker->bm = ((1 << PIXMAN_FORMAT_B (format)) - 1) << checker->bs;
Packit 030a23
Packit 030a23
    checker->aw = PIXMAN_FORMAT_A (format);
Packit 030a23
    checker->rw = PIXMAN_FORMAT_R (format);
Packit 030a23
    checker->gw = PIXMAN_FORMAT_G (format);
Packit 030a23
    checker->bw = PIXMAN_FORMAT_B (format);
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
pixel_checker_split_pixel (const pixel_checker_t *checker, uint32_t pixel,
Packit 030a23
			   int *a, int *r, int *g, int *b)
Packit 030a23
{
Packit 030a23
    *a = (pixel & checker->am) >> checker->as;
Packit 030a23
    *r = (pixel & checker->rm) >> checker->rs;
Packit 030a23
    *g = (pixel & checker->gm) >> checker->gs;
Packit 030a23
    *b = (pixel & checker->bm) >> checker->bs;
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
pixel_checker_get_masks (const pixel_checker_t *checker,
Packit 030a23
                         uint32_t              *am,
Packit 030a23
                         uint32_t              *rm,
Packit 030a23
                         uint32_t              *gm,
Packit 030a23
                         uint32_t              *bm)
Packit 030a23
{
Packit 030a23
    if (am)
Packit 030a23
        *am = checker->am;
Packit 030a23
    if (rm)
Packit 030a23
        *rm = checker->rm;
Packit 030a23
    if (gm)
Packit 030a23
        *gm = checker->gm;
Packit 030a23
    if (bm)
Packit 030a23
        *bm = checker->bm;
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
pixel_checker_convert_pixel_to_color (const pixel_checker_t *checker,
Packit 030a23
                                      uint32_t pixel, color_t *color)
Packit 030a23
{
Packit 030a23
    int a, r, g, b;
Packit 030a23
Packit 030a23
    pixel_checker_split_pixel (checker, pixel, &a, &r, &g, &b);
Packit 030a23
Packit 030a23
    if (checker->am == 0)
Packit 030a23
        color->a = 1.0;
Packit 030a23
    else
Packit 030a23
        color->a = a / (double)(checker->am >> checker->as);
Packit 030a23
Packit 030a23
    if (checker->rm == 0)
Packit 030a23
        color->r = 0.0;
Packit 030a23
    else
Packit 030a23
        color->r = r / (double)(checker->rm >> checker->rs);
Packit 030a23
Packit 030a23
    if (checker->gm == 0)
Packit 030a23
        color->g = 0.0;
Packit 030a23
    else
Packit 030a23
        color->g = g / (double)(checker->gm >> checker->gs);
Packit 030a23
Packit 030a23
    if (checker->bm == 0)
Packit 030a23
        color->b = 0.0;
Packit 030a23
    else
Packit 030a23
        color->b = b / (double)(checker->bm >> checker->bs);
Packit 030a23
Packit 030a23
    if (PIXMAN_FORMAT_TYPE (checker->format) == PIXMAN_TYPE_ARGB_SRGB)
Packit 030a23
    {
Packit 030a23
	color->r = convert_srgb_to_linear (color->r);
Packit 030a23
	color->g = convert_srgb_to_linear (color->g);
Packit 030a23
	color->b = convert_srgb_to_linear (color->b);
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
static int32_t
Packit 030a23
convert (double v, uint32_t width, uint32_t mask, uint32_t shift, double def)
Packit 030a23
{
Packit 030a23
    int32_t r;
Packit 030a23
Packit 030a23
    if (!mask)
Packit 030a23
	v = def;
Packit 030a23
Packit 030a23
    r = (v * ((mask >> shift) + 1));
Packit 030a23
    r -= r >> width;
Packit 030a23
Packit 030a23
    return r;
Packit 030a23
}
Packit 030a23
Packit 030a23
static void
Packit 030a23
get_limits (const pixel_checker_t *checker, double limit,
Packit 030a23
	    color_t *color,
Packit 030a23
	    int *ao, int *ro, int *go, int *bo)
Packit 030a23
{
Packit 030a23
    color_t tmp;
Packit 030a23
Packit 030a23
    if (PIXMAN_FORMAT_TYPE (checker->format) == PIXMAN_TYPE_ARGB_SRGB)
Packit 030a23
    {
Packit 030a23
	tmp.a = color->a;
Packit 030a23
	tmp.r = convert_linear_to_srgb (color->r);
Packit 030a23
	tmp.g = convert_linear_to_srgb (color->g);
Packit 030a23
	tmp.b = convert_linear_to_srgb (color->b);
Packit 030a23
Packit 030a23
	color = &tm;;
Packit 030a23
    }
Packit 030a23
    
Packit 030a23
    *ao = convert (color->a + limit, checker->aw, checker->am, checker->as, 1.0);
Packit 030a23
    *ro = convert (color->r + limit, checker->rw, checker->rm, checker->rs, 0.0);
Packit 030a23
    *go = convert (color->g + limit, checker->gw, checker->gm, checker->gs, 0.0);
Packit 030a23
    *bo = convert (color->b + limit, checker->bw, checker->bm, checker->bs, 0.0);
Packit 030a23
}
Packit 030a23
Packit 030a23
/* The acceptable deviation in units of [0.0, 1.0]
Packit 030a23
 */
Packit 030a23
#define DEVIATION (0.0128)
Packit 030a23
Packit 030a23
void
Packit 030a23
pixel_checker_get_max (const pixel_checker_t *checker, color_t *color,
Packit 030a23
		       int *am, int *rm, int *gm, int *bm)
Packit 030a23
{
Packit 030a23
    get_limits (checker, DEVIATION, color, am, rm, gm, bm);
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
pixel_checker_get_min (const pixel_checker_t *checker, color_t *color,
Packit 030a23
		       int *am, int *rm, int *gm, int *bm)
Packit 030a23
{
Packit 030a23
    get_limits (checker, - DEVIATION, color, am, rm, gm, bm);
Packit 030a23
}
Packit 030a23
Packit 030a23
pixman_bool_t
Packit 030a23
pixel_checker_check (const pixel_checker_t *checker, uint32_t pixel,
Packit 030a23
		     color_t *color)
Packit 030a23
{
Packit 030a23
    int32_t a_lo, a_hi, r_lo, r_hi, g_lo, g_hi, b_lo, b_hi;
Packit 030a23
    int32_t ai, ri, gi, bi;
Packit 030a23
    pixman_bool_t result;
Packit 030a23
Packit 030a23
    pixel_checker_get_min (checker, color, &a_lo, &r_lo, &g_lo, &b_lo);
Packit 030a23
    pixel_checker_get_max (checker, color, &a_hi, &r_hi, &g_hi, &b_hi);
Packit 030a23
    pixel_checker_split_pixel (checker, pixel, &ai, &ri, &gi, &bi);
Packit 030a23
Packit 030a23
    result =
Packit 030a23
	a_lo <= ai && ai <= a_hi	&&
Packit 030a23
	r_lo <= ri && ri <= r_hi	&&
Packit 030a23
	g_lo <= gi && gi <= g_hi	&&
Packit 030a23
	b_lo <= bi && bi <= b_hi;
Packit 030a23
Packit 030a23
    return result;
Packit 030a23
}