static cairo_xcb_pixmap_t * _pixmap_from_image (cairo_xcb_surface_t *target, xcb_render_pictformat_t format, cairo_image_surface_t *image, cairo_xcb_shm_info_t *shm_info) { xcb_gcontext_t gc; cairo_xcb_pixmap_t *pixmap; pixmap = _cairo_xcb_pixmap_create (target, image->width, image->height); if (unlikely (pixmap->base.status)) return pixmap; gc = _cairo_xcb_screen_get_gc (target->screen, pixmap->pixmap, image->depth); if (shm_info != NULL) { shm_info->seqno = _cairo_xcb_connection_shm_put_image (target->connection, pixmap->pixmap, gc, image->width, image->height, 0, 0, image->width, image->height, 0, 0, image->depth, shm_info->shm, shm_info->offset); } else { int len; /* Do we need to trim the image? */ len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format)); if (len == image->stride) { _cairo_xcb_connection_put_image (target->connection, pixmap->pixmap, gc, image->width, image->height, 0, 0, image->depth, image->stride, image->data); } else { _cairo_xcb_connection_put_subimage (target->connection, pixmap->pixmap, gc, 0, 0, image->width, image->height, PIXMAN_FORMAT_BPP (image->pixman_format) / 8, image->stride, 0, 0, image->depth, image->data); } } _cairo_xcb_screen_put_gc (target->screen, image->depth, gc); return pixmap; }
static cairo_status_t _put_image_boxes (cairo_xcb_surface_t *surface, cairo_image_surface_t *image, cairo_boxes_t *boxes) { cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; xcb_gcontext_t gc; if (boxes->num_boxes == 0) return CAIRO_STATUS_SUCCESS; /* XXX track damaged region? */ status = _cairo_xcb_connection_acquire (surface->connection); if (unlikely (status)) return status; assert (image->pixman_format == surface->pixman_format); assert (image->depth == surface->depth); assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format))); gc = _cairo_xcb_screen_get_gc (surface->screen, surface->drawable, surface->depth); status = _put_shm_image_boxes (surface, image, gc, boxes); if (status == CAIRO_INT_STATUS_UNSUPPORTED) { struct _cairo_boxes_chunk *chunk; for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { int i; for (i = 0; i < chunk->count; i++) { cairo_box_t *b = &chunk->base[i]; int x = _cairo_fixed_integer_part (b->p1.x); int y = _cairo_fixed_integer_part (b->p1.y); int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x); int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y); _cairo_xcb_connection_put_image (surface->connection, surface->drawable, gc, width, height, x, y, image->depth, image->stride, image->data + x * PIXMAN_FORMAT_BPP (image->pixman_format) / 8 + y * image->stride); } } status = CAIRO_STATUS_SUCCESS; } _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc); _cairo_xcb_connection_release (surface->connection); return status; }
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 cairo_status_t _put_image (cairo_xcb_surface_t *surface, cairo_image_surface_t *image) { cairo_status_t status = CAIRO_STATUS_SUCCESS; /* XXX track damaged region? */ status = _cairo_xcb_connection_acquire (surface->connection); if (unlikely (status)) return status; status = _cairo_xcb_connection_take_socket (surface->connection); if (unlikely (status)) { _cairo_xcb_connection_release (surface->connection); return status; } if (image->pixman_format == surface->pixman_format) { xcb_gcontext_t gc; assert (image->width == surface->width); assert (image->height == surface->height); assert (image->depth == surface->depth); assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format))); gc = _cairo_xcb_screen_get_gc (surface->screen, surface->drawable, surface->depth); status = _put_shm_image (surface, gc, image); if (status == CAIRO_INT_STATUS_UNSUPPORTED) { _cairo_xcb_connection_put_image (surface->connection, surface->drawable, gc, image->width, image->height, 0, 0, image->depth, image->stride, image->data); status = CAIRO_STATUS_SUCCESS; } _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc); } else { ASSERT_NOT_REACHED; } _cairo_xcb_connection_release (surface->connection); return status; }
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_format_stride_for_width: * @format: A #cairo_format_t value * @width: The desired width of an image surface to be created. * * This function provides a stride value that will respect all * alignment requirements of the accelerated image-rendering code * within cairo. Typical usage will be of the form: * * <informalexample><programlisting> * int stride; * unsigned char *data; * #cairo_surface_t *surface; * * stride = cairo_format_stride_for_width (format, width); * data = malloc (stride * height); * surface = cairo_image_surface_create_for_data (data, format, * width, height, * stride); * </programlisting></informalexample> * * Return value: the appropriate stride to use given the desired * format and width, or -1 if either the format is invalid or the width * too large. * * Since: 1.6 **/ int cairo_format_stride_for_width (cairo_format_t format, int width) { int bpp; if (! CAIRO_FORMAT_VALID (format)) { _cairo_error_throw (CAIRO_STATUS_INVALID_FORMAT); return -1; } bpp = _cairo_format_bits_per_pixel (format); if ((unsigned) (width) >= (INT32_MAX - 7) / (unsigned) (bpp)) return -1; return CAIRO_STRIDE_FOR_WIDTH_BPP (width, bpp); }
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; }
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_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; }