예제 #1
0
static cairo_status_t
_cairo_xcb_surface_acquire_source_image (void *abstract_surface,
					 cairo_image_surface_t **image_out,
					 void **image_extra)
{
    cairo_xcb_surface_t *surface = abstract_surface;
    cairo_surface_t *image;

    if (surface->fallback != NULL) {
	image = cairo_surface_reference (&surface->fallback->base);
	goto DONE;
    }

    image = _cairo_surface_has_snapshot (&surface->base,
					 &_cairo_image_surface_backend);
    if (image != NULL) {
	image = cairo_surface_reference (image);
	goto DONE;
    }

    image = _get_image (surface, FALSE, 0, 0, surface->width, surface->height);
    if (unlikely (image->status))
	return image->status;

    _cairo_surface_attach_snapshot (&surface->base, image, NULL);

DONE:
    *image_out = (cairo_image_surface_t *) image;
    *image_extra = NULL;
    return CAIRO_STATUS_SUCCESS;
}
예제 #2
0
/**
 * _cairo_surface_snapshot:
 * @surface: a #cairo_surface_t
 *
 * Make an immutable reference to @surface. It is an error to call a
 * surface-modifying function on the result of this function. The
 * resulting 'snapshot' is a lazily copied-on-write surface i.e. it
 * remains a reference to the original surface until that surface is
 * written to again, at which time a copy is made of the original surface
 * and the snapshot then points to that instead. Multiple snapshots of the
 * same unmodified surface point to the same copy.
 *
 * The caller owns the return value and should call
 * cairo_surface_destroy() when finished with it. This function will not
 * return %NULL, but will return a nil surface instead.
 *
 * Return value: The snapshot surface. Note that the return surface
 * may not necessarily be of the same type as @surface.
 **/
cairo_surface_t *
_cairo_surface_snapshot (cairo_surface_t *surface)
{
    cairo_surface_snapshot_t *snapshot;
    cairo_status_t status;

    TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, surface->unique_id));

    if (unlikely (surface->status))
	return _cairo_surface_create_in_error (surface->status);

    if (unlikely (surface->finished))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));

    if (surface->snapshot_of != NULL)
	return cairo_surface_reference (surface);

    if (_cairo_surface_is_snapshot (surface))
	return cairo_surface_reference (surface);

    snapshot = (cairo_surface_snapshot_t *)
	_cairo_surface_has_snapshot (surface, &_cairo_surface_snapshot_backend);
    if (snapshot != NULL)
	return cairo_surface_reference (&snapshot->base);

    snapshot = malloc (sizeof (cairo_surface_snapshot_t));
    if (unlikely (snapshot == NULL))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));

    _cairo_surface_init (&snapshot->base,
			 &_cairo_surface_snapshot_backend,
			 NULL, /* device */
			 surface->content);
    snapshot->base.type = surface->type;

    CAIRO_MUTEX_INIT (snapshot->mutex);
    snapshot->target = surface;
    snapshot->clone = NULL;

    status = _cairo_surface_copy_mime_data (&snapshot->base, surface);
    if (unlikely (status)) {
	cairo_surface_destroy (&snapshot->base);
	return _cairo_surface_create_in_error (status);
    }

    snapshot->base.device_transform = surface->device_transform;
    snapshot->base.device_transform_inverse = surface->device_transform_inverse;

    _cairo_surface_attach_snapshot (surface,
				    &snapshot->base,
				    _cairo_surface_snapshot_copy_on_write);

    return &snapshot->base;
}
예제 #3
0
static cairo_surface_t *
attach_proxy (cairo_surface_t *source,
	      cairo_surface_t *target)
{
    struct proxy *proxy;

    proxy = malloc (sizeof (*proxy));
    if (unlikely (proxy == NULL))
	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);

    _cairo_surface_init (&proxy->base, &proxy_backend, NULL, target->content, target->is_vector);

    proxy->target = target;
    _cairo_surface_attach_snapshot (source, &proxy->base, NULL);

    return &proxy->base;
}
예제 #4
0
static cairo_status_t
_cairo_xcb_surface_flush (void *abstract_surface,
			  unsigned flags)
{
    cairo_xcb_surface_t *surface = abstract_surface;
    cairo_status_t status;

    if (flags)
	return CAIRO_STATUS_SUCCESS;

    if (likely (surface->fallback == NULL)) {
	status = CAIRO_STATUS_SUCCESS;
	if (! surface->base.finished && surface->deferred_clear)
	    status = _cairo_xcb_surface_clear (surface);

	return status;
    }

    status = surface->base.status;
    if (status == CAIRO_STATUS_SUCCESS &&
	(! surface->base._finishing || ! surface->owns_pixmap)) {
	status = cairo_surface_status (&surface->fallback->base);

	if (status == CAIRO_STATUS_SUCCESS)
		status = _cairo_bentley_ottmann_tessellate_boxes (&surface->fallback_damage,
								  CAIRO_FILL_RULE_WINDING,
								  &surface->fallback_damage);

	if (status == CAIRO_STATUS_SUCCESS)
	    status = _put_image_boxes (surface,
				       surface->fallback,
				       &surface->fallback_damage);

	if (status == CAIRO_STATUS_SUCCESS && ! surface->base._finishing) {
	    _cairo_surface_attach_snapshot (&surface->base,
					    &surface->fallback->base,
					    cairo_surface_finish);
	}
    }

    _cairo_boxes_clear (&surface->fallback_damage);
    cairo_surface_destroy (&surface->fallback->base);
    surface->fallback = NULL;

    return status;
}
예제 #5
0
cairo_status_t
intel_surface_acquire_source_image (void *abstract_surface,
				    cairo_image_surface_t **image_out,
				    void **image_extra)
{
    intel_surface_t *surface = abstract_surface;
    cairo_surface_t *image;
    cairo_status_t status;
    void *ptr;

    if (surface->drm.fallback != NULL) {
	image = surface->drm.fallback;
	goto DONE;
    }

    image = _cairo_surface_has_snapshot (&surface->drm.base,
	                                 &_cairo_image_surface_backend);
    if (image != NULL)
	goto DONE;

    if (surface->drm.base.backend->flush != NULL) {
	status = surface->drm.base.backend->flush (surface);
	if (unlikely (status))
	    return status;
    }

    ptr = intel_bo_map (to_intel_device (surface->drm.base.device),
			to_intel_bo (surface->drm.bo));
    if (unlikely (ptr == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    image = cairo_image_surface_create_for_data (ptr,
						 surface->drm.format,
						 surface->drm.width,
						 surface->drm.height,
						 surface->drm.stride);
    if (unlikely (image->status))
	return image->status;

    _cairo_surface_attach_snapshot (&surface->drm.base, image, surface_finish_and_destroy);

DONE:
    *image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
    *image_extra = NULL;
    return CAIRO_STATUS_SUCCESS;
}
void
_cairo_surface_subsurface_set_snapshot (cairo_surface_t *surface,
					cairo_surface_t *snapshot)
{
    cairo_surface_subsurface_t *ss = (cairo_surface_subsurface_t *) surface;

    TRACE ((stderr, "%s: target=%d, snapshot=%d\n", __FUNCTION__,
	    ss->target->unique_id, snapshot->unique_id));

    if (ss->snapshot)
	_cairo_surface_detach_snapshot (ss->snapshot);

    ss->snapshot = cairo_surface_reference (snapshot);

    _cairo_surface_attach_snapshot (ss->target, &ss->base,
				    _cairo_surface_subsurface_detach_snapshot);
}
예제 #7
0
static cairo_status_t
radeon_surface_acquire_source_image (void *abstract_surface,
				     cairo_image_surface_t **image_out,
				     void **image_extra)
{
    radeon_surface_t *surface = abstract_surface;
    cairo_surface_t *image;
    cairo_status_t status;

    /* XXX batch flush */

    if (surface->base.fallback != NULL) {
	image = surface->base.fallback;
	goto DONE;
    }

    image = _cairo_surface_has_snapshot (&surface->base.base,
	                                 &_cairo_image_surface_backend);
    if (image != NULL)
	goto DONE;

    if (surface->base.base.backend->flush != NULL) {
	status = surface->base.base.backend->flush (surface);
	if (unlikely (status))
	    return status;
    }

    image = radeon_bo_get_image (to_radeon_device (surface->base.base.device),
				to_radeon_bo (surface->base.bo),
				&surface->base);
    status = image->status;
    if (unlikely (status))
	return status;

    _cairo_surface_attach_snapshot (&surface->base.base, image, cairo_surface_destroy);

DONE:
    *image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
    *image_extra = NULL;
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_recording_surface_acquire_source_image (void			 *abstract_surface,
					       cairo_image_surface_t	**image_out,
					       void			**image_extra)
{
    cairo_status_t status;
    cairo_recording_surface_t *surface = abstract_surface;
    cairo_surface_t *image;

    image = _cairo_surface_has_snapshot (&surface->base,
					 &_cairo_image_surface_backend);
    if (image != NULL) {
	*image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
	*image_extra = NULL;
	return CAIRO_STATUS_SUCCESS;
    }

    image = _cairo_image_surface_create_with_content (surface->content,
						      surface->extents.width,
						      surface->extents.height);
    if (unlikely (image->status))
	return image->status;

    cairo_surface_set_device_offset (image,
				     -surface->extents.x,
				     -surface->extents.y);

    status = _cairo_recording_surface_replay (&surface->base, image);
    if (unlikely (status)) {
	cairo_surface_destroy (image);
	return status;
    }

    _cairo_surface_attach_snapshot (&surface->base, image, NULL);

    *image_out = (cairo_image_surface_t *) image;
    *image_extra = NULL;
    return CAIRO_STATUS_SUCCESS;
}
예제 #9
0
static cairo_status_t
_cairo_xcb_surface_flush (void *abstract_surface)
{
    cairo_xcb_surface_t *surface = abstract_surface;
    cairo_status_t status;

    if (surface->drm != NULL && ! surface->marked_dirty)
	return surface->drm->backend->flush (surface->drm);

    if (likely (surface->fallback == NULL)) {
	status = CAIRO_STATUS_SUCCESS;
	if (! surface->base.finished && surface->deferred_clear)
	    status = _cairo_xcb_surface_clear (surface);

	return status;
    }

    status = surface->base.status;
    if (status == CAIRO_STATUS_SUCCESS && ! surface->base.finished) {
	status = cairo_surface_status (surface->fallback);

	if (status == CAIRO_STATUS_SUCCESS) {
	    status = _put_image (surface,
				 (cairo_image_surface_t *) surface->fallback);
	}

	if (status == CAIRO_STATUS_SUCCESS) {
	    _cairo_surface_attach_snapshot (&surface->base,
					    surface->fallback,
					    cairo_surface_finish);
	}
    }

    cairo_surface_destroy (surface->fallback);
    surface->fallback = NULL;

    return status;
}
예제 #10
0
static cairo_status_t
_cairo_xcb_surface_acquire_source_image (void *abstract_surface,
					 cairo_image_surface_t **image_out,
					 void **image_extra)
{
    cairo_xcb_surface_t *surface = abstract_surface;
    cairo_image_surface_t *image;
    cairo_status_t status;

    if (surface->drm != NULL && ! surface->marked_dirty) {
	return _cairo_surface_acquire_source_image (surface->drm,
						    image_out, image_extra);
    }

    if (surface->fallback != NULL) {
	image = (cairo_image_surface_t *) cairo_surface_reference (surface->fallback);
	goto DONE;
    }

    image = (cairo_image_surface_t *)
	_cairo_surface_has_snapshot (&surface->base,
				     &_cairo_image_surface_backend);
    if (image != NULL) {
	image = (cairo_image_surface_t *) cairo_surface_reference (&image->base);
	goto DONE;
    }

    status = _get_image (surface, FALSE, &image);
    if (unlikely (status))
	return status;

    _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);

DONE:
    *image_out = image;
    *image_extra = NULL;
    return CAIRO_STATUS_SUCCESS;
}
예제 #11
0
void
_cairo_surface_subsurface_set_snapshot (cairo_surface_t *surface,
					cairo_surface_t *snapshot)
{
    cairo_surface_subsurface_t *ss = (cairo_surface_subsurface_t *) surface;

    TRACE ((stderr, "%s: target=%d, snapshot=%d\n", __FUNCTION__,
	    ss->target->unique_id, snapshot->unique_id));

    /* FIXME: attaching the subsurface as a snapshot to its target creates
     * a reference cycle.  Let's make this call as a no-op until that bug
     * is fixed.
     */
    return;

    if (ss->snapshot)
	_cairo_surface_detach_snapshot (ss->snapshot);

    ss->snapshot = cairo_surface_reference (snapshot);

    _cairo_surface_attach_snapshot (ss->target, &ss->base,
				    _cairo_surface_subsurface_detach_snapshot);
}
예제 #12
0
/**
 * _cairo_surface_snapshot
 * @surface: a #cairo_surface_t
 *
 * Make an immutable reference to @surface. It is an error to call a
 * surface-modifying function on the result of this function. The
 * resulting 'snapshot' is a lazily copied-on-write surface i.e. it
 * remains a reference to the original surface until that surface is
 * written to again, at which time a copy is made of the original surface
 * and the snapshot then points to that instead. Multiple snapshots of the
 * same unmodified surface point to the same copy.
 *
 * The caller owns the return value and should call
 * cairo_surface_destroy() when finished with it. This function will not
 * return %NULL, but will return a nil surface instead.
 *
 * Return value: The snapshot surface. Note that the return surface
 * may not necessarily be of the same type as @surface.
 **/
cairo_surface_t *
_cairo_surface_snapshot (cairo_surface_t *surface)
{
    cairo_surface_snapshot_t *snapshot;
    cairo_status_t status;

    if (unlikely (surface->status))
	return _cairo_surface_create_in_error (surface->status);

    if (surface->finished)
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));

    if (surface->snapshot_of != NULL)
	return cairo_surface_reference (surface);

    if (surface->backend->snapshot != NULL) {
	cairo_surface_t *snap;

	snap = _cairo_surface_has_snapshot (surface, surface->backend);
	if (snap != NULL)
	    return cairo_surface_reference (snap);

	snap = surface->backend->snapshot (surface);
	if (snap != NULL) {
	    if (unlikely (snap->status))
		return snap;

	    status = _cairo_surface_copy_mime_data (snap, surface);
	    if (unlikely (status)) {
		cairo_surface_destroy (snap);
		return _cairo_surface_create_in_error (status);
	    }

	    snap->device_transform = surface->device_transform;
	    snap->device_transform_inverse = surface->device_transform_inverse;

	    _cairo_surface_attach_snapshot (surface, snap, NULL);

	    return snap;
	}
    }

    snapshot = (cairo_surface_snapshot_t *)
	_cairo_surface_has_snapshot (surface, &_cairo_surface_snapshot_backend);
    if (snapshot != NULL)
	return cairo_surface_reference (&snapshot->base);

    snapshot = malloc (sizeof (cairo_surface_snapshot_t));
    if (unlikely (snapshot == NULL))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));

    _cairo_surface_init (&snapshot->base,
			 &_cairo_surface_snapshot_backend,
			 NULL, /* device */
			 surface->content);
    snapshot->base.type = surface->type;

    snapshot->target = surface;
    snapshot->clone = NULL;

    status = _cairo_surface_copy_mime_data (&snapshot->base, surface);
    if (unlikely (status)) {
	cairo_surface_destroy (&snapshot->base);
	return _cairo_surface_create_in_error (status);
    }

    snapshot->base.device_transform = surface->device_transform;
    snapshot->base.device_transform_inverse = surface->device_transform_inverse;

    _cairo_surface_attach_snapshot (surface,
				    &snapshot->base,
				    _cairo_surface_snapshot_copy_on_write);

    return &snapshot->base;
}
예제 #13
0
static cairo_xcb_pixmap_t *
_cairo_xcb_surface_pixmap (cairo_xcb_surface_t *target,
			   const cairo_surface_pattern_t *pattern,
			   const cairo_rectangle_int_t *extents,
			   int tx, int ty)
{
    cairo_surface_t *source;
    cairo_xcb_pixmap_t *pixmap;

    source =  pattern->surface;
    pixmap = (cairo_xcb_pixmap_t *)
	_cairo_surface_has_snapshot (source, &_cairo_xcb_pixmap_backend);
    if (pixmap != NULL && pixmap->screen == target->screen)
	return (cairo_xcb_pixmap_t *) cairo_surface_reference (&pixmap->base);

    if (source->type == CAIRO_SURFACE_TYPE_XCB &&
	((cairo_xcb_surface_t *) source)->screen == target->screen)
    {
	cairo_xcb_surface_t *xcb_source = (cairo_xcb_surface_t *) source;

	if (xcb_source->depth == target->depth)
	    pixmap = _copy_to_pixmap (xcb_source);
    }
#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
    else if (source->type == CAIRO_SURFACE_TYPE_XLIB &&
	     ((cairo_xlib_xcb_surface_t *) source)->xcb->screen == target->screen)
    {
	cairo_xcb_surface_t *xcb_source = ((cairo_xlib_xcb_surface_t *) source)->xcb;

	if (xcb_source->depth == target->depth)
	    pixmap = _copy_to_pixmap (xcb_source);
    }
#endif

    if (pixmap == NULL) {
	cairo_rectangle_int_t rect;

	if (! _cairo_surface_get_extents (source, &rect)) {
	    rect.x = rect.y = 0;
	    rect.width  = target->width;
	    rect.height = target->height;
	}

	pixmap = _render_to_pixmap (target, &pattern->base, &rect);
    }

    if (unlikely (pixmap->base.status))
	return pixmap;

    _cairo_surface_attach_snapshot (source, &pixmap->base, NULL);

    if (pattern->base.extend != CAIRO_EXTEND_NONE) {
	if (extents->x < 0 || extents->y < 0 ||
	    extents->x + extents->width  > pixmap->width ||
	    extents->y + extents->height > pixmap->height)
	{
	    pixmap->repeat = TRUE;
	}
    }

    pixmap->x0 += tx;
    pixmap->y0 += ty;

    return pixmap;
}