#include #include "utils.h" static const pixman_format_code_t glyph_formats[] = { PIXMAN_a8r8g8b8, PIXMAN_a8, PIXMAN_a4, PIXMAN_a1, PIXMAN_x8r8g8b8, PIXMAN_r3g3b2, PIXMAN_null, }; static const pixman_format_code_t formats[] = { PIXMAN_a8r8g8b8, PIXMAN_a8b8g8r8, PIXMAN_x8r8g8b8, PIXMAN_x8b8g8r8, PIXMAN_r5g6b5, PIXMAN_b5g6r5, PIXMAN_a8, PIXMAN_a1, PIXMAN_r3g3b2, PIXMAN_b8g8r8a8, PIXMAN_b8g8r8x8, PIXMAN_r8g8b8a8, PIXMAN_r8g8b8x8, PIXMAN_x14r6g6b6, PIXMAN_r8g8b8, PIXMAN_b8g8r8, PIXMAN_x2r10g10b10, PIXMAN_a2r10g10b10, PIXMAN_x2b10g10r10, PIXMAN_a2b10g10r10, PIXMAN_a1r5g5b5, PIXMAN_x1r5g5b5, PIXMAN_a1b5g5r5, PIXMAN_x1b5g5r5, PIXMAN_a4r4g4b4, PIXMAN_x4r4g4b4, PIXMAN_a4b4g4r4, PIXMAN_x4b4g4r4, PIXMAN_r3g3b2, PIXMAN_b2g3r3, PIXMAN_a2r2g2b2, PIXMAN_a2b2g2r2, PIXMAN_x4a4, PIXMAN_a4, PIXMAN_r1g2b1, PIXMAN_b1g2r1, PIXMAN_a1r1g1b1, PIXMAN_a1b1g1r1, PIXMAN_null, }; static const pixman_op_t operators[] = { PIXMAN_OP_SRC, PIXMAN_OP_OVER, PIXMAN_OP_ADD, PIXMAN_OP_CLEAR, PIXMAN_OP_SRC, PIXMAN_OP_DST, PIXMAN_OP_OVER, PIXMAN_OP_OVER_REVERSE, PIXMAN_OP_IN, PIXMAN_OP_IN_REVERSE, PIXMAN_OP_OUT, PIXMAN_OP_OUT_REVERSE, PIXMAN_OP_ATOP, PIXMAN_OP_ATOP_REVERSE, PIXMAN_OP_XOR, PIXMAN_OP_ADD }; enum { ALLOW_CLIPPED = (1 << 0), ALLOW_ALPHA_MAP = (1 << 1), ALLOW_SOURCE_CLIPPING = (1 << 2), ALLOW_REPEAT = (1 << 3), ALLOW_SOLID = (1 << 4), ALLOW_FENCED_MEMORY = (1 << 5), }; static void destroy_fenced (pixman_image_t *image, void *data) { fence_free (data); } static void destroy_malloced (pixman_image_t *image, void *data) { free (data); } static pixman_format_code_t random_format (const pixman_format_code_t *formats) { int i; i = 0; while (formats[i] != PIXMAN_null) ++i; return formats[lcg_rand_n (i)]; } static pixman_image_t * create_image (int max_size, const pixman_format_code_t *formats, uint32_t flags) { int width, height; pixman_image_t *image; pixman_format_code_t format; uint32_t *data; int bpp; int stride; int i; pixman_image_destroy_func_t destroy; if ((flags & ALLOW_SOLID) && lcg_rand_n (4) == 0) { pixman_color_t color; color.alpha = lcg_rand_u32(); color.red = lcg_rand_u32(); color.green = lcg_rand_u32(); color.blue = lcg_rand_u32(); return pixman_image_create_solid_fill (&color); } width = lcg_rand_n (max_size) + 1; height = lcg_rand_n (max_size) + 1; format = random_format (formats); bpp = PIXMAN_FORMAT_BPP (format); stride = (width * bpp + 7) / 8 + lcg_rand_n (17); stride = (stride + 3) & ~3; if (lcg_rand_n (64) == 0) { if (!(data = (uint32_t *)make_random_bytes (stride * height))) { fprintf (stderr, "Out of memory\n"); abort (); } destroy = destroy_fenced; } else { uint8_t *d8; data = malloc (stride * height); d8 = (uint8_t *)data; for (i = 0; i < height * stride; ++i) d8[i] = lcg_rand_n (256); destroy = destroy_malloced; } image = pixman_image_create_bits (format, width, height, data, stride); pixman_image_set_destroy_function (image, destroy, data); if ((flags & ALLOW_CLIPPED) && lcg_rand_n (8) == 0) { pixman_box16_t clip_boxes[8]; pixman_region16_t clip; int n = lcg_rand_n (8) + 1; for (i = 0; i < n; i++) { clip_boxes[i].x1 = lcg_rand_n (width); clip_boxes[i].y1 = lcg_rand_n (height); clip_boxes[i].x2 = clip_boxes[i].x1 + lcg_rand_n (width - clip_boxes[i].x1); clip_boxes[i].y2 = clip_boxes[i].y1 + lcg_rand_n (height - clip_boxes[i].y1); } pixman_region_init_rects (&clip, clip_boxes, n); pixman_image_set_clip_region (image, &clip); pixman_region_fini (&clip); } if ((flags & ALLOW_SOURCE_CLIPPING) && lcg_rand_n (4) == 0) { pixman_image_set_source_clipping (image, TRUE); pixman_image_set_has_client_clip (image, TRUE); } if ((flags & ALLOW_ALPHA_MAP) && lcg_rand_n (16) == 0) { pixman_image_t *alpha_map; int alpha_x, alpha_y; alpha_x = lcg_rand_n (width); alpha_y = lcg_rand_n (height); alpha_map = create_image (max_size, formats, (flags & ~(ALLOW_ALPHA_MAP | ALLOW_SOLID))); pixman_image_set_alpha_map (image, alpha_map, alpha_x, alpha_y); pixman_image_unref (alpha_map); } if ((flags & ALLOW_REPEAT) && lcg_rand_n (2) == 0) pixman_image_set_repeat (image, lcg_rand_n (4)); image_endian_swap (image); return image; } #define KEY1(p) ((void *)(((unsigned long)p) ^ (0xa7e23dfaUL))) #define KEY2(p) ((void *)(((unsigned long)p) ^ (0xabcd9876UL))) #define MAX_GLYPHS 32 uint32_t test_glyphs (int testnum, int verbose) { pixman_image_t *glyph_images[MAX_GLYPHS]; pixman_glyph_t glyphs[4 * MAX_GLYPHS]; uint32_t crc32 = 0; pixman_image_t *source, *dest; int n_glyphs, i; pixman_glyph_cache_t *cache; lcg_srand (testnum); cache = pixman_glyph_cache_create (); source = create_image (300, formats, ALLOW_CLIPPED | ALLOW_ALPHA_MAP | ALLOW_SOURCE_CLIPPING | ALLOW_REPEAT | ALLOW_SOLID); dest = create_image (128, formats, ALLOW_CLIPPED | ALLOW_ALPHA_MAP | ALLOW_SOURCE_CLIPPING); pixman_glyph_cache_freeze (cache); n_glyphs = lcg_rand_n (MAX_GLYPHS); for (i = 0; i < n_glyphs; ++i) glyph_images[i] = create_image (32, glyph_formats, 0); for (i = 0; i < 4 * n_glyphs; ++i) { int g = lcg_rand_n (n_glyphs); pixman_image_t *glyph_img = glyph_images[g]; void *key1 = KEY1 (glyph_img); void *key2 = KEY2 (glyph_img); const void *glyph; if (!(glyph = pixman_glyph_cache_lookup (cache, key1, key2))) { glyph = pixman_glyph_cache_insert (cache, key1, key2, 5, 8, glyph_img); } glyphs[i].glyph = glyph; glyphs[i].x = lcg_rand_n (128); glyphs[i].y = lcg_rand_n (128); } if (lcg_rand_n (2) == 0) { int src_x = lcg_rand_n (300) - 150; int src_y = lcg_rand_n (300) - 150; int mask_x = lcg_rand_n (64) - 32; int mask_y = lcg_rand_n (64) - 32; int dest_x = lcg_rand_n (64) - 32; int dest_y = lcg_rand_n (64) - 32; int width = lcg_rand_n (64); int height = lcg_rand_n (64); pixman_op_t op = operators[lcg_rand_n (ARRAY_LENGTH (operators))]; pixman_format_code_t format = random_format (glyph_formats); pixman_composite_glyphs ( op, source, dest, format, src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height, cache, 4 * n_glyphs, glyphs); } else { pixman_op_t op = operators[lcg_rand_n (ARRAY_LENGTH (operators))]; int src_x = lcg_rand_n (300) - 150; int src_y = lcg_rand_n (300) - 150; int dest_x = lcg_rand_n (64) - 32; int dest_y = lcg_rand_n (64) - 32; pixman_composite_glyphs_no_mask ( op, source, dest, src_x, src_y, dest_x, dest_y, cache, 4 * n_glyphs, glyphs); } pixman_glyph_cache_thaw (cache); for (i = 0; i < n_glyphs; ++i) { pixman_image_t *img = glyph_images[i]; void *key1, *key2; key1 = KEY1 (img); key2 = KEY2 (img); pixman_glyph_cache_remove (cache, key1, key2); pixman_image_unref (glyph_images[i]); } crc32 = compute_crc32_for_image (0, dest); pixman_image_unref (source); pixman_image_unref (dest); pixman_glyph_cache_destroy (cache); return crc32; } int main (int argc, const char *argv[]) { return fuzzer_test_main ("glyph", 30000, 0x741CB2DB, test_glyphs, argc, argv); }