diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2009-09-30 19:50:44 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2009-09-30 20:11:07 +0100 |
commit | e9bc2180d73acc7133d715ed4380ed20fb4364c0 (patch) | |
tree | 491caca556027fa602da362616f9264d3c6314b3 /src | |
parent | 8e4e0aa7ee5b4e0963409cda825705a09aae61e1 (diff) |
[xcb] Deferred error checking.
XCB avoids the dreaded abort on XError mechanism by forcing the client
to perform deferred error checking. So do so. This allows us to combine
the fire-and-forget rendering model with accurate error checking,
without killing the client or mixing our errors with theirs.
XCB for the win!
Diffstat (limited to 'src')
-rw-r--r-- | src/cairo-freelist-private.h | 5 | ||||
-rw-r--r-- | src/cairo-freelist.c | 33 | ||||
-rw-r--r-- | src/cairo-xcb-surface.c | 712 |
3 files changed, 504 insertions, 246 deletions
diff --git a/src/cairo-freelist-private.h b/src/cairo-freelist-private.h index d48a7201..5be22b1f 100644 --- a/src/cairo-freelist-private.h +++ b/src/cairo-freelist-private.h @@ -132,6 +132,11 @@ _cairo_freepool_alloc (cairo_freepool_t *freepool) return node; } +cairo_private cairo_status_t +_cairo_freepool_alloc_array (cairo_freepool_t *freepool, + int count, + void **array); + static inline void _cairo_freepool_free (cairo_freepool_t *freepool, void *ptr) { diff --git a/src/cairo-freelist.c b/src/cairo-freelist.c index 6277f907..acf31573 100644 --- a/src/cairo-freelist.c +++ b/src/cairo-freelist.c @@ -138,3 +138,36 @@ _cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool) return pool + 1; } + +cairo_status_t +_cairo_freepool_alloc_array (cairo_freepool_t *freepool, + int count, + void **array) +{ + int i; + + for (i = 0; i < count; i++) { + cairo_freelist_node_t *node; + + node = freepool->first_free_node; + if (likely (node != NULL)) { + VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next))); + freepool->first_free_node = node->next; + VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freepool->nodesize)); + } else { + node = _cairo_freepool_alloc_from_pool (freepool); + if (unlikely (node == NULL)) + goto CLEANUP; + } + + array[i] = node; + } + + return CAIRO_STATUS_SUCCESS; + + CLEANUP: + while (i--) + _cairo_freepool_free (freepool, array[i]); + + return _cairo_error (CAIRO_STATUS_NO_MEMORY); +} diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index 7c5731f4..1e47c989 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -38,6 +38,8 @@ #include "cairo-xcb.h" #include "cairo-xcb-xrender.h" #include "cairo-clip-private.h" +#include "cairo-list-private.h" +#include "cairo-freelist-private.h" #include <xcb/xcb_renderutil.h> #define AllPlanes ((unsigned long)~0L) @@ -79,8 +81,16 @@ typedef struct cairo_xcb_surface { xcb_render_picture_t src_picture, dst_picture; xcb_render_pictforminfo_t xrender_format; + + cairo_list_t to_be_checked; + cairo_freepool_t cookie_pool; } cairo_xcb_surface_t; +typedef struct _cairo_xcb_cookie { + cairo_list_t link; + xcb_void_cookie_t xcb; +} cairo_xcb_cookie_t; + #define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \ (((surface)->render_major > major) || \ (((surface)->render_major == major) && ((surface)->render_minor >= minor))) @@ -105,7 +115,7 @@ typedef struct cairo_xcb_surface { #define CAIRO_SURFACE_RENDER_HAS_REPEAT_PAD(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10) #define CAIRO_SURFACE_RENDER_HAS_REPEAT_REFLECT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10) -static void +static cairo_status_t _cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface); static int @@ -124,6 +134,22 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format) } } +static cairo_status_t +_cairo_xcb_add_cookie_to_be_checked (cairo_xcb_surface_t *surface, + xcb_void_cookie_t xcb) +{ + cairo_xcb_cookie_t *cookie; + + cookie = _cairo_freepool_alloc (&surface->cookie_pool); + if (unlikely (cookie == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + cookie->xcb = xcb; + cairo_list_add_tail (&cookie->link, &surface->to_be_checked); + + return CAIRO_STATUS_SUCCESS; +} + static xcb_render_pictforminfo_t * _CAIRO_FORMAT_TO_XRENDER_FORMAT(xcb_connection_t *dpy, cairo_format_t format) { @@ -167,24 +193,40 @@ _xcb_render_format_to_content (xcb_render_pictforminfo_t *xrender_format) return CAIRO_CONTENT_COLOR; } -static void +static cairo_status_t _cairo_xcb_surface_set_gc_clip_rects (cairo_xcb_surface_t *surface) { - if (surface->have_clip_rects) - xcb_set_clip_rectangles(surface->dpy, XCB_CLIP_ORDERING_YX_SORTED, surface->gc, - 0, 0, - surface->num_clip_rects, - surface->clip_rects ); + if (surface->have_clip_rects) { + xcb_void_cookie_t cookie; + + cookie = xcb_set_clip_rectangles_checked (surface->dpy, + XCB_CLIP_ORDERING_YX_SORTED, surface->gc, + 0, 0, + surface->num_clip_rects, + surface->clip_rects); + + return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); + } + + return CAIRO_STATUS_SUCCESS; } -static void +static cairo_status_t _cairo_xcb_surface_set_picture_clip_rects (cairo_xcb_surface_t *surface) { - if (surface->have_clip_rects) - xcb_render_set_picture_clip_rectangles (surface->dpy, surface->dst_picture, - 0, 0, - surface->num_clip_rects, - surface->clip_rects); + if (surface->have_clip_rects) { + xcb_void_cookie_t cookie; + + cookie = xcb_render_set_picture_clip_rectangles_checked (surface->dpy, + surface->dst_picture, + 0, 0, + surface->num_clip_rects, + surface->clip_rects); + + return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); + } + + return CAIRO_STATUS_SUCCESS; } static cairo_status_t @@ -298,6 +340,7 @@ static cairo_status_t _cairo_xcb_surface_finish (void *abstract_surface) { cairo_xcb_surface_t *surface = abstract_surface; + if (surface->dst_picture != XCB_NONE) xcb_render_free_picture (surface->dpy, surface->dst_picture); @@ -313,6 +356,8 @@ _cairo_xcb_surface_finish (void *abstract_surface) free (surface->clip_rects); cairo_region_destroy (surface->clip_region); + _cairo_freepool_fini (&surface->cookie_pool); + surface->dpy = NULL; return CAIRO_STATUS_SUCCESS; @@ -418,12 +463,15 @@ _get_image_surface (cairo_xcb_surface_t *surface, if (surface->use_pixmap == 0) { xcb_generic_error_t *error; - imagerep = xcb_get_image_reply(surface->dpy, - xcb_get_image(surface->dpy, XCB_IMAGE_FORMAT_Z_PIXMAP, - surface->drawable, - extents.x, extents.y, - extents.width, extents.height, - AllPlanes), &error); + + imagerep = xcb_get_image_reply (surface->dpy, + xcb_get_image (surface->dpy, + XCB_IMAGE_FORMAT_Z_PIXMAP, + surface->drawable, + extents.x, extents.y, + extents.width, extents.height, + AllPlanes), + &error); /* If we get an error, the surface must have been a window, * so retry with the safe code path. @@ -446,27 +494,48 @@ _get_image_surface (cairo_xcb_surface_t *surface, * temporary pixmap */ xcb_pixmap_t pixmap; + cairo_xcb_cookie_t *cookies[2]; + cairo_status_t status; + + status = _cairo_xcb_surface_ensure_gc (surface); + if (unlikely (status)) + return status; + + status = _cairo_freepool_alloc_array (&surface->cookie_pool, + ARRAY_LENGTH (cookies), + (void **) cookies); + if (unlikely (status)) + return status; + pixmap = xcb_generate_id (surface->dpy); - xcb_create_pixmap (surface->dpy, - surface->depth, - pixmap, - surface->drawable, - extents.width, extents.height); - _cairo_xcb_surface_ensure_gc (surface); - - xcb_copy_area (surface->dpy, surface->drawable, pixmap, surface->gc, - extents.x, extents.y, 0, 0, extents.width, extents.height); - - imagerep = xcb_get_image_reply(surface->dpy, - xcb_get_image(surface->dpy, XCB_IMAGE_FORMAT_Z_PIXMAP, - pixmap, - extents.x, extents.y, - extents.width, extents.height, - AllPlanes), 0); + cookies[0]->xcb = xcb_create_pixmap_checked (surface->dpy, + surface->depth, + pixmap, + surface->drawable, + extents.width, extents.height); + cairo_list_add_tail (&cookies[0]->link, &surface->to_be_checked); + + cookies[1]->xcb = xcb_copy_area_checked (surface->dpy, + surface->drawable, + pixmap, surface->gc, + extents.x, extents.y, + 0, 0, + extents.width, extents.height); + cairo_list_add_tail (&cookies[1]->link, &surface->to_be_checked); + + imagerep = xcb_get_image_reply (surface->dpy, + xcb_get_image (surface->dpy, + XCB_IMAGE_FORMAT_Z_PIXMAP, + pixmap, + extents.x, extents.y, + extents.width, extents.height, + AllPlanes), + 0); + xcb_free_pixmap (surface->dpy, pixmap); } - if (!imagerep) + if (unlikely (imagerep == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); bpp = _bits_per_pixel(surface->dpy, imagerep->depth); @@ -551,43 +620,57 @@ _get_image_surface (cairo_xcb_surface_t *surface, return _cairo_error (CAIRO_STATUS_NO_MEMORY); } -static void +static cairo_status_t _cairo_xcb_surface_ensure_src_picture (cairo_xcb_surface_t *surface) { if (!surface->src_picture) { - surface->src_picture = xcb_generate_id(surface->dpy); - xcb_render_create_picture (surface->dpy, - surface->src_picture, - surface->drawable, - surface->xrender_format.id, - 0, NULL); + xcb_void_cookie_t cookie; + + surface->src_picture = xcb_generate_id (surface->dpy); + cookie = xcb_render_create_picture_checked (surface->dpy, + surface->src_picture, + surface->drawable, + surface->xrender_format.id, + 0, NULL); + + return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); } + + return CAIRO_STATUS_SUCCESS; } -static void +static cairo_status_t _cairo_xcb_surface_ensure_dst_picture (cairo_xcb_surface_t *surface) { if (!surface->dst_picture) { - surface->dst_picture = xcb_generate_id(surface->dpy); - xcb_render_create_picture (surface->dpy, - surface->dst_picture, - surface->drawable, - surface->xrender_format.id, - 0, NULL); - _cairo_xcb_surface_set_picture_clip_rects (surface); + xcb_void_cookie_t cookie; + + surface->dst_picture = xcb_generate_id (surface->dpy); + cookie = xcb_render_create_picture_checked (surface->dpy, + surface->dst_picture, + surface->drawable, + surface->xrender_format.id, + 0, NULL); + + return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); } + return CAIRO_STATUS_SUCCESS; } -static void +static cairo_status_t _cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface) { + xcb_void_cookie_t cookie; + if (surface->gc) - return; + return CAIRO_STATUS_SUCCESS; surface->gc = xcb_generate_id(surface->dpy); - xcb_create_gc (surface->dpy, surface->gc, surface->drawable, 0, 0); - _cairo_xcb_surface_set_gc_clip_rects(surface); + cookie = xcb_create_gc_checked (surface->dpy, surface->gc, surface->drawable, 0, 0); + _cairo_xcb_surface_set_gc_clip_rects (surface); + + return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); } static cairo_status_t @@ -603,6 +686,7 @@ _draw_image_surface (cairo_xcb_surface_t *surface, int bpp, bpl; uint32_t data_len; uint8_t *data, left_pad=0; + xcb_void_cookie_t cookie; /* equivalent of XPutImage(..., src_x,src_y, dst_x,dst_y, width,height); */ /* XXX: assumes image and surface formats and depths are the same */ @@ -650,17 +734,17 @@ _draw_image_surface (cairo_xcb_surface_t *surface, } } _cairo_xcb_surface_ensure_gc (surface); - xcb_put_image (surface->dpy, XCB_IMAGE_FORMAT_Z_PIXMAP, - surface->drawable, surface->gc, - width, height, - dst_x, dst_y, - left_pad, image->depth, - data_len, data); + cookie = xcb_put_image_checked (surface->dpy, XCB_IMAGE_FORMAT_Z_PIXMAP, + surface->drawable, surface->gc, + width, height, + dst_x, dst_y, + left_pad, image->depth, + data_len, data); if (data < image->data || data >= image->data + image->height * bpl) - free(data); + free (data); - return CAIRO_STATUS_SUCCESS; + return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); } static cairo_status_t @@ -817,9 +901,7 @@ _cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface, cairo_matrix_t *matrix) { xcb_render_transform_t xtransform; - - if (!surface->src_picture) - return CAIRO_STATUS_SUCCESS; + xcb_void_cookie_t cookie; xtransform.matrix11 = _cairo_fixed_16_16_from_double (matrix->xx); xtransform.matrix12 = _cairo_fixed_16_16_from_double (matrix->xy); @@ -847,9 +929,10 @@ _cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface, return CAIRO_INT_STATUS_UNSUPPORTED; } - xcb_render_set_picture_transform (surface->dpy, surface->src_picture, xtransform); - - return CAIRO_STATUS_SUCCESS; + cookie = xcb_render_set_picture_transform_checked (surface->dpy, + surface->src_picture, + xtransform); + return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); } static cairo_status_t @@ -857,9 +940,7 @@ _cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface, cairo_filter_t filter) { const char *render_filter; - - if (!surface->src_picture) - return CAIRO_STATUS_SUCCESS; + xcb_void_cookie_t cookie; if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) { @@ -891,59 +972,70 @@ _cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface, break; } - xcb_render_set_picture_filter(surface->dpy, surface->src_picture, - strlen(render_filter), render_filter, 0, NULL); + cookie = xcb_render_set_picture_filter_checked (surface->dpy, surface->src_picture, + strlen(render_filter), render_filter, + 0, NULL); - return CAIRO_STATUS_SUCCESS; + return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); } static cairo_status_t -_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, int repeat) +_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, cairo_extend_t extend) { uint32_t mask = XCB_RENDER_CP_REPEAT; - uint32_t pa[] = { repeat }; - - if (!surface->src_picture) - return CAIRO_STATUS_SUCCESS; - - xcb_render_change_picture (surface->dpy, surface->src_picture, mask, pa); - - return CAIRO_STATUS_SUCCESS; -} + uint32_t pa[1]; + xcb_void_cookie_t cookie; -static cairo_int_status_t -_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface, - cairo_surface_attributes_t *attributes) -{ - cairo_int_status_t status; - - _cairo_xcb_surface_ensure_src_picture (surface); - - status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix); - if (status) - return status; - - switch (attributes->extend) { + switch (extend) { case CAIRO_EXTEND_NONE: - _cairo_xcb_surface_set_repeat (surface, XCB_RENDER_REPEAT_NONE); + pa[0] = XCB_RENDER_REPEAT_NONE; break; + case CAIRO_EXTEND_REPEAT: - _cairo_xcb_surface_set_repeat (surface, XCB_RENDER_REPEAT_NORMAL); + pa[0] = XCB_RENDER_REPEAT_NORMAL; break; + case CAIRO_EXTEND_REFLECT: if (!CAIRO_SURFACE_RENDER_HAS_REPEAT_REFLECT(surface)) return CAIRO_INT_STATUS_UNSUPPORTED; - _cairo_xcb_surface_set_repeat (surface, XCB_RENDER_REPEAT_REFLECT); + + pa[0] = XCB_RENDER_REPEAT_REFLECT; break; + case CAIRO_EXTEND_PAD: if (!CAIRO_SURFACE_RENDER_HAS_REPEAT_PAD(surface)) return CAIRO_INT_STATUS_UNSUPPORTED; - _cairo_xcb_surface_set_repeat (surface, XCB_RENDER_REPEAT_PAD); + + pa[0] = XCB_RENDER_REPEAT_PAD; break; + default: return CAIRO_INT_STATUS_UNSUPPORTED; } + cookie = xcb_render_change_picture_checked (surface->dpy, surface->src_picture, + mask, pa); + return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); +} + +static cairo_int_status_t +_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface, + cairo_surface_attributes_t *attributes) +{ + cairo_int_status_t status; + + status = _cairo_xcb_surface_ensure_src_picture (surface); + if (status) + return status; + + status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix); + if (status) + return status; + + status = _cairo_xcb_surface_set_repeat (surface, attributes->extend); + if (status) + return status; + status = _cairo_xcb_surface_set_filter (surface, attributes->filter); if (status) return status; @@ -1204,6 +1296,7 @@ _cairo_xcb_surface_composite (cairo_operator_t op, composite_operation_t operation; int itx, ity; cairo_bool_t is_integer_translation; + xcb_void_cookie_t cookie; if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -1244,49 +1337,55 @@ _cairo_xcb_surface_composite (cairo_operator_t op, switch (operation) { case DO_RENDER: - _cairo_xcb_surface_ensure_dst_picture (dst); + status = _cairo_xcb_surface_ensure_dst_picture (dst); + if (unlikely (status)) + goto BAIL; + if (mask) { status = _cairo_xcb_surface_set_attributes (mask, &mask_attr); - if (status) + if (unlikely (status)) goto BAIL; - xcb_render_composite (dst->dpy, - _render_operator (op), - src->src_picture, - mask->src_picture, - dst->dst_picture, - src_x + src_attr.x_offset, - src_y + src_attr.y_offset, - mask_x + mask_attr.x_offset, - mask_y + mask_attr.y_offset, - dst_x, dst_y, - width, height); + cookie = xcb_render_composite_checked (dst->dpy, + _render_operator (op), + src->src_picture, + mask->src_picture, + dst->dst_picture, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + mask_x + mask_attr.x_offset, + mask_y + mask_attr.y_offset, + dst_x, dst_y, + width, height); } else { static xcb_render_picture_t maskpict = { XCB_NONE }; - xcb_render_composite (dst->dpy, - _render_operator (op), - src->src_picture, - maskpict, - dst->dst_picture, - src_x + src_attr.x_offset, - src_y + src_attr.y_offset, - 0, 0, - dst_x, dst_y, - width, height); + cookie = xcb_render_composite_checked (dst->dpy, + _render_operator (op), + src->src_picture, + maskpict, + dst->dst_picture, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + 0, 0, + dst_x, dst_y, + width, height); } break; case DO_XCOPYAREA: - _cairo_xcb_surface_ensure_gc (dst); - xcb_copy_area (dst->dpy, - src->drawable, - dst->drawable, - dst->gc, - src_x + src_attr.x_offset, - src_y + src_attr.y_offset, - dst_x, dst_y, - width, height); + status = _cairo_xcb_surface_ensure_gc (dst); + if (unlikely (status)) + return status; + + cookie = xcb_copy_area_checked (dst->dpy, + src->drawable, + dst->drawable, + dst->gc, + src_x + src_attr.x_offset, + src_y + src_attr.y_offset, + dst_x, dst_y, + width, height); break; case DO_XTILE: @@ -1298,7 +1397,10 @@ _cairo_xcb_surface_composite (cairo_operator_t op, * _recategorize_composite_operation. */ - _cairo_xcb_surface_ensure_gc (dst); + status = _cairo_xcb_surface_ensure_gc (dst); + if (unlikely (status)) + return status; + is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity); assert (is_integer_translation == TRUE); @@ -1314,7 +1416,10 @@ _cairo_xcb_surface_composite (cairo_operator_t op, xcb_rectangle_t rect = { dst_x, dst_y, width, height }; xcb_change_gc( dst->dpy, dst->gc, mask, values ); - xcb_poly_fill_rectangle(dst->dpy, dst->drawable, dst->gc, 1, &rect); + cookie = xcb_poly_fill_rectangle_checked (dst->dpy, + dst->drawable, + dst->gc, + 1, &rect); } break; @@ -1323,7 +1428,11 @@ _cairo_xcb_surface_composite (cairo_operator_t op, ASSERT_NOT_REACHED; } - if (!_cairo_operator_bounded_by_source (op)) + status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie); + if (unlikely (status)) + goto BAIL; + + if (!_cairo_operator_bounded_by_source (op)) { status = _cairo_surface_composite_fixup_unbounded (&dst->base, &src_attr, src->width, src->height, mask ? &mask_attr : NULL, @@ -1333,6 +1442,7 @@ _cairo_xcb_surface_composite (cairo_operator_t op, mask_x, mask_y, dst_x, dst_y, width, height, clip_region); + } BAIL: if (mask) @@ -1355,6 +1465,7 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface, xcb_rectangle_t static_xrects[16]; xcb_rectangle_t *xrects = static_xrects; cairo_status_t status; + xcb_void_cookie_t cookie; int i; if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface)) @@ -1381,45 +1492,74 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface, xrects[i].height = rects[i].height; } - _cairo_xcb_surface_ensure_dst_picture (surface); - xcb_render_fill_rectangles (surface->dpy, - _render_operator (op), - surface->dst_picture, - render_color, num_rects, xrects); + status = _cairo_xcb_surface_ensure_dst_picture (surface); + if (unlikely (status)) { + if (xrects != static_xrects) + free (xrects); + return status; + } + + cookie = xcb_render_fill_rectangles_checked (surface->dpy, + _render_operator (op), + surface->dst_picture, + render_color, num_rects, xrects); if (xrects != static_xrects) - free(xrects); + free (xrects); - return CAIRO_STATUS_SUCCESS; + return _cairo_xcb_add_cookie_to_be_checked (surface, cookie); } /* Creates an A8 picture of size @width x @height, initialized with @color */ -static xcb_render_picture_t +static cairo_status_t _create_a8_picture (cairo_xcb_surface_t *surface, xcb_render_color_t *color, int width, int height, - cairo_bool_t repeat) + cairo_bool_t repeat, + xcb_render_picture_t *out) { uint32_t values[] = { TRUE }; uint32_t mask = repeat ? XCB_RENDER_CP_REPEAT : 0; - xcb_pixmap_t pixmap = xcb_generate_id (surface->dpy); - xcb_render_picture_t picture = xcb_generate_id (surface->dpy); - - xcb_render_pictforminfo_t *format - = _CAIRO_FORMAT_TO_XRENDER_FORMAT (surface->dpy, CAIRO_FORMAT_A8); + xcb_pixmap_t pixmap; + xcb_render_picture_t picture; + xcb_render_pictforminfo_t *format; xcb_rectangle_t rect = { 0, 0, width, height }; - xcb_create_pixmap (surface->dpy, 8, pixmap, surface->drawable, - width <= 0 ? 1 : width, - height <= 0 ? 1 : height); - xcb_render_create_picture (surface->dpy, picture, pixmap, format->id, mask, values); - xcb_render_fill_rectangles (surface->dpy, XCB_RENDER_PICT_OP_SRC, picture, *color, 1, &rect); + cairo_xcb_cookie_t *cookie[3]; + cairo_status_t status; + + status = _cairo_freepool_alloc_array (&surface->cookie_pool, + ARRAY_LENGTH (cookie), + (void **) cookie); + if (unlikely (status)) + return status; + + pixmap = xcb_generate_id (surface->dpy); + picture = xcb_generate_id (surface->dpy); + + cookie[0]->xcb = xcb_create_pixmap_checked (surface->dpy, 8, pixmap, surface->drawable, + width <= 0 ? 1 : width, + height <= 0 ? 1 : height); + cairo_list_add_tail (&cookie[0]->link, &surface->to_be_checked); + + format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (surface->dpy, CAIRO_FORMAT_A8); + cookie[1]->xcb = xcb_render_create_picture_checked (surface->dpy, + picture, pixmap, format->id, + mask, values); + cairo_list_add_tail (&cookie[1]->link, &surface->to_be_checked); + + cookie[2]->xcb = xcb_render_fill_rectangles_checked (surface->dpy, + XCB_RENDER_PICT_OP_SRC, + picture, *color, 1, &rect); + cairo_list_add_tail (&cookie[2]->link, &surface->to_be_checked); + xcb_free_pixmap (surface->dpy, pixmap); - return picture; + *out = picture; + return CAIRO_STATUS_SUCCESS; } /* Creates a temporary mask for the trapezoids covering the area @@ -1440,6 +1580,8 @@ _create_trapezoid_mask (cairo_xcb_surface_t *dst, xcb_render_color_t solid = { 0xffff, 0xffff, 0xffff, 0xffff }; xcb_render_picture_t mask_picture, solid_picture; xcb_render_trapezoid_t *offset_traps; + xcb_void_cookie_t cookie; + cairo_status_t status; int i; /* This would be considerably simpler using XRenderAddTraps(), but since @@ -1449,12 +1591,22 @@ _create_trapezoid_mask (cairo_xcb_surface_t *dst, * optimization that avoids creating another intermediate surface on * the servers that have XRenderAddTraps(). */ - mask_picture = _create_a8_picture (dst, &transparent, width, height, FALSE); - solid_picture = _create_a8_picture (dst, &solid, width, height, TRUE); + status = _create_a8_picture (dst, &transparent, width, height, FALSE, &mask_picture); + if (unlikely (status)) + return status; + + status = _create_a8_picture (dst, &solid, 1, 1, TRUE, &solid_picture); + if (unlikely (status)) { + xcb_render_free_picture (dst->dpy, mask_picture); + return status; + } offset_traps = _cairo_malloc_ab (num_traps, sizeof (xcb_render_trapezoid_t)); - if (offset_traps == NULL) + if (offset_traps == NULL) { + xcb_render_free_picture (dst->dpy, solid_picture); + xcb_render_free_picture (dst->dpy, mask_picture); return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } for (i = 0; i < num_traps; i++) { offset_traps[i].top = _cairo_fixed_to_16_16(traps[i].top) - 0x10000 * dst_y; @@ -1469,15 +1621,21 @@ _create_trapezoid_mask (cairo_xcb_surface_t *dst, offset_traps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y) - 0x10000 * dst_y; } - xcb_render_trapezoids (dst->dpy, XCB_RENDER_PICT_OP_ADD, - solid_picture, mask_picture, - pict_format->id, - 0, 0, - num_traps, offset_traps); + cookie = xcb_render_trapezoids_checked (dst->dpy, XCB_RENDER_PICT_OP_ADD, + solid_picture, mask_picture, + pict_format->id, + 0, 0, + num_traps, offset_traps); xcb_render_free_picture (dst->dpy, solid_picture); free (offset_traps); + status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie); + if (unlikely (status)) { + xcb_render_free_picture (dst->dpy, mask_picture); + return status; + } + *mask_picture_out = mask_picture; return CAIRO_STATUS_SUCCESS; } @@ -1554,7 +1712,9 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op, render_src_x = src_x + render_reference_x - dst_x; render_src_y = src_y + render_reference_y - dst_y; - _cairo_xcb_surface_ensure_dst_picture (dst); + status = _cairo_xcb_surface_ensure_dst_picture (dst); + if (unlikely (status)) + goto BAIL; status = _cairo_xcb_surface_set_clip_region (dst, clip_region); if (unlikely (status)) @@ -1565,6 +1725,8 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op, goto BAIL; if (!_cairo_operator_bounded_by_mask (op)) { + xcb_void_cookie_t cookie; + /* xcb_render_composite+trapezoids() creates a mask only large enough for the * trapezoids themselves, but if the operator is unbounded, then we need * to actually composite all the way out to the bounds, so we create @@ -1583,19 +1745,22 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op, if (status) goto BAIL; - xcb_render_composite (dst->dpy, - _render_operator (op), - src->src_picture, - mask_picture, - dst->dst_picture, - src_x + attributes.x_offset, - src_y + attributes.y_offset, - 0, 0, - dst_x, dst_y, - width, height); - + cookie = xcb_render_composite_checked (dst->dpy, + _render_operator (op), + src->src_picture, + mask_picture, + dst->dst_picture, + src_x + attributes.x_offset, + src_y + attributes.y_offset, + 0, 0, + dst_x, dst_y, + width, height); xcb_render_free_picture (dst->dpy, mask_picture); + status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie); + if (unlikely (status)) + goto BAIL; + status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base, &attributes, src->width, src->height, width, height, @@ -1605,8 +1770,9 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op, clip_region); } else { - xcb_render_trapezoid_t xtraps_stack[16]; + xcb_render_trapezoid_t xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (xcb_render_trapezoid_t)]; xcb_render_trapezoid_t *xtraps = xtraps_stack; + xcb_void_cookie_t cookie; int i; if (num_traps > ARRAY_LENGTH(xtraps_stack)) { @@ -1630,16 +1796,18 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op, xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y); } - xcb_render_trapezoids (dst->dpy, - _render_operator (op), - src->src_picture, dst->dst_picture, - render_format->id, - render_src_x + attributes.x_offset, - render_src_y + attributes.y_offset, - num_traps, xtraps); + cookie = xcb_render_trapezoids_checked (dst->dpy, + _render_operator (op), + src->src_picture, dst->dst_picture, + render_format->id, + render_src_x + attributes.x_offset, + render_src_y + attributes.y_offset, + num_traps, xtraps); if (xtraps != xtraps_stack) - free(xtraps); + free (xtraps); + + status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie); } BAIL: @@ -1663,6 +1831,41 @@ _cairo_xcb_surface_get_extents (void *abstract_surface, return TRUE; } +static cairo_status_t +_cairo_xcb_surface_flush (void *abstract_surface) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + while (! cairo_list_is_empty (&surface->to_be_checked)) { + cairo_xcb_cookie_t *cookie; + xcb_generic_error_t *error; + + cookie = cairo_list_first_entry (&surface->to_be_checked, + cairo_xcb_cookie_t, + link); + + error = xcb_request_check (surface->dpy, cookie->xcb); + if (error != NULL) { +#if 0 + /* XXX */ + fprintf (stderr, "Delayed error detected: %d, major=%d, minor=%d, seqno=%d\n", + error->error_code, + error->major_code, + error->minor_code, + error->sequence); +#endif + if (status == CAIRO_STATUS_SUCCESS) + status = _cairo_error (CAIRO_STATUS_WRITE_ERROR); /* XXX CAIRO_STATUS_CONNECTION_ERROR */ + } + + cairo_list_del (&cookie->link); + _cairo_freepool_free (&surface->cookie_pool, cookie); + } + + return status; +} + /* XXX: _cairo_xcb_surface_get_font_options */ static void @@ -1733,7 +1936,7 @@ static const cairo_surface_backend_t cairo_xcb_surface_backend = { _cairo_xcb_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ - NULL, /* flush */ + _cairo_xcb_surface_flush, NULL, /* mark_dirty_rectangle */ _cairo_xcb_surface_scaled_font_fini, _cairo_xcb_surface_scaled_glyph_fini, @@ -1867,6 +2070,10 @@ _cairo_xcb_surface_create_internal (xcb_connection_t *dpy, surface->num_clip_rects = 0; surface->clip_region = NULL; + cairo_list_init (&surface->to_be_checked); + _cairo_freepool_init (&surface->cookie_pool, + sizeof (cairo_xcb_cookie_t)); + return &surface->base; } @@ -2050,10 +2257,15 @@ _cairo_xcb_surface_font_init (xcb_connection_t *dpy, font_private->format = format; font_private->xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT(dpy, format); font_private->glyphset = xcb_generate_id(dpy); - xcb_render_create_glyph_set (dpy, font_private->glyphset, font_private->xrender_format->id); + + /* XXX checking, adding to CloseDisplay */ + xcb_render_create_glyph_set (dpy, + font_private->glyphset, + font_private->xrender_format->id); scaled_font->surface_private = font_private; scaled_font->surface_backend = &cairo_xcb_surface_backend; + return CAIRO_STATUS_SUCCESS; } @@ -2077,8 +2289,8 @@ _cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, if (font_private != NULL && scaled_glyph->surface_private != NULL) { xcb_render_glyph_t glyph_index = _cairo_scaled_glyph_index(scaled_glyph); xcb_render_free_glyphs (font_private->dpy, - font_private->glyphset, - 1, &glyph_index); + font_private->glyphset, + 1, &glyph_index); } } @@ -2091,9 +2303,9 @@ _native_byte_order_lsb (void) } static cairo_status_t -_cairo_xcb_surface_add_glyph (xcb_connection_t *dpy, - cairo_scaled_font_t *scaled_font, - cairo_scaled_glyph_t *scaled_glyph) +_cairo_xcb_surface_add_glyph (cairo_xcb_surface_t *dst, + cairo_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) { xcb_render_glyphinfo_t glyph_info; xcb_render_glyph_t glyph_index; @@ -2101,10 +2313,11 @@ _cairo_xcb_surface_add_glyph (xcb_connection_t *dpy, cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_xcb_surface_font_private_t *font_private; cairo_image_surface_t *glyph_surface = scaled_glyph->surface; + xcb_void_cookie_t cookie; if (scaled_font->surface_private == NULL) { - status = _cairo_xcb_surface_font_init (dpy, scaled_font, - glyph_surface->format); + status = _cairo_xcb_surface_font_init (dst->dpy, scaled_font, + glyph_surface->format); if (status) return status; } @@ -2115,29 +2328,28 @@ _cairo_xcb_surface_add_glyph (xcb_connection_t *dpy, * format. */ if (glyph_surface->format != font_private->format) { - cairo_t *cr; + cairo_surface_pattern_t pattern; cairo_surface_t *tmp_surface; - double x_offset, y_offset; tmp_surface = cairo_image_surface_create (font_private->format, glyph_surface->width, glyph_surface->height); - cr = cairo_create (tmp_surface); - cairo_surface_get_device_offset (&glyph_surface->base, &x_offset, &y_offset); - cairo_set_source_surface (cr, &glyph_surface->base, x_offset, y_offset); - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - cairo_paint (cr); - - status = cairo_status (cr); - - cairo_destroy (cr); + status = tmp_surface->status; + if (unlikely (status)) + goto BAIL; tmp_surface->device_transform = glyph_surface->base.device_transform; tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse; + _cairo_pattern_init_for_surface (&pattern, &glyph_surface->base); + status = _cairo_surface_paint (tmp_surface, + CAIRO_OPERATOR_SOURCE, &pattern.base, + NULL); + _cairo_pattern_fini (&pattern.base); + glyph_surface = (cairo_image_surface_t *) tmp_surface; - if (status) + if (unlikely (status)) goto BAIL; } @@ -2155,7 +2367,7 @@ _cairo_xcb_surface_add_glyph (xcb_connection_t *dpy, switch (scaled_glyph->surface->format) { case CAIRO_FORMAT_A1: /* local bitmaps are always stored with bit == byte */ - if (_native_byte_order_lsb() != (xcb_get_setup(dpy)->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) { + if (_native_byte_order_lsb() != (xcb_get_setup(dst->dpy)->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) { int c = glyph_surface->stride * glyph_surface->height; unsigned char *d; unsigned char *new, *n; @@ -2181,7 +2393,7 @@ _cairo_xcb_surface_add_glyph (xcb_connection_t *dpy, case CAIRO_FORMAT_A8: break; case CAIRO_FORMAT_ARGB32: - if (_native_byte_order_lsb() != (xcb_get_setup(dpy)->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) { + if (_native_byte_order_lsb() != (xcb_get_setup(dst->dpy)->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) { unsigned int c = glyph_surface->stride * glyph_surface->height; unsigned char *d; unsigned char *new, *n; @@ -2215,14 +2427,16 @@ _cairo_xcb_surface_add_glyph (xcb_connection_t *dpy, glyph_index = _cairo_scaled_glyph_index (scaled_glyph); - xcb_render_add_glyphs (dpy, font_private->glyphset, - 1, &glyph_index, &glyph_info, - glyph_surface->stride * glyph_surface->height, - data); + cookie = xcb_render_add_glyphs_checked (dst->dpy, font_private->glyphset, + 1, &glyph_index, &glyph_info, + glyph_surface->stride * glyph_surface->height, + data); if (data != glyph_surface->data) free (data); + status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie); + BAIL: if (glyph_surface != scaled_glyph->surface) cairo_surface_destroy (&glyph_surface->base); @@ -2243,6 +2457,7 @@ _cairo_xcb_surface_show_glyphs_8 (cairo_xcb_surface_t *dst, { cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private; xcb_render_util_composite_text_stream_t *stream; + xcb_void_cookie_t cookie; int i; int thisX, thisY; int lastX = 0, lastY = 0; @@ -2259,18 +2474,18 @@ _cairo_xcb_surface_show_glyphs_8 (cairo_xcb_surface_t *dst, lastY = thisY; } - xcb_render_util_composite_text (dst->dpy, - _render_operator (op), - src->src_picture, - dst->dst_picture, - font_private->xrender_format->id, - src_x_offset + _cairo_lround (glyphs[0].x), - src_y_offset + _cairo_lround (glyphs[0].y), - stream); + cookie = xcb_render_util_composite_text_checked (dst->dpy, + _render_operator (op), + src->src_picture, + dst->dst_picture, + font_private->xrender_format->id, + src_x_offset + _cairo_lround (glyphs[0].x), + src_y_offset + _cairo_lround (glyphs[0].y), + stream); xcb_render_util_composite_text_free (stream); - return CAIRO_STATUS_SUCCESS; + return _cairo_xcb_add_cookie_to_be_checked (dst, cookie); } static cairo_status_t @@ -2284,6 +2499,7 @@ _cairo_xcb_surface_show_glyphs_16 (cairo_xcb_surface_t *dst, { cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private; xcb_render_util_composite_text_stream_t *stream; + xcb_void_cookie_t cookie; int i; int thisX, thisY; int lastX = 0, lastY = 0; @@ -2300,18 +2516,18 @@ _cairo_xcb_surface_show_glyphs_16 (cairo_xcb_surface_t *dst, lastY = thisY; } - xcb_render_util_composite_text (dst->dpy, - _render_operator (op), - src->src_picture, - dst->dst_picture, - font_private->xrender_format->id, - src_x_offset + _cairo_lround (glyphs[0].x), - src_y_offset + _cairo_lround (glyphs[0].y), - stream); + cookie = xcb_render_util_composite_text_checked (dst->dpy, + _render_operator (op), + src->src_picture, + dst->dst_picture, + font_private->xrender_format->id, + src_x_offset + _cairo_lround (glyphs[0].x), + src_y_offset + _cairo_lround (glyphs[0].y), + stream); xcb_render_util_composite_text_free (stream); - return CAIRO_STATUS_SUCCESS; + return _cairo_xcb_add_cookie_to_be_checked (dst, cookie); } static cairo_status_t @@ -2325,6 +2541,7 @@ _cairo_xcb_surface_show_glyphs_32 (cairo_xcb_surface_t *dst, { cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private; xcb_render_util_composite_text_stream_t *stream; + xcb_void_cookie_t cookie; int i; int thisX, thisY; int lastX = 0, lastY = 0; @@ -2341,18 +2558,18 @@ _cairo_xcb_surface_show_glyphs_32 (cairo_xcb_surface_t *dst, lastY = thisY; } - xcb_render_util_composite_text (dst->dpy, - _render_operator (op), - src->src_picture, - dst->dst_picture, - font_private->xrender_format->id, - src_x_offset + _cairo_lround (glyphs[0].x), - src_y_offset + _cairo_lround (glyphs[0].y), - stream); + cookie = xcb_render_util_composite_text_checked (dst->dpy, + _render_operator (op), + src->src_picture, + dst->dst_picture, + font_private->xrender_format->id, + src_x_offset + _cairo_lround (glyphs[0].x), + src_y_offset + _cairo_lround (glyphs[0].y), + stream); xcb_render_util_composite_text_free (stream); - return CAIRO_STATUS_SUCCESS; + return _cairo_xcb_add_cookie_to_be_checked (dst, cookie); } typedef cairo_status_t (*cairo_xcb_surface_show_glyphs_func_t) @@ -2376,8 +2593,6 @@ _cairo_xcb_surface_owns_font (cairo_xcb_surface_t *dst, return TRUE; } - - static cairo_status_t _cairo_xcb_surface_emit_glyphs (cairo_xcb_surface_t *dst, cairo_glyph_t *glyphs, @@ -2422,14 +2637,18 @@ _cairo_xcb_surface_emit_glyphs (cairo_xcb_surface_t *dst, if (scaled_glyph->surface->width && scaled_glyph->surface->height) { output_glyphs[o++] = glyphs[i]; if (scaled_glyph->surface_private == NULL) { - _cairo_xcb_surface_add_glyph (dst->dpy, scaled_font, scaled_glyph); + _cairo_xcb_surface_add_glyph (dst, scaled_font, scaled_glyph); scaled_glyph->surface_private = (void *) 1; } } } num_glyphs = o; - _cairo_xcb_surface_ensure_dst_picture (dst); + status = _cairo_xcb_surface_ensure_dst_picture (dst); + if (status) { + free (output_glyphs); + return status; + } max_chunk_size = xcb_get_maximum_request_length (dst->dpy); if (max_index < 256) { @@ -2592,7 +2811,7 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst, /* Send all unsent glyphs to the server, and count the max of the glyph indices */ _cairo_scaled_font_freeze_cache (scaled_font); - if (_cairo_xcb_surface_owns_font (dst, scaled_font)) + if (_cairo_xcb_surface_owns_font (dst, scaled_font)) { status = _cairo_xcb_surface_emit_glyphs (dst, glyphs, num_glyphs, scaled_font, @@ -2600,8 +2819,9 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst, src, &attributes, remaining_glyphs); - else + } else { status = CAIRO_INT_STATUS_UNSUPPORTED; + } _cairo_scaled_font_thaw_cache (scaled_font); BAIL: |