114b11b2bSmrg#define _GNU_SOURCE
214b11b2bSmrg
314b11b2bSmrg#include "utils.h"
414b11b2bSmrg#include <math.h>
514b11b2bSmrg#include <signal.h>
614b11b2bSmrg#include <stdlib.h>
714b11b2bSmrg#include <float.h>
814b11b2bSmrg#include <ctype.h>
914b11b2bSmrg#include <limits.h>
1014b11b2bSmrg
1114b11b2bSmrg#ifdef HAVE_GETTIMEOFDAY
1214b11b2bSmrg#include <sys/time.h>
1314b11b2bSmrg#else
1414b11b2bSmrg#include <time.h>
1514b11b2bSmrg#endif
1614b11b2bSmrg
1714b11b2bSmrg#ifdef HAVE_UNISTD_H
1814b11b2bSmrg#include <unistd.h>
1914b11b2bSmrg#endif
2014b11b2bSmrg
2114b11b2bSmrg#ifdef HAVE_SYS_MMAN_H
2214b11b2bSmrg#include <sys/mman.h>
2314b11b2bSmrg#endif
2414b11b2bSmrg
2514b11b2bSmrg#ifdef HAVE_FENV_H
2614b11b2bSmrg#include <fenv.h>
2714b11b2bSmrg#endif
2814b11b2bSmrg
2914b11b2bSmrg#ifdef HAVE_LIBPNG
3014b11b2bSmrg#include <png.h>
3114b11b2bSmrg#endif
3214b11b2bSmrg
3314b11b2bSmrg#define ROUND_UP(x, mult) (((x) + (mult) - 1) / (mult) * (mult))
3414b11b2bSmrg
3514b11b2bSmrg/* Random number generator state
3614b11b2bSmrg */
3714b11b2bSmrg
3814b11b2bSmrgprng_t prng_state_data = {0};
3914b11b2bSmrgprng_t *prng_state = NULL;
4014b11b2bSmrg
4114b11b2bSmrg/*----------------------------------------------------------------------------*\
4214b11b2bSmrg *  CRC-32 version 2.0.0 by Craig Bruce, 2006-04-29.
4314b11b2bSmrg *
4414b11b2bSmrg *  This program generates the CRC-32 values for the files named in the
4514b11b2bSmrg *  command-line arguments.  These are the same CRC-32 values used by GZIP,
4614b11b2bSmrg *  PKZIP, and ZMODEM.  The Crc32_ComputeBuf () can also be detached and
4714b11b2bSmrg *  used independently.
4814b11b2bSmrg *
4914b11b2bSmrg *  THIS PROGRAM IS PUBLIC-DOMAIN SOFTWARE.
5014b11b2bSmrg *
5114b11b2bSmrg *  Based on the byte-oriented implementation "File Verification Using CRC"
5214b11b2bSmrg *  by Mark R. Nelson in Dr. Dobb's Journal, May 1992, pp. 64-67.
5314b11b2bSmrg *
5414b11b2bSmrg *  v1.0.0: original release.
5514b11b2bSmrg *  v1.0.1: fixed printf formats.
5614b11b2bSmrg *  v1.0.2: fixed something else.
5714b11b2bSmrg *  v1.0.3: replaced CRC constant table by generator function.
5814b11b2bSmrg *  v1.0.4: reformatted code, made ANSI C.  1994-12-05.
5914b11b2bSmrg *  v2.0.0: rewrote to use memory buffer & static table, 2006-04-29.
6014b11b2bSmrg\*----------------------------------------------------------------------------*/
6114b11b2bSmrg
6214b11b2bSmrg/*----------------------------------------------------------------------------*\
6314b11b2bSmrg *  NAME:
6414b11b2bSmrg *     Crc32_ComputeBuf () - computes the CRC-32 value of a memory buffer
6514b11b2bSmrg *  DESCRIPTION:
6614b11b2bSmrg *     Computes or accumulates the CRC-32 value for a memory buffer.
6714b11b2bSmrg *     The 'inCrc32' gives a previously accumulated CRC-32 value to allow
6814b11b2bSmrg *     a CRC to be generated for multiple sequential buffer-fuls of data.
6914b11b2bSmrg *     The 'inCrc32' for the first buffer must be zero.
7014b11b2bSmrg *  ARGUMENTS:
7114b11b2bSmrg *     inCrc32 - accumulated CRC-32 value, must be 0 on first call
7214b11b2bSmrg *     buf     - buffer to compute CRC-32 value for
7314b11b2bSmrg *     bufLen  - number of bytes in buffer
7414b11b2bSmrg *  RETURNS:
7514b11b2bSmrg *     crc32 - computed CRC-32 value
7614b11b2bSmrg *  ERRORS:
7714b11b2bSmrg *     (no errors are possible)
7814b11b2bSmrg\*----------------------------------------------------------------------------*/
7914b11b2bSmrg
8014b11b2bSmrguint32_t
8114b11b2bSmrgcompute_crc32 (uint32_t    in_crc32,
8214b11b2bSmrg	       const void *buf,
8314b11b2bSmrg	       size_t      buf_len)
8414b11b2bSmrg{
8514b11b2bSmrg    static const uint32_t crc_table[256] = {
8614b11b2bSmrg	0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
8714b11b2bSmrg	0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
8814b11b2bSmrg	0x09B64C2B, 0x7EB17CBD,	0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
8914b11b2bSmrg	0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
9014b11b2bSmrg	0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,	0x14015C4F, 0x63066CD9,
9114b11b2bSmrg	0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
9214b11b2bSmrg	0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
9314b11b2bSmrg	0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
9414b11b2bSmrg	0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
9514b11b2bSmrg	0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
9614b11b2bSmrg	0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
9714b11b2bSmrg	0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
9814b11b2bSmrg	0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
9914b11b2bSmrg	0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
10014b11b2bSmrg	0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
10114b11b2bSmrg	0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
10214b11b2bSmrg	0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
10314b11b2bSmrg	0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
10414b11b2bSmrg	0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
10514b11b2bSmrg	0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
10614b11b2bSmrg	0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
10714b11b2bSmrg	0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
10814b11b2bSmrg	0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
10914b11b2bSmrg	0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
11014b11b2bSmrg	0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
11114b11b2bSmrg	0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
11214b11b2bSmrg	0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
11314b11b2bSmrg	0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
11414b11b2bSmrg	0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
11514b11b2bSmrg	0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
11614b11b2bSmrg	0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
11714b11b2bSmrg	0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
11814b11b2bSmrg	0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
11914b11b2bSmrg	0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
12014b11b2bSmrg	0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
12114b11b2bSmrg	0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
12214b11b2bSmrg	0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
12314b11b2bSmrg	0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
12414b11b2bSmrg	0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
12514b11b2bSmrg	0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
12614b11b2bSmrg	0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
12714b11b2bSmrg	0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
12814b11b2bSmrg	0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
12914b11b2bSmrg    };
13014b11b2bSmrg
13114b11b2bSmrg    uint32_t              crc32;
13214b11b2bSmrg    unsigned char *       byte_buf;
13314b11b2bSmrg    size_t                i;
13414b11b2bSmrg
13514b11b2bSmrg    /* accumulate crc32 for buffer */
13614b11b2bSmrg    crc32 = in_crc32 ^ 0xFFFFFFFF;
13714b11b2bSmrg    byte_buf = (unsigned char*) buf;
13814b11b2bSmrg
13914b11b2bSmrg    for (i = 0; i < buf_len; i++)
14014b11b2bSmrg	crc32 = (crc32 >> 8) ^ crc_table[(crc32 ^ byte_buf[i]) & 0xFF];
14114b11b2bSmrg
14214b11b2bSmrg    return (crc32 ^ 0xFFFFFFFF);
14314b11b2bSmrg}
14414b11b2bSmrg
14514b11b2bSmrgstatic uint32_t
14614b11b2bSmrgcompute_crc32_for_image_internal (uint32_t        crc32,
14714b11b2bSmrg				  pixman_image_t *img,
14814b11b2bSmrg				  pixman_bool_t	  remove_alpha,
14914b11b2bSmrg				  pixman_bool_t	  remove_rgb)
15014b11b2bSmrg{
15114b11b2bSmrg    pixman_format_code_t fmt = pixman_image_get_format (img);
15214b11b2bSmrg    uint32_t *data = pixman_image_get_data (img);
15314b11b2bSmrg    int stride = pixman_image_get_stride (img);
15414b11b2bSmrg    int height = pixman_image_get_height (img);
15514b11b2bSmrg    uint32_t mask = 0xffffffff;
15614b11b2bSmrg    int i;
15714b11b2bSmrg
15814b11b2bSmrg    if (stride < 0)
15914b11b2bSmrg    {
16014b11b2bSmrg	data += (stride / 4) * (height - 1);
16114b11b2bSmrg	stride = - stride;
16214b11b2bSmrg    }
16314b11b2bSmrg
16414b11b2bSmrg    /* mask unused 'x' part */
16514b11b2bSmrg    if (PIXMAN_FORMAT_BPP (fmt) - PIXMAN_FORMAT_DEPTH (fmt) &&
16614b11b2bSmrg	PIXMAN_FORMAT_DEPTH (fmt) != 0)
16714b11b2bSmrg    {
16814b11b2bSmrg	uint32_t m = (1 << PIXMAN_FORMAT_DEPTH (fmt)) - 1;
16914b11b2bSmrg
17014b11b2bSmrg	if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_BGRA ||
17114b11b2bSmrg	    PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_RGBA)
17214b11b2bSmrg	{
17314b11b2bSmrg	    m <<= (PIXMAN_FORMAT_BPP (fmt) - PIXMAN_FORMAT_DEPTH (fmt));
17414b11b2bSmrg	}
17514b11b2bSmrg
17614b11b2bSmrg	mask &= m;
17714b11b2bSmrg    }
17814b11b2bSmrg
17914b11b2bSmrg    /* mask alpha channel */
18014b11b2bSmrg    if (remove_alpha && PIXMAN_FORMAT_A (fmt))
18114b11b2bSmrg    {
18214b11b2bSmrg	uint32_t m;
18314b11b2bSmrg
18414b11b2bSmrg	if (PIXMAN_FORMAT_BPP (fmt) == 32)
18514b11b2bSmrg	    m = 0xffffffff;
18614b11b2bSmrg	else
18714b11b2bSmrg	    m = (1 << PIXMAN_FORMAT_BPP (fmt)) - 1;
18814b11b2bSmrg
18914b11b2bSmrg	m >>= PIXMAN_FORMAT_A (fmt);
19014b11b2bSmrg
19114b11b2bSmrg	if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_BGRA ||
19214b11b2bSmrg	    PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_RGBA ||
19314b11b2bSmrg	    PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_A)
19414b11b2bSmrg	{
19514b11b2bSmrg	    /* Alpha is at the bottom of the pixel */
19614b11b2bSmrg	    m <<= PIXMAN_FORMAT_A (fmt);
19714b11b2bSmrg	}
19814b11b2bSmrg
19914b11b2bSmrg	mask &= m;
20014b11b2bSmrg    }
20114b11b2bSmrg
20214b11b2bSmrg    /* mask rgb channels */
20314b11b2bSmrg    if (remove_rgb && PIXMAN_FORMAT_RGB (fmt))
20414b11b2bSmrg    {
20514b11b2bSmrg	uint32_t m = ((uint32_t)~0) >> (32 - PIXMAN_FORMAT_BPP (fmt));
20614b11b2bSmrg	uint32_t size = PIXMAN_FORMAT_R (fmt) + PIXMAN_FORMAT_G (fmt) + PIXMAN_FORMAT_B (fmt);
20714b11b2bSmrg
20814b11b2bSmrg	m &= ~((1 << size) - 1);
20914b11b2bSmrg
21014b11b2bSmrg	if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_BGRA ||
21114b11b2bSmrg	    PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_RGBA)
21214b11b2bSmrg	{
21314b11b2bSmrg	    /* RGB channels are at the top of the pixel */
21414b11b2bSmrg	    m >>= size;
21514b11b2bSmrg	}
21614b11b2bSmrg
21714b11b2bSmrg	mask &= m;
21814b11b2bSmrg    }
21914b11b2bSmrg
22014b11b2bSmrg    for (i = 0; i * PIXMAN_FORMAT_BPP (fmt) < 32; i++)
22114b11b2bSmrg	mask |= mask << (i * PIXMAN_FORMAT_BPP (fmt));
22214b11b2bSmrg
22314b11b2bSmrg    for (i = 0; i < stride * height / 4; i++)
22414b11b2bSmrg	data[i] &= mask;
22514b11b2bSmrg
22614b11b2bSmrg    /* swap endiannes in order to provide identical results on both big
22714b11b2bSmrg     * and litte endian systems
22814b11b2bSmrg     */
22914b11b2bSmrg    image_endian_swap (img);
23014b11b2bSmrg
23114b11b2bSmrg    return compute_crc32 (crc32, data, stride * height);
23214b11b2bSmrg}
23314b11b2bSmrg
23414b11b2bSmrguint32_t
23514b11b2bSmrgcompute_crc32_for_image (uint32_t        crc32,
23614b11b2bSmrg			 pixman_image_t *img)
23714b11b2bSmrg{
23814b11b2bSmrg    if (img->common.alpha_map)
23914b11b2bSmrg    {
24014b11b2bSmrg	crc32 = compute_crc32_for_image_internal (crc32, img, TRUE, FALSE);
24114b11b2bSmrg	crc32 = compute_crc32_for_image_internal (
24214b11b2bSmrg	    crc32, (pixman_image_t *)img->common.alpha_map, FALSE, TRUE);
24314b11b2bSmrg    }
24414b11b2bSmrg    else
24514b11b2bSmrg    {
24614b11b2bSmrg	crc32 = compute_crc32_for_image_internal (crc32, img, FALSE, FALSE);
24714b11b2bSmrg    }
24814b11b2bSmrg
24914b11b2bSmrg    return crc32;
25014b11b2bSmrg}
25114b11b2bSmrg
25214b11b2bSmrgvoid
25314b11b2bSmrgprint_image (pixman_image_t *image)
25414b11b2bSmrg{
25514b11b2bSmrg    int i, j;
25614b11b2bSmrg    int width, height, stride;
25714b11b2bSmrg    pixman_format_code_t format;
25814b11b2bSmrg    uint8_t *buffer;
25914b11b2bSmrg    int s;
26014b11b2bSmrg
26114b11b2bSmrg    width = pixman_image_get_width (image);
26214b11b2bSmrg    height = pixman_image_get_height (image);
26314b11b2bSmrg    stride = pixman_image_get_stride (image);
26414b11b2bSmrg    format = pixman_image_get_format (image);
26514b11b2bSmrg    buffer = (uint8_t *)pixman_image_get_data (image);
26614b11b2bSmrg
26714b11b2bSmrg    s = (stride >= 0)? stride : - stride;
26814b11b2bSmrg
26914b11b2bSmrg    printf ("---\n");
27014b11b2bSmrg    for (i = 0; i < height; i++)
27114b11b2bSmrg    {
27214b11b2bSmrg	for (j = 0; j < s; j++)
27314b11b2bSmrg	{
27414b11b2bSmrg	    if (j == (width * PIXMAN_FORMAT_BPP (format) + 7) / 8)
27514b11b2bSmrg		printf ("| ");
27614b11b2bSmrg
27714b11b2bSmrg	    printf ("%02X ", *((uint8_t *)buffer + i * stride + j));
27814b11b2bSmrg	}
27914b11b2bSmrg	printf ("\n");
28014b11b2bSmrg    }
28114b11b2bSmrg    printf ("---\n");
28214b11b2bSmrg}
28314b11b2bSmrg
28414b11b2bSmrg/* perform endian conversion of pixel data
28514b11b2bSmrg */
28614b11b2bSmrgvoid
28714b11b2bSmrgimage_endian_swap (pixman_image_t *img)
28814b11b2bSmrg{
28914b11b2bSmrg    int stride = pixman_image_get_stride (img);
29014b11b2bSmrg    uint32_t *data = pixman_image_get_data (img);
29114b11b2bSmrg    int height = pixman_image_get_height (img);
29214b11b2bSmrg    int bpp = PIXMAN_FORMAT_BPP (pixman_image_get_format (img));
29314b11b2bSmrg    int i, j;
29414b11b2bSmrg
29514b11b2bSmrg    /* swap bytes only on big endian systems */
29614b11b2bSmrg    if (is_little_endian())
29714b11b2bSmrg	return;
29814b11b2bSmrg
29914b11b2bSmrg    if (bpp == 8)
30014b11b2bSmrg	return;
30114b11b2bSmrg
30214b11b2bSmrg    for (i = 0; i < height; i++)
30314b11b2bSmrg    {
30414b11b2bSmrg	uint8_t *line_data = (uint8_t *)data + stride * i;
30514b11b2bSmrg	int s = (stride >= 0)? stride : - stride;
30614b11b2bSmrg
30714b11b2bSmrg	switch (bpp)
30814b11b2bSmrg	{
30914b11b2bSmrg	case 1:
31014b11b2bSmrg	    for (j = 0; j < s; j++)
31114b11b2bSmrg	    {
31214b11b2bSmrg		line_data[j] =
31314b11b2bSmrg		    ((line_data[j] & 0x80) >> 7) |
31414b11b2bSmrg		    ((line_data[j] & 0x40) >> 5) |
31514b11b2bSmrg		    ((line_data[j] & 0x20) >> 3) |
31614b11b2bSmrg		    ((line_data[j] & 0x10) >> 1) |
31714b11b2bSmrg		    ((line_data[j] & 0x08) << 1) |
31814b11b2bSmrg		    ((line_data[j] & 0x04) << 3) |
31914b11b2bSmrg		    ((line_data[j] & 0x02) << 5) |
32014b11b2bSmrg		    ((line_data[j] & 0x01) << 7);
32114b11b2bSmrg	    }
32214b11b2bSmrg	    break;
32314b11b2bSmrg	case 4:
32414b11b2bSmrg	    for (j = 0; j < s; j++)
32514b11b2bSmrg	    {
32614b11b2bSmrg		line_data[j] = (line_data[j] >> 4) | (line_data[j] << 4);
32714b11b2bSmrg	    }
32814b11b2bSmrg	    break;
32914b11b2bSmrg	case 16:
33014b11b2bSmrg	    for (j = 0; j + 2 <= s; j += 2)
33114b11b2bSmrg	    {
33214b11b2bSmrg		char t1 = line_data[j + 0];
33314b11b2bSmrg		char t2 = line_data[j + 1];
33414b11b2bSmrg
33514b11b2bSmrg		line_data[j + 1] = t1;
33614b11b2bSmrg		line_data[j + 0] = t2;
33714b11b2bSmrg	    }
33814b11b2bSmrg	    break;
33914b11b2bSmrg	case 24:
34014b11b2bSmrg	    for (j = 0; j + 3 <= s; j += 3)
34114b11b2bSmrg	    {
34214b11b2bSmrg		char t1 = line_data[j + 0];
34314b11b2bSmrg		char t2 = line_data[j + 1];
34414b11b2bSmrg		char t3 = line_data[j + 2];
34514b11b2bSmrg
34614b11b2bSmrg		line_data[j + 2] = t1;
34714b11b2bSmrg		line_data[j + 1] = t2;
34814b11b2bSmrg		line_data[j + 0] = t3;
34914b11b2bSmrg	    }
35014b11b2bSmrg	    break;
35114b11b2bSmrg	case 32:
35214b11b2bSmrg	    for (j = 0; j + 4 <= s; j += 4)
35314b11b2bSmrg	    {
35414b11b2bSmrg		char t1 = line_data[j + 0];
35514b11b2bSmrg		char t2 = line_data[j + 1];
35614b11b2bSmrg		char t3 = line_data[j + 2];
35714b11b2bSmrg		char t4 = line_data[j + 3];
35814b11b2bSmrg
35914b11b2bSmrg		line_data[j + 3] = t1;
36014b11b2bSmrg		line_data[j + 2] = t2;
36114b11b2bSmrg		line_data[j + 1] = t3;
36214b11b2bSmrg		line_data[j + 0] = t4;
36314b11b2bSmrg	    }
36414b11b2bSmrg	    break;
36514b11b2bSmrg	default:
36614b11b2bSmrg	    assert (FALSE);
36714b11b2bSmrg	    break;
36814b11b2bSmrg	}
36914b11b2bSmrg    }
37014b11b2bSmrg}
37114b11b2bSmrg
37214b11b2bSmrg#define N_LEADING_PROTECTED	10
37314b11b2bSmrg#define N_TRAILING_PROTECTED	10
37414b11b2bSmrg
37514b11b2bSmrgtypedef struct
37614b11b2bSmrg{
37714b11b2bSmrg    void *addr;
37814b11b2bSmrg    uint32_t len;
37914b11b2bSmrg    uint8_t *trailing;
38014b11b2bSmrg    int n_bytes;
38114b11b2bSmrg} info_t;
38214b11b2bSmrg
38314b11b2bSmrg#if FENCE_MALLOC_ACTIVE
38414b11b2bSmrg
38514b11b2bSmrgunsigned long
38614b11b2bSmrgfence_get_page_size ()
38714b11b2bSmrg{
38814b11b2bSmrg    /* You can fake a page size here, if you want to test e.g. 64 kB
38914b11b2bSmrg     * pages on a 4 kB page system. Just put a multiplier below.
39014b11b2bSmrg     */
39114b11b2bSmrg    return getpagesize ();
39214b11b2bSmrg}
39314b11b2bSmrg
39414b11b2bSmrg/* This is apparently necessary on at least OS X */
39514b11b2bSmrg#ifndef MAP_ANONYMOUS
39614b11b2bSmrg#define MAP_ANONYMOUS MAP_ANON
39714b11b2bSmrg#endif
39814b11b2bSmrg
39914b11b2bSmrgvoid *
40014b11b2bSmrgfence_malloc (int64_t len)
40114b11b2bSmrg{
40214b11b2bSmrg    unsigned long page_size = fence_get_page_size ();
40314b11b2bSmrg    unsigned long page_mask = page_size - 1;
40414b11b2bSmrg    uint32_t n_payload_bytes = (len + page_mask) & ~page_mask;
40514b11b2bSmrg    uint32_t n_bytes =
40614b11b2bSmrg	(page_size * (N_LEADING_PROTECTED + N_TRAILING_PROTECTED + 2) +
40714b11b2bSmrg	 n_payload_bytes) & ~page_mask;
40814b11b2bSmrg    uint8_t *initial_page;
40914b11b2bSmrg    uint8_t *leading_protected;
41014b11b2bSmrg    uint8_t *trailing_protected;
41114b11b2bSmrg    uint8_t *payload;
41214b11b2bSmrg    uint8_t *addr;
41314b11b2bSmrg
41414b11b2bSmrg    if (len < 0)
41514b11b2bSmrg	abort();
41614b11b2bSmrg
41714b11b2bSmrg    addr = mmap (NULL, n_bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
41814b11b2bSmrg		 -1, 0);
41914b11b2bSmrg
42014b11b2bSmrg    if (addr == MAP_FAILED)
42114b11b2bSmrg    {
42214b11b2bSmrg	printf ("mmap failed on %lld %u\n", (long long int)len, n_bytes);
42314b11b2bSmrg	return NULL;
42414b11b2bSmrg    }
42514b11b2bSmrg
42614b11b2bSmrg    initial_page = (uint8_t *)(((uintptr_t)addr + page_mask) & ~page_mask);
42714b11b2bSmrg    leading_protected = initial_page + page_size;
42814b11b2bSmrg    payload = leading_protected + N_LEADING_PROTECTED * page_size;
42914b11b2bSmrg    trailing_protected = payload + n_payload_bytes;
43014b11b2bSmrg
43114b11b2bSmrg    ((info_t *)initial_page)->addr = addr;
43214b11b2bSmrg    ((info_t *)initial_page)->len = len;
43314b11b2bSmrg    ((info_t *)initial_page)->trailing = trailing_protected;
43414b11b2bSmrg    ((info_t *)initial_page)->n_bytes = n_bytes;
43514b11b2bSmrg
43614b11b2bSmrg    if ((mprotect (leading_protected, N_LEADING_PROTECTED * page_size,
43714b11b2bSmrg		  PROT_NONE) == -1) ||
43814b11b2bSmrg	(mprotect (trailing_protected, N_TRAILING_PROTECTED * page_size,
43914b11b2bSmrg		  PROT_NONE) == -1))
44014b11b2bSmrg    {
44114b11b2bSmrg	munmap (addr, n_bytes);
44214b11b2bSmrg	return NULL;
44314b11b2bSmrg    }
44414b11b2bSmrg
44514b11b2bSmrg    return payload;
44614b11b2bSmrg}
44714b11b2bSmrg
44814b11b2bSmrgvoid
44914b11b2bSmrgfence_free (void *data)
45014b11b2bSmrg{
45114b11b2bSmrg    uint32_t page_size = fence_get_page_size ();
45214b11b2bSmrg    uint8_t *payload = data;
45314b11b2bSmrg    uint8_t *leading_protected = payload - N_LEADING_PROTECTED * page_size;
45414b11b2bSmrg    uint8_t *initial_page = leading_protected - page_size;
45514b11b2bSmrg    info_t *info = (info_t *)initial_page;
45614b11b2bSmrg
45714b11b2bSmrg    munmap (info->addr, info->n_bytes);
45814b11b2bSmrg}
45914b11b2bSmrg
46014b11b2bSmrgstatic void
46114b11b2bSmrgfence_image_destroy (pixman_image_t *image, void *data)
46214b11b2bSmrg{
46314b11b2bSmrg    fence_free (data);
46414b11b2bSmrg}
46514b11b2bSmrg
46614b11b2bSmrg/* Create an image with fence pages.
46714b11b2bSmrg *
46814b11b2bSmrg * Creates an image, where the data area is allocated with fence_malloc ().
46914b11b2bSmrg * Each row has an additional page in the stride.
47014b11b2bSmrg *
47114b11b2bSmrg * min_width is only a minimum width for the image. The width is aligned up
47214b11b2bSmrg * for the row size to be divisible by both page size and pixel size.
47314b11b2bSmrg *
47414b11b2bSmrg * If stride_fence is true, the additional page on each row will be
47514b11b2bSmrg * armed to cause SIGSEGV or SIGBUS on all accesses. This should catch
47614b11b2bSmrg * all accesses outside the valid row pixels.
47714b11b2bSmrg */
47814b11b2bSmrgpixman_image_t *
47914b11b2bSmrgfence_image_create_bits (pixman_format_code_t format,
48014b11b2bSmrg                         int min_width,
48114b11b2bSmrg                         int height,
48214b11b2bSmrg                         pixman_bool_t stride_fence)
48314b11b2bSmrg{
48414b11b2bSmrg    unsigned page_size = fence_get_page_size ();
48514b11b2bSmrg    unsigned page_mask = page_size - 1;
48614b11b2bSmrg    unsigned bitspp = PIXMAN_FORMAT_BPP (format);
48714b11b2bSmrg    unsigned bits_boundary;
48814b11b2bSmrg    unsigned row_bits;
48914b11b2bSmrg    int width;       /* pixels */
49014b11b2bSmrg    unsigned stride; /* bytes */
49114b11b2bSmrg    void *pixels;
49214b11b2bSmrg    pixman_image_t *image;
49314b11b2bSmrg    int i;
49414b11b2bSmrg
49514b11b2bSmrg    /* must be power of two */
49614b11b2bSmrg    assert (page_size && (page_size & page_mask) == 0);
49714b11b2bSmrg
49814b11b2bSmrg    if (bitspp < 1 || min_width < 1 || height < 1)
49914b11b2bSmrg        abort ();
50014b11b2bSmrg
50114b11b2bSmrg    /* least common multiple between page size * 8 and bitspp */
50214b11b2bSmrg    bits_boundary = bitspp;
50314b11b2bSmrg    while (! (bits_boundary & 1))
50414b11b2bSmrg        bits_boundary >>= 1;
50514b11b2bSmrg    bits_boundary *= page_size * 8;
50614b11b2bSmrg
50714b11b2bSmrg    /* round up to bits_boundary */
50814b11b2bSmrg    row_bits = ROUND_UP ( (unsigned)min_width * bitspp, bits_boundary);
50914b11b2bSmrg    width = row_bits / bitspp;
51014b11b2bSmrg
51114b11b2bSmrg    stride = row_bits / 8;
51214b11b2bSmrg    if (stride_fence)
51314b11b2bSmrg        stride += page_size; /* add fence page */
51414b11b2bSmrg
51514b11b2bSmrg    if (UINT_MAX / stride < (unsigned)height)
51614b11b2bSmrg        abort ();
51714b11b2bSmrg
51814b11b2bSmrg    pixels = fence_malloc (stride * (unsigned)height);
51914b11b2bSmrg    if (!pixels)
52014b11b2bSmrg        return NULL;
52114b11b2bSmrg
52214b11b2bSmrg    if (stride_fence)
52314b11b2bSmrg    {
52414b11b2bSmrg        uint8_t *guard = (uint8_t *)pixels + stride - page_size;
52514b11b2bSmrg
52614b11b2bSmrg        /* arm row end fence pages */
52714b11b2bSmrg        for (i = 0; i < height; i++)
52814b11b2bSmrg        {
52914b11b2bSmrg            if (mprotect (guard + i * stride, page_size, PROT_NONE) == -1)
53014b11b2bSmrg                goto out_fail;
53114b11b2bSmrg        }
53214b11b2bSmrg    }
53314b11b2bSmrg
53414b11b2bSmrg    assert (width >= min_width);
53514b11b2bSmrg
53614b11b2bSmrg    image = pixman_image_create_bits_no_clear (format, width, height,
53714b11b2bSmrg                                               pixels, stride);
53814b11b2bSmrg    if (!image)
53914b11b2bSmrg        goto out_fail;
54014b11b2bSmrg
54114b11b2bSmrg    pixman_image_set_destroy_function (image, fence_image_destroy, pixels);
54214b11b2bSmrg
54314b11b2bSmrg    return image;
54414b11b2bSmrg
54514b11b2bSmrgout_fail:
54614b11b2bSmrg    fence_free (pixels);
54714b11b2bSmrg
54814b11b2bSmrg    return NULL;
54914b11b2bSmrg}
55014b11b2bSmrg
55114b11b2bSmrg#else /* FENCE_MALLOC_ACTIVE */
55214b11b2bSmrg
55314b11b2bSmrgvoid *
55414b11b2bSmrgfence_malloc (int64_t len)
55514b11b2bSmrg{
55614b11b2bSmrg    return malloc (len);
55714b11b2bSmrg}
55814b11b2bSmrg
55914b11b2bSmrgvoid
56014b11b2bSmrgfence_free (void *data)
56114b11b2bSmrg{
56214b11b2bSmrg    free (data);
56314b11b2bSmrg}
56414b11b2bSmrg
56514b11b2bSmrgpixman_image_t *
56614b11b2bSmrgfence_image_create_bits (pixman_format_code_t format,
56714b11b2bSmrg                         int min_width,
56814b11b2bSmrg                         int height,
56914b11b2bSmrg                         pixman_bool_t stride_fence)
57014b11b2bSmrg{
57114b11b2bSmrg    return pixman_image_create_bits (format, min_width, height, NULL, 0);
57214b11b2bSmrg    /* Implicitly allocated storage does not need a destroy function
57314b11b2bSmrg     * to get freed on refcount hitting zero.
57414b11b2bSmrg     */
57514b11b2bSmrg}
57614b11b2bSmrg
57714b11b2bSmrgunsigned long
57814b11b2bSmrgfence_get_page_size ()
57914b11b2bSmrg{
58014b11b2bSmrg    return 0;
58114b11b2bSmrg}
58214b11b2bSmrg
58314b11b2bSmrg#endif /* FENCE_MALLOC_ACTIVE */
58414b11b2bSmrg
58514b11b2bSmrguint8_t *
58614b11b2bSmrgmake_random_bytes (int n_bytes)
58714b11b2bSmrg{
58814b11b2bSmrg    uint8_t *bytes = fence_malloc (n_bytes);
58914b11b2bSmrg
59014b11b2bSmrg    if (!bytes)
59114b11b2bSmrg	return NULL;
59214b11b2bSmrg
59314b11b2bSmrg    prng_randmemset (bytes, n_bytes, 0);
59414b11b2bSmrg
59514b11b2bSmrg    return bytes;
59614b11b2bSmrg}
59714b11b2bSmrg
59814b11b2bSmrgfloat *
59914b11b2bSmrgmake_random_floats (int n_bytes)
60014b11b2bSmrg{
60114b11b2bSmrg    uint8_t *bytes = fence_malloc (n_bytes);
60214b11b2bSmrg    float *vals = (float *)bytes;
60314b11b2bSmrg
60414b11b2bSmrg    if (!bytes)
60514b11b2bSmrg	return 0;
60614b11b2bSmrg
60714b11b2bSmrg    for (n_bytes /= 4; n_bytes; vals++, n_bytes--)
60814b11b2bSmrg	*vals = (float)rand() / (float)RAND_MAX;
60914b11b2bSmrg
61014b11b2bSmrg    return (float *)bytes;
61114b11b2bSmrg}
61214b11b2bSmrg
61314b11b2bSmrgvoid
61414b11b2bSmrga8r8g8b8_to_rgba_np (uint32_t *dst, uint32_t *src, int n_pixels)
61514b11b2bSmrg{
61614b11b2bSmrg    uint8_t *dst8 = (uint8_t *)dst;
61714b11b2bSmrg    int i;
61814b11b2bSmrg
61914b11b2bSmrg    for (i = 0; i < n_pixels; ++i)
62014b11b2bSmrg    {
62114b11b2bSmrg	uint32_t p = src[i];
62214b11b2bSmrg	uint8_t a, r, g, b;
62314b11b2bSmrg
62414b11b2bSmrg	a = (p & 0xff000000) >> 24;
62514b11b2bSmrg	r = (p & 0x00ff0000) >> 16;
62614b11b2bSmrg	g = (p & 0x0000ff00) >> 8;
62714b11b2bSmrg	b = (p & 0x000000ff) >> 0;
62814b11b2bSmrg
62914b11b2bSmrg	if (a != 0)
63014b11b2bSmrg	{
63114b11b2bSmrg#define DIVIDE(c, a)							\
63214b11b2bSmrg	    do								\
63314b11b2bSmrg	    {								\
63414b11b2bSmrg		int t = ((c) * 255) / a;				\
63514b11b2bSmrg		(c) = t < 0? 0 : t > 255? 255 : t;			\
63614b11b2bSmrg	    } while (0)
63714b11b2bSmrg
63814b11b2bSmrg	    DIVIDE (r, a);
63914b11b2bSmrg	    DIVIDE (g, a);
64014b11b2bSmrg	    DIVIDE (b, a);
64114b11b2bSmrg	}
64214b11b2bSmrg
64314b11b2bSmrg	*dst8++ = r;
64414b11b2bSmrg	*dst8++ = g;
64514b11b2bSmrg	*dst8++ = b;
64614b11b2bSmrg	*dst8++ = a;
64714b11b2bSmrg    }
64814b11b2bSmrg}
64914b11b2bSmrg
65014b11b2bSmrg#ifdef HAVE_LIBPNG
65114b11b2bSmrg
65214b11b2bSmrgpixman_bool_t
65314b11b2bSmrgwrite_png (pixman_image_t *image, const char *filename)
65414b11b2bSmrg{
65514b11b2bSmrg    int width = pixman_image_get_width (image);
65614b11b2bSmrg    int height = pixman_image_get_height (image);
65714b11b2bSmrg    int stride = width * 4;
65814b11b2bSmrg    uint32_t *data = malloc (height * stride);
65914b11b2bSmrg    pixman_image_t *copy;
66014b11b2bSmrg    png_struct *write_struct;
66114b11b2bSmrg    png_info *info_struct;
66214b11b2bSmrg    pixman_bool_t result = FALSE;
66314b11b2bSmrg    FILE *f = fopen (filename, "wb");
66414b11b2bSmrg    png_bytep *row_pointers;
66514b11b2bSmrg    int i;
66614b11b2bSmrg
66714b11b2bSmrg    if (!f)
66814b11b2bSmrg	return FALSE;
66914b11b2bSmrg
67014b11b2bSmrg    row_pointers = malloc (height * sizeof (png_bytep));
67114b11b2bSmrg
67214b11b2bSmrg    copy = pixman_image_create_bits (
67314b11b2bSmrg	PIXMAN_a8r8g8b8, width, height, data, stride);
67414b11b2bSmrg
67514b11b2bSmrg    pixman_image_composite32 (
67614b11b2bSmrg	PIXMAN_OP_SRC, image, NULL, copy, 0, 0, 0, 0, 0, 0, width, height);
67714b11b2bSmrg
67814b11b2bSmrg    a8r8g8b8_to_rgba_np (data, data, height * width);
67914b11b2bSmrg
68014b11b2bSmrg    for (i = 0; i < height; ++i)
68114b11b2bSmrg	row_pointers[i] = (png_bytep)(data + i * width);
68214b11b2bSmrg
68314b11b2bSmrg    if (!(write_struct = png_create_write_struct (
68414b11b2bSmrg	      PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)))
68514b11b2bSmrg	goto out1;
68614b11b2bSmrg
68714b11b2bSmrg    if (!(info_struct = png_create_info_struct (write_struct)))
68814b11b2bSmrg	goto out2;
68914b11b2bSmrg
69014b11b2bSmrg    png_init_io (write_struct, f);
69114b11b2bSmrg
69214b11b2bSmrg    png_set_IHDR (write_struct, info_struct, width, height,
69314b11b2bSmrg		  8, PNG_COLOR_TYPE_RGB_ALPHA,
69414b11b2bSmrg		  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
69514b11b2bSmrg		  PNG_FILTER_TYPE_BASE);
69614b11b2bSmrg
69714b11b2bSmrg    png_write_info (write_struct, info_struct);
69814b11b2bSmrg
69914b11b2bSmrg    png_write_image (write_struct, row_pointers);
70014b11b2bSmrg
70114b11b2bSmrg    png_write_end (write_struct, NULL);
70214b11b2bSmrg
70314b11b2bSmrg    result = TRUE;
70414b11b2bSmrg
70514b11b2bSmrgout2:
70614b11b2bSmrg    png_destroy_write_struct (&write_struct, &info_struct);
70714b11b2bSmrg
70814b11b2bSmrgout1:
70914b11b2bSmrg    if (fclose (f) != 0)
71014b11b2bSmrg	result = FALSE;
71114b11b2bSmrg
71214b11b2bSmrg    pixman_image_unref (copy);
71314b11b2bSmrg    free (row_pointers);
71414b11b2bSmrg    free (data);
71514b11b2bSmrg    return result;
71614b11b2bSmrg}
71714b11b2bSmrg
71814b11b2bSmrg#else /* no libpng */
71914b11b2bSmrg
72014b11b2bSmrgpixman_bool_t
72114b11b2bSmrgwrite_png (pixman_image_t *image, const char *filename)
72214b11b2bSmrg{
72314b11b2bSmrg    return FALSE;
72414b11b2bSmrg}
72514b11b2bSmrg
72614b11b2bSmrg#endif
72714b11b2bSmrg
72814b11b2bSmrgstatic void
72914b11b2bSmrgcolor8_to_color16 (uint32_t color8, pixman_color_t *color16)
73014b11b2bSmrg{
73114b11b2bSmrg    color16->alpha = ((color8 & 0xff000000) >> 24);
73214b11b2bSmrg    color16->red =   ((color8 & 0x00ff0000) >> 16);
73314b11b2bSmrg    color16->green = ((color8 & 0x0000ff00) >> 8);
73414b11b2bSmrg    color16->blue =  ((color8 & 0x000000ff) >> 0);
73514b11b2bSmrg
73614b11b2bSmrg    color16->alpha |= color16->alpha << 8;
73714b11b2bSmrg    color16->red   |= color16->red << 8;
73814b11b2bSmrg    color16->blue  |= color16->blue << 8;
73914b11b2bSmrg    color16->green |= color16->green << 8;
74014b11b2bSmrg}
74114b11b2bSmrg
74214b11b2bSmrgvoid
74314b11b2bSmrgdraw_checkerboard (pixman_image_t *image,
74414b11b2bSmrg		   int check_size,
74514b11b2bSmrg		   uint32_t color1, uint32_t color2)
74614b11b2bSmrg{
74714b11b2bSmrg    pixman_color_t check1, check2;
74814b11b2bSmrg    pixman_image_t *c1, *c2;
74914b11b2bSmrg    int n_checks_x, n_checks_y;
75014b11b2bSmrg    int i, j;
75114b11b2bSmrg
75214b11b2bSmrg    color8_to_color16 (color1, &check1);
75314b11b2bSmrg    color8_to_color16 (color2, &check2);
75414b11b2bSmrg
75514b11b2bSmrg    c1 = pixman_image_create_solid_fill (&check1);
75614b11b2bSmrg    c2 = pixman_image_create_solid_fill (&check2);
75714b11b2bSmrg
75814b11b2bSmrg    n_checks_x = (
75914b11b2bSmrg	pixman_image_get_width (image) + check_size - 1) / check_size;
76014b11b2bSmrg    n_checks_y = (
76114b11b2bSmrg	pixman_image_get_height (image) + check_size - 1) / check_size;
76214b11b2bSmrg
76314b11b2bSmrg    for (j = 0; j < n_checks_y; j++)
76414b11b2bSmrg    {
76514b11b2bSmrg	for (i = 0; i < n_checks_x; i++)
76614b11b2bSmrg	{
76714b11b2bSmrg	    pixman_image_t *src;
76814b11b2bSmrg
76914b11b2bSmrg	    if (((i ^ j) & 1))
77014b11b2bSmrg		src = c1;
77114b11b2bSmrg	    else
77214b11b2bSmrg		src = c2;
77314b11b2bSmrg
77414b11b2bSmrg	    pixman_image_composite32 (PIXMAN_OP_SRC, src, NULL, image,
77514b11b2bSmrg				      0, 0, 0, 0,
77614b11b2bSmrg				      i * check_size, j * check_size,
77714b11b2bSmrg				      check_size, check_size);
77814b11b2bSmrg	}
77914b11b2bSmrg    }
78014b11b2bSmrg}
78114b11b2bSmrg
78214b11b2bSmrgstatic uint32_t
78314b11b2bSmrgcall_test_function (uint32_t    (*test_function)(int testnum, int verbose),
78414b11b2bSmrg		    int		testnum,
78514b11b2bSmrg		    int		verbose)
78614b11b2bSmrg{
78714b11b2bSmrg    uint32_t retval;
78814b11b2bSmrg
78914b11b2bSmrg#if defined (__GNUC__) && defined (_WIN32) && (defined (__i386) || defined (__i386__))
79014b11b2bSmrg    __asm__ (
79114b11b2bSmrg	/* Deliberately avoid aligning the stack to 16 bytes */
79214b11b2bSmrg	"pushl	%1\n\t"
79314b11b2bSmrg	"pushl	%2\n\t"
79414b11b2bSmrg	"call	*%3\n\t"
79514b11b2bSmrg	"addl	$8, %%esp\n\t"
79614b11b2bSmrg	: "=a" (retval)
79714b11b2bSmrg	: "r" (verbose),
79814b11b2bSmrg	  "r" (testnum),
79914b11b2bSmrg	  "r" (test_function)
80014b11b2bSmrg	: "edx", "ecx"); /* caller save registers */
80114b11b2bSmrg#else
80214b11b2bSmrg    retval = test_function (testnum, verbose);
80314b11b2bSmrg#endif
80414b11b2bSmrg
80514b11b2bSmrg    return retval;
80614b11b2bSmrg}
80714b11b2bSmrg
80814b11b2bSmrg/*
80914b11b2bSmrg * A function, which can be used as a core part of the test programs,
81014b11b2bSmrg * intended to detect various problems with the help of fuzzing input
81114b11b2bSmrg * to pixman API (according to some templates, aka "smart" fuzzing).
81214b11b2bSmrg * Some general information about such testing can be found here:
81314b11b2bSmrg * http://en.wikipedia.org/wiki/Fuzz_testing
81414b11b2bSmrg *
81514b11b2bSmrg * It may help detecting:
81614b11b2bSmrg *  - crashes on bad handling of valid or reasonably invalid input to
81714b11b2bSmrg *    pixman API.
81814b11b2bSmrg *  - deviations from the behavior of older pixman releases.
81914b11b2bSmrg *  - deviations from the behavior of the same pixman release, but
82014b11b2bSmrg *    configured in a different way (for example with SIMD optimizations
82114b11b2bSmrg *    disabled), or running on a different OS or hardware.
82214b11b2bSmrg *
82314b11b2bSmrg * The test is performed by calling a callback function a huge number
82414b11b2bSmrg * of times. The callback function is expected to run some snippet of
82514b11b2bSmrg * pixman code with pseudorandom variations to the data feeded to
82614b11b2bSmrg * pixman API. A result of running each callback function should be
82714b11b2bSmrg * some deterministic value which depends on test number (test number
82814b11b2bSmrg * can be used as a seed for PRNG). When 'verbose' argument is nonzero,
82914b11b2bSmrg * callback function is expected to print to stdout some information
83014b11b2bSmrg * about what it does.
83114b11b2bSmrg *
83214b11b2bSmrg * Return values from many small tests are accumulated together and
83314b11b2bSmrg * used as final checksum, which can be compared to some expected
83414b11b2bSmrg * value. Running the tests not individually, but in a batch helps
83514b11b2bSmrg * to reduce process start overhead and also allows to parallelize
83614b11b2bSmrg * testing and utilize multiple CPU cores.
83714b11b2bSmrg *
83814b11b2bSmrg * The resulting executable can be run without any arguments. In
83914b11b2bSmrg * this case it runs a batch of tests starting from 1 and up to
84014b11b2bSmrg * 'default_number_of_iterations'. The resulting checksum is
84114b11b2bSmrg * compared with 'expected_checksum' and FAIL or PASS verdict
84214b11b2bSmrg * depends on the result of this comparison.
84314b11b2bSmrg *
84414b11b2bSmrg * If the executable is run with 2 numbers provided as command line
84514b11b2bSmrg * arguments, they specify the starting and ending numbers for a test
84614b11b2bSmrg * batch.
84714b11b2bSmrg *
84814b11b2bSmrg * If the executable is run with only one number provided as a command
84914b11b2bSmrg * line argument, then this number is used to call the callback function
85014b11b2bSmrg * once, and also with verbose flag set.
85114b11b2bSmrg */
85214b11b2bSmrgint
85314b11b2bSmrgfuzzer_test_main (const char *test_name,
85414b11b2bSmrg		  int         default_number_of_iterations,
85514b11b2bSmrg		  uint32_t    expected_checksum,
85614b11b2bSmrg		  uint32_t    (*test_function)(int testnum, int verbose),
85714b11b2bSmrg		  int         argc,
85814b11b2bSmrg		  const char *argv[])
85914b11b2bSmrg{
86014b11b2bSmrg    int i, n1 = 1, n2 = 0;
86114b11b2bSmrg    uint32_t checksum = 0;
86214b11b2bSmrg    int verbose = getenv ("VERBOSE") != NULL;
86314b11b2bSmrg
86414b11b2bSmrg    if (argc >= 3)
86514b11b2bSmrg    {
86614b11b2bSmrg	n1 = atoi (argv[1]);
86714b11b2bSmrg	n2 = atoi (argv[2]);
86814b11b2bSmrg	if (n2 < n1)
86914b11b2bSmrg	{
87014b11b2bSmrg	    printf ("invalid test range\n");
87114b11b2bSmrg	    return 1;
87214b11b2bSmrg	}
87314b11b2bSmrg    }
87414b11b2bSmrg    else if (argc >= 2)
87514b11b2bSmrg    {
87614b11b2bSmrg	n2 = atoi (argv[1]);
87714b11b2bSmrg
87814b11b2bSmrg	checksum = call_test_function (test_function, n2, 1);
87914b11b2bSmrg
88014b11b2bSmrg	printf ("%d: checksum=%08X\n", n2, checksum);
88114b11b2bSmrg	return 0;
88214b11b2bSmrg    }
88314b11b2bSmrg    else
88414b11b2bSmrg    {
88514b11b2bSmrg	n1 = 1;
88614b11b2bSmrg	n2 = default_number_of_iterations;
88714b11b2bSmrg    }
88814b11b2bSmrg
88914b11b2bSmrg#ifdef USE_OPENMP
89014b11b2bSmrg    #pragma omp parallel for reduction(+:checksum) default(none) \
89114b11b2bSmrg					shared(n1, n2, test_function, verbose)
89214b11b2bSmrg#endif
89314b11b2bSmrg    for (i = n1; i <= n2; i++)
89414b11b2bSmrg    {
89514b11b2bSmrg	uint32_t crc = call_test_function (test_function, i, 0);
89614b11b2bSmrg	if (verbose)
89714b11b2bSmrg	    printf ("%d: %08X\n", i, crc);
89814b11b2bSmrg	checksum += crc;
89914b11b2bSmrg    }
90014b11b2bSmrg
90114b11b2bSmrg    if (n1 == 1 && n2 == default_number_of_iterations)
90214b11b2bSmrg    {
90314b11b2bSmrg	if (checksum == expected_checksum)
90414b11b2bSmrg	{
90514b11b2bSmrg	    printf ("%s test passed (checksum=%08X)\n",
90614b11b2bSmrg		    test_name, checksum);
90714b11b2bSmrg	}
90814b11b2bSmrg	else
90914b11b2bSmrg	{
91014b11b2bSmrg	    printf ("%s test failed! (checksum=%08X, expected %08X)\n",
91114b11b2bSmrg		    test_name, checksum, expected_checksum);
91214b11b2bSmrg	    return 1;
91314b11b2bSmrg	}
91414b11b2bSmrg    }
91514b11b2bSmrg    else
91614b11b2bSmrg    {
91714b11b2bSmrg	printf ("%d-%d: checksum=%08X\n", n1, n2, checksum);
91814b11b2bSmrg    }
91914b11b2bSmrg
92014b11b2bSmrg    return 0;
92114b11b2bSmrg}
92214b11b2bSmrg
92314b11b2bSmrg/* Try to obtain current time in seconds */
92414b11b2bSmrgdouble
92514b11b2bSmrggettime (void)
92614b11b2bSmrg{
92714b11b2bSmrg#ifdef HAVE_GETTIMEOFDAY
92814b11b2bSmrg    struct timeval tv;
92914b11b2bSmrg
93014b11b2bSmrg    gettimeofday (&tv, NULL);
93114b11b2bSmrg    return (double)((int64_t)tv.tv_sec * 1000000 + tv.tv_usec) / 1000000.;
93214b11b2bSmrg#else
93314b11b2bSmrg    return (double)clock() / (double)CLOCKS_PER_SEC;
93414b11b2bSmrg#endif
93514b11b2bSmrg}
93614b11b2bSmrg
93714b11b2bSmrguint32_t
93814b11b2bSmrgget_random_seed (void)
93914b11b2bSmrg{
94014b11b2bSmrg    union { double d; uint32_t u32; } t;
94114b11b2bSmrg    t.d = gettime();
94214b11b2bSmrg    prng_srand (t.u32);
94314b11b2bSmrg
94414b11b2bSmrg    return prng_rand ();
94514b11b2bSmrg}
94614b11b2bSmrg
94714b11b2bSmrg#ifdef HAVE_SIGACTION
94814b11b2bSmrg#ifdef HAVE_ALARM
94914b11b2bSmrgstatic const char *global_msg;
95014b11b2bSmrg
95114b11b2bSmrgstatic void
95214b11b2bSmrgon_alarm (int signo)
95314b11b2bSmrg{
95414b11b2bSmrg    printf ("%s\n", global_msg);
95514b11b2bSmrg    exit (1);
95614b11b2bSmrg}
95714b11b2bSmrg#endif
95814b11b2bSmrg#endif
95914b11b2bSmrg
96014b11b2bSmrgvoid
96114b11b2bSmrgfail_after (int seconds, const char *msg)
96214b11b2bSmrg{
96314b11b2bSmrg#ifdef HAVE_SIGACTION
96414b11b2bSmrg#ifdef HAVE_ALARM
96514b11b2bSmrg    struct sigaction action;
96614b11b2bSmrg
96714b11b2bSmrg    global_msg = msg;
96814b11b2bSmrg
96914b11b2bSmrg    memset (&action, 0, sizeof (action));
97014b11b2bSmrg    action.sa_handler = on_alarm;
97114b11b2bSmrg
97214b11b2bSmrg    alarm (seconds);
97314b11b2bSmrg
97414b11b2bSmrg    sigaction (SIGALRM, &action, NULL);
97514b11b2bSmrg#endif
97614b11b2bSmrg#endif
97714b11b2bSmrg}
97814b11b2bSmrg
97914b11b2bSmrgvoid
98014b11b2bSmrgenable_divbyzero_exceptions (void)
98114b11b2bSmrg{
98214b11b2bSmrg#ifdef HAVE_FENV_H
98314b11b2bSmrg#ifdef HAVE_FEENABLEEXCEPT
98414b11b2bSmrg#ifdef HAVE_FEDIVBYZERO
98514b11b2bSmrg    feenableexcept (FE_DIVBYZERO);
98614b11b2bSmrg#endif
98714b11b2bSmrg#endif
98814b11b2bSmrg#endif
98914b11b2bSmrg}
99014b11b2bSmrg
99114b11b2bSmrgvoid
99214b11b2bSmrgenable_invalid_exceptions (void)
99314b11b2bSmrg{
99414b11b2bSmrg#ifdef HAVE_FENV_H
99514b11b2bSmrg#ifdef HAVE_FEENABLEEXCEPT
99614b11b2bSmrg#ifdef FE_INVALID
99714b11b2bSmrg    feenableexcept (FE_INVALID);
99814b11b2bSmrg#endif
99914b11b2bSmrg#endif
100014b11b2bSmrg#endif
100114b11b2bSmrg}
100214b11b2bSmrg
100314b11b2bSmrgvoid *
100414b11b2bSmrgaligned_malloc (size_t align, size_t size)
100514b11b2bSmrg{
100614b11b2bSmrg    void *result;
100714b11b2bSmrg
100814b11b2bSmrg#ifdef HAVE_POSIX_MEMALIGN
100914b11b2bSmrg    if (posix_memalign (&result, align, size) != 0)
101014b11b2bSmrg      result = NULL;
101114b11b2bSmrg#else
101214b11b2bSmrg    result = malloc (size);
101314b11b2bSmrg#endif
101414b11b2bSmrg
101514b11b2bSmrg    return result;
101614b11b2bSmrg}
101714b11b2bSmrg
101814b11b2bSmrg#define CONVERT_15(c, is_rgb)						\
101914b11b2bSmrg    (is_rgb?								\
102014b11b2bSmrg     ((((c) >> 3) & 0x001f) |						\
102114b11b2bSmrg      (((c) >> 6) & 0x03e0) |						\
102214b11b2bSmrg      (((c) >> 9) & 0x7c00)) :						\
102314b11b2bSmrg     (((((c) >> 16) & 0xff) * 153 +					\
102414b11b2bSmrg       (((c) >>  8) & 0xff) * 301 +					\
102514b11b2bSmrg       (((c)      ) & 0xff) * 58) >> 2))
102614b11b2bSmrg
102714b11b2bSmrgdouble
102814b11b2bSmrgconvert_srgb_to_linear (double c)
102914b11b2bSmrg{
103014b11b2bSmrg    if (c <= 0.04045)
103114b11b2bSmrg        return c / 12.92;
103214b11b2bSmrg    else
103314b11b2bSmrg        return pow ((c + 0.055) / 1.055, 2.4);
103414b11b2bSmrg}
103514b11b2bSmrg
103614b11b2bSmrgdouble
103714b11b2bSmrgconvert_linear_to_srgb (double c)
103814b11b2bSmrg{
103914b11b2bSmrg    if (c <= 0.0031308)
104014b11b2bSmrg        return c * 12.92;
104114b11b2bSmrg    else
104214b11b2bSmrg        return 1.055 * pow (c, 1.0/2.4) - 0.055;
104314b11b2bSmrg}
104414b11b2bSmrg
104514b11b2bSmrgvoid
104614b11b2bSmrginitialize_palette (pixman_indexed_t *palette, uint32_t depth, int is_rgb)
104714b11b2bSmrg{
104814b11b2bSmrg    int i;
104914b11b2bSmrg    uint32_t mask = (1 << depth) - 1;
105014b11b2bSmrg
105114b11b2bSmrg    for (i = 0; i < 32768; ++i)
105214b11b2bSmrg	palette->ent[i] = prng_rand() & mask;
105314b11b2bSmrg
105414b11b2bSmrg    memset (palette->rgba, 0, sizeof (palette->rgba));
105514b11b2bSmrg
105614b11b2bSmrg    for (i = 0; i < mask + 1; ++i)
105714b11b2bSmrg    {
105814b11b2bSmrg	uint32_t rgba24;
105914b11b2bSmrg 	pixman_bool_t retry;
106014b11b2bSmrg	uint32_t i15;
106114b11b2bSmrg
106214b11b2bSmrg	/* We filled the rgb->index map with random numbers, but we
106314b11b2bSmrg	 * do need the ability to round trip, that is if some indexed
106414b11b2bSmrg	 * color expands to an argb24, then the 15 bit version of that
106514b11b2bSmrg	 * color must map back to the index. Anything else, we don't
106614b11b2bSmrg	 * care about too much.
106714b11b2bSmrg	 */
106814b11b2bSmrg	do
106914b11b2bSmrg	{
107014b11b2bSmrg	    uint32_t old_idx;
107114b11b2bSmrg
107214b11b2bSmrg	    rgba24 = prng_rand();
107314b11b2bSmrg	    i15 = CONVERT_15 (rgba24, is_rgb);
107414b11b2bSmrg
107514b11b2bSmrg	    old_idx = palette->ent[i15];
107614b11b2bSmrg	    if (CONVERT_15 (palette->rgba[old_idx], is_rgb) == i15)
107714b11b2bSmrg		retry = 1;
107814b11b2bSmrg	    else
107914b11b2bSmrg		retry = 0;
108014b11b2bSmrg	} while (retry);
108114b11b2bSmrg
108214b11b2bSmrg	palette->rgba[i] = rgba24;
108314b11b2bSmrg	palette->ent[i15] = i;
108414b11b2bSmrg    }
108514b11b2bSmrg
108614b11b2bSmrg    for (i = 0; i < mask + 1; ++i)
108714b11b2bSmrg    {
108814b11b2bSmrg	assert (palette->ent[CONVERT_15 (palette->rgba[i], is_rgb)] == i);
108914b11b2bSmrg    }
109014b11b2bSmrg}
109114b11b2bSmrg
109214b11b2bSmrgstruct operator_entry {
109314b11b2bSmrg    pixman_op_t		 op;
109414b11b2bSmrg    const char		*name;
109514b11b2bSmrg    pixman_bool_t	 is_alias;
109614b11b2bSmrg};
109714b11b2bSmrg
109814b11b2bSmrgtypedef struct operator_entry operator_entry_t;
109914b11b2bSmrg
110014b11b2bSmrgstatic const operator_entry_t op_list[] =
110114b11b2bSmrg{
110214b11b2bSmrg#define ENTRY(op)							\
110314b11b2bSmrg    { PIXMAN_OP_##op, "PIXMAN_OP_" #op, FALSE }
110414b11b2bSmrg#define ALIAS(op, nam)							\
110514b11b2bSmrg    { PIXMAN_OP_##op, nam, TRUE }
110614b11b2bSmrg
110714b11b2bSmrg    /* operator_name () will return the first hit in this table,
110814b11b2bSmrg     * so keep the list properly ordered between entries and aliases.
110914b11b2bSmrg     * Aliases are not listed by list_operators ().
111014b11b2bSmrg     */
111114b11b2bSmrg
111214b11b2bSmrg    ENTRY (CLEAR),
111314b11b2bSmrg    ENTRY (SRC),
111414b11b2bSmrg    ENTRY (DST),
111514b11b2bSmrg    ENTRY (OVER),
111614b11b2bSmrg    ENTRY (OVER_REVERSE),
111714b11b2bSmrg    ALIAS (OVER_REVERSE,		"overrev"),
111814b11b2bSmrg    ENTRY (IN),
111914b11b2bSmrg    ENTRY (IN_REVERSE),
112014b11b2bSmrg    ALIAS (IN_REVERSE,			"inrev"),
112114b11b2bSmrg    ENTRY (OUT),
112214b11b2bSmrg    ENTRY (OUT_REVERSE),
112314b11b2bSmrg    ALIAS (OUT_REVERSE,			"outrev"),
112414b11b2bSmrg    ENTRY (ATOP),
112514b11b2bSmrg    ENTRY (ATOP_REVERSE),
112614b11b2bSmrg    ALIAS (ATOP_REVERSE,		"atoprev"),
112714b11b2bSmrg    ENTRY (XOR),
112814b11b2bSmrg    ENTRY (ADD),
112914b11b2bSmrg    ENTRY (SATURATE),
113014b11b2bSmrg
113114b11b2bSmrg    ENTRY (DISJOINT_CLEAR),
113214b11b2bSmrg    ENTRY (DISJOINT_SRC),
113314b11b2bSmrg    ENTRY (DISJOINT_DST),
113414b11b2bSmrg    ENTRY (DISJOINT_OVER),
113514b11b2bSmrg    ENTRY (DISJOINT_OVER_REVERSE),
113614b11b2bSmrg    ENTRY (DISJOINT_IN),
113714b11b2bSmrg    ENTRY (DISJOINT_IN_REVERSE),
113814b11b2bSmrg    ENTRY (DISJOINT_OUT),
113914b11b2bSmrg    ENTRY (DISJOINT_OUT_REVERSE),
114014b11b2bSmrg    ENTRY (DISJOINT_ATOP),
114114b11b2bSmrg    ENTRY (DISJOINT_ATOP_REVERSE),
114214b11b2bSmrg    ENTRY (DISJOINT_XOR),
114314b11b2bSmrg
114414b11b2bSmrg    ENTRY (CONJOINT_CLEAR),
114514b11b2bSmrg    ENTRY (CONJOINT_SRC),
114614b11b2bSmrg    ENTRY (CONJOINT_DST),
114714b11b2bSmrg    ENTRY (CONJOINT_OVER),
114814b11b2bSmrg    ENTRY (CONJOINT_OVER_REVERSE),
114914b11b2bSmrg    ENTRY (CONJOINT_IN),
115014b11b2bSmrg    ENTRY (CONJOINT_IN_REVERSE),
115114b11b2bSmrg    ENTRY (CONJOINT_OUT),
115214b11b2bSmrg    ENTRY (CONJOINT_OUT_REVERSE),
115314b11b2bSmrg    ENTRY (CONJOINT_ATOP),
115414b11b2bSmrg    ENTRY (CONJOINT_ATOP_REVERSE),
115514b11b2bSmrg    ENTRY (CONJOINT_XOR),
115614b11b2bSmrg
115714b11b2bSmrg    ENTRY (MULTIPLY),
115814b11b2bSmrg    ENTRY (SCREEN),
115914b11b2bSmrg    ENTRY (OVERLAY),
116014b11b2bSmrg    ENTRY (DARKEN),
116114b11b2bSmrg    ENTRY (LIGHTEN),
116214b11b2bSmrg    ENTRY (COLOR_DODGE),
116314b11b2bSmrg    ENTRY (COLOR_BURN),
116414b11b2bSmrg    ENTRY (HARD_LIGHT),
116514b11b2bSmrg    ENTRY (SOFT_LIGHT),
116614b11b2bSmrg    ENTRY (DIFFERENCE),
116714b11b2bSmrg    ENTRY (EXCLUSION),
116814b11b2bSmrg    ENTRY (HSL_HUE),
116914b11b2bSmrg    ENTRY (HSL_SATURATION),
117014b11b2bSmrg    ENTRY (HSL_COLOR),
117114b11b2bSmrg    ENTRY (HSL_LUMINOSITY),
117214b11b2bSmrg
117314b11b2bSmrg    ALIAS (NONE, "<invalid operator 'none'>")
117414b11b2bSmrg
117514b11b2bSmrg#undef ENTRY
117614b11b2bSmrg#undef ALIAS
117714b11b2bSmrg};
117814b11b2bSmrg
117914b11b2bSmrgtypedef struct {
118014b11b2bSmrg    pixman_dither_t	 dither;
118114b11b2bSmrg    const char		*name;
118214b11b2bSmrg    pixman_bool_t	 is_alias;
118314b11b2bSmrg} dither_entry_t;
118414b11b2bSmrg
118514b11b2bSmrgstatic const dither_entry_t dither_list[] =
118614b11b2bSmrg{
118714b11b2bSmrg#define ENTRY(dither)							\
118814b11b2bSmrg    { PIXMAN_DITHER_##dither, "PIXMAN_DITHER_" #dither, FALSE }
118914b11b2bSmrg#define ALIAS(dither, nam)							\
119014b11b2bSmrg    { PIXMAN_DITHER_##dither, nam, TRUE }
119114b11b2bSmrg
119214b11b2bSmrg    /* dither_name () will return the first hit in this table,
119314b11b2bSmrg     * so keep the list properly ordered between entries and aliases.
119414b11b2bSmrg     * Aliases are not listed by list_dithers ().
119514b11b2bSmrg     */
119614b11b2bSmrg
119714b11b2bSmrg    ENTRY (ORDERED_BAYER_8),
119814b11b2bSmrg    ENTRY (ORDERED_BLUE_NOISE_64),
119914b11b2bSmrg    ENTRY (NONE),
120014b11b2bSmrg
120114b11b2bSmrg#undef ENTRY
120214b11b2bSmrg#undef ALIAS
120314b11b2bSmrg};
120414b11b2bSmrg
120514b11b2bSmrgstruct format_entry
120614b11b2bSmrg{
120714b11b2bSmrg    pixman_format_code_t format;
120814b11b2bSmrg    const char		*name;
120914b11b2bSmrg    pixman_bool_t	 is_alias;
121014b11b2bSmrg};
121114b11b2bSmrg
121214b11b2bSmrgtypedef struct format_entry format_entry_t;
121314b11b2bSmrg
121414b11b2bSmrgstatic const format_entry_t format_list[] =
121514b11b2bSmrg{
121614b11b2bSmrg#define ENTRY(f)							\
121714b11b2bSmrg    { PIXMAN_##f, #f, FALSE }
121814b11b2bSmrg#define ALIAS(f, nam)							\
121914b11b2bSmrg    { PIXMAN_##f, nam, TRUE }
122014b11b2bSmrg
122114b11b2bSmrg    /* format_name () will return the first hit in this table,
122214b11b2bSmrg     * so keep the list properly ordered between entries and aliases.
122314b11b2bSmrg     * Aliases are not listed by list_formats ().
122414b11b2bSmrg     */
122514b11b2bSmrg
122614b11b2bSmrg/* 128bpp formats */
122714b11b2bSmrg    ENTRY (rgba_float),
122814b11b2bSmrg/* 96bpp formats */
122914b11b2bSmrg    ENTRY (rgb_float),
123014b11b2bSmrg
123114b11b2bSmrg/* 64bpp formats */
123214b11b2bSmrg    ENTRY (a16b16g16r16),
123314b11b2bSmrg
123414b11b2bSmrg/* 32bpp formats */
123514b11b2bSmrg    ENTRY (a8r8g8b8),
123614b11b2bSmrg    ALIAS (a8r8g8b8,		"8888"),
123714b11b2bSmrg    ENTRY (x8r8g8b8),
123814b11b2bSmrg    ALIAS (x8r8g8b8,		"x888"),
123914b11b2bSmrg    ENTRY (a8b8g8r8),
124014b11b2bSmrg    ENTRY (x8b8g8r8),
124114b11b2bSmrg    ENTRY (b8g8r8a8),
124214b11b2bSmrg    ENTRY (b8g8r8x8),
124314b11b2bSmrg    ENTRY (r8g8b8a8),
124414b11b2bSmrg    ENTRY (r8g8b8x8),
124514b11b2bSmrg    ENTRY (x14r6g6b6),
124614b11b2bSmrg    ENTRY (x2r10g10b10),
124714b11b2bSmrg    ALIAS (x2r10g10b10,		"2x10"),
124814b11b2bSmrg    ENTRY (a2r10g10b10),
124914b11b2bSmrg    ALIAS (a2r10g10b10,		"2a10"),
125014b11b2bSmrg    ENTRY (x2b10g10r10),
125114b11b2bSmrg    ENTRY (a2b10g10r10),
125214b11b2bSmrg
125314b11b2bSmrg/* sRGB formats */
125414b11b2bSmrg    ENTRY (a8r8g8b8_sRGB),
125514b11b2bSmrg    ENTRY (r8g8b8_sRGB),
125614b11b2bSmrg
125714b11b2bSmrg/* 24bpp formats */
125814b11b2bSmrg    ENTRY (r8g8b8),
125914b11b2bSmrg    ALIAS (r8g8b8,		"0888"),
126014b11b2bSmrg    ENTRY (b8g8r8),
126114b11b2bSmrg
126214b11b2bSmrg/* 16 bpp formats */
126314b11b2bSmrg    ENTRY (r5g6b5),
126414b11b2bSmrg    ALIAS (r5g6b5,		"0565"),
126514b11b2bSmrg    ENTRY (b5g6r5),
126614b11b2bSmrg
126714b11b2bSmrg    ENTRY (a1r5g5b5),
126814b11b2bSmrg    ALIAS (a1r5g5b5,		"1555"),
126914b11b2bSmrg    ENTRY (x1r5g5b5),
127014b11b2bSmrg    ENTRY (a1b5g5r5),
127114b11b2bSmrg    ENTRY (x1b5g5r5),
127214b11b2bSmrg    ENTRY (a4r4g4b4),
127314b11b2bSmrg    ALIAS (a4r4g4b4,		"4444"),
127414b11b2bSmrg    ENTRY (x4r4g4b4),
127514b11b2bSmrg    ENTRY (a4b4g4r4),
127614b11b2bSmrg    ENTRY (x4b4g4r4),
127714b11b2bSmrg
127814b11b2bSmrg/* 8bpp formats */
127914b11b2bSmrg    ENTRY (a8),
128014b11b2bSmrg    ALIAS (a8,			"8"),
128114b11b2bSmrg    ENTRY (r3g3b2),
128214b11b2bSmrg    ENTRY (b2g3r3),
128314b11b2bSmrg    ENTRY (a2r2g2b2),
128414b11b2bSmrg    ALIAS (a2r2g2b2,		"2222"),
128514b11b2bSmrg    ENTRY (a2b2g2r2),
128614b11b2bSmrg
128714b11b2bSmrg    ALIAS (c8,			"x4c4 / c8"),
128814b11b2bSmrg    /* ENTRY (c8), */
128914b11b2bSmrg    ALIAS (g8,			"x4g4 / g8"),
129014b11b2bSmrg    /* ENTRY (g8), */
129114b11b2bSmrg
129214b11b2bSmrg    ENTRY (x4a4),
129314b11b2bSmrg
129414b11b2bSmrg    /* These format codes are identical to c8 and g8, respectively. */
129514b11b2bSmrg    /* ENTRY (x4c4), */
129614b11b2bSmrg    /* ENTRY (x4g4), */
129714b11b2bSmrg
129814b11b2bSmrg/* 4 bpp formats */
129914b11b2bSmrg    ENTRY (a4),
130014b11b2bSmrg    ENTRY (r1g2b1),
130114b11b2bSmrg    ENTRY (b1g2r1),
130214b11b2bSmrg    ENTRY (a1r1g1b1),
130314b11b2bSmrg    ENTRY (a1b1g1r1),
130414b11b2bSmrg
130514b11b2bSmrg    ALIAS (c4,			"c4"),
130614b11b2bSmrg    /* ENTRY (c4), */
130714b11b2bSmrg    ALIAS (g4,			"g4"),
130814b11b2bSmrg    /* ENTRY (g4), */
130914b11b2bSmrg
131014b11b2bSmrg/* 1bpp formats */
131114b11b2bSmrg    ENTRY (a1),
131214b11b2bSmrg
131314b11b2bSmrg    ALIAS (g1,			"g1"),
131414b11b2bSmrg    /* ENTRY (g1), */
131514b11b2bSmrg
131614b11b2bSmrg/* YUV formats */
131714b11b2bSmrg    ALIAS (yuy2,		"yuy2"),
131814b11b2bSmrg    /* ENTRY (yuy2), */
131914b11b2bSmrg    ALIAS (yv12,		"yv12"),
132014b11b2bSmrg    /* ENTRY (yv12), */
132114b11b2bSmrg
132214b11b2bSmrg/* Fake formats, not in pixman_format_code_t enum */
132314b11b2bSmrg    ALIAS (null,		"null"),
132414b11b2bSmrg    ALIAS (solid,		"solid"),
132514b11b2bSmrg    ALIAS (solid,		"n"),
132614b11b2bSmrg    ALIAS (pixbuf,		"pixbuf"),
132714b11b2bSmrg    ALIAS (rpixbuf,		"rpixbuf"),
132814b11b2bSmrg    ALIAS (unknown,		"unknown"),
132914b11b2bSmrg
133014b11b2bSmrg#undef ENTRY
133114b11b2bSmrg#undef ALIAS
133214b11b2bSmrg};
133314b11b2bSmrg
133414b11b2bSmrgpixman_format_code_t
133514b11b2bSmrgformat_from_string (const char *s)
133614b11b2bSmrg{
133714b11b2bSmrg    int i;
133814b11b2bSmrg
133914b11b2bSmrg    for (i = 0; i < ARRAY_LENGTH (format_list); ++i)
134014b11b2bSmrg    {
134114b11b2bSmrg        const format_entry_t *ent = &format_list[i];
134214b11b2bSmrg
134314b11b2bSmrg        if (strcasecmp (ent->name, s) == 0)
134414b11b2bSmrg            return ent->format;
134514b11b2bSmrg    }
134614b11b2bSmrg
134714b11b2bSmrg    return PIXMAN_null;
134814b11b2bSmrg}
134914b11b2bSmrg
135014b11b2bSmrgstatic void
135114b11b2bSmrgemit (const char *s, int *n_chars)
135214b11b2bSmrg{
135314b11b2bSmrg    *n_chars += printf ("%s,", s);
135414b11b2bSmrg    if (*n_chars > 60)
135514b11b2bSmrg    {
135614b11b2bSmrg        printf ("\n    ");
135714b11b2bSmrg        *n_chars = 0;
135814b11b2bSmrg    }
135914b11b2bSmrg    else
136014b11b2bSmrg    {
136114b11b2bSmrg        printf (" ");
136214b11b2bSmrg        (*n_chars)++;
136314b11b2bSmrg    }
136414b11b2bSmrg}
136514b11b2bSmrg
136614b11b2bSmrgvoid
136714b11b2bSmrglist_formats (void)
136814b11b2bSmrg{
136914b11b2bSmrg    int n_chars;
137014b11b2bSmrg    int i;
137114b11b2bSmrg
137214b11b2bSmrg    printf ("Formats:\n    ");
137314b11b2bSmrg
137414b11b2bSmrg    n_chars = 0;
137514b11b2bSmrg    for (i = 0; i < ARRAY_LENGTH (format_list); ++i)
137614b11b2bSmrg    {
137714b11b2bSmrg        const format_entry_t *ent = &format_list[i];
137814b11b2bSmrg
137914b11b2bSmrg        if (ent->is_alias)
138014b11b2bSmrg            continue;
138114b11b2bSmrg
138214b11b2bSmrg        emit (ent->name, &n_chars);
138314b11b2bSmrg    }
138414b11b2bSmrg
138514b11b2bSmrg    printf ("\n\n");
138614b11b2bSmrg}
138714b11b2bSmrg
138814b11b2bSmrgvoid
138914b11b2bSmrglist_operators (void)
139014b11b2bSmrg{
139114b11b2bSmrg    char short_name [128] = { 0 };
139214b11b2bSmrg    int i, n_chars;
139314b11b2bSmrg
139414b11b2bSmrg    printf ("Operators:\n    ");
139514b11b2bSmrg
139614b11b2bSmrg    n_chars = 0;
139714b11b2bSmrg    for (i = 0; i < ARRAY_LENGTH (op_list); ++i)
139814b11b2bSmrg    {
139914b11b2bSmrg        const operator_entry_t *ent = &op_list[i];
140014b11b2bSmrg        int j;
140114b11b2bSmrg
140214b11b2bSmrg        if (ent->is_alias)
140314b11b2bSmrg            continue;
140414b11b2bSmrg
140514b11b2bSmrg        snprintf (short_name, sizeof (short_name) - 1, "%s",
140614b11b2bSmrg                  ent->name + strlen ("PIXMAN_OP_"));
140714b11b2bSmrg
140814b11b2bSmrg        for (j = 0; short_name[j] != '\0'; ++j)
140914b11b2bSmrg            short_name[j] = tolower (short_name[j]);
141014b11b2bSmrg
141114b11b2bSmrg        emit (short_name, &n_chars);
141214b11b2bSmrg    }
141314b11b2bSmrg
141414b11b2bSmrg    printf ("\n\n");
141514b11b2bSmrg}
141614b11b2bSmrg
141714b11b2bSmrgvoid
141814b11b2bSmrglist_dithers (void)
141914b11b2bSmrg{
142014b11b2bSmrg    int n_chars;
142114b11b2bSmrg    int i;
142214b11b2bSmrg
142314b11b2bSmrg    printf ("Dithers:\n    ");
142414b11b2bSmrg
142514b11b2bSmrg    n_chars = 0;
142614b11b2bSmrg    for (i = 0; i < ARRAY_LENGTH (dither_list); ++i)
142714b11b2bSmrg    {
142814b11b2bSmrg        const dither_entry_t *ent = &dither_list[i];
142914b11b2bSmrg
143014b11b2bSmrg        if (ent->is_alias)
143114b11b2bSmrg            continue;
143214b11b2bSmrg
143314b11b2bSmrg        emit (ent->name, &n_chars);
143414b11b2bSmrg    }
143514b11b2bSmrg
143614b11b2bSmrg    printf ("\n\n");
143714b11b2bSmrg}
143814b11b2bSmrg
143914b11b2bSmrgpixman_op_t
144014b11b2bSmrgoperator_from_string (const char *s)
144114b11b2bSmrg{
144214b11b2bSmrg    int i;
144314b11b2bSmrg
144414b11b2bSmrg    for (i = 0; i < ARRAY_LENGTH (op_list); ++i)
144514b11b2bSmrg    {
144614b11b2bSmrg        const operator_entry_t *ent = &op_list[i];
144714b11b2bSmrg
144814b11b2bSmrg        if (ent->is_alias)
144914b11b2bSmrg        {
145014b11b2bSmrg            if (strcasecmp (ent->name, s) == 0)
145114b11b2bSmrg                return ent->op;
145214b11b2bSmrg        }
145314b11b2bSmrg        else
145414b11b2bSmrg        {
145514b11b2bSmrg            if (strcasecmp (ent->name + strlen ("PIXMAN_OP_"), s) == 0)
145614b11b2bSmrg                return ent->op;
145714b11b2bSmrg        }
145814b11b2bSmrg    }
145914b11b2bSmrg
146014b11b2bSmrg    return PIXMAN_OP_NONE;
146114b11b2bSmrg}
146214b11b2bSmrg
146314b11b2bSmrgpixman_dither_t
146414b11b2bSmrgdither_from_string (const char *s)
146514b11b2bSmrg{
146614b11b2bSmrg    int i;
146714b11b2bSmrg
146814b11b2bSmrg    for (i = 0; i < ARRAY_LENGTH (dither_list); ++i)
146914b11b2bSmrg    {
147014b11b2bSmrg        const dither_entry_t *ent = &dither_list[i];
147114b11b2bSmrg
147214b11b2bSmrg        if (strcasecmp (ent->name, s) == 0)
147314b11b2bSmrg            return ent->dither;
147414b11b2bSmrg    }
147514b11b2bSmrg
147614b11b2bSmrg    return PIXMAN_DITHER_NONE;
147714b11b2bSmrg}
147814b11b2bSmrg
147914b11b2bSmrgconst char *
148014b11b2bSmrgoperator_name (pixman_op_t op)
148114b11b2bSmrg{
148214b11b2bSmrg    int i;
148314b11b2bSmrg
148414b11b2bSmrg    for (i = 0; i < ARRAY_LENGTH (op_list); ++i)
148514b11b2bSmrg    {
148614b11b2bSmrg        const operator_entry_t *ent = &op_list[i];
148714b11b2bSmrg
148814b11b2bSmrg        if (ent->op == op)
148914b11b2bSmrg            return ent->name;
149014b11b2bSmrg    }
149114b11b2bSmrg
149214b11b2bSmrg    return "<unknown operator>";
149314b11b2bSmrg}
149414b11b2bSmrg
149514b11b2bSmrgconst char *
149614b11b2bSmrgformat_name (pixman_format_code_t format)
149714b11b2bSmrg{
149814b11b2bSmrg    int i;
149914b11b2bSmrg
150014b11b2bSmrg    for (i = 0; i < ARRAY_LENGTH (format_list); ++i)
150114b11b2bSmrg    {
150214b11b2bSmrg        const format_entry_t *ent = &format_list[i];
150314b11b2bSmrg
150414b11b2bSmrg        if (ent->format == format)
150514b11b2bSmrg            return ent->name;
150614b11b2bSmrg    }
150714b11b2bSmrg
150814b11b2bSmrg    return "<unknown format>";
150914b11b2bSmrg};
151014b11b2bSmrg
151114b11b2bSmrgconst char *
151214b11b2bSmrgdither_name (pixman_dither_t dither)
151314b11b2bSmrg{
151414b11b2bSmrg    int i;
151514b11b2bSmrg
151614b11b2bSmrg    for (i = 0; i < ARRAY_LENGTH (dither_list); ++i)
151714b11b2bSmrg    {
151814b11b2bSmrg	const dither_entry_t *ent = &dither_list[i];
151914b11b2bSmrg
152014b11b2bSmrg	if (ent->dither == dither)
152114b11b2bSmrg	    return ent->name;
152214b11b2bSmrg    }
152314b11b2bSmrg
152414b11b2bSmrg    return "<unknown dither>";
152514b11b2bSmrg}
152614b11b2bSmrg
152714b11b2bSmrg#define IS_ZERO(f)     (-DBL_MIN < (f) && (f) < DBL_MIN)
152814b11b2bSmrg
152914b11b2bSmrgtypedef double (* blend_func_t) (double as, double s, double ad, double d);
153014b11b2bSmrg
153114b11b2bSmrgstatic force_inline double
153214b11b2bSmrgblend_multiply (double sa, double s, double da, double d)
153314b11b2bSmrg{
153414b11b2bSmrg    return d * s;
153514b11b2bSmrg}
153614b11b2bSmrg
153714b11b2bSmrgstatic force_inline double
153814b11b2bSmrgblend_screen (double sa, double s, double da, double d)
153914b11b2bSmrg{
154014b11b2bSmrg    return d * sa + s * da - s * d;
154114b11b2bSmrg}
154214b11b2bSmrg
154314b11b2bSmrgstatic force_inline double
154414b11b2bSmrgblend_overlay (double sa, double s, double da, double d)
154514b11b2bSmrg{
154614b11b2bSmrg    if (2 * d < da)
154714b11b2bSmrg        return 2 * s * d;
154814b11b2bSmrg    else
154914b11b2bSmrg        return sa * da - 2 * (da - d) * (sa - s);
155014b11b2bSmrg}
155114b11b2bSmrg
155214b11b2bSmrgstatic force_inline double
155314b11b2bSmrgblend_darken (double sa, double s, double da, double d)
155414b11b2bSmrg{
155514b11b2bSmrg    s = s * da;
155614b11b2bSmrg    d = d * sa;
155714b11b2bSmrg
155814b11b2bSmrg    if (s > d)
155914b11b2bSmrg        return d;
156014b11b2bSmrg    else
156114b11b2bSmrg        return s;
156214b11b2bSmrg}
156314b11b2bSmrg
156414b11b2bSmrgstatic force_inline double
156514b11b2bSmrgblend_lighten (double sa, double s, double da, double d)
156614b11b2bSmrg{
156714b11b2bSmrg    s = s * da;
156814b11b2bSmrg    d = d * sa;
156914b11b2bSmrg
157014b11b2bSmrg    if (s > d)
157114b11b2bSmrg        return s;
157214b11b2bSmrg    else
157314b11b2bSmrg        return d;
157414b11b2bSmrg}
157514b11b2bSmrg
157614b11b2bSmrgstatic force_inline double
157714b11b2bSmrgblend_color_dodge (double sa, double s, double da, double d)
157814b11b2bSmrg{
157914b11b2bSmrg    if (IS_ZERO (d))
158014b11b2bSmrg        return 0.0f;
158114b11b2bSmrg    else if (d * sa >= sa * da - s * da)
158214b11b2bSmrg        return sa * da;
158314b11b2bSmrg    else if (IS_ZERO (sa - s))
158414b11b2bSmrg        return sa * da;
158514b11b2bSmrg    else
158614b11b2bSmrg        return sa * sa * d / (sa - s);
158714b11b2bSmrg}
158814b11b2bSmrg
158914b11b2bSmrgstatic force_inline double
159014b11b2bSmrgblend_color_burn (double sa, double s, double da, double d)
159114b11b2bSmrg{
159214b11b2bSmrg    if (d >= da)
159314b11b2bSmrg        return sa * da;
159414b11b2bSmrg    else if (sa * (da - d) >= s * da)
159514b11b2bSmrg        return 0.0f;
159614b11b2bSmrg    else if (IS_ZERO (s))
159714b11b2bSmrg        return 0.0f;
159814b11b2bSmrg    else
159914b11b2bSmrg        return sa * (da - sa * (da - d) / s);
160014b11b2bSmrg}
160114b11b2bSmrg
160214b11b2bSmrgstatic force_inline double
160314b11b2bSmrgblend_hard_light (double sa, double s, double da, double d)
160414b11b2bSmrg{
160514b11b2bSmrg    if (2 * s < sa)
160614b11b2bSmrg        return 2 * s * d;
160714b11b2bSmrg    else
160814b11b2bSmrg        return sa * da - 2 * (da - d) * (sa - s);
160914b11b2bSmrg}
161014b11b2bSmrg
161114b11b2bSmrgstatic force_inline double
161214b11b2bSmrgblend_soft_light (double sa, double s, double da, double d)
161314b11b2bSmrg{
161414b11b2bSmrg    if (2 * s <= sa)
161514b11b2bSmrg    {
161614b11b2bSmrg        if (IS_ZERO (da))
161714b11b2bSmrg            return d * sa;
161814b11b2bSmrg        else
161914b11b2bSmrg            return d * sa - d * (da - d) * (sa - 2 * s) / da;
162014b11b2bSmrg    }
162114b11b2bSmrg    else
162214b11b2bSmrg    {
162314b11b2bSmrg        if (IS_ZERO (da))
162414b11b2bSmrg        {
162514b11b2bSmrg	    return d * sa;
162614b11b2bSmrg        }
162714b11b2bSmrg        else
162814b11b2bSmrg        {
162914b11b2bSmrg            if (4 * d <= da)
163014b11b2bSmrg                return d * sa + (2 * s - sa) * d * ((16 * d / da - 12) * d / da + 3);
163114b11b2bSmrg            else
163214b11b2bSmrg                return d * sa + (sqrt (d * da) - d) * (2 * s - sa);
163314b11b2bSmrg        }
163414b11b2bSmrg    }
163514b11b2bSmrg}
163614b11b2bSmrg
163714b11b2bSmrgstatic force_inline double
163814b11b2bSmrgblend_difference (double sa, double s, double da, double d)
163914b11b2bSmrg{
164014b11b2bSmrg    double dsa = d * sa;
164114b11b2bSmrg    double sda = s * da;
164214b11b2bSmrg
164314b11b2bSmrg    if (sda < dsa)
164414b11b2bSmrg        return dsa - sda;
164514b11b2bSmrg    else
164614b11b2bSmrg        return sda - dsa;
164714b11b2bSmrg}
164814b11b2bSmrg
164914b11b2bSmrgstatic force_inline double
165014b11b2bSmrgblend_exclusion (double sa, double s, double da, double d)
165114b11b2bSmrg{
165214b11b2bSmrg    return s * da + d * sa - 2 * d * s;
165314b11b2bSmrg}
165414b11b2bSmrg
165514b11b2bSmrgstatic double
165614b11b2bSmrgclamp (double d)
165714b11b2bSmrg{
165814b11b2bSmrg    if (d > 1.0)
165914b11b2bSmrg	return 1.0;
166014b11b2bSmrg    else if (d < 0.0)
166114b11b2bSmrg	return 0.0;
166214b11b2bSmrg    else
166314b11b2bSmrg	return d;
166414b11b2bSmrg}
166514b11b2bSmrg
166614b11b2bSmrgstatic double
166714b11b2bSmrgblend_channel (double as, double s, double ad, double d,
166814b11b2bSmrg                   blend_func_t blend)
166914b11b2bSmrg{
167014b11b2bSmrg    return clamp ((1 - ad) * s + (1 - as) * d + blend (as, s, ad, d));
167114b11b2bSmrg}
167214b11b2bSmrg
167314b11b2bSmrgstatic double
167414b11b2bSmrgcalc_op (pixman_op_t op, double src, double dst, double srca, double dsta)
167514b11b2bSmrg{
167614b11b2bSmrg#define mult_chan(src, dst, Fa, Fb) MIN ((src) * (Fa) + (dst) * (Fb), 1.0)
167714b11b2bSmrg
167814b11b2bSmrg    double Fa, Fb;
167914b11b2bSmrg
168014b11b2bSmrg    switch (op)
168114b11b2bSmrg    {
168214b11b2bSmrg    case PIXMAN_OP_CLEAR:
168314b11b2bSmrg    case PIXMAN_OP_DISJOINT_CLEAR:
168414b11b2bSmrg    case PIXMAN_OP_CONJOINT_CLEAR:
168514b11b2bSmrg	return mult_chan (src, dst, 0.0, 0.0);
168614b11b2bSmrg
168714b11b2bSmrg    case PIXMAN_OP_SRC:
168814b11b2bSmrg    case PIXMAN_OP_DISJOINT_SRC:
168914b11b2bSmrg    case PIXMAN_OP_CONJOINT_SRC:
169014b11b2bSmrg	return mult_chan (src, dst, 1.0, 0.0);
169114b11b2bSmrg
169214b11b2bSmrg    case PIXMAN_OP_DST:
169314b11b2bSmrg    case PIXMAN_OP_DISJOINT_DST:
169414b11b2bSmrg    case PIXMAN_OP_CONJOINT_DST:
169514b11b2bSmrg	return mult_chan (src, dst, 0.0, 1.0);
169614b11b2bSmrg
169714b11b2bSmrg    case PIXMAN_OP_OVER:
169814b11b2bSmrg	return mult_chan (src, dst, 1.0, 1.0 - srca);
169914b11b2bSmrg
170014b11b2bSmrg    case PIXMAN_OP_OVER_REVERSE:
170114b11b2bSmrg	return mult_chan (src, dst, 1.0 - dsta, 1.0);
170214b11b2bSmrg
170314b11b2bSmrg    case PIXMAN_OP_IN:
170414b11b2bSmrg	return mult_chan (src, dst, dsta, 0.0);
170514b11b2bSmrg
170614b11b2bSmrg    case PIXMAN_OP_IN_REVERSE:
170714b11b2bSmrg	return mult_chan (src, dst, 0.0, srca);
170814b11b2bSmrg
170914b11b2bSmrg    case PIXMAN_OP_OUT:
171014b11b2bSmrg	return mult_chan (src, dst, 1.0 - dsta, 0.0);
171114b11b2bSmrg
171214b11b2bSmrg    case PIXMAN_OP_OUT_REVERSE:
171314b11b2bSmrg	return mult_chan (src, dst, 0.0, 1.0 - srca);
171414b11b2bSmrg
171514b11b2bSmrg    case PIXMAN_OP_ATOP:
171614b11b2bSmrg	return mult_chan (src, dst, dsta, 1.0 - srca);
171714b11b2bSmrg
171814b11b2bSmrg    case PIXMAN_OP_ATOP_REVERSE:
171914b11b2bSmrg	return mult_chan (src, dst, 1.0 - dsta,  srca);
172014b11b2bSmrg
172114b11b2bSmrg    case PIXMAN_OP_XOR:
172214b11b2bSmrg	return mult_chan (src, dst, 1.0 - dsta, 1.0 - srca);
172314b11b2bSmrg
172414b11b2bSmrg    case PIXMAN_OP_ADD:
172514b11b2bSmrg	return mult_chan (src, dst, 1.0, 1.0);
172614b11b2bSmrg
172714b11b2bSmrg    case PIXMAN_OP_SATURATE:
172814b11b2bSmrg    case PIXMAN_OP_DISJOINT_OVER_REVERSE:
172914b11b2bSmrg	if (srca == 0.0)
173014b11b2bSmrg	    Fa = 1.0;
173114b11b2bSmrg	else
173214b11b2bSmrg	    Fa = MIN (1.0, (1.0 - dsta) / srca);
173314b11b2bSmrg	return mult_chan (src, dst, Fa, 1.0);
173414b11b2bSmrg
173514b11b2bSmrg    case PIXMAN_OP_DISJOINT_OVER:
173614b11b2bSmrg	if (dsta == 0.0)
173714b11b2bSmrg	    Fb = 1.0;
173814b11b2bSmrg	else
173914b11b2bSmrg	    Fb = MIN (1.0, (1.0 - srca) / dsta);
174014b11b2bSmrg	return mult_chan (src, dst, 1.0, Fb);
174114b11b2bSmrg
174214b11b2bSmrg    case PIXMAN_OP_DISJOINT_IN:
174314b11b2bSmrg	if (srca == 0.0)
174414b11b2bSmrg	    Fa = 0.0;
174514b11b2bSmrg	else
174614b11b2bSmrg	    Fa = MAX (0.0, 1.0 - (1.0 - dsta) / srca);
174714b11b2bSmrg	return mult_chan (src, dst, Fa, 0.0);
174814b11b2bSmrg
174914b11b2bSmrg    case PIXMAN_OP_DISJOINT_IN_REVERSE:
175014b11b2bSmrg	if (dsta == 0.0)
175114b11b2bSmrg	    Fb = 0.0;
175214b11b2bSmrg	else
175314b11b2bSmrg	    Fb = MAX (0.0, 1.0 - (1.0 - srca) / dsta);
175414b11b2bSmrg	return mult_chan (src, dst, 0.0, Fb);
175514b11b2bSmrg
175614b11b2bSmrg    case PIXMAN_OP_DISJOINT_OUT:
175714b11b2bSmrg	if (srca == 0.0)
175814b11b2bSmrg	    Fa = 1.0;
175914b11b2bSmrg	else
176014b11b2bSmrg	    Fa = MIN (1.0, (1.0 - dsta) / srca);
176114b11b2bSmrg	return mult_chan (src, dst, Fa, 0.0);
176214b11b2bSmrg
176314b11b2bSmrg    case PIXMAN_OP_DISJOINT_OUT_REVERSE:
176414b11b2bSmrg	if (dsta == 0.0)
176514b11b2bSmrg	    Fb = 1.0;
176614b11b2bSmrg	else
176714b11b2bSmrg	    Fb = MIN (1.0, (1.0 - srca) / dsta);
176814b11b2bSmrg	return mult_chan (src, dst, 0.0, Fb);
176914b11b2bSmrg
177014b11b2bSmrg    case PIXMAN_OP_DISJOINT_ATOP:
177114b11b2bSmrg	if (srca == 0.0)
177214b11b2bSmrg	    Fa = 0.0;
177314b11b2bSmrg	else
177414b11b2bSmrg	    Fa = MAX (0.0, 1.0 - (1.0 - dsta) / srca);
177514b11b2bSmrg	if (dsta == 0.0)
177614b11b2bSmrg	    Fb = 1.0;
177714b11b2bSmrg	else
177814b11b2bSmrg	    Fb = MIN (1.0, (1.0 - srca) / dsta);
177914b11b2bSmrg	return mult_chan (src, dst, Fa, Fb);
178014b11b2bSmrg
178114b11b2bSmrg    case PIXMAN_OP_DISJOINT_ATOP_REVERSE:
178214b11b2bSmrg	if (srca == 0.0)
178314b11b2bSmrg	    Fa = 1.0;
178414b11b2bSmrg	else
178514b11b2bSmrg	    Fa = MIN (1.0, (1.0 - dsta) / srca);
178614b11b2bSmrg	if (dsta == 0.0)
178714b11b2bSmrg	    Fb = 0.0;
178814b11b2bSmrg	else
178914b11b2bSmrg	    Fb = MAX (0.0, 1.0 - (1.0 - srca) / dsta);
179014b11b2bSmrg	return mult_chan (src, dst, Fa, Fb);
179114b11b2bSmrg
179214b11b2bSmrg    case PIXMAN_OP_DISJOINT_XOR:
179314b11b2bSmrg	if (srca == 0.0)
179414b11b2bSmrg	    Fa = 1.0;
179514b11b2bSmrg	else
179614b11b2bSmrg	    Fa = MIN (1.0, (1.0 - dsta) / srca);
179714b11b2bSmrg	if (dsta == 0.0)
179814b11b2bSmrg	    Fb = 1.0;
179914b11b2bSmrg	else
180014b11b2bSmrg	    Fb = MIN (1.0, (1.0 - srca) / dsta);
180114b11b2bSmrg	return mult_chan (src, dst, Fa, Fb);
180214b11b2bSmrg
180314b11b2bSmrg    case PIXMAN_OP_CONJOINT_OVER:
180414b11b2bSmrg	if (dsta == 0.0)
180514b11b2bSmrg	    Fb = 0.0;
180614b11b2bSmrg	else
180714b11b2bSmrg	    Fb = MAX (0.0, 1.0 - srca / dsta);
180814b11b2bSmrg	return mult_chan (src, dst, 1.0, Fb);
180914b11b2bSmrg
181014b11b2bSmrg    case PIXMAN_OP_CONJOINT_OVER_REVERSE:
181114b11b2bSmrg	if (srca == 0.0)
181214b11b2bSmrg	    Fa = 0.0;
181314b11b2bSmrg	else
181414b11b2bSmrg	    Fa = MAX (0.0, 1.0 - dsta / srca);
181514b11b2bSmrg	return mult_chan (src, dst, Fa, 1.0);
181614b11b2bSmrg
181714b11b2bSmrg    case PIXMAN_OP_CONJOINT_IN:
181814b11b2bSmrg	if (srca == 0.0)
181914b11b2bSmrg	    Fa = 1.0;
182014b11b2bSmrg	else
182114b11b2bSmrg	    Fa = MIN (1.0, dsta / srca);
182214b11b2bSmrg	return mult_chan (src, dst, Fa, 0.0);
182314b11b2bSmrg
182414b11b2bSmrg    case PIXMAN_OP_CONJOINT_IN_REVERSE:
182514b11b2bSmrg	if (dsta == 0.0)
182614b11b2bSmrg	    Fb = 1.0;
182714b11b2bSmrg	else
182814b11b2bSmrg	    Fb = MIN (1.0, srca / dsta);
182914b11b2bSmrg	return mult_chan (src, dst, 0.0, Fb);
183014b11b2bSmrg
183114b11b2bSmrg    case PIXMAN_OP_CONJOINT_OUT:
183214b11b2bSmrg	if (srca == 0.0)
183314b11b2bSmrg	    Fa = 0.0;
183414b11b2bSmrg	else
183514b11b2bSmrg	    Fa = MAX (0.0, 1.0 - dsta / srca);
183614b11b2bSmrg	return mult_chan (src, dst, Fa, 0.0);
183714b11b2bSmrg
183814b11b2bSmrg    case PIXMAN_OP_CONJOINT_OUT_REVERSE:
183914b11b2bSmrg	if (dsta == 0.0)
184014b11b2bSmrg	    Fb = 0.0;
184114b11b2bSmrg	else
184214b11b2bSmrg	    Fb = MAX (0.0, 1.0 - srca / dsta);
184314b11b2bSmrg	return mult_chan (src, dst, 0.0, Fb);
184414b11b2bSmrg
184514b11b2bSmrg    case PIXMAN_OP_CONJOINT_ATOP:
184614b11b2bSmrg	if (srca == 0.0)
184714b11b2bSmrg	    Fa = 1.0;
184814b11b2bSmrg	else
184914b11b2bSmrg	    Fa = MIN (1.0, dsta / srca);
185014b11b2bSmrg	if (dsta == 0.0)
185114b11b2bSmrg	    Fb = 0.0;
185214b11b2bSmrg	else
185314b11b2bSmrg	    Fb = MAX (0.0, 1.0 - srca / dsta);
185414b11b2bSmrg	return mult_chan (src, dst, Fa, Fb);
185514b11b2bSmrg
185614b11b2bSmrg    case PIXMAN_OP_CONJOINT_ATOP_REVERSE:
185714b11b2bSmrg	if (srca == 0.0)
185814b11b2bSmrg	    Fa = 0.0;
185914b11b2bSmrg	else
186014b11b2bSmrg	    Fa = MAX (0.0, 1.0 - dsta / srca);
186114b11b2bSmrg	if (dsta == 0.0)
186214b11b2bSmrg	    Fb = 1.0;
186314b11b2bSmrg	else
186414b11b2bSmrg	    Fb = MIN (1.0, srca / dsta);
186514b11b2bSmrg	return mult_chan (src, dst, Fa, Fb);
186614b11b2bSmrg
186714b11b2bSmrg    case PIXMAN_OP_CONJOINT_XOR:
186814b11b2bSmrg	if (srca == 0.0)
186914b11b2bSmrg	    Fa = 0.0;
187014b11b2bSmrg	else
187114b11b2bSmrg	    Fa = MAX (0.0, 1.0 - dsta / srca);
187214b11b2bSmrg	if (dsta == 0.0)
187314b11b2bSmrg	    Fb = 0.0;
187414b11b2bSmrg	else
187514b11b2bSmrg	    Fb = MAX (0.0, 1.0 - srca / dsta);
187614b11b2bSmrg	return mult_chan (src, dst, Fa, Fb);
187714b11b2bSmrg
187814b11b2bSmrg    case PIXMAN_OP_MULTIPLY:
187914b11b2bSmrg    case PIXMAN_OP_SCREEN:
188014b11b2bSmrg    case PIXMAN_OP_OVERLAY:
188114b11b2bSmrg    case PIXMAN_OP_DARKEN:
188214b11b2bSmrg    case PIXMAN_OP_LIGHTEN:
188314b11b2bSmrg    case PIXMAN_OP_COLOR_DODGE:
188414b11b2bSmrg    case PIXMAN_OP_COLOR_BURN:
188514b11b2bSmrg    case PIXMAN_OP_HARD_LIGHT:
188614b11b2bSmrg    case PIXMAN_OP_SOFT_LIGHT:
188714b11b2bSmrg    case PIXMAN_OP_DIFFERENCE:
188814b11b2bSmrg    case PIXMAN_OP_EXCLUSION:
188914b11b2bSmrg    case PIXMAN_OP_HSL_HUE:
189014b11b2bSmrg    case PIXMAN_OP_HSL_SATURATION:
189114b11b2bSmrg    case PIXMAN_OP_HSL_COLOR:
189214b11b2bSmrg    case PIXMAN_OP_HSL_LUMINOSITY:
189314b11b2bSmrg    default:
189414b11b2bSmrg	abort();
189514b11b2bSmrg	return 0; /* silence MSVC */
189614b11b2bSmrg    }
189714b11b2bSmrg#undef mult_chan
189814b11b2bSmrg}
189914b11b2bSmrg
190014b11b2bSmrgvoid
190114b11b2bSmrgdo_composite (pixman_op_t op,
190214b11b2bSmrg	      const color_t *src,
190314b11b2bSmrg	      const color_t *mask,
190414b11b2bSmrg	      const color_t *dst,
190514b11b2bSmrg	      color_t *result,
190614b11b2bSmrg	      pixman_bool_t component_alpha)
190714b11b2bSmrg{
190814b11b2bSmrg    color_t srcval, srcalpha;
190914b11b2bSmrg
191014b11b2bSmrg    static const blend_func_t blend_funcs[] =
191114b11b2bSmrg    {
191214b11b2bSmrg        blend_multiply,
191314b11b2bSmrg        blend_screen,
191414b11b2bSmrg        blend_overlay,
191514b11b2bSmrg        blend_darken,
191614b11b2bSmrg        blend_lighten,
191714b11b2bSmrg        blend_color_dodge,
191814b11b2bSmrg        blend_color_burn,
191914b11b2bSmrg        blend_hard_light,
192014b11b2bSmrg        blend_soft_light,
192114b11b2bSmrg        blend_difference,
192214b11b2bSmrg        blend_exclusion,
192314b11b2bSmrg    };
192414b11b2bSmrg
192514b11b2bSmrg    if (mask == NULL)
192614b11b2bSmrg    {
192714b11b2bSmrg	srcval = *src;
192814b11b2bSmrg
192914b11b2bSmrg	srcalpha.r = src->a;
193014b11b2bSmrg	srcalpha.g = src->a;
193114b11b2bSmrg	srcalpha.b = src->a;
193214b11b2bSmrg	srcalpha.a = src->a;
193314b11b2bSmrg    }
193414b11b2bSmrg    else if (component_alpha)
193514b11b2bSmrg    {
193614b11b2bSmrg	srcval.r = src->r * mask->r;
193714b11b2bSmrg	srcval.g = src->g * mask->g;
193814b11b2bSmrg	srcval.b = src->b * mask->b;
193914b11b2bSmrg	srcval.a = src->a * mask->a;
194014b11b2bSmrg
194114b11b2bSmrg	srcalpha.r = src->a * mask->r;
194214b11b2bSmrg	srcalpha.g = src->a * mask->g;
194314b11b2bSmrg	srcalpha.b = src->a * mask->b;
194414b11b2bSmrg	srcalpha.a = src->a * mask->a;
194514b11b2bSmrg    }
194614b11b2bSmrg    else
194714b11b2bSmrg    {
194814b11b2bSmrg	srcval.r = src->r * mask->a;
194914b11b2bSmrg	srcval.g = src->g * mask->a;
195014b11b2bSmrg	srcval.b = src->b * mask->a;
195114b11b2bSmrg	srcval.a = src->a * mask->a;
195214b11b2bSmrg
195314b11b2bSmrg	srcalpha.r = src->a * mask->a;
195414b11b2bSmrg	srcalpha.g = src->a * mask->a;
195514b11b2bSmrg	srcalpha.b = src->a * mask->a;
195614b11b2bSmrg	srcalpha.a = src->a * mask->a;
195714b11b2bSmrg    }
195814b11b2bSmrg
195914b11b2bSmrg    if (op >= PIXMAN_OP_MULTIPLY)
196014b11b2bSmrg    {
196114b11b2bSmrg        blend_func_t func = blend_funcs[op - PIXMAN_OP_MULTIPLY];
196214b11b2bSmrg
196314b11b2bSmrg	result->a = srcalpha.a + dst->a - srcalpha.a * dst->a;
196414b11b2bSmrg	result->r = blend_channel (srcalpha.r, srcval.r, dst->a, dst->r, func);
196514b11b2bSmrg	result->g = blend_channel (srcalpha.g, srcval.g, dst->a, dst->g, func);
196614b11b2bSmrg	result->b = blend_channel (srcalpha.b, srcval.b, dst->a, dst->b, func);
196714b11b2bSmrg    }
196814b11b2bSmrg    else
196914b11b2bSmrg    {
197014b11b2bSmrg        result->r = calc_op (op, srcval.r, dst->r, srcalpha.r, dst->a);
197114b11b2bSmrg        result->g = calc_op (op, srcval.g, dst->g, srcalpha.g, dst->a);
197214b11b2bSmrg        result->b = calc_op (op, srcval.b, dst->b, srcalpha.b, dst->a);
197314b11b2bSmrg        result->a = calc_op (op, srcval.a, dst->a, srcalpha.a, dst->a);
197414b11b2bSmrg    }
197514b11b2bSmrg}
197614b11b2bSmrg
197714b11b2bSmrgstatic double
197814b11b2bSmrground_channel (double p, int m)
197914b11b2bSmrg{
198014b11b2bSmrg    int t;
198114b11b2bSmrg    double r;
198214b11b2bSmrg
198314b11b2bSmrg    t = p * ((1 << m));
198414b11b2bSmrg    t -= t >> m;
198514b11b2bSmrg
198614b11b2bSmrg    r = t / (double)((1 << m) - 1);
198714b11b2bSmrg
198814b11b2bSmrg    return r;
198914b11b2bSmrg}
199014b11b2bSmrg
199114b11b2bSmrgvoid
199214b11b2bSmrground_color (pixman_format_code_t format, color_t *color)
199314b11b2bSmrg{
199414b11b2bSmrg    if (PIXMAN_FORMAT_R (format) == 0)
199514b11b2bSmrg    {
199614b11b2bSmrg	color->r = 0.0;
199714b11b2bSmrg	color->g = 0.0;
199814b11b2bSmrg	color->b = 0.0;
199914b11b2bSmrg    }
200014b11b2bSmrg    else
200114b11b2bSmrg    {
200214b11b2bSmrg	color->r = round_channel (color->r, PIXMAN_FORMAT_R (format));
200314b11b2bSmrg	color->g = round_channel (color->g, PIXMAN_FORMAT_G (format));
200414b11b2bSmrg	color->b = round_channel (color->b, PIXMAN_FORMAT_B (format));
200514b11b2bSmrg    }
200614b11b2bSmrg
200714b11b2bSmrg    if (PIXMAN_FORMAT_A (format) == 0)
200814b11b2bSmrg	color->a = 1;
200914b11b2bSmrg    else
201014b11b2bSmrg	color->a = round_channel (color->a, PIXMAN_FORMAT_A (format));
201114b11b2bSmrg}
201214b11b2bSmrg
201314b11b2bSmrg/* The acceptable deviation in units of [0.0, 1.0]
201414b11b2bSmrg */
201514b11b2bSmrg#define DEVIATION (0.0128)
201614b11b2bSmrg
201714b11b2bSmrg/* Check whether @pixel is a valid quantization of the a, r, g, b
201814b11b2bSmrg * parameters. Some slack is permitted.
201914b11b2bSmrg */
202014b11b2bSmrgvoid
202114b11b2bSmrgpixel_checker_init (pixel_checker_t *checker, pixman_format_code_t format)
202214b11b2bSmrg{
202314b11b2bSmrg    assert (PIXMAN_FORMAT_VIS (format));
202414b11b2bSmrg
202514b11b2bSmrg    checker->format = format;
202614b11b2bSmrg
202714b11b2bSmrg    if (format == PIXMAN_rgba_float ||
202814b11b2bSmrg	format == PIXMAN_rgb_float)
202914b11b2bSmrg	return;
203014b11b2bSmrg
203114b11b2bSmrg    switch (PIXMAN_FORMAT_TYPE (format))
203214b11b2bSmrg    {
203314b11b2bSmrg    case PIXMAN_TYPE_A:
203414b11b2bSmrg	checker->bs = 0;
203514b11b2bSmrg	checker->gs = 0;
203614b11b2bSmrg	checker->rs = 0;
203714b11b2bSmrg	checker->as = 0;
203814b11b2bSmrg	break;
203914b11b2bSmrg
204014b11b2bSmrg    case PIXMAN_TYPE_ARGB:
204114b11b2bSmrg    case PIXMAN_TYPE_ARGB_SRGB:
204214b11b2bSmrg	checker->bs = 0;
204314b11b2bSmrg	checker->gs = checker->bs + PIXMAN_FORMAT_B (format);
204414b11b2bSmrg	checker->rs = checker->gs + PIXMAN_FORMAT_G (format);
204514b11b2bSmrg	checker->as = checker->rs + PIXMAN_FORMAT_R (format);
204614b11b2bSmrg	break;
204714b11b2bSmrg
204814b11b2bSmrg    case PIXMAN_TYPE_ABGR:
204914b11b2bSmrg	checker->rs = 0;
205014b11b2bSmrg	checker->gs = checker->rs + PIXMAN_FORMAT_R (format);
205114b11b2bSmrg	checker->bs = checker->gs + PIXMAN_FORMAT_G (format);
205214b11b2bSmrg	checker->as = checker->bs + PIXMAN_FORMAT_B (format);
205314b11b2bSmrg	break;
205414b11b2bSmrg
205514b11b2bSmrg    case PIXMAN_TYPE_BGRA:
205614b11b2bSmrg	/* With BGRA formats we start counting at the high end of the pixel */
205714b11b2bSmrg	checker->bs = PIXMAN_FORMAT_BPP (format) - PIXMAN_FORMAT_B (format);
205814b11b2bSmrg	checker->gs = checker->bs - PIXMAN_FORMAT_B (format);
205914b11b2bSmrg	checker->rs = checker->gs - PIXMAN_FORMAT_G (format);
206014b11b2bSmrg	checker->as = checker->rs - PIXMAN_FORMAT_R (format);
206114b11b2bSmrg	break;
206214b11b2bSmrg
206314b11b2bSmrg    case PIXMAN_TYPE_RGBA:
206414b11b2bSmrg	/* With BGRA formats we start counting at the high end of the pixel */
206514b11b2bSmrg	checker->rs = PIXMAN_FORMAT_BPP (format) - PIXMAN_FORMAT_R (format);
206614b11b2bSmrg	checker->gs = checker->rs - PIXMAN_FORMAT_R (format);
206714b11b2bSmrg	checker->bs = checker->gs - PIXMAN_FORMAT_G (format);
206814b11b2bSmrg	checker->as = checker->bs - PIXMAN_FORMAT_B (format);
206914b11b2bSmrg	break;
207014b11b2bSmrg
207114b11b2bSmrg    default:
207214b11b2bSmrg	assert (0);
207314b11b2bSmrg	break;
207414b11b2bSmrg    }
207514b11b2bSmrg
207614b11b2bSmrg    checker->am = ((1U << PIXMAN_FORMAT_A (format)) - 1) << checker->as;
207714b11b2bSmrg    checker->rm = ((1U << PIXMAN_FORMAT_R (format)) - 1) << checker->rs;
207814b11b2bSmrg    checker->gm = ((1U << PIXMAN_FORMAT_G (format)) - 1) << checker->gs;
207914b11b2bSmrg    checker->bm = ((1U << PIXMAN_FORMAT_B (format)) - 1) << checker->bs;
208014b11b2bSmrg
208114b11b2bSmrg    checker->aw = PIXMAN_FORMAT_A (format);
208214b11b2bSmrg    checker->rw = PIXMAN_FORMAT_R (format);
208314b11b2bSmrg    checker->gw = PIXMAN_FORMAT_G (format);
208414b11b2bSmrg    checker->bw = PIXMAN_FORMAT_B (format);
208514b11b2bSmrg
208614b11b2bSmrg    checker->ad = DEVIATION;
208714b11b2bSmrg    checker->rd = DEVIATION;
208814b11b2bSmrg    checker->gd = DEVIATION;
208914b11b2bSmrg    checker->bd = DEVIATION;
209014b11b2bSmrg}
209114b11b2bSmrg
209214b11b2bSmrg/* When dithering is enabled, we allow one extra pixel of tolerance
209314b11b2bSmrg */
209414b11b2bSmrgvoid
209514b11b2bSmrgpixel_checker_allow_dither (pixel_checker_t *checker)
209614b11b2bSmrg{
209714b11b2bSmrg    checker->ad += 1 / (double)((1 << checker->aw) - 1);
209814b11b2bSmrg    checker->rd += 1 / (double)((1 << checker->rw) - 1);
209914b11b2bSmrg    checker->gd += 1 / (double)((1 << checker->gw) - 1);
210014b11b2bSmrg    checker->bd += 1 / (double)((1 << checker->bw) - 1);
210114b11b2bSmrg}
210214b11b2bSmrg
210314b11b2bSmrgstatic void
210414b11b2bSmrgpixel_checker_require_uint32_format (const pixel_checker_t *checker)
210514b11b2bSmrg{
210614b11b2bSmrg    assert (checker->format != PIXMAN_rgba_float &&
210714b11b2bSmrg	    checker->format != PIXMAN_rgb_float);
210814b11b2bSmrg}
210914b11b2bSmrg
211014b11b2bSmrgvoid
211114b11b2bSmrgpixel_checker_split_pixel (const pixel_checker_t *checker, uint32_t pixel,
211214b11b2bSmrg			   int *a, int *r, int *g, int *b)
211314b11b2bSmrg{
211414b11b2bSmrg    pixel_checker_require_uint32_format(checker);
211514b11b2bSmrg
211614b11b2bSmrg    *a = (pixel & checker->am) >> checker->as;
211714b11b2bSmrg    *r = (pixel & checker->rm) >> checker->rs;
211814b11b2bSmrg    *g = (pixel & checker->gm) >> checker->gs;
211914b11b2bSmrg    *b = (pixel & checker->bm) >> checker->bs;
212014b11b2bSmrg}
212114b11b2bSmrg
212214b11b2bSmrgvoid
212314b11b2bSmrgpixel_checker_get_masks (const pixel_checker_t *checker,
212414b11b2bSmrg                         uint32_t              *am,
212514b11b2bSmrg                         uint32_t              *rm,
212614b11b2bSmrg                         uint32_t              *gm,
212714b11b2bSmrg                         uint32_t              *bm)
212814b11b2bSmrg{
212914b11b2bSmrg    pixel_checker_require_uint32_format(checker);
213014b11b2bSmrg
213114b11b2bSmrg    if (am)
213214b11b2bSmrg        *am = checker->am;
213314b11b2bSmrg    if (rm)
213414b11b2bSmrg        *rm = checker->rm;
213514b11b2bSmrg    if (gm)
213614b11b2bSmrg        *gm = checker->gm;
213714b11b2bSmrg    if (bm)
213814b11b2bSmrg        *bm = checker->bm;
213914b11b2bSmrg}
214014b11b2bSmrg
214114b11b2bSmrgvoid
214214b11b2bSmrgpixel_checker_convert_pixel_to_color (const pixel_checker_t *checker,
214314b11b2bSmrg                                      uint32_t pixel, color_t *color)
214414b11b2bSmrg{
214514b11b2bSmrg    int a, r, g, b;
214614b11b2bSmrg
214714b11b2bSmrg    pixel_checker_require_uint32_format(checker);
214814b11b2bSmrg
214914b11b2bSmrg    pixel_checker_split_pixel (checker, pixel, &a, &r, &g, &b);
215014b11b2bSmrg
215114b11b2bSmrg    if (checker->am == 0)
215214b11b2bSmrg        color->a = 1.0;
215314b11b2bSmrg    else
215414b11b2bSmrg        color->a = a / (double)(checker->am >> checker->as);
215514b11b2bSmrg
215614b11b2bSmrg    if (checker->rm == 0)
215714b11b2bSmrg        color->r = 0.0;
215814b11b2bSmrg    else
215914b11b2bSmrg        color->r = r / (double)(checker->rm >> checker->rs);
216014b11b2bSmrg
216114b11b2bSmrg    if (checker->gm == 0)
216214b11b2bSmrg        color->g = 0.0;
216314b11b2bSmrg    else
216414b11b2bSmrg        color->g = g / (double)(checker->gm >> checker->gs);
216514b11b2bSmrg
216614b11b2bSmrg    if (checker->bm == 0)
216714b11b2bSmrg        color->b = 0.0;
216814b11b2bSmrg    else
216914b11b2bSmrg        color->b = b / (double)(checker->bm >> checker->bs);
217014b11b2bSmrg
217114b11b2bSmrg    if (PIXMAN_FORMAT_TYPE (checker->format) == PIXMAN_TYPE_ARGB_SRGB)
217214b11b2bSmrg    {
217314b11b2bSmrg	color->r = convert_srgb_to_linear (color->r);
217414b11b2bSmrg	color->g = convert_srgb_to_linear (color->g);
217514b11b2bSmrg	color->b = convert_srgb_to_linear (color->b);
217614b11b2bSmrg    }
217714b11b2bSmrg}
217814b11b2bSmrg
217914b11b2bSmrgstatic int32_t
218014b11b2bSmrgconvert (double v, uint32_t width, uint32_t mask, uint32_t shift, double def)
218114b11b2bSmrg{
218214b11b2bSmrg    int32_t r;
218314b11b2bSmrg
218414b11b2bSmrg    if (!mask)
218514b11b2bSmrg	v = def;
218614b11b2bSmrg
218714b11b2bSmrg    r = (v * ((mask >> shift) + 1));
218814b11b2bSmrg    r -= r >> width;
218914b11b2bSmrg
219014b11b2bSmrg    return r;
219114b11b2bSmrg}
219214b11b2bSmrg
219314b11b2bSmrgstatic void
219414b11b2bSmrgget_limits (const pixel_checker_t *checker, double sign,
219514b11b2bSmrg	    color_t *color,
219614b11b2bSmrg	    int *ao, int *ro, int *go, int *bo)
219714b11b2bSmrg{
219814b11b2bSmrg    color_t tmp;
219914b11b2bSmrg
220014b11b2bSmrg    if (PIXMAN_FORMAT_TYPE (checker->format) == PIXMAN_TYPE_ARGB_SRGB)
220114b11b2bSmrg    {
220214b11b2bSmrg	tmp.a = color->a;
220314b11b2bSmrg	tmp.r = convert_linear_to_srgb (color->r);
220414b11b2bSmrg	tmp.g = convert_linear_to_srgb (color->g);
220514b11b2bSmrg	tmp.b = convert_linear_to_srgb (color->b);
220614b11b2bSmrg
220714b11b2bSmrg	color = &tmp;
220814b11b2bSmrg    }
220914b11b2bSmrg
221014b11b2bSmrg    *ao = convert (color->a + sign * checker->ad,
221114b11b2bSmrg		   checker->aw, checker->am, checker->as, 1.0);
221214b11b2bSmrg    *ro = convert (color->r + sign * checker->rd,
221314b11b2bSmrg		   checker->rw, checker->rm, checker->rs, 0.0);
221414b11b2bSmrg    *go = convert (color->g + sign * checker->gd,
221514b11b2bSmrg		   checker->gw, checker->gm, checker->gs, 0.0);
221614b11b2bSmrg    *bo = convert (color->b + sign * checker->bd,
221714b11b2bSmrg		   checker->bw, checker->bm, checker->bs, 0.0);
221814b11b2bSmrg}
221914b11b2bSmrg
222014b11b2bSmrgvoid
222114b11b2bSmrgpixel_checker_get_max (const pixel_checker_t *checker, color_t *color,
222214b11b2bSmrg		       int *am, int *rm, int *gm, int *bm)
222314b11b2bSmrg{
222414b11b2bSmrg    pixel_checker_require_uint32_format(checker);
222514b11b2bSmrg
222614b11b2bSmrg    get_limits (checker, 1, color, am, rm, gm, bm);
222714b11b2bSmrg}
222814b11b2bSmrg
222914b11b2bSmrgvoid
223014b11b2bSmrgpixel_checker_get_min (const pixel_checker_t *checker, color_t *color,
223114b11b2bSmrg		       int *am, int *rm, int *gm, int *bm)
223214b11b2bSmrg{
223314b11b2bSmrg    pixel_checker_require_uint32_format(checker);
223414b11b2bSmrg
223514b11b2bSmrg    get_limits (checker, - 1, color, am, rm, gm, bm);
223614b11b2bSmrg}
223714b11b2bSmrg
223814b11b2bSmrgpixman_bool_t
223914b11b2bSmrgpixel_checker_check (const pixel_checker_t *checker, uint32_t pixel,
224014b11b2bSmrg		     color_t *color)
224114b11b2bSmrg{
224214b11b2bSmrg    int32_t a_lo, a_hi, r_lo, r_hi, g_lo, g_hi, b_lo, b_hi;
224314b11b2bSmrg    int32_t ai, ri, gi, bi;
224414b11b2bSmrg    pixman_bool_t result;
224514b11b2bSmrg
224614b11b2bSmrg    pixel_checker_require_uint32_format(checker);
224714b11b2bSmrg
224814b11b2bSmrg    pixel_checker_get_min (checker, color, &a_lo, &r_lo, &g_lo, &b_lo);
224914b11b2bSmrg    pixel_checker_get_max (checker, color, &a_hi, &r_hi, &g_hi, &b_hi);
225014b11b2bSmrg    pixel_checker_split_pixel (checker, pixel, &ai, &ri, &gi, &bi);
225114b11b2bSmrg
225214b11b2bSmrg    result =
225314b11b2bSmrg	a_lo <= ai && ai <= a_hi	&&
225414b11b2bSmrg	r_lo <= ri && ri <= r_hi	&&
225514b11b2bSmrg	g_lo <= gi && gi <= g_hi	&&
225614b11b2bSmrg	b_lo <= bi && bi <= b_hi;
225714b11b2bSmrg
225814b11b2bSmrg    return result;
225914b11b2bSmrg}
226014b11b2bSmrg
226114b11b2bSmrgstatic void
226214b11b2bSmrgcolor_limits (const pixel_checker_t *checker,
226314b11b2bSmrg	      double limit, const color_t *color, color_t *out)
226414b11b2bSmrg{
226514b11b2bSmrg    if (PIXMAN_FORMAT_A(checker->format))
226614b11b2bSmrg	out->a = color->a + limit;
226714b11b2bSmrg    else
226814b11b2bSmrg	out->a = 1.;
226914b11b2bSmrg
227014b11b2bSmrg    out->r = color->r + limit;
227114b11b2bSmrg    out->g = color->g + limit;
227214b11b2bSmrg    out->b = color->b + limit;
227314b11b2bSmrg}
227414b11b2bSmrg
227514b11b2bSmrgpixman_bool_t
227614b11b2bSmrgpixel_checker_check_color (const pixel_checker_t *checker,
227714b11b2bSmrg			   const color_t *actual, const color_t *reference)
227814b11b2bSmrg{
227914b11b2bSmrg    color_t min, max;
228014b11b2bSmrg    pixman_bool_t result;
228114b11b2bSmrg
228214b11b2bSmrg    color_limits(checker, -DEVIATION, reference, &min);
228314b11b2bSmrg    color_limits(checker, DEVIATION, reference, &max);
228414b11b2bSmrg
228514b11b2bSmrg    result =
228614b11b2bSmrg	actual->a >= min.a && actual->a <= max.a &&
228714b11b2bSmrg	actual->r >= min.r && actual->r <= max.r &&
228814b11b2bSmrg	actual->g >= min.g && actual->g <= max.g &&
228914b11b2bSmrg	actual->b >= min.b && actual->b <= max.b;
229014b11b2bSmrg
229114b11b2bSmrg    return result;
229214b11b2bSmrg}
2293