cairo_surface_t * _cairo_image_surface_snapshot (void *abstract_surface) { cairo_image_surface_t *image = abstract_surface; cairo_image_surface_t *clone; clone = (cairo_image_surface_t *) _cairo_image_surface_create_with_pixman_format (NULL, image->pixman_format, image->width, image->height, 0); if (unlikely (clone->base.status)) return &clone->base; if (clone->stride == image->stride) { memcpy (clone->data, image->data, clone->stride * clone->height); } else { pixman_image_composite32 (PIXMAN_OP_SRC, image->pixman_image, NULL, clone->pixman_image, 0, 0, 0, 0, 0, 0, image->width, image->height); } clone->base.is_clear = FALSE; return &clone->base; }
/* Handles compositing with a clip surface when we have to do the operation * in two pieces and combine them together. */ static cairo_status_t clip_and_composite_combine (const cairo_composite_rectangles_t*extents, draw_func_t draw_func, void *draw_closure) { cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface; cairo_image_surface_t *tmp, *clip; int clip_x, clip_y; cairo_status_t status; TRACE ((stderr, "%s\n", __FUNCTION__)); tmp = (cairo_image_surface_t *) _cairo_image_surface_create_with_pixman_format (NULL, dst->pixman_format, extents->bounded.width, extents->bounded.height, 0); if (unlikely (tmp->base.status)) return tmp->base.status; pixman_image_composite32 (PIXMAN_OP_SRC, dst->pixman_image, NULL, tmp->pixman_image, extents->bounded.x, extents->bounded.y, 0, 0, 0, 0, extents->bounded.width, extents->bounded.height); status = draw_func (tmp, draw_closure, extents->op, &extents->source_pattern.base, extents->bounded.x, extents->bounded.y, &extents->bounded); if (unlikely (status)) goto error; clip = (cairo_image_surface_t *) _cairo_clip_get_surface (extents->clip, &dst->base, &clip_x, &clip_y); if (unlikely (clip->base.status)) goto error; pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, clip->pixman_image, NULL, dst->pixman_image, extents->bounded.x - clip_x, extents->bounded.y - clip_y, 0, 0, extents->bounded.x, extents->bounded.y, extents->bounded.width, extents->bounded.height); pixman_image_composite32 (PIXMAN_OP_ADD, tmp->pixman_image, clip->pixman_image, dst->pixman_image, 0, 0, extents->bounded.x - clip_x, extents->bounded.y - clip_y, extents->bounded.x, extents->bounded.y, extents->bounded.width, extents->bounded.height); cairo_surface_destroy (&clip->base); error: cairo_surface_destroy (&tmp->base); return status; }
/** * cairo_image_surface_create_for_data: * @data: a pointer to a buffer supplied by the application in which * to write contents. This pointer must be suitably aligned for any * kind of variable, (for example, a pointer returned by malloc). * @format: the format of pixels in the buffer * @width: the width of the image to be stored in the buffer * @height: the height of the image to be stored in the buffer * @stride: the number of bytes between the start of rows in the * buffer as allocated. This value should always be computed by * cairo_format_stride_for_width() before allocating the data * buffer. * * Creates an image surface for the provided pixel data. The output * buffer must be kept around until the #cairo_surface_t is destroyed * or cairo_surface_finish() is called on the surface. The initial * contents of @data will be used as the initial image contents; you * must explicitly clear the buffer, using, for example, * cairo_rectangle() and cairo_fill() if you want it cleared. * * Note that the stride may be larger than * width*bytes_per_pixel to provide proper alignment for each pixel * and row. This alignment is required to allow high-performance rendering * within cairo. The correct way to obtain a legal stride value is to * call cairo_format_stride_for_width() with the desired format and * maximum image width value, and the use the resulting stride value * to allocate the data and to create the image surface. See * cairo_format_stride_for_width() for example code. * * Return value: a pointer to the newly created surface. The caller * owns the surface and should call cairo_surface_destroy() when done * with it. * * This function always returns a valid pointer, but it will return a * pointer to a "nil" surface in the case of an error such as out of * memory or an invalid stride value. In case of invalid stride value * the error status of the returned surface will be * %CAIRO_STATUS_INVALID_STRIDE. You can use * cairo_surface_status() to check for this. * * See cairo_surface_set_user_data() for a means of attaching a * destroy-notification fallback to the surface if necessary. **/ cairo_surface_t * cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format, int width, int height, int stride) { pixman_format_code_t pixman_format; int minstride; if (! CAIRO_FORMAT_VALID (format)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); if ((stride & (CAIRO_STRIDE_ALIGNMENT-1)) != 0) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); minstride = cairo_format_stride_for_width (format, width); if (stride < 0) { if (stride > -minstride) { return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); } } else { if (stride < minstride) { return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); } } pixman_format = _cairo_format_to_pixman_format_code (format); return _cairo_image_surface_create_with_pixman_format (data, pixman_format, width, height, stride); }
cairo_surface_t * _cairo_test_fallback16_surface_create (cairo_content_t content, int width, int height) { test_fallback16_surface_t *surface; cairo_surface_t *backing; pixman_format_code_t format; format = content & CAIRO_CONTENT_ALPHA ? PIXMAN_a1r5g5b5: PIXMAN_r5g6b5; backing = _cairo_image_surface_create_with_pixman_format (NULL, format, width, height, -1); if (cairo_surface_status (backing)) return backing; surface = malloc (sizeof (test_fallback16_surface_t)); if (unlikely (surface == NULL)) { cairo_surface_destroy (backing); return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } _cairo_surface_init (&surface->base, &test_fallback16_surface_backend, content); surface->backing = backing; return &surface->base; }
/* XXX: This function really should be eliminated. We don't really * want to advertise a cairo image surface that supports any possible * format. A minimal step would be to replace this function with one * that accepts a #cairo_internal_format_t rather than mask values. */ cairo_surface_t * _cairo_image_surface_create_with_masks (unsigned char *data, cairo_format_masks_t *masks, int width, int height, int stride) { pixman_format_code_t pixman_format; if (! _pixman_format_from_masks (masks, &pixman_format)) { fprintf (stderr, "Error: Cairo %s does not yet support the requested image format:\n" "\tDepth: %d\n" "\tAlpha mask: 0x%08lx\n" "\tRed mask: 0x%08lx\n" "\tGreen mask: 0x%08lx\n" "\tBlue mask: 0x%08lx\n" #ifdef PACKAGE_BUGGREPORT "Please file an enhancement request (quoting the above) at:\n" PACKAGE_BUGREPORT"\n" #endif , cairo_version_string (), masks->bpp, masks->alpha_mask, masks->red_mask, masks->green_mask, masks->blue_mask); ASSERT_NOT_REACHED; } return _cairo_image_surface_create_with_pixman_format (data, pixman_format, width, height, stride); }
static cairo_int_status_t _cairo_xcb_surface_create_shm_image (cairo_xcb_surface_t *target, cairo_image_surface_t **image_out, cairo_xcb_shm_info_t **shm_info_out) { cairo_image_surface_t *image; cairo_xcb_shm_info_t *shm_info; cairo_status_t status; size_t size, stride; if ((target->flags & CAIRO_XCB_HAS_SHM) == 0) return CAIRO_INT_STATUS_UNSUPPORTED; stride = CAIRO_STRIDE_FOR_WIDTH_BPP (target->width, PIXMAN_FORMAT_BPP (target->pixman_format)); size = stride * target->height; if (size < CAIRO_XCB_SHM_SMALL_IMAGE) { target->flags &= ~CAIRO_XCB_HAS_SHM; return CAIRO_INT_STATUS_UNSUPPORTED; } status = _cairo_xcb_connection_allocate_shm_info (target->screen->connection, size, &shm_info); if (unlikely (status)) return status; image = (cairo_image_surface_t *) _cairo_image_surface_create_with_pixman_format (shm_info->mem, target->pixman_format, target->width, target->height, stride); status = image->base.status; if (unlikely (status)) { _cairo_xcb_shm_info_destroy (shm_info); return status; } status = _cairo_user_data_array_set_data (&image->base.user_data, (const cairo_user_data_key_t *) target->connection, shm_info, (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy); if (unlikely (status)) { cairo_surface_destroy (&image->base); _cairo_xcb_shm_info_destroy (shm_info); return status; } *image_out = image; *shm_info_out = shm_info; return CAIRO_STATUS_SUCCESS; }
static void _cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface) { cairo_surface_snapshot_t *snapshot = (cairo_surface_snapshot_t *) surface; cairo_image_surface_t *image; cairo_image_surface_t *clone; void *extra; cairo_status_t status; /* We need to make an image copy of the original surface since the * snapshot may exceed the lifetime of the original device, i.e. * when we later need to use the snapshot the data may have already * been lost. */ status = _cairo_surface_acquire_source_image (snapshot->target, &image, &extra); if (unlikely (status)) { snapshot->target = _cairo_surface_create_in_error (status); status = _cairo_surface_set_error (surface, status); return; } clone = (cairo_image_surface_t *) _cairo_image_surface_create_with_pixman_format (NULL, image->pixman_format, image->width, image->height, 0); if (likely (clone->base.status == CAIRO_STATUS_SUCCESS)) { if (clone->stride == image->stride) { memcpy (clone->data, image->data, image->stride * image->height); } else { pixman_image_composite32 (PIXMAN_OP_SRC, image->pixman_image, NULL, clone->pixman_image, 0, 0, 0, 0, 0, 0, image->width, image->height); } clone->base.is_clear = FALSE; snapshot->clone = &clone->base; } else { snapshot->clone = &clone->base; status = _cairo_surface_set_error (surface, clone->base.status); } _cairo_surface_release_source_image (snapshot->target, image, extra); snapshot->target = snapshot->clone; snapshot->base.type = snapshot->target->type; }
static cairo_surface_t * _cairo_xcb_surface_create_shm_image (cairo_xcb_connection_t *connection, pixman_format_code_t pixman_format, int width, int height, cairo_bool_t might_reuse, cairo_xcb_shm_info_t **shm_info_out) { cairo_surface_t *image; cairo_xcb_shm_info_t *shm_info; cairo_int_status_t status; size_t stride; *shm_info_out = NULL; stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format)); status = _cairo_xcb_connection_allocate_shm_info (connection, stride * height, might_reuse, &shm_info); if (unlikely (status)) { if (status == CAIRO_INT_STATUS_UNSUPPORTED) return NULL; return _cairo_surface_create_in_error (status); } image = _cairo_image_surface_create_with_pixman_format (shm_info->mem, pixman_format, width, height, stride); if (unlikely (image->status)) { _cairo_xcb_shm_info_destroy (shm_info); return image; } 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 _cairo_surface_create_in_error (status); } *shm_info_out = shm_info; return image; }
/** * cairo_image_surface_create: * @format: format of pixels in the surface to create * @width: width of the surface, in pixels * @height: height of the surface, in pixels * * Creates an image surface of the specified format and * dimensions. Initially the surface contents are all * 0. (Specifically, within each pixel, each color or alpha channel * belonging to format will be 0. The contents of bits within a pixel, * but not belonging to the given format are undefined). * * Return value: a pointer to the newly created surface. The caller * owns the surface and should call cairo_surface_destroy() when done * with it. * * This function always returns a valid pointer, but it will return a * pointer to a "nil" surface if an error such as out of memory * occurs. You can use cairo_surface_status() to check for this. * * Since: 1.0 **/ cairo_surface_t * cairo_image_surface_create (cairo_format_t format, int width, int height) { pixman_format_code_t pixman_format; if (! CAIRO_FORMAT_VALID (format)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); pixman_format = _cairo_format_to_pixman_format_code (format); return _cairo_image_surface_create_with_pixman_format (NULL, pixman_format, width, height, -1); }
cairo_surface_t * _cairo_image_surface_snapshot (void *abstract_surface) { cairo_image_surface_t *image = abstract_surface; cairo_image_surface_t *clone; /* If we own the image, we can simply steal the memory for the snapshot */ if (image->owns_data && image->base._finishing) { clone = (cairo_image_surface_t *) _cairo_image_surface_create_for_pixman_image (image->pixman_image, image->pixman_format); if (unlikely (clone->base.status)) return &clone->base; image->pixman_image = NULL; image->owns_data = FALSE; clone->transparency = image->transparency; clone->color = image->color; clone->owns_data = FALSE; return &clone->base; } clone = (cairo_image_surface_t *) _cairo_image_surface_create_with_pixman_format (NULL, image->pixman_format, image->width, image->height, 0); if (unlikely (clone->base.status)) return &clone->base; if (clone->stride == image->stride) { memcpy (clone->data, image->data, clone->stride * clone->height); } else { pixman_image_composite32 (PIXMAN_OP_SRC, image->pixman_image, NULL, clone->pixman_image, 0, 0, 0, 0, 0, 0, image->width, image->height); } clone->base.is_clear = FALSE; return &clone->base; }
cairo_surface_t * _cairo_xcb_surface_create_similar_image (cairo_xcb_surface_t *other, cairo_content_t content, int width, int height) { cairo_surface_t *image = NULL; pixman_format_code_t pixman_format; /* XXX choose pixman_format from connection->image_formats */ switch (content) { case CAIRO_CONTENT_ALPHA: pixman_format = PIXMAN_a8; break; case CAIRO_CONTENT_COLOR: pixman_format = PIXMAN_x8r8g8b8; break; default: ASSERT_NOT_REACHED; case CAIRO_CONTENT_COLOR_ALPHA: pixman_format = PIXMAN_a8r8g8b8; break; } #if CAIRO_HAS_XCB_SHM_FUNCTIONS if (other->flags & CAIRO_XCB_HAS_SHM) { cairo_status_t status; status = _cairo_xcb_surface_create_similar_shm (other, pixman_format, width, height, &image); if (_cairo_status_is_error (status)) return _cairo_surface_create_in_error (status); } #endif if (image == NULL) { image = _cairo_image_surface_create_with_pixman_format (NULL, pixman_format, width, height, 0); } return image; }
static cairo_status_t _cairo_xcb_surface_create_similar_shm (cairo_xcb_surface_t *other, pixman_format_code_t pixman_format, int width, int height, cairo_surface_t **out) { size_t size, stride; cairo_xcb_shm_info_t *shm_info; cairo_status_t status; cairo_surface_t *image; stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format)); size = stride * height; if (size < CAIRO_XCB_SHM_SMALL_IMAGE) return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_xcb_connection_allocate_shm_info (other->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 *) other->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; } *out = image; return CAIRO_STATUS_SUCCESS; }
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; }
static cairo_image_surface_t * create_composite_mask (cairo_image_surface_t *dst, void *draw_closure, draw_func_t draw_func, const cairo_composite_rectangles_t *extents) { cairo_image_surface_t *surface; cairo_int_status_t status; TRACE ((stderr, "%s\n", __FUNCTION__)); surface = (cairo_image_surface_t *) _cairo_image_surface_create_with_pixman_format (NULL, PIXMAN_a8, extents->bounded.width, extents->bounded.height, 0); if (unlikely (surface->base.status)) return surface; status = draw_func (surface, draw_closure, CAIRO_OPERATOR_ADD, &_cairo_pattern_white.base, extents->bounded.x, extents->bounded.y, &extents->bounded); if (unlikely (status)) goto error; status = _cairo_clip_combine_with_surface (extents->clip, &surface->base, extents->bounded.x, extents->bounded.y); if (unlikely (status)) goto error; return surface; error: cairo_surface_destroy (&surface->base); return (cairo_image_surface_t *)_cairo_surface_create_in_error (status); }
static cairo_surface_t * _cairo_image_surface_create_similar (void *abstract_other, cairo_content_t content, int width, int height) { cairo_image_surface_t *other = abstract_other; TRACE ((stderr, "%s (other=%u)\n", __FUNCTION__, other->base.unique_id)); if (! _cairo_image_surface_is_size_valid (width, height)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); if (content == other->base.content) { return _cairo_image_surface_create_with_pixman_format (NULL, other->pixman_format, width, height, 0); } return _cairo_image_surface_create_with_content (content, width, height); }
static cairo_int_status_t traps_to_operand (void *_dst, const cairo_rectangle_int_t *extents, cairo_antialias_t antialias, cairo_traps_t *traps, cairo_gl_operand_t *operand, int dst_x, int dst_y) { pixman_format_code_t pixman_format; pixman_image_t *pixman_image; cairo_surface_t *image, *mask; cairo_surface_pattern_t pattern; cairo_status_t status; pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1; pixman_image = pixman_image_create_bits (pixman_format, extents->width, extents->height, NULL, 0); if (unlikely (pixman_image == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); _pixman_image_add_traps (pixman_image, extents->x, extents->y, traps); image = _cairo_image_surface_create_for_pixman_image (pixman_image, pixman_format); if (unlikely (image->status)) { pixman_image_unref (pixman_image); return image->status; } /* GLES2 only supports RGB/RGBA when uploading */ if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES) { cairo_surface_pattern_t pattern; cairo_surface_t *rgba_image; /* XXX perform this fixup inside _cairo_gl_draw_image() */ rgba_image = _cairo_image_surface_create_with_pixman_format (NULL, _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8, extents->width, extents->height, 0); if (unlikely (rgba_image->status)) return rgba_image->status; _cairo_pattern_init_for_surface (&pattern, image); status = _cairo_surface_paint (rgba_image, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL); _cairo_pattern_fini (&pattern.base); cairo_surface_destroy (image); image = rgba_image; if (unlikely (status)) { cairo_surface_destroy (image); return status; } } mask = _cairo_surface_create_similar_scratch (_dst, CAIRO_CONTENT_COLOR_ALPHA, extents->width, extents->height); if (unlikely (mask->status)) { cairo_surface_destroy (image); return mask->status; } status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask, (cairo_image_surface_t *)image, 0, 0, extents->width, extents->height, 0, 0); cairo_surface_destroy (image); if (unlikely (status)) goto error; _cairo_pattern_init_for_surface (&pattern, mask); cairo_matrix_init_translate (&pattern.base.matrix, -extents->x+dst_x, -extents->y+dst_y); pattern.base.filter = CAIRO_FILTER_NEAREST; pattern.base.extend = CAIRO_EXTEND_NONE; status = _cairo_gl_operand_init (operand, &pattern.base, _dst, &_cairo_unbounded_rectangle, &_cairo_unbounded_rectangle); _cairo_pattern_fini (&pattern.base); if (unlikely (status)) goto error; operand->texture.owns_surface = mask; return CAIRO_STATUS_SUCCESS; error: cairo_surface_destroy (mask); return status; }
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); }
static cairo_surface_t * _cairo_gl_surface_map_to_image (void *abstract_surface, const cairo_rectangle_int_t *extents) { cairo_gl_surface_t *surface = abstract_surface; cairo_image_surface_t *image; cairo_gl_context_t *ctx; GLenum format, type; pixman_format_code_t pixman_format; unsigned int cpp; cairo_bool_t invert; cairo_status_t status; /* Want to use a switch statement here but the compiler gets whiny. */ if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) { format = GL_BGRA; pixman_format = PIXMAN_a8r8g8b8; type = GL_UNSIGNED_INT_8_8_8_8_REV; cpp = 4; } else if (surface->base.content == CAIRO_CONTENT_COLOR) { format = GL_BGRA; pixman_format = PIXMAN_x8r8g8b8; type = GL_UNSIGNED_INT_8_8_8_8_REV; cpp = 4; } else if (surface->base.content == CAIRO_CONTENT_ALPHA) { format = GL_ALPHA; pixman_format = PIXMAN_a8; type = GL_UNSIGNED_BYTE; cpp = 1; } else { ASSERT_NOT_REACHED; return NULL; } /* * GLES2 supports only RGBA, UNSIGNED_BYTE so use that. * We are also using this format for ALPHA as GLES2 does not * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the * pixman image that is created has row_stride = row_width * bpp. */ if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES) { format = GL_RGBA; if (! _cairo_is_little_endian ()) { if (surface->base.content == CAIRO_CONTENT_COLOR) pixman_format = PIXMAN_r8g8b8x8; else pixman_format = PIXMAN_r8g8b8a8; } else { if (surface->base.content == CAIRO_CONTENT_COLOR) pixman_format = PIXMAN_x8b8g8r8; else pixman_format = PIXMAN_a8b8g8r8; } type = GL_UNSIGNED_BYTE; cpp = 4; } image = (cairo_image_surface_t*) _cairo_image_surface_create_with_pixman_format (NULL, pixman_format, extents->width, extents->height, -1); if (unlikely (image->base.status)) return &image->base; if (surface->base.serial == 0) return &image->base; status = _cairo_gl_context_acquire (surface->base.device, &ctx); if (unlikely (status)) { cairo_surface_destroy (&image->base); return _cairo_surface_create_in_error (status); } cairo_surface_set_device_offset (&image->base, -extents->x, -extents->y); /* This is inefficient, as we'd rather just read the thing without making * it the destination. But then, this is the fallback path, so let's not * fall back instead. */ _cairo_gl_composite_flush (ctx); _cairo_gl_context_set_destination (ctx, surface); invert = ! _cairo_gl_surface_is_texture (surface) && ctx->has_mesa_pack_invert; glPixelStorei (GL_PACK_ALIGNMENT, 4); if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp); if (invert) glPixelStorei (GL_PACK_INVERT_MESA, 1); glReadPixels (extents->x, extents->y, extents->width, extents->height, format, type, image->data); if (invert) glPixelStorei (GL_PACK_INVERT_MESA, 0); status = _cairo_gl_context_release (ctx, status); if (unlikely (status)) { cairo_surface_destroy (&image->base); image = (cairo_image_surface_t *) _cairo_surface_create_in_error (status); } return &image->base; }
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 _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; }