Example #1
0
static cairo_xcb_pixmap_t *
_copy_to_pixmap (cairo_xcb_surface_t *source)
{
    cairo_xcb_pixmap_t *pixmap;

    /* If the source may be a window, we need to copy it and its children
     * via a temporary pixmap so that we can IncludeInferiors on the source
     * and use ClipByChildren on the destination.
     */
    if (source->owns_pixmap) {
	pixmap = _cairo_xcb_pixmap_copy (source);
	if (unlikely (pixmap->base.status))
	    return pixmap;
    } else {
	uint32_t values[1];
	xcb_gcontext_t gc;

	pixmap = _cairo_xcb_pixmap_create (source,
					   source->width,
					   source->height);
	if (unlikely (pixmap->base.status))
	    return pixmap;

	gc = _cairo_xcb_screen_get_gc (source->screen,
				       pixmap->pixmap,
				       pixmap->depth);

	values[0] = TRUE;
	_cairo_xcb_connection_change_gc (pixmap->connection, gc,
					 XCB_GC_SUBWINDOW_MODE, values);

	_cairo_xcb_connection_copy_area (pixmap->connection,
					 source->drawable,
					 pixmap->pixmap, gc,
					 0, 0,
					 0, 0,
					 source->width,
					 source->height);

	values[0] = FALSE;
	_cairo_xcb_connection_change_gc (pixmap->connection, gc,
					 XCB_GC_SUBWINDOW_MODE, values);

	_cairo_xcb_screen_put_gc (source->screen,
				  pixmap->depth,
				  gc);
    }

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

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

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

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

    connection = surface->connection;

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

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

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

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

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

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

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

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

	if (unlikely (status))
	    goto FAIL;
    }

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

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

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

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

    _cairo_xcb_connection_release (connection);

    return image;

FAIL:
    _cairo_xcb_connection_release (connection);
    return _cairo_surface_create_in_error (status);
}
Example #3
0
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;
}
Example #4
0
static cairo_status_t
_get_image (cairo_xcb_surface_t		 *surface,
	    cairo_bool_t		  use_shm,
	    cairo_image_surface_t	**image_out)
{
    cairo_image_surface_t *image;
    cairo_xcb_connection_t *connection;
    xcb_get_image_reply_t *reply;
    cairo_status_t status;

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

    connection = surface->connection;

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

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

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

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

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

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

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

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

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

	if (unlikely (status))
	    goto FAIL;
    }

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

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

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

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

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

    _cairo_xcb_connection_release (connection);

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

    *image_out = image;
    return CAIRO_STATUS_SUCCESS;

FAIL:
    _cairo_xcb_connection_release (connection);
    return status;
}