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; }
/** * _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; }
static cairo_int_status_t _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface, const cairo_pattern_t *pattern) { const cairo_surface_pattern_t *surface_pattern; cairo_analysis_surface_t *tmp; cairo_surface_t *source, *proxy; cairo_matrix_t p2d; cairo_status_t status, analysis_status; assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE); surface_pattern = (const cairo_surface_pattern_t *) pattern; assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING); source = surface_pattern->surface; proxy = _cairo_surface_has_snapshot (source, &proxy_backend); if (proxy != NULL) { /* nothing untoward found so far */ return CAIRO_STATUS_SUCCESS; } tmp = (cairo_analysis_surface_t *) _cairo_analysis_surface_create (surface->target); if (unlikely (tmp->base.status)) return tmp->base.status; proxy = attach_proxy (source, &tmp->base); p2d = pattern->matrix; status = cairo_matrix_invert (&p2d); assert (status == CAIRO_STATUS_SUCCESS); cairo_matrix_multiply (&tmp->ctm, &p2d, &surface->ctm); tmp->has_ctm = ! _cairo_matrix_is_identity (&tmp->ctm); if (_cairo_surface_is_snapshot (source)) source = _cairo_surface_snapshot_get_target (source); if (_cairo_surface_is_subsurface (source)) source = _cairo_surface_subsurface_get_target (source); status = _cairo_recording_surface_replay_and_create_regions (source, &tmp->base); analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS; detach_proxy (proxy); cairo_surface_destroy (&tmp->base); if (unlikely (status)) return status; return analysis_status; }
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; }
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; }
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; }
/** * _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; }
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; }
static cairo_int_status_t _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface, const cairo_pattern_t *pattern, cairo_rectangle_int_t *extents) { const cairo_surface_pattern_t *surface_pattern; cairo_analysis_surface_t *tmp; cairo_surface_t *source, *proxy; cairo_matrix_t p2d; cairo_int_status_t status, analysis_status; cairo_bool_t surface_is_unbounded; cairo_bool_t unused; assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE); surface_pattern = (const cairo_surface_pattern_t *) pattern; assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING); source = surface_pattern->surface; proxy = _cairo_surface_has_snapshot (source, &proxy_backend); if (proxy != NULL) { /* nothing untoward found so far */ return CAIRO_STATUS_SUCCESS; } tmp = (cairo_analysis_surface_t *) _cairo_analysis_surface_create (surface->target); if (unlikely (tmp->base.status)) { status =tmp->base.status; goto cleanup1; } proxy = attach_proxy (source, &tmp->base); p2d = pattern->matrix; status = cairo_matrix_invert (&p2d); assert (status == CAIRO_INT_STATUS_SUCCESS); _cairo_analysis_surface_set_ctm (&tmp->base, &p2d); source = _cairo_surface_get_source (source, NULL); surface_is_unbounded = (pattern->extend == CAIRO_EXTEND_REPEAT || pattern->extend == CAIRO_EXTEND_REFLECT); status = _cairo_recording_surface_replay_and_create_regions (source, &pattern->matrix, &tmp->base, surface_is_unbounded); if (unlikely (status)) goto cleanup2; /* black background or mime data fills entire extents */ if (!(source->content & CAIRO_CONTENT_ALPHA) || _cairo_surface_has_mime_image (source)) { cairo_rectangle_int_t rect; if (_cairo_surface_get_extents (source, &rect)) { cairo_box_t bbox; _cairo_box_from_rectangle (&bbox, &rect); _cairo_matrix_transform_bounding_box_fixed (&p2d, &bbox, NULL); _cairo_box_round_to_rectangle (&bbox, &rect); status = _add_operation (tmp, &rect, CAIRO_INT_STATUS_SUCCESS); if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) status = CAIRO_INT_STATUS_SUCCESS; if (unlikely (status)) goto cleanup2; } } if (tmp->has_supported) { surface->has_supported = TRUE; unused = cairo_region_union (&surface->supported_region, &tmp->supported_region); } if (tmp->has_unsupported) { surface->has_unsupported = TRUE; unused = cairo_region_union (&surface->fallback_region, &tmp->fallback_region); } analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS; if (pattern->extend != CAIRO_EXTEND_NONE) { _cairo_unbounded_rectangle_init (extents); } else { status = cairo_matrix_invert (&tmp->ctm); _cairo_matrix_transform_bounding_box_fixed (&tmp->ctm, &tmp->page_bbox, NULL); _cairo_box_round_to_rectangle (&tmp->page_bbox, extents); } cleanup2: detach_proxy (proxy); cleanup1: cairo_surface_destroy (&tmp->base); if (unlikely (status)) return status; return analysis_status; }