static cairo_status_t _cairo_xcb_surface_finish (void *abstract_surface) { cairo_xcb_surface_t *surface = abstract_surface; cairo_status_t status; if (surface->fallback != NULL) { cairo_surface_finish (&surface->fallback->base); cairo_surface_destroy (&surface->fallback->base); } _cairo_boxes_fini (&surface->fallback_damage); cairo_list_del (&surface->link); status = _cairo_xcb_connection_acquire (surface->connection); if (status == CAIRO_STATUS_SUCCESS) { if (surface->picture != XCB_NONE) { _cairo_xcb_connection_render_free_picture (surface->connection, surface->picture); } if (surface->owns_pixmap) _cairo_xcb_connection_free_pixmap (surface->connection, surface->drawable); _cairo_xcb_connection_release (surface->connection); } _cairo_xcb_connection_destroy (surface->connection); return status; }
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; }
cairo_status_t _cairo_xcb_surface_core_fill_boxes (cairo_xcb_surface_t *dst, const cairo_color_t *color, cairo_boxes_t *boxes) { struct _cairo_boxes_chunk *chunk; xcb_gcontext_t gc; cairo_status_t status; status = _cairo_xcb_connection_acquire (dst->connection); if (unlikely (status)) return status; status = _cairo_xcb_connection_take_socket (dst->connection); if (unlikely (status)) { _cairo_xcb_connection_release (dst->connection); return status; } gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth); #if 0 xcb_pixmap_t source; source = _dither_source (dst, color); XSetTSOrigin (surface->dpy, gc, 0, 0); XSetTile (surface->dpy, gc, source); #endif for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { xcb_rectangle_t *xcb_rects; int i; xcb_rects = (xcb_rectangle_t *) chunk->base; for (i = 0; i < chunk->count; i++) { int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x); int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x); int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y); int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y); xcb_rects[i].x = x1; xcb_rects[i].y = y1; xcb_rects[i].width = x2 - x1; xcb_rects[i].height = y2 - y1; } _cairo_xcb_connection_poly_fill_rectangle (dst->connection, dst->drawable, gc, chunk->count, xcb_rects); } _cairo_xcb_screen_put_gc (dst->screen, dst->depth, gc); _cairo_xcb_connection_release (dst->connection); return CAIRO_STATUS_SUCCESS; }
/** * cairo_xcb_surface_set_drawable: * @surface: a #cairo_surface_t for the XCB backend * @drawable: the new drawable of the surface * @width: the new width of the surface * @height: the new height of the surface * * Informs cairo of the new drawable and size of the XCB drawable underlying the * surface. * * If cairo_surface_flush() wasn't called, some pending operations * might be discarded. **/ void cairo_xcb_surface_set_drawable (cairo_surface_t *abstract_surface, xcb_drawable_t drawable, int width, int height) { cairo_xcb_surface_t *surface; if (unlikely (abstract_surface->status)) return; if (unlikely (abstract_surface->finished)) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); return; } if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_INVALID_SIZE)); return; } surface = (cairo_xcb_surface_t *) abstract_surface; /* XXX: and what about this case? */ if (surface->owns_pixmap) return; _drawable_changed (surface); if (surface->drawable != drawable) { cairo_status_t status; status = _cairo_xcb_connection_acquire (surface->connection); if (unlikely (status)) return; if (surface->picture != XCB_NONE) { _cairo_xcb_connection_render_free_picture (surface->connection, surface->picture); surface->picture = XCB_NONE; } _cairo_xcb_connection_release (surface->connection); surface->drawable = drawable; } surface->width = width; surface->height = height; }
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_status_t _cairo_xcb_surface_finish (void *abstract_surface) { cairo_xcb_surface_t *surface = abstract_surface; cairo_status_t status; if (surface->fallback != NULL) { cairo_surface_finish (surface->fallback); cairo_surface_destroy (surface->fallback); } cairo_list_del (&surface->link); #if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS if (surface->drm != NULL) { cairo_surface_finish (surface->drm); cairo_surface_destroy (surface->drm); xcb_dri2_destroy_drawable (surface->connection->xcb_connection, surface->drawable); } #endif status = _cairo_xcb_connection_acquire (surface->connection); if (status == CAIRO_STATUS_SUCCESS) { if (_cairo_xcb_connection_take_socket (surface->connection) == CAIRO_STATUS_SUCCESS) { if (surface->picture != XCB_NONE) { _cairo_xcb_connection_render_free_picture (surface->connection, surface->picture); } if (surface->owns_pixmap) _cairo_xcb_connection_free_pixmap (surface->connection, surface->drawable); } _cairo_xcb_connection_release (surface->connection); } _cairo_xcb_connection_destroy (surface->connection); return status; }
static cairo_status_t _cairo_xcb_pixmap_finish (void *abstract_surface) { cairo_xcb_pixmap_t *surface = abstract_surface; cairo_status_t status; if (surface->owner != NULL) { cairo_surface_destroy (surface->owner); } else { status = _cairo_xcb_connection_acquire (surface->connection); if (unlikely (status)) return status; if (_cairo_xcb_connection_take_socket (surface->connection) == CAIRO_STATUS_SUCCESS) { _cairo_xcb_connection_free_pixmap (surface->connection, surface->pixmap); } _cairo_xcb_connection_release (surface->connection); } return CAIRO_STATUS_SUCCESS; }
cairo_surface_t * _cairo_xcb_surface_create_similar (void *abstract_other, cairo_content_t content, int width, int height) { cairo_xcb_surface_t *other = abstract_other; cairo_xcb_surface_t *surface; cairo_xcb_connection_t *connection; xcb_pixmap_t pixmap; cairo_status_t status; if (unlikely(width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0)) return cairo_image_surface_create (_cairo_format_from_content (content), width, height); if ((other->connection->flags & CAIRO_XCB_HAS_RENDER) == 0) return _cairo_xcb_surface_create_similar_image (other, _cairo_format_from_content (content), width, height); connection = other->connection; status = _cairo_xcb_connection_acquire (connection); if (unlikely (status)) return _cairo_surface_create_in_error (status); if (content == other->base.content) { pixmap = _cairo_xcb_connection_create_pixmap (connection, other->depth, other->drawable, width, height); surface = (cairo_xcb_surface_t *) _cairo_xcb_surface_create_internal (other->screen, pixmap, TRUE, other->pixman_format, other->xrender_format, width, height); } else { cairo_format_t format; pixman_format_code_t pixman_format; /* XXX find a compatible xrender format */ switch (content) { case CAIRO_CONTENT_ALPHA: pixman_format = PIXMAN_a8; format = CAIRO_FORMAT_A8; break; case CAIRO_CONTENT_COLOR: pixman_format = PIXMAN_x8r8g8b8; format = CAIRO_FORMAT_RGB24; break; default: ASSERT_NOT_REACHED; case CAIRO_CONTENT_COLOR_ALPHA: pixman_format = PIXMAN_a8r8g8b8; format = CAIRO_FORMAT_ARGB32; break; } pixmap = _cairo_xcb_connection_create_pixmap (connection, PIXMAN_FORMAT_DEPTH (pixman_format), other->drawable, width, height); surface = (cairo_xcb_surface_t *) _cairo_xcb_surface_create_internal (other->screen, pixmap, TRUE, pixman_format, connection->standard_formats[format], width, height); } if (unlikely (surface->base.status)) _cairo_xcb_connection_free_pixmap (connection, pixmap); _cairo_xcb_connection_release (connection); return &surface->base; }
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); }
cairo_status_t _cairo_xcb_surface_core_copy_boxes (cairo_xcb_surface_t *dst, const cairo_pattern_t *src_pattern, const cairo_rectangle_int_t *extents, const cairo_boxes_t *boxes) { cairo_xcb_pixmap_t *src; const struct _cairo_boxes_chunk *chunk; xcb_gcontext_t gc; cairo_status_t status; status = _cairo_xcb_connection_acquire (dst->connection); if (unlikely (status)) return status; status = _cairo_xcb_connection_take_socket (dst->connection); if (unlikely (status)) goto CLEANUP_CONNECTION; src = _cairo_xcb_pixmap_for_pattern (dst, src_pattern, extents); status = src->base.status; if (unlikely (status)) goto CLEANUP_CONNECTION; assert (src->depth == dst->depth); gc = _cairo_xcb_screen_get_gc (dst->screen, src->pixmap, src->depth); if (src->repeat) { uint32_t mask = XCB_GC_FILL_STYLE | XCB_GC_TILE | XCB_GC_TILE_STIPPLE_ORIGIN_X | XCB_GC_TILE_STIPPLE_ORIGIN_Y; uint32_t values[] = { XCB_FILL_STYLE_TILED, src->pixmap, - src->x0, - src->y0, }; xcb_rectangle_t *xcb_rects; _cairo_xcb_connection_change_gc (dst->connection, gc, mask, values); for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { int i; xcb_rects = (xcb_rectangle_t *) chunk->base; for (i = 0; i < chunk->count; i++) { int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x); int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x); int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y); int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y); xcb_rects[i].x = x1; xcb_rects[i].y = y1; xcb_rects[i].width = x2 - x1; xcb_rects[i].height = y2 - y1; } _cairo_xcb_connection_poly_fill_rectangle (dst->connection, dst->drawable, gc, chunk->count, xcb_rects); } values[0] = 0; _cairo_xcb_connection_change_gc (dst->connection, gc, XCB_GC_FILL_STYLE, values); } else { for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { int i; for (i = 0; i < chunk->count; i++) { int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x); int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x); int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y); int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y); _cairo_xcb_connection_copy_area (dst->connection, src->pixmap, dst->drawable, gc, src->x0 + x1, src->y0 + y1, x1, y1, x2 - x2, y2 - x2); } } } _cairo_xcb_screen_put_gc (dst->screen, src->depth, gc); cairo_surface_destroy (&src->base); CLEANUP_CONNECTION: _cairo_xcb_connection_release (dst->connection); return status; }
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; }