cairo_image_surface_t *
_cairo_image_surface_map_to_image (void *abstract_other,
				   const cairo_rectangle_int_t *extents)
{
    cairo_image_surface_t *other = abstract_other;
    cairo_surface_t *surface;
    uint8_t *data;

    data = other->data;
    data += extents->y * other->stride;
    data += extents->x * PIXMAN_FORMAT_BPP (other->pixman_format)/ 8;

    surface =
	_cairo_image_surface_create_with_pixman_format (data,
							other->pixman_format,
							extents->width,
							extents->height,
							other->stride);

    cairo_surface_set_device_offset (surface, -extents->x, -extents->y);
    return (cairo_image_surface_t *) surface;
}
Exemple #2
0
pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
                                       pixman_format_code_t pixman_format, int width,
                                       int height, int gross_pixels, int top_down)
{
    int stride;
    pixman_image_t *surface = NULL;

    stride = (gross_pixels / height) * (PIXMAN_FORMAT_BPP (pixman_format) / 8);

    /* pixman requires strides to be 4-byte aligned */
    stride = SPICE_ALIGN(stride, 4);
    
    if (!top_down) {
        stride = -stride;
    }

   surface = surface_create_stride(
#ifdef WIN32
            canvas_data->dc,
#endif
            pixman_format, width, height, stride);
    canvas_data->out_surface = surface;
    return surface;
}
/*
 * Composite operation with pseudorandom images
 */
uint32_t
test_composite (int testnum, int verbose)
{
    int i;
    pixman_image_t *src_img = NULL;
    pixman_image_t *dst_img = NULL;
    pixman_image_t *mask_img = NULL;
    int src_width, src_height;
    int dst_width, dst_height;
    int src_stride, dst_stride;
    int src_x, src_y;
    int dst_x, dst_y;
    int mask_x, mask_y;
    int w, h;
    pixman_op_t op;
    pixman_format_code_t src_fmt, dst_fmt, mask_fmt;
    uint32_t *dstbuf, *srcbuf, *maskbuf;
    uint32_t crc32;
    int max_width, max_height, max_extra_stride;
    FLOAT_REGS_CORRUPTION_DETECTOR_START ();

    max_width = max_height = 24 + testnum / 10000;
    max_extra_stride = 4 + testnum / 1000000;

    if (max_width > 256)
	max_width = 256;

    if (max_height > 16)
	max_height = 16;

    if (max_extra_stride > 8)
	max_extra_stride = 8;

    lcg_srand (testnum);

    op = op_list[lcg_rand_n (sizeof (op_list) / sizeof (op_list[0]))];

    if (lcg_rand_n (8))
    {
	/* normal image */
	src_img = create_random_image (img_fmt_list, max_width, max_height,
				       max_extra_stride, &src_fmt);
    }
    else
    {
	/* solid case */
	src_img = create_random_image (img_fmt_list, 1, 1,
				       max_extra_stride, &src_fmt);

	pixman_image_set_repeat (src_img, PIXMAN_REPEAT_NORMAL);
    }

    dst_img = create_random_image (img_fmt_list, max_width, max_height,
				   max_extra_stride, &dst_fmt);

    src_width = pixman_image_get_width (src_img);
    src_height = pixman_image_get_height (src_img);
    src_stride = pixman_image_get_stride (src_img);

    dst_width = pixman_image_get_width (dst_img);
    dst_height = pixman_image_get_height (dst_img);
    dst_stride = pixman_image_get_stride (dst_img);

    dstbuf = pixman_image_get_data (dst_img);
    srcbuf = pixman_image_get_data (src_img);

    src_x = lcg_rand_n (src_width);
    src_y = lcg_rand_n (src_height);
    dst_x = lcg_rand_n (dst_width);
    dst_y = lcg_rand_n (dst_height);

    mask_img = NULL;
    mask_fmt = PIXMAN_null;
    mask_x = 0;
    mask_y = 0;
    maskbuf = NULL;

    if ((src_fmt == PIXMAN_x8r8g8b8 || src_fmt == PIXMAN_x8b8g8r8) &&
	(lcg_rand_n (4) == 0))
    {
	/* PIXBUF */
	mask_fmt = lcg_rand_n (2) ? PIXMAN_a8r8g8b8 : PIXMAN_a8b8g8r8;
	mask_img = pixman_image_create_bits (mask_fmt,
	                                     src_width,
	                                     src_height,
	                                     srcbuf,
	                                     src_stride);
	mask_x = src_x;
	mask_y = src_y;
	maskbuf = srcbuf;
    }
    else if (lcg_rand_n (2))
    {
	if (lcg_rand_n (2))
	{
	    mask_img = create_random_image (mask_fmt_list, max_width, max_height,
					   max_extra_stride, &mask_fmt);
	}
	else
	{
	    /* solid case */
	    mask_img = create_random_image (mask_fmt_list, 1, 1,
					   max_extra_stride, &mask_fmt);
	    pixman_image_set_repeat (mask_img, PIXMAN_REPEAT_NORMAL);
	}

	if (lcg_rand_n (2))
	    pixman_image_set_component_alpha (mask_img, 1);

	mask_x = lcg_rand_n (pixman_image_get_width (mask_img));
	mask_y = lcg_rand_n (pixman_image_get_height (mask_img));
    }


    w = lcg_rand_n (dst_width - dst_x + 1);
    h = lcg_rand_n (dst_height - dst_y + 1);

    if (verbose)
    {
	printf ("op=%d, src_fmt=%08X, dst_fmt=%08X, mask_fmt=%08X\n",
	    op, src_fmt, dst_fmt, mask_fmt);
	printf ("src_width=%d, src_height=%d, dst_width=%d, dst_height=%d\n",
	    src_width, src_height, dst_width, dst_height);
	printf ("src_x=%d, src_y=%d, dst_x=%d, dst_y=%d\n",
	    src_x, src_y, dst_x, dst_y);
	printf ("src_stride=%d, dst_stride=%d\n",
	    src_stride, dst_stride);
	printf ("w=%d, h=%d\n", w, h);
    }

    pixman_image_composite (op, src_img, mask_img, dst_img,
			    src_x, src_y, mask_x, mask_y, dst_x, dst_y, w, h);

    if (verbose)
    {
	int j;

	printf ("---\n");
	for (i = 0; i < dst_height; i++)
	{
	    for (j = 0; j < dst_stride; j++)
	    {
		if (j == (dst_width * PIXMAN_FORMAT_BPP (dst_fmt) + 7) / 8)
		    printf ("| ");

		printf ("%02X ", *((uint8_t *)dstbuf + i * dst_stride + j));
	    }
	    printf ("\n");
	}
	printf ("---\n");
    }

    free_random_image (0, src_img, PIXMAN_null);
    crc32 = free_random_image (0, dst_img, dst_fmt);

    if (mask_img)
    {
	if (srcbuf == maskbuf)
	    pixman_image_unref(mask_img);
	else
	    free_random_image (0, mask_img, PIXMAN_null);
    }

    FLOAT_REGS_CORRUPTION_DETECTOR_FINISH ();
    return crc32;
}
/*
 * Composite operation with pseudorandom images
 */
uint32_t
test_composite (int      testnum,
		int      verbose)
{
    int                i;
    pixman_image_t *   src_img;
    pixman_image_t *   dst_img;
    pixman_region16_t  clip;
    int                dst_width, dst_height;
    int                dst_stride;
    int                dst_x, dst_y;
    int                dst_bpp;
    pixman_op_t        op;
    uint32_t *         dst_bits;
    uint32_t           crc32;
    pixman_format_code_t mask_format, dst_format;
    pixman_trapezoid_t *traps;
    int src_x, src_y;
    int n_traps;

    static pixman_color_t colors[] =
    {
	{ 0xffff, 0xffff, 0xffff, 0xffff },
	{ 0x0000, 0x0000, 0x0000, 0x0000 },
	{ 0xabcd, 0xabcd, 0x0000, 0xabcd },
	{ 0x0000, 0x0000, 0x0000, 0xffff },
	{ 0x0101, 0x0101, 0x0101, 0x0101 },
	{ 0x7777, 0x6666, 0x5555, 0x9999 },
    };
    
    FLOAT_REGS_CORRUPTION_DETECTOR_START ();

    lcg_srand (testnum);

    op = RANDOM_ELT (operators);
    mask_format = RANDOM_ELT (mask_formats);

    /* Create source image */
    
    if (lcg_rand_n (4) == 0)
    {
	src_img = pixman_image_create_solid_fill (
	    &(colors[lcg_rand_n (ARRAY_LENGTH (colors))]));

	src_x = 10;
	src_y = 234;
    }
    else
    {
	pixman_format_code_t src_format = RANDOM_ELT(formats);
	int src_bpp = (PIXMAN_FORMAT_BPP (src_format) + 7) / 8;
	int src_width = lcg_rand_n (MAX_SRC_WIDTH) + 1;
	int src_height = lcg_rand_n (MAX_SRC_HEIGHT) + 1;
	int src_stride = src_width * src_bpp + lcg_rand_n (MAX_STRIDE) * src_bpp;
	uint32_t *bits;

	src_x = -(src_width / 4) + lcg_rand_n (src_width * 3 / 2);
	src_y = -(src_height / 4) + lcg_rand_n (src_height * 3 / 2);

	src_stride = (src_stride + 3) & ~3;
	
	bits = (uint32_t *)make_random_bytes (src_stride * src_height);

	src_img = pixman_image_create_bits (
	    src_format, src_width, src_height, bits, src_stride);

	pixman_image_set_destroy_function (src_img, destroy_bits, bits);

	if (lcg_rand_n (8) == 0)
	{
	    pixman_box16_t clip_boxes[2];
	    int            n = lcg_rand_n (2) + 1;
	    
	    for (i = 0; i < n; i++)
	    {
		clip_boxes[i].x1 = lcg_rand_n (src_width);
		clip_boxes[i].y1 = lcg_rand_n (src_height);
		clip_boxes[i].x2 =
		    clip_boxes[i].x1 + lcg_rand_n (src_width - clip_boxes[i].x1);
		clip_boxes[i].y2 =
		    clip_boxes[i].y1 + lcg_rand_n (src_height - clip_boxes[i].y1);
		
		if (verbose)
		{
		    printf ("source clip box: [%d,%d-%d,%d]\n",
			    clip_boxes[i].x1, clip_boxes[i].y1,
			    clip_boxes[i].x2, clip_boxes[i].y2);
		}
	    }
	    
	    pixman_region_init_rects (&clip, clip_boxes, n);
	    pixman_image_set_clip_region (src_img, &clip);
	    pixman_image_set_source_clipping (src_img, 1);
	    pixman_region_fini (&clip);
	}

	image_endian_swap (src_img);
    }

    /* Create destination image */
    {
	dst_format = RANDOM_ELT(formats);
	dst_bpp = (PIXMAN_FORMAT_BPP (dst_format) + 7) / 8;
	dst_width = lcg_rand_n (MAX_DST_WIDTH) + 1;
	dst_height = lcg_rand_n (MAX_DST_HEIGHT) + 1;
	dst_stride = dst_width * dst_bpp + lcg_rand_n (MAX_STRIDE) * dst_bpp;
	dst_stride = (dst_stride + 3) & ~3;
	
	dst_bits = (uint32_t *)make_random_bytes (dst_stride * dst_height);

	dst_x = -(dst_width / 4) + lcg_rand_n (dst_width * 3 / 2);
	dst_y = -(dst_height / 4) + lcg_rand_n (dst_height * 3 / 2);
	
	dst_img = pixman_image_create_bits (
	    dst_format, dst_width, dst_height, dst_bits, dst_stride);

	image_endian_swap (dst_img);
    }

    /* Create traps */
    {
	int i;

	n_traps = lcg_rand_n (25);
	traps = fence_malloc (n_traps * sizeof (pixman_trapezoid_t));

	for (i = 0; i < n_traps; ++i)
	{
	    pixman_trapezoid_t *t = &(traps[i]);
	    
	    t->top = random_fixed (MAX_DST_HEIGHT) - MAX_DST_HEIGHT / 2;
	    t->bottom = t->top + random_fixed (MAX_DST_HEIGHT);
	    t->left.p1.x = random_fixed (MAX_DST_WIDTH) - MAX_DST_WIDTH / 2;
	    t->left.p1.y = t->top - random_fixed (50);
	    t->left.p2.x = random_fixed (MAX_DST_WIDTH) - MAX_DST_WIDTH / 2;
	    t->left.p2.y = t->bottom + random_fixed (50);
	    t->right.p1.x = t->left.p1.x + random_fixed (MAX_DST_WIDTH);
	    t->right.p1.y = t->top - random_fixed (50);
	    t->right.p2.x = t->left.p2.x + random_fixed (MAX_DST_WIDTH);
	    t->right.p2.y = t->bottom - random_fixed (50);
	}
    }
    
    if (lcg_rand_n (8) == 0)
    {
	pixman_box16_t clip_boxes[2];
	int            n = lcg_rand_n (2) + 1;
	for (i = 0; i < n; i++)
	{
	    clip_boxes[i].x1 = lcg_rand_n (dst_width);
	    clip_boxes[i].y1 = lcg_rand_n (dst_height);
	    clip_boxes[i].x2 =
		clip_boxes[i].x1 + lcg_rand_n (dst_width - clip_boxes[i].x1);
	    clip_boxes[i].y2 =
		clip_boxes[i].y1 + lcg_rand_n (dst_height - clip_boxes[i].y1);

	    if (verbose)
	    {
		printf ("destination clip box: [%d,%d-%d,%d]\n",
		        clip_boxes[i].x1, clip_boxes[i].y1,
		        clip_boxes[i].x2, clip_boxes[i].y2);
	    }
	}
	pixman_region_init_rects (&clip, clip_boxes, n);
	pixman_image_set_clip_region (dst_img, &clip);
	pixman_region_fini (&clip);
    }

    pixman_composite_trapezoids (op, src_img, dst_img, mask_format,
				 src_x, src_y, dst_x, dst_y, n_traps, traps);

    if (dst_format == PIXMAN_x8r8g8b8)
    {
	/* ignore unused part */
	for (i = 0; i < dst_stride * dst_height / 4; i++)
	    dst_bits[i] &= 0xFFFFFF;
    }

    image_endian_swap (dst_img);

    if (verbose)
    {
	int j;
	
	for (i = 0; i < dst_height; i++)
	{
	    for (j = 0; j < dst_stride; j++)
		printf ("%02X ", *((uint8_t *)dst_bits + i * dst_stride + j));

	    printf ("\n");
	}
    }

    crc32 = compute_crc32 (0, dst_bits, dst_stride * dst_height);

    fence_free (dst_bits);
    
    pixman_image_unref (src_img);
    pixman_image_unref (dst_img);
    fence_free (traps);

    FLOAT_REGS_CORRUPTION_DETECTOR_FINISH ();
    return crc32;
}
Exemple #5
0
static cairo_surface_t *
_get_image (cairo_xcb_surface_t		 *surface,
	    cairo_bool_t		  use_shm,
	    int x, int y,
	    int width, int height)
{
    cairo_surface_t *image;
    cairo_xcb_connection_t *connection;
    xcb_get_image_reply_t *reply;
    cairo_int_status_t status;

    assert (surface->fallback == NULL);
    assert (x >= 0);
    assert (y >= 0);
    assert (x + width <= surface->width);
    assert (y + height <= surface->height);

    if (surface->deferred_clear) {
	image =
	    _cairo_image_surface_create_with_pixman_format (NULL,
							    surface->pixman_format,
							    width, height,
							    0);
	if (surface->deferred_clear_color.alpha_short > 0x00ff) {
	    cairo_solid_pattern_t solid;

	    _cairo_pattern_init_solid (&solid, &surface->deferred_clear_color);
	    status = _cairo_surface_paint (image,
					   CAIRO_OPERATOR_SOURCE,
					   &solid.base,
					   NULL);
	    if (unlikely (status)) {
		cairo_surface_destroy (image);
		image = _cairo_surface_create_in_error (status);
	    }
	}
	return image;
    }

    connection = surface->connection;

    status = _cairo_xcb_connection_acquire (connection);
    if (unlikely (status))
	return _cairo_surface_create_in_error (status);

    if (use_shm) {
	image = _get_shm_image (surface, x, y, width, height);
	if (image) {
	    if (image->status) {
		_cairo_xcb_connection_release (connection);
		return image;
	    }
	    cairo_surface_destroy (image);
	}
    }

    status = _cairo_xcb_connection_get_image (connection,
					      surface->drawable,
					      x, y,
					      width, height,
					      &reply);
    if (unlikely (status))
	goto FAIL;

    if (reply == NULL && ! surface->owns_pixmap) {
	/* xcb_get_image_t from a window is dangerous because it can
	 * produce errors if the window is unmapped or partially
	 * outside the screen. We could check for errors and
	 * retry, but to keep things simple, we just create a
	 * temporary pixmap
	 *
	 * If we hit this fallback too often, we should remember so and
	 * skip the round-trip from the above GetImage request,
	 * similar to what cairo-xlib does.
	 */
	xcb_pixmap_t pixmap;
	xcb_gcontext_t gc;

	gc = _cairo_xcb_screen_get_gc (surface->screen,
				       surface->drawable,
				       surface->depth);
	pixmap = _cairo_xcb_connection_create_pixmap (connection,
						      surface->depth,
						      surface->drawable,
						      width, height);

	/* XXX IncludeInferiors? */
	_cairo_xcb_connection_copy_area (connection,
					 surface->drawable,
					 pixmap, gc,
					 x, y,
					 0, 0,
					 width, height);

	_cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);

	status = _cairo_xcb_connection_get_image (connection,
						  pixmap,
						  0, 0,
						  width, height,
						  &reply);
	_cairo_xcb_connection_free_pixmap (connection, pixmap);

	if (unlikely (status))
	    goto FAIL;
    }

    if (unlikely (reply == NULL)) {
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	goto FAIL;
    }

    /* XXX byte swap */
    /* XXX format conversion */
    assert (reply->depth == surface->depth);

    image = _cairo_image_surface_create_with_pixman_format
	(xcb_get_image_data (reply),
	 surface->pixman_format,
	 width, height,
	 CAIRO_STRIDE_FOR_WIDTH_BPP (width,
				     PIXMAN_FORMAT_BPP (surface->pixman_format)));
    status = image->status;
    if (unlikely (status)) {
	free (reply);
	goto FAIL;
    }

    /* XXX */
    pixman_image_set_destroy_function (((cairo_image_surface_t *)image)->pixman_image, _destroy_image, reply);

    _cairo_xcb_connection_release (connection);

    return image;

FAIL:
    _cairo_xcb_connection_release (connection);
    return _cairo_surface_create_in_error (status);
}
/* Create random image for testing purposes */
static pixman_image_t *
create_random_image (pixman_format_code_t *allowed_formats,
		     int                   max_width,
		     int                   max_height,
		     int                   max_extra_stride,
		     pixman_format_code_t *used_fmt)
{
    int n = 0, width, height, stride;
    pixman_format_code_t fmt;
    uint32_t *buf;
    pixman_image_t *img;

    while (allowed_formats[n] != PIXMAN_null)
	n++;

    if (n > N_MOST_LIKELY_FORMATS && prng_rand_n (4) != 0)
	n = N_MOST_LIKELY_FORMATS;
    fmt = allowed_formats[prng_rand_n (n)];

    width = prng_rand_n (max_width) + 1;
    height = prng_rand_n (max_height) + 1;
    stride = (width * PIXMAN_FORMAT_BPP (fmt) + 7) / 8 +
	prng_rand_n (max_extra_stride + 1);
    stride = (stride + 3) & ~3;

    /* do the allocation */
    buf = aligned_malloc (64, stride * height);

    if (prng_rand_n (4) == 0)
    {
	/* uniform distribution */
	prng_randmemset (buf, stride * height, 0);
    }
    else
    {
	/* significantly increased probability for 0x00 and 0xFF */
	prng_randmemset (buf, stride * height, RANDMEMSET_MORE_00_AND_FF);
    }

    /* test negative stride */
    if (prng_rand_n (4) == 0)
    {
	buf += (stride / 4) * (height - 1);
	stride = - stride;
    }
    
    img = pixman_image_create_bits (fmt, width, height, buf, stride);

    if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_COLOR)
    {
	pixman_image_set_indexed (img, &(rgb_palette[PIXMAN_FORMAT_BPP (fmt)]));
    }
    else if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_GRAY)
    {
	pixman_image_set_indexed (img, &(y_palette[PIXMAN_FORMAT_BPP (fmt)]));
    }

    if (prng_rand_n (16) == 0)
	pixman_image_set_filter (img, PIXMAN_FILTER_BILINEAR, NULL, 0);

    image_endian_swap (img);

    if (used_fmt) *used_fmt = fmt;
    return img;
}
Exemple #7
0
cairo_status_t
_cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
			      cairo_image_surface_t *src,
			      int src_x, int src_y,
			      int width, int height,
			      int dst_x, int dst_y)
{
    GLenum internal_format, format, type;
    cairo_bool_t has_alpha, needs_swap;
    cairo_image_surface_t *clone = NULL;
    cairo_gl_context_t *ctx;
    int cpp;
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;

    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
    if (unlikely (status))
	return status;

    if (! _cairo_gl_get_image_format_and_type (ctx->gl_flavor,
					       src->pixman_format,
					       &internal_format,
					       &format,
					       &type,
					       &has_alpha,
					       &needs_swap))
    {
	cairo_bool_t is_supported;

	clone = _cairo_image_surface_coerce (src);
	if (unlikely (status = clone->base.status))
	    goto FAIL;

	is_supported =
	    _cairo_gl_get_image_format_and_type (ctx->gl_flavor,
						 clone->pixman_format,
		                                 &internal_format,
						 &format,
						 &type,
						 &has_alpha,
						 &needs_swap);
	assert (is_supported);
	assert (!needs_swap);
	src = clone;
    }

    cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8;

    status = _cairo_gl_surface_flush (&dst->base);
    if (unlikely (status))
	goto FAIL;

    if (_cairo_gl_surface_is_texture (dst)) {
	void *data_start = src->data + src_y * src->stride + src_x * cpp;
	void *data_start_gles2 = NULL;

	/*
	 * Due to GL_UNPACK_ROW_LENGTH missing in GLES2 we have to extract the
	 * image data ourselves in some cases. In particular, we must extract
	 * the pixels if:
	 * a. we don't want full-length lines or
	 * b. the row stride cannot be handled by GL itself using a 4 byte
	 *     alignment constraint
	 */
	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
	    (src->width * cpp < src->stride - 3 ||
	     width != src->width))
	{
	    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
	    status = _cairo_gl_surface_extract_image_data (src, src_x, src_y,
							   width, height,
							   &data_start_gles2);
	    if (unlikely (status))
		goto FAIL;

	    data_start = data_start_gles2;
	}
	else
	{
	    glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
	    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
		glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp);
	}

        _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
	glBindTexture (ctx->tex_target, dst->tex);
	glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexSubImage2D (ctx->tex_target, 0,
			 dst_x, dst_y, width, height,
			 format, type, data_start);

	free (data_start_gles2);

	/* If we just treated some rgb-only data as rgba, then we have to
	 * go back and fix up the alpha channel where we filled in this
	 * texture data.
	 */
	if (!has_alpha) {
	    _cairo_gl_surface_fill_alpha_channel (dst, ctx,
						  dst_x, dst_y,
						  width, height);
	}
    } else {
        cairo_surface_t *tmp;

        tmp = _cairo_gl_surface_create_scratch (ctx,
                                                dst->base.content,
                                                width, height);
        if (unlikely (tmp->status))
            goto FAIL;

        status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *) tmp,
                                               src,
                                               src_x, src_y,
                                               width, height,
                                               0, 0);
        if (status == CAIRO_INT_STATUS_SUCCESS) {
            cairo_surface_pattern_t tmp_pattern;
	    cairo_rectangle_int_t r;
	    cairo_clip_t *clip;

            _cairo_pattern_init_for_surface (&tmp_pattern, tmp);
	    cairo_matrix_init_translate (&tmp_pattern.base.matrix,
					 -dst_x, -dst_y);
	    tmp_pattern.base.filter = CAIRO_FILTER_NEAREST;
	    tmp_pattern.base.extend = CAIRO_EXTEND_NONE;

	    r.x = dst_x;
	    r.y = dst_y;
	    r.width = width;
	    r.height = height;
	    clip = _cairo_clip_intersect_rectangle (NULL, &r);
	    status = _cairo_surface_paint (&dst->base,
					   CAIRO_OPERATOR_SOURCE,
					   &tmp_pattern.base,
					   clip);
	    _cairo_clip_destroy (clip);
            _cairo_pattern_fini (&tmp_pattern.base);
        }

        cairo_surface_destroy (tmp);
    }

FAIL:
    status = _cairo_gl_context_release (ctx, status);

    if (clone)
        cairo_surface_destroy (&clone->base);

    return status;
}
static force_inline void
bits_image_fetch_bilinear_affine (pixman_image_t * image,
				  int              offset,
				  int              line,
				  int              width,
				  uint32_t *       buffer,
				  const uint32_t * mask,

				  convert_pixel_t	convert_pixel,
				  pixman_format_code_t	format,
				  pixman_repeat_t	repeat_mode)
{
    pixman_fixed_t x, y;
    pixman_fixed_t ux, uy;
    pixman_vector_t v;
    bits_image_t *bits = &image->bits;
    int i;

    /* reference point is the center of the pixel */
    v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2;
    v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2;
    v.vector[2] = pixman_fixed_1;

    if (!pixman_transform_point_3d (image->common.transform, &v))
	return;

    ux = image->common.transform->matrix[0][0];
    uy = image->common.transform->matrix[1][0];

    x = v.vector[0];
    y = v.vector[1];

    for (i = 0; i < width; ++i)
    {
	int x1, y1, x2, y2;
	uint32_t tl, tr, bl, br;
	int32_t distx, disty;
	int width = image->bits.width;
	int height = image->bits.height;
	const uint8_t *row1;
	const uint8_t *row2;

	if (mask && !mask[i])
	    goto next;

	x1 = x - pixman_fixed_1 / 2;
	y1 = y - pixman_fixed_1 / 2;

	distx = pixman_fixed_to_bilinear_weight (x1);
	disty = pixman_fixed_to_bilinear_weight (y1);

	y1 = pixman_fixed_to_int (y1);
	y2 = y1 + 1;
	x1 = pixman_fixed_to_int (x1);
	x2 = x1 + 1;

	if (repeat_mode != PIXMAN_REPEAT_NONE)
	{
	    uint32_t mask;

	    mask = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;

	    repeat (repeat_mode, &x1, width);
	    repeat (repeat_mode, &y1, height);
	    repeat (repeat_mode, &x2, width);
	    repeat (repeat_mode, &y2, height);

	    row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1;
	    row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2;

	    tl = convert_pixel (row1, x1) | mask;
	    tr = convert_pixel (row1, x2) | mask;
	    bl = convert_pixel (row2, x1) | mask;
	    br = convert_pixel (row2, x2) | mask;
	}
	else
	{
	    uint32_t mask1, mask2;
	    int bpp;

	    /* Note: PIXMAN_FORMAT_BPP() returns an unsigned value,
	     * which means if you use it in expressions, those
	     * expressions become unsigned themselves. Since
	     * the variables below can be negative in some cases,
	     * that will lead to crashes on 64 bit architectures.
	     *
	     * So this line makes sure bpp is signed
	     */
	    bpp = PIXMAN_FORMAT_BPP (format);

	    if (x1 >= width || x2 < 0 || y1 >= height || y2 < 0)
	    {
		buffer[i] = 0;
		goto next;
	    }

	    if (y2 == 0)
	    {
		row1 = zero;
		mask1 = 0;
	    }
	    else
	    {
		row1 = (uint8_t *)bits->bits + bits->rowstride * 4 * y1;
		row1 += bpp / 8 * x1;

		mask1 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;
	    }

	    if (y1 == height - 1)
	    {
		row2 = zero;
		mask2 = 0;
	    }
	    else
	    {
		row2 = (uint8_t *)bits->bits + bits->rowstride * 4 * y2;
		row2 += bpp / 8 * x1;

		mask2 = PIXMAN_FORMAT_A (format)? 0 : 0xff000000;
	    }

	    if (x2 == 0)
	    {
		tl = 0;
		bl = 0;
	    }
	    else
	    {
		tl = convert_pixel (row1, 0) | mask1;
		bl = convert_pixel (row2, 0) | mask2;
	    }

	    if (x1 == width - 1)
	    {
		tr = 0;
		br = 0;
	    }
	    else
	    {
		tr = convert_pixel (row1, 1) | mask1;
		br = convert_pixel (row2, 1) | mask2;
	    }
	}

	buffer[i] = bilinear_interpolation (
	    tl, tr, bl, br, distx, disty);

    next:
	x += ux;
	y += uy;
    }
}
static void
uxa_check_glyphs(CARD8 op,
		 PicturePtr src,
		 PicturePtr dst,
		 PictFormatPtr maskFormat,
		 INT16 xSrc,
		 INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
{
	pixman_image_t *image;
	PixmapPtr scratch;
	PicturePtr mask, mask_src = NULL, mask_dst = NULL, white = NULL;
	int width = 0, height = 0;
	int x, y, n;
	int xDst = list->xOff, yDst = list->yOff;
	BoxRec extents = { 0, 0, 0, 0 };
	CARD8 mask_op = 0;

	if (maskFormat) {
		pixman_format_code_t format;
		CARD32 component_alpha;
		xRenderColor color;
		int error;

		uxa_glyph_extents(nlist, list, glyphs, &extents);
		if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
			return;

		width = extents.x2 - extents.x1;
		height = extents.y2 - extents.y1;

		format = maskFormat->format |
			(BitsPerPixel(maskFormat->depth) << 24);
		image =
			pixman_image_create_bits(format, width, height, NULL, 0);
		if (!image)
			return;

		scratch = GetScratchPixmapHeader(dst->pDrawable->pScreen, width, height,
						 PIXMAN_FORMAT_DEPTH(format),
						 PIXMAN_FORMAT_BPP(format),
						 pixman_image_get_stride(image),
						 pixman_image_get_data(image));

		if (!scratch) {
			pixman_image_unref(image);
			return;
		}

		component_alpha = NeedsComponent(maskFormat->format);
		mask = CreatePicture(0, &scratch->drawable,
				     maskFormat, CPComponentAlpha,
				     &component_alpha, serverClient, &error);
		if (!mask) {
			FreeScratchPixmapHeader(scratch);
			pixman_image_unref(image);
			return;
		}
		ValidatePicture(mask);

		x = -extents.x1;
		y = -extents.y1;

		color.red = color.green = color.blue = color.alpha = 0xffff;
		white = CreateSolidPicture(0, &color, &error);

		mask_op = op;
		op = PictOpAdd;

		mask_src = src;
		src = white;

		mask_dst = dst;
		dst = mask;
	} else {
		mask = dst;
		x = 0;
		y = 0;
	}

	while (nlist--) {
		x += list->xOff;
		y += list->yOff;
		n = list->len;
		while (n--) {
			GlyphPtr glyph = *glyphs++;
			PicturePtr g = GetGlyphPicture(glyph, dst->pDrawable->pScreen);
			if (g) {
				CompositePicture(op, src, g, dst,
						 xSrc + (x - glyph->info.x) - xDst,
						 ySrc + (y - glyph->info.y) - yDst,
						 0, 0,
						 x - glyph->info.x,
						 y - glyph->info.y,
						 glyph->info.width,
						 glyph->info.height);
			}

			x += glyph->info.xOff;
			y += glyph->info.yOff;
		}
		list++;
	}

	if (white)
		FreePicture(white, 0);

	if (maskFormat) {
		x = extents.x1;
		y = extents.y1;
		CompositePicture(mask_op, mask_src, mask, mask_dst,
				 xSrc + x - xDst,
				 ySrc + y - yDst,
				 0, 0,
				 x, y,
				 width, height);
		FreePicture(mask, 0);
		FreeScratchPixmapHeader(scratch);
		pixman_image_unref(image);
	}
}
Exemple #10
0
static cairo_status_t
_cairo_xcb_shm_image_create (cairo_xcb_connection_t *connection,
			     pixman_format_code_t pixman_format,
			     int width, int height,
			     cairo_image_surface_t **image_out,
			     cairo_xcb_shm_info_t **shm_info_out)
{
    cairo_surface_t *image = NULL;
    cairo_xcb_shm_info_t *shm_info = NULL;
    cairo_status_t status;

#if CAIRO_HAS_XCB_SHM_FUNCTIONS
    if ((connection->flags & CAIRO_XCB_HAS_SHM)) {
	size_t size, stride;

	stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format));
	size = stride * height;
	if (size > CAIRO_XCB_SHM_SMALL_IMAGE) {
	    status = _cairo_xcb_connection_allocate_shm_info (connection,
							      size, &shm_info);
	    if (unlikely (status))
		return status;

	    image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
								    pixman_format,
								    width, height,
								    stride);
	    status = image->status;
	    if (unlikely (status)) {
		_cairo_xcb_shm_info_destroy (shm_info);
		return status;
	    }

	    status = _cairo_user_data_array_set_data (&image->user_data,
						      (const cairo_user_data_key_t *) connection,
						      shm_info,
						      (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
	    if (unlikely (status)) {
		cairo_surface_destroy (image);
		_cairo_xcb_shm_info_destroy (shm_info);
		return status;
	    }
	}
    }
#endif

    if (image == NULL) {
	image = _cairo_image_surface_create_with_pixman_format (NULL,
								pixman_format,
								width, height,
								0);
	status = image->status;
	if (unlikely (status))
	    return status;
    }


    *image_out = (cairo_image_surface_t *) image;
    *shm_info_out = shm_info;
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_gl_glyph_cache_add_glyph (cairo_gl_glyph_cache_t *cache,
				 cairo_scaled_glyph_t  *scaled_glyph)
{
    cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
    cairo_gl_glyph_private_t *glyph_private;
    cairo_rtree_node_t *node = NULL;
    cairo_image_surface_t *clone = NULL;
    cairo_status_t status;
    int width, height;
    GLenum internal_format, format, type;
    cairo_bool_t has_alpha;

    if (! _cairo_gl_get_image_format_and_type (glyph_surface->pixman_format,
					       &internal_format,
					       &format,
					       &type,
					       &has_alpha))
    {
	cairo_bool_t is_supported;

	clone = _cairo_image_surface_coerce (glyph_surface,
		                             _cairo_format_from_content (glyph_surface->base.content));
	if (unlikely (clone->base.status))
	    return clone->base.status;

	is_supported =
	    _cairo_gl_get_image_format_and_type (clone->pixman_format,
					         &internal_format,
						 &format,
						 &type,
						 &has_alpha);
	assert (is_supported);
	glyph_surface = clone;
    }

    width = glyph_surface->width;
    if (width < GLYPH_CACHE_MIN_SIZE)
	width = GLYPH_CACHE_MIN_SIZE;
    height = glyph_surface->height;
    if (height < GLYPH_CACHE_MIN_SIZE)
	height = GLYPH_CACHE_MIN_SIZE;

    /* search for an available slot */
    status = _cairo_rtree_insert (&cache->rtree, width, height, &node);
    /* search for an unlocked slot */
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
	status = _cairo_rtree_evict_random (&cache->rtree,
				            width, height, &node);
	if (status == CAIRO_STATUS_SUCCESS) {
	    status = _cairo_rtree_node_insert (&cache->rtree,
		                               node, width, height, &node);
	}
    }
    if (status)
	return status;

    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
    glPixelStorei (GL_UNPACK_ROW_LENGTH,
		   glyph_surface->stride /
		   (PIXMAN_FORMAT_BPP (glyph_surface->pixman_format) / 8));
    glTexSubImage2D (GL_TEXTURE_2D, 0,
		     node->x, node->y,
		     glyph_surface->width, glyph_surface->height,
		     format, type,
		     glyph_surface->data);
    glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);

    scaled_glyph->surface_private = node;
    node->owner = &scaled_glyph->surface_private;

    glyph_private = (cairo_gl_glyph_private_t *) node;
    glyph_private->cache = cache;

    /* compute tex coords */
    glyph_private->p1.x = node->x / (double) cache->width;
    glyph_private->p1.y = node->y / (double) cache->height;
    glyph_private->p2.x =
	(node->x + glyph_surface->width) / (double) cache->width;
    glyph_private->p2.y =
	(node->y + glyph_surface->height) / (double) cache->height;

    cairo_surface_destroy (&clone->base);

    return CAIRO_STATUS_SUCCESS;
}
Exemple #12
0
static cairo_status_t
_get_image (cairo_xcb_surface_t		 *surface,
	    cairo_bool_t		  use_shm,
	    cairo_image_surface_t	**image_out)
{
    cairo_image_surface_t *image;
    cairo_xcb_connection_t *connection;
    xcb_get_image_reply_t *reply;
    cairo_status_t status;

    if (surface->base.is_clear || surface->deferred_clear) {
	image = (cairo_image_surface_t *)
	    _cairo_image_surface_create_with_pixman_format (NULL,
							    surface->pixman_format,
							    surface->width,
							    surface->height,
							    0);
	*image_out = image;
	return image->base.status;
    }

    connection = surface->connection;

    status = _cairo_xcb_connection_acquire (connection);
    if (unlikely (status))
	return status;

    status = _cairo_xcb_connection_take_socket (connection);
    if (unlikely (status))
	goto FAIL;

    if (use_shm) {
	status = _get_shm_image (surface, image_out);
	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	    goto FAIL;
    }

    if (surface->use_pixmap == 0) {
	status = _cairo_xcb_connection_get_image (connection,
						  surface->drawable,
						  0, 0,
						  surface->width,
						  surface->height,
						  &reply);
	if (unlikely (status))
	    goto FAIL;
    } else {
	surface->use_pixmap--;
	reply = NULL;
    }

    if (reply == NULL && ! surface->owns_pixmap) {
	/* xcb_get_image_t from a window is dangerous because it can
	 * produce errors if the window is unmapped or partially
	 * outside the screen. We could check for errors and
	 * retry, but to keep things simple, we just create a
	 * temporary pixmap
	 */
	xcb_pixmap_t pixmap;
	xcb_gcontext_t gc;

	gc = _cairo_xcb_screen_get_gc (surface->screen,
				       surface->drawable,
				       surface->depth);
	pixmap = _cairo_xcb_connection_create_pixmap (connection,
						      surface->depth,
						      surface->drawable,
						      surface->width,
						      surface->height);

	/* XXX IncludeInferiors? */
	_cairo_xcb_connection_copy_area (connection,
					 surface->drawable,
					 pixmap, gc,
					 0, 0,
					 0, 0,
					 surface->width,
					 surface->height);

	_cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);

	status = _cairo_xcb_connection_get_image (connection,
						  pixmap,
						  0, 0,
						  surface->width,
						  surface->height,
						  &reply);
	_cairo_xcb_connection_free_pixmap (connection, pixmap);

	if (unlikely (status))
	    goto FAIL;
    }

    if (unlikely (reply == NULL)) {
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	goto FAIL;
    }

    /* XXX byte swap */
    /* XXX format conversion */
    assert (reply->depth == surface->depth);

    image = (cairo_image_surface_t *)
	_cairo_image_surface_create_with_pixman_format
	(xcb_get_image_data (reply),
	 surface->pixman_format,
	 surface->width,
	 surface->height,
	 CAIRO_STRIDE_FOR_WIDTH_BPP (surface->width,
				     PIXMAN_FORMAT_BPP (surface->pixman_format)));
    status = image->base.status;
    if (unlikely (status)) {
	free (reply);
	goto FAIL;
    }

    assert (xcb_get_image_data_length (reply) == image->height * image->stride);

    pixman_image_set_destroy_function (image->pixman_image, _destroy_image, reply);

    _cairo_xcb_connection_release (connection);

    /* synchronisation point */
    surface->marked_dirty = FALSE;

    *image_out = image;
    return CAIRO_STATUS_SUCCESS;

FAIL:
    _cairo_xcb_connection_release (connection);
    return status;
}
Exemple #13
0
static cairo_surface_t *
map_qimage_to_image (QImage *qimg, const cairo_rectangle_int_t *extents)
{
    struct _qimage_surface  *surface;
    pixman_image_t *pixman_image;
    pixman_format_code_t pixman_format;
    uint8_t *data;

    if (qimg == NULL)
        return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);

    switch (qimg->format()) {
    case QImage::Format_ARGB32_Premultiplied:
	pixman_format = PIXMAN_a8r8g8b8;
	break;
    case QImage::Format_RGB32:
	pixman_format = PIXMAN_x8r8g8b8;
	break;
    case QImage::Format_Indexed8: // XXX not quite
	pixman_format = PIXMAN_a8;
	break;
#ifdef WORDS_BIGENDIAN
    case QImage::Format_Mono:
#else
    case QImage::Format_MonoLSB:
#endif
	pixman_format = PIXMAN_a1;
	break;

    case QImage::Format_Invalid:
#ifdef WORDS_BIGENDIAN
    case QImage::Format_MonoLSB:
#else
    case QImage::Format_Mono:
#endif
    case QImage::Format_ARGB32:
    case QImage::Format_RGB16:
    case QImage::Format_ARGB8565_Premultiplied:
    case QImage::Format_RGB666:
    case QImage::Format_ARGB6666_Premultiplied:
    case QImage::Format_RGB555:
    case QImage::Format_ARGB8555_Premultiplied:
    case QImage::Format_RGB888:
    case QImage::Format_RGB444:
    case QImage::Format_ARGB4444_Premultiplied:
    case QImage::NImageFormats:
    default:
	delete qimg;
	return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_FORMAT);
    }

    data = qimg->bits();
    data += extents->y * qimg->bytesPerLine();
    data += extents->x * PIXMAN_FORMAT_BPP (pixman_format) / 8;

    pixman_image = pixman_image_create_bits (pixman_format,
					     extents->width,
					     extents->height,
					     (uint32_t *)data,
					     qimg->bytesPerLine());
    if (pixman_image == NULL) {
	delete qimg;
	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
    }

    surface = (struct _qimage_surface *) malloc (sizeof(*surface));
    if (unlikely (surface == NULL)) {
	pixman_image_unref (pixman_image);
	delete qimg;
	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
    }

    _cairo_image_surface_init (&surface->image, pixman_image, pixman_format);
    surface->qimg = qimg;

    cairo_surface_set_device_offset (&surface->image.base,
				     -extents->x, -extents->y);

    return &surface->image.base;
}
Exemple #14
0
static void
composite_clipped(pixman_image_t *src,
		  pixman_image_t *mask,
		  pixman_image_t *dest,
		  const pixman_transform_t *transform,
		  pixman_filter_t filter,
		  pixman_region32_t *src_clip)
{
	int n_box;
	pixman_box32_t *boxes;
	int32_t dest_width;
	int32_t dest_height;
	int src_stride;
	int bitspp;
	pixman_format_code_t src_format;
	void *src_data;
	int i;

	/* Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
	 * a Pixman image produces (0,0,0,0) instead of discarding the
	 * fragment.
	 */

	dest_width = pixman_image_get_width(dest);
	dest_height = pixman_image_get_height(dest);
	src_format = pixman_image_get_format(src);
	src_stride = pixman_image_get_stride(src);
	bitspp = PIXMAN_FORMAT_BPP(src_format);
	src_data = pixman_image_get_data(src);

	assert(src_format);

	/* This would be massive overdraw, except when n_box is 1. */
	boxes = pixman_region32_rectangles(src_clip, &n_box);
	for (i = 0; i < n_box; i++) {
		uint8_t *ptr = src_data;
		pixman_image_t *boximg;
		pixman_transform_t adj = *transform;

		ptr += boxes[i].y1 * src_stride;
		ptr += boxes[i].x1 * bitspp / 8;
		boximg = pixman_image_create_bits_no_clear(src_format,
					boxes[i].x2 - boxes[i].x1,
					boxes[i].y2 - boxes[i].y1,
					(uint32_t *)ptr, src_stride);

		pixman_transform_translate(&adj, NULL,
					   pixman_int_to_fixed(-boxes[i].x1),
					   pixman_int_to_fixed(-boxes[i].y1));
		pixman_image_set_transform(boximg, &adj);

		pixman_image_set_filter(boximg, filter, NULL, 0);
		pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
					 0, 0, /* src_x, src_y */
					 0, 0, /* mask_x, mask_y */
					 0, 0, /* dest_x, dest_y */
					 dest_width, dest_height);

		pixman_image_unref(boximg);
	}

	if (n_box > 1) {
		static bool warned = false;

		if (!warned)
			weston_log("Pixman-renderer warning: %dx overdraw\n",
				   n_box);
		warned = true;
	}
}
Exemple #15
0
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;
}