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