Fix shared use of recording surface with paginated targets

The problem is _cairo_recording_surface_replay_and_create_regions()
stores the cairo_recording_region_type_t in the same structure as the
recording commands. This does not work well when the recording surface
is used as source by multiple surfaces

Fix this by moving the cairo_recording_region_type_t into a separate
struct cairo_recording_regions_array_t. This struct is stored in a
list that allows multiple create regions results to be store in the
surface.

The new function _cairo_recording_surface_region_array_attach() is
used to create a new cairo_recording_regions_array_t, attach it to the
recording surface and return a unique region id.

The _cairo_recording_surface_replay_and_create_regions() and
_cairo_recording_surface_replay_region() functions use this region id
to identify the cairo_recording_regions_array_t.

To handle nested recording surfaces, when replaying a recording, the
region id is passed to the target as an extra parameter in the surface
pattern. The wrapper surface makes a temporary copy of the pattern to
ensure the snapshot pattern in the recording surface is not modified.

cairo_recording_regions_array_t has a reference count so the target
can hold on to the cairo_recording_regions_array_t after the paginated
surface has called _cairo_recording_surface_region_array_remove().
This commit is contained in:
Adrian Johnson 2023-01-01 15:14:08 +10:30
parent a2b376ed78
commit 7146358250
23 changed files with 1000 additions and 176 deletions

View file

@ -38,7 +38,8 @@
#include "cairoint.h"
cairo_private cairo_surface_t *
_cairo_analysis_surface_create (cairo_surface_t *target);
_cairo_analysis_surface_create (cairo_surface_t *target,
cairo_bool_t create_region_ids);
cairo_private void
_cairo_analysis_surface_set_ctm (cairo_surface_t *surface,
@ -64,6 +65,12 @@ cairo_private void
_cairo_analysis_surface_get_bounding_box (cairo_surface_t *surface,
cairo_box_t *bbox);
cairo_private unsigned int
_cairo_analysis_surface_get_source_region_id (cairo_surface_t *surface);
cairo_private unsigned int
_cairo_analysis_surface_get_mask_region_id (cairo_surface_t *surface);
cairo_private cairo_int_status_t
_cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
cairo_int_status_t status_b);
@ -71,4 +78,10 @@ _cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
cairo_private cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content);
static inline cairo_bool_t
_cairo_surface_is_analysis (const cairo_surface_t *surface)
{
return (cairo_internal_surface_type_t)surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS;
}
#endif /* CAIRO_ANALYSIS_SURFACE_H */

View file

@ -1,3 +1,4 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/*
* Copyright © 2006 Keith Packard
* Copyright © 2007 Adrian Johnson
@ -59,6 +60,10 @@ typedef struct {
cairo_region_t fallback_region;
cairo_box_t page_bbox;
cairo_bool_t create_region_ids;
unsigned source_region_id;
unsigned mask_region_id;
cairo_bool_t has_ctm;
cairo_matrix_t ctm;
@ -257,7 +262,8 @@ _add_operation (cairo_analysis_surface_t *surface,
static cairo_int_status_t
_analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents)
cairo_rectangle_int_t *extents,
unsigned int *regions_id)
{
const cairo_surface_pattern_t *surface_pattern;
cairo_analysis_surface_t *tmp;
@ -280,7 +286,7 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
}
tmp = (cairo_analysis_surface_t *)
_cairo_analysis_surface_create (surface->target);
_cairo_analysis_surface_create (surface->target, surface->create_region_ids);
if (unlikely (tmp->base.status)) {
status =tmp->base.status;
goto cleanup1;
@ -295,13 +301,29 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
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;
|| pattern->extend == CAIRO_EXTEND_REFLECT);
if (surface->create_region_ids) {
status = _cairo_recording_surface_region_array_attach (source, regions_id);
if (unlikely (status))
goto cleanup2;
status = _cairo_recording_surface_replay_and_create_regions (source,
*regions_id,
&pattern->matrix,
&tmp->base,
surface_is_unbounded);
if (unlikely (status))
goto cleanup2;
} else {
status = _cairo_recording_surface_replay_with_clip (source,
&pattern->matrix,
&tmp->base,
NULL, /* target clip */
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)) {
@ -412,6 +434,8 @@ _cairo_analysis_surface_paint (void *abstract_surface,
cairo_int_status_t backend_status;
cairo_rectangle_int_t extents;
surface->source_region_id = 0;
surface->mask_region_id = 0;
if (surface->target->backend->paint == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
@ -427,7 +451,10 @@ _cairo_analysis_surface_paint (void *abstract_surface,
&extents);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
cairo_rectangle_int_t rec_extents;
backend_status = _analyze_recording_surface_pattern (surface, source, &rec_extents);
backend_status = _analyze_recording_surface_pattern (surface,
source,
&rec_extents,
&surface->source_region_id);
_cairo_rectangle_intersect (&extents, &rec_extents);
}
@ -445,6 +472,8 @@ _cairo_analysis_surface_mask (void *abstract_surface,
cairo_int_status_t backend_status;
cairo_rectangle_int_t extents;
surface->source_region_id = 0;
surface->mask_region_id = 0;
if (surface->target->backend->mask == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
@ -468,7 +497,10 @@ _cairo_analysis_surface_mask (void *abstract_surface,
src_surface = _cairo_surface_get_source (src_surface, NULL);
if (_cairo_surface_is_recording (src_surface)) {
backend_source_status =
_analyze_recording_surface_pattern (surface, source, &rec_extents);
_analyze_recording_surface_pattern (surface,
source,
&rec_extents,
&surface->source_region_id);
if (_cairo_int_status_is_error (backend_source_status))
return backend_source_status;
@ -481,7 +513,10 @@ _cairo_analysis_surface_mask (void *abstract_surface,
mask_surface = _cairo_surface_get_source (mask_surface, NULL);
if (_cairo_surface_is_recording (mask_surface)) {
backend_mask_status =
_analyze_recording_surface_pattern (surface, mask, &rec_extents);
_analyze_recording_surface_pattern (surface,
mask,
&rec_extents,
&surface->mask_region_id);
if (_cairo_int_status_is_error (backend_mask_status))
return backend_mask_status;
@ -520,6 +555,8 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
cairo_int_status_t backend_status;
cairo_rectangle_int_t extents;
surface->source_region_id = 0;
surface->mask_region_id = 0;
if (surface->target->backend->stroke == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
@ -538,7 +575,10 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
&extents);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
cairo_rectangle_int_t rec_extents;
backend_status = _analyze_recording_surface_pattern (surface, source, &rec_extents);
backend_status = _analyze_recording_surface_pattern (surface,
source,
&rec_extents,
&surface->source_region_id);
_cairo_rectangle_intersect (&extents, &rec_extents);
}
@ -590,7 +630,10 @@ _cairo_analysis_surface_fill (void *abstract_surface,
&extents);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
cairo_rectangle_int_t rec_extents;
backend_status = _analyze_recording_surface_pattern (surface, source, &rec_extents);
backend_status = _analyze_recording_surface_pattern (surface,
source,
&rec_extents,
&surface->source_region_id);
_cairo_rectangle_intersect (&extents, &rec_extents);
}
@ -619,6 +662,9 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_int_status_t status, backend_status;
cairo_rectangle_int_t extents, glyph_extents;
surface->source_region_id = 0;
surface->mask_region_id = 0;
/* Adapted from _cairo_surface_show_glyphs */
if (surface->target->backend->show_glyphs != NULL) {
backend_status =
@ -654,7 +700,10 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
&extents);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
cairo_rectangle_int_t rec_extents;
backend_status = _analyze_recording_surface_pattern (surface, source, &rec_extents);
backend_status = _analyze_recording_surface_pattern (surface,
source,
&rec_extents,
&surface->source_region_id);
_cairo_rectangle_intersect (&extents, &rec_extents);
}
@ -699,6 +748,9 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
cairo_int_status_t status, backend_status;
cairo_rectangle_int_t extents, glyph_extents;
surface->source_region_id = 0;
surface->mask_region_id = 0;
/* Adapted from _cairo_surface_show_glyphs */
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->target->backend->show_text_glyphs != NULL) {
@ -732,7 +784,10 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
&extents);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
cairo_rectangle_int_t rec_extents;
backend_status = _analyze_recording_surface_pattern (surface, source, &rec_extents);
_analyze_recording_surface_pattern (surface,
source,
&rec_extents,
&surface->source_region_id);
_cairo_rectangle_intersect (&extents, &rec_extents);
}
@ -760,6 +815,8 @@ _cairo_analysis_surface_tag (void *abstract_surface,
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t backend_status;
surface->source_region_id = 0;
surface->mask_region_id = 0;
backend_status = CAIRO_INT_STATUS_SUCCESS;
if (surface->target->backend->tag != NULL) {
backend_status =
@ -812,7 +869,8 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
};
cairo_surface_t *
_cairo_analysis_surface_create (cairo_surface_t *target)
_cairo_analysis_surface_create (cairo_surface_t *target,
cairo_bool_t create_region_ids)
{
cairo_analysis_surface_t *surface;
cairo_status_t status;
@ -841,6 +899,10 @@ _cairo_analysis_surface_create (cairo_surface_t *target)
surface->has_supported = FALSE;
surface->has_unsupported = FALSE;
surface->create_region_ids = create_region_ids;
surface->source_region_id = 0;
surface->mask_region_id = 0;
_cairo_region_init (&surface->supported_region);
_cairo_region_init (&surface->fallback_region);
@ -918,6 +980,23 @@ _cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
*bbox = surface->page_bbox;
}
unsigned int
_cairo_analysis_surface_get_source_region_id (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
return surface->source_region_id;
}
unsigned int
_cairo_analysis_surface_get_mask_region_id (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
return surface->mask_region_id;
}
/* null surface type: a surface that does nothing (has no side effects, yay!) */
static cairo_int_status_t

View file

@ -319,3 +319,101 @@ _cairo_debug_print_rect (FILE *file, const cairo_rectangle_int_t *rect)
rect->x, rect->y,
rect->width, rect->height);
}
const char *
_cairo_debug_operator_to_string (cairo_operator_t op)
{
switch (op) {
case CAIRO_OPERATOR_CLEAR: return "CLEAR";
case CAIRO_OPERATOR_SOURCE: return "SOURCE";
case CAIRO_OPERATOR_OVER: return "OVER";
case CAIRO_OPERATOR_IN: return "IN";
case CAIRO_OPERATOR_OUT: return "OUT";
case CAIRO_OPERATOR_ATOP: return "ATOP";
case CAIRO_OPERATOR_DEST: return "DEST";
case CAIRO_OPERATOR_DEST_OVER: return "DEST_OVER";
case CAIRO_OPERATOR_DEST_IN: return "DEST_IN";
case CAIRO_OPERATOR_DEST_OUT: return "DEST_OUT";
case CAIRO_OPERATOR_DEST_ATOP: return "DEST_ATOP";
case CAIRO_OPERATOR_XOR: return "XOR";
case CAIRO_OPERATOR_ADD: return "ADD";
case CAIRO_OPERATOR_SATURATE: return "SATURATE";
case CAIRO_OPERATOR_MULTIPLY: return "MULTIPLY";
case CAIRO_OPERATOR_SCREEN: return "SCREEN";
case CAIRO_OPERATOR_OVERLAY: return "OVERLAY";
case CAIRO_OPERATOR_DARKEN: return "DARKEN";
case CAIRO_OPERATOR_LIGHTEN: return "LIGHTEN";
case CAIRO_OPERATOR_COLOR_DODGE: return "COLOR_DODGE";
case CAIRO_OPERATOR_COLOR_BURN: return "COLOR_BURN";
case CAIRO_OPERATOR_HARD_LIGHT: return "HARD_LIGHT";
case CAIRO_OPERATOR_SOFT_LIGHT: return "SOFT_LIGHT";
case CAIRO_OPERATOR_DIFFERENCE: return "DIFFERENCE";
case CAIRO_OPERATOR_EXCLUSION: return "EXCLUSION";
case CAIRO_OPERATOR_HSL_HUE: return "HSL_HUE";
case CAIRO_OPERATOR_HSL_SATURATION: return "HSL_SATURATION";
case CAIRO_OPERATOR_HSL_COLOR: return "HSL_COLOR";
case CAIRO_OPERATOR_HSL_LUMINOSITY: return "HSL_LUMINOSITY";
}
return "UNKNOWN";
}
const char *
_cairo_debug_status_to_string (cairo_int_status_t status)
{
switch (status) {
case CAIRO_INT_STATUS_SUCCESS: return "SUCCESS";
case CAIRO_INT_STATUS_NO_MEMORY: return "NO_MEMORY";
case CAIRO_INT_STATUS_INVALID_RESTORE: return "INVALID_RESTORE";
case CAIRO_INT_STATUS_INVALID_POP_GROUP: return "INVALID_POP_GROUP";
case CAIRO_INT_STATUS_NO_CURRENT_POINT: return "NO_CURRENT_POINT";
case CAIRO_INT_STATUS_INVALID_MATRIX: return "INVALID_MATRIX";
case CAIRO_INT_STATUS_INVALID_STATUS: return "INVALID_STATUS";
case CAIRO_INT_STATUS_NULL_POINTER: return "NULL_POINTER";
case CAIRO_INT_STATUS_INVALID_STRING: return "INVALID_STRING";
case CAIRO_INT_STATUS_INVALID_PATH_DATA: return "INVALID_PATH_DATA";
case CAIRO_INT_STATUS_READ_ERROR: return "READ_ERROR";
case CAIRO_INT_STATUS_WRITE_ERROR: return "WRITE_ERROR";
case CAIRO_INT_STATUS_SURFACE_FINISHED: return "SURFACE_FINISHED";
case CAIRO_INT_STATUS_SURFACE_TYPE_MISMATCH: return "SURFACE_TYPE_MISMATCH";
case CAIRO_INT_STATUS_PATTERN_TYPE_MISMATCH: return "PATTERN_TYPE_MISMATCH";
case CAIRO_INT_STATUS_INVALID_CONTENT: return "INVALID_CONTENT";
case CAIRO_INT_STATUS_INVALID_FORMAT: return "INVALID_FORMAT";
case CAIRO_INT_STATUS_INVALID_VISUAL: return "INVALID_VISUAL";
case CAIRO_INT_STATUS_FILE_NOT_FOUND: return "FILE_NOT_FOUND";
case CAIRO_INT_STATUS_INVALID_DASH: return "INVALID_DASH";
case CAIRO_INT_STATUS_INVALID_DSC_COMMENT: return "INVALID_DSC_COMMENT";
case CAIRO_INT_STATUS_INVALID_INDEX: return "INVALID_INDEX";
case CAIRO_INT_STATUS_CLIP_NOT_REPRESENTABLE: return "CLIP_NOT_REPRESENTABLE";
case CAIRO_INT_STATUS_TEMP_FILE_ERROR: return "TEMP_FILE_ERROR";
case CAIRO_INT_STATUS_INVALID_STRIDE: return "INVALID_STRIDE";
case CAIRO_INT_STATUS_FONT_TYPE_MISMATCH: return "FONT_TYPE_MISMATCH";
case CAIRO_INT_STATUS_USER_FONT_IMMUTABLE: return "USER_FONT_IMMUTABLE";
case CAIRO_INT_STATUS_USER_FONT_ERROR: return "USER_FONT_ERROR";
case CAIRO_INT_STATUS_NEGATIVE_COUNT: return "NEGATIVE_COUNT";
case CAIRO_INT_STATUS_INVALID_CLUSTERS: return "INVALID_CLUSTERS";
case CAIRO_INT_STATUS_INVALID_SLANT: return "INVALID_SLANT";
case CAIRO_INT_STATUS_INVALID_WEIGHT: return "INVALID_WEIGHT";
case CAIRO_INT_STATUS_INVALID_SIZE: return "INVALID_SIZE";
case CAIRO_INT_STATUS_USER_FONT_NOT_IMPLEMENTED: return "USER_FONT_NOT_IMPLEMENTED";
case CAIRO_INT_STATUS_DEVICE_TYPE_MISMATCH: return "DEVICE_TYPE_MISMATCH";
case CAIRO_INT_STATUS_DEVICE_ERROR: return "DEVICE_ERROR";
case CAIRO_INT_STATUS_INVALID_MESH_CONSTRUCTION: return "INVALID_MESH_CONSTRUCTION";
case CAIRO_INT_STATUS_DEVICE_FINISHED: return "DEVICE_FINISHED";
case CAIRO_INT_STATUS_JBIG2_GLOBAL_MISSING: return "JBIG2_GLOBAL_MISSING";
case CAIRO_INT_STATUS_PNG_ERROR: return "PNG_ERROR";
case CAIRO_INT_STATUS_FREETYPE_ERROR: return "FREETYPE_ERROR";
case CAIRO_INT_STATUS_WIN32_GDI_ERROR: return "WIN32_GDI_ERROR";
case CAIRO_INT_STATUS_TAG_ERROR: return "TAG_ERROR";
case CAIRO_INT_STATUS_DWRITE_ERROR: return "DWRITE_ERROR";
case CAIRO_INT_STATUS_LAST_STATUS: return "LAST_STATUS";
case CAIRO_INT_STATUS_UNSUPPORTED: return "UNSUPPORTED";
case CAIRO_INT_STATUS_DEGENERATE: return "DEGENERATE";
case CAIRO_INT_STATUS_NOTHING_TO_DO: return "NOTHING_TO_DO";
case CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY: return "FLATTEN_TRANSPARENCY";
case CAIRO_INT_STATUS_IMAGE_FALLBACK: return "IMAGE_FALLBACK";
case CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN: return "ANALYZE_RECORDING_SURFACE_PATTERN";
}
return "UNKNOWN";
}

View file

@ -1225,7 +1225,7 @@ _pixman_image_for_recording (cairo_image_surface_t *dst,
/* Handle recursion by returning future reads from the current image */
proxy = attach_proxy (source, clone);
status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL);
status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL, FALSE);
if (clone->foreground_used)
dst->base.foreground_used = clone->foreground_used;
detach_proxy (source, proxy);

View file

@ -1,3 +1,4 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
@ -401,11 +402,12 @@ _paint_page (cairo_paginated_surface_t *surface)
cairo_surface_t *analysis;
cairo_int_status_t status;
cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
unsigned int regions_id = 0;
if (unlikely (surface->target->status))
return surface->target->status;
analysis = _cairo_analysis_surface_create (surface->target);
analysis = _cairo_analysis_surface_create (surface->target, TRUE);
if (unlikely (analysis->status))
return _cairo_surface_set_error (surface->target, analysis->status);
@ -414,21 +416,26 @@ _paint_page (cairo_paginated_surface_t *surface)
if (unlikely (status))
goto FAIL;
status = _cairo_recording_surface_region_array_attach (surface->recording_surface, &regions_id);
if (status)
goto FAIL;
status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface,
regions_id,
NULL, analysis, FALSE);
if (status)
goto FAIL;
assert (analysis->status == CAIRO_STATUS_SUCCESS);
if (surface->backend->set_bounding_box) {
cairo_box_t bbox;
if (surface->backend->set_bounding_box) {
cairo_box_t bbox;
_cairo_analysis_surface_get_bounding_box (analysis, &bbox);
status = surface->backend->set_bounding_box (surface->target, &bbox);
if (unlikely (status))
goto FAIL;
}
_cairo_analysis_surface_get_bounding_box (analysis, &bbox);
status = surface->backend->set_bounding_box (surface->target, &bbox);
if (unlikely (status))
goto FAIL;
}
if (surface->backend->set_fallback_images_required) {
cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis);
@ -467,6 +474,7 @@ _paint_page (cairo_paginated_surface_t *surface)
goto FAIL;
status = _cairo_recording_surface_replay_region (surface->recording_surface,
regions_id,
NULL,
surface->target,
CAIRO_RECORDING_REGION_NATIVE);
@ -525,6 +533,9 @@ _paint_page (cairo_paginated_surface_t *surface)
}
FAIL:
if (regions_id)
_cairo_recording_surface_region_array_remove (surface->recording_surface, regions_id);
cairo_surface_destroy (analysis);
return _cairo_surface_set_error (surface->target, status);

View file

@ -87,6 +87,12 @@ typedef struct _cairo_surface_pattern {
cairo_pattern_t base;
cairo_surface_t *surface;
/* This field is only used by the wrapper surface for retreiving
* the region id from the target during create regions and passing
* the region id to the target surface during playback.
*/
unsigned int region_array_id;
} cairo_surface_pattern_t;
typedef struct _cairo_gradient_stop {

View file

@ -561,6 +561,7 @@ _cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
_cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SURFACE);
pattern->surface = cairo_surface_reference (surface);
pattern->region_array_id = 0;
}
static void

View file

@ -95,6 +95,7 @@ typedef struct _cairo_pdf_source_surface_entry {
typedef struct _cairo_pdf_source_surface {
cairo_pattern_type_t type;
cairo_surface_t *surface;
unsigned int region_id;
cairo_pattern_t *raster_pattern;
cairo_pdf_source_surface_entry_t *hash_entry;
} cairo_pdf_source_surface_t;
@ -279,9 +280,9 @@ struct _cairo_pdf_surface {
cairo_array_t pages;
cairo_array_t rgb_linear_functions;
cairo_array_t alpha_linear_functions;
cairo_array_t page_patterns;
cairo_array_t page_surfaces;
cairo_array_t doc_surfaces;
cairo_array_t page_patterns; /* cairo_pdf_pattern_t */
cairo_array_t page_surfaces; /* cairo_pdf_source_surface_t */
cairo_array_t doc_surfaces; /* cairo_pdf_source_surface_t */
cairo_hash_table_t *all_surfaces;
cairo_array_t smask_groups;
cairo_array_t knockout_group;

View file

@ -54,6 +54,7 @@
#include "cairo-error-private.h"
#include "cairo-image-surface-inline.h"
#include "cairo-image-info-private.h"
#include "cairo-recording-surface-inline.h"
#include "cairo-recording-surface-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-paginated-private.h"
@ -1014,7 +1015,13 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
size = _cairo_array_num_elements (&surface->page_surfaces);
for (i = 0; i < size; i++) {
src_surface = (cairo_pdf_source_surface_t *) _cairo_array_index (&surface->page_surfaces, i);
cairo_surface_destroy (src_surface->surface);
if (src_surface->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
cairo_pattern_destroy (src_surface->raster_pattern);
} else {
if (_cairo_surface_is_recording (src_surface->surface) && src_surface->region_id != 0)
_cairo_recording_surface_region_array_remove (src_surface->surface, src_surface->region_id);
cairo_surface_destroy (src_surface->surface);
}
}
_cairo_array_truncate (&surface->page_surfaces, 0);
@ -1723,6 +1730,7 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
_cairo_pdf_source_surface_init_key (surface_entry);
src_surface.hash_entry = surface_entry;
src_surface.region_id = 0;
if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
src_surface.type = CAIRO_PATTERN_TYPE_RASTER_SOURCE;
src_surface.surface = NULL;
@ -1734,6 +1742,16 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
src_surface.type = CAIRO_PATTERN_TYPE_SURFACE;
src_surface.surface = cairo_surface_reference (source_surface);
src_surface.raster_pattern = NULL;
if (source_pattern) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source_pattern;
src_surface.region_id = surface_pattern->region_array_id;
if (_cairo_surface_is_recording (surface_pattern->surface) &&
surface_pattern->region_array_id != 0)
{
_cairo_recording_surface_region_array_reference (surface_pattern->surface,
surface_pattern->region_array_id);
}
}
}
surface_entry->surface_res = _cairo_pdf_surface_new_object (surface);
@ -2593,7 +2611,13 @@ _cairo_pdf_surface_finish (void *abstract_surface)
size = _cairo_array_num_elements (&surface->doc_surfaces);
for (i = 0; i < size; i++) {
_cairo_array_copy_element (&surface->doc_surfaces, i, &doc_surface);
cairo_surface_destroy (doc_surface.surface);
if (doc_surface.type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
cairo_pattern_destroy (doc_surface.raster_pattern);
} else {
if (_cairo_surface_is_recording (doc_surface.surface) && doc_surface.region_id != 0)
_cairo_recording_surface_region_array_remove (doc_surface.surface, doc_surface.region_id);
cairo_surface_destroy (doc_surface.surface);
}
}
_cairo_array_fini (&surface->doc_surfaces);
_cairo_hash_table_foreach (surface->all_surfaces,
@ -3720,6 +3744,7 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
}
status = _cairo_recording_surface_replay_region (source,
pdf_source->region_id,
is_subsurface ? extents : NULL,
&surface->base,
CAIRO_RECORDING_REGION_NATIVE);

View file

@ -56,6 +56,7 @@ typedef struct _cairo_ps_form {
cairo_bool_t is_image;
int id;
cairo_surface_t *src_surface;
unsigned int regions_id;
cairo_rectangle_int_t src_surface_extents;
cairo_bool_t src_surface_bounded;
cairo_filter_t filter;

View file

@ -66,18 +66,19 @@
#include "cairo-composite-rectangles-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
#include "cairo-image-info-private.h"
#include "cairo-image-surface-inline.h"
#include "cairo-list-inline.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-paginated-private.h"
#include "cairo-recording-surface-inline.h"
#include "cairo-recording-surface-private.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-surface-snapshot-inline.h"
#include "cairo-surface-subsurface-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-type3-glyph-surface-private.h"
#include "cairo-image-info-private.h"
#include "cairo-tag-attributes-private.h"
#include "cairo-type3-glyph-surface-private.h"
#include <stdio.h>
#include <ctype.h>
@ -176,6 +177,7 @@ typedef enum {
typedef struct {
/* input params */
cairo_surface_t *src_surface;
unsigned int regions_id;
cairo_operator_t op;
const cairo_rectangle_int_t *src_surface_extents;
cairo_bool_t src_surface_bounded;
@ -286,6 +288,8 @@ _cairo_ps_form_pluck (void *entry, void *closure)
_cairo_hash_table_remove (patterns, &surface_entry->base);
free (surface_entry->unique_id);
if (_cairo_surface_is_recording (surface_entry->src_surface) && surface_entry->regions_id != 0)
_cairo_recording_surface_region_array_remove (surface_entry->src_surface, surface_entry->regions_id);
cairo_surface_destroy (surface_entry->src_surface);
free (surface_entry);
}
@ -3308,6 +3312,7 @@ _cairo_ps_surface_emit_eps (cairo_ps_surface_t *surface,
static cairo_status_t
_cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
cairo_surface_t *recording_surface,
unsigned int regions_id,
const cairo_rectangle_int_t *recording_extents,
cairo_bool_t subsurface)
{
@ -3378,6 +3383,7 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
}
status = _cairo_recording_surface_replay_region (recording_surface,
regions_id,
subsurface ? recording_extents : NULL,
&surface->base,
CAIRO_RECORDING_REGION_NATIVE);
@ -3530,6 +3536,9 @@ _cairo_ps_surface_use_form (cairo_ps_surface_t *surface,
source_entry->unique_id = unique_id;
source_entry->id = surface->num_forms++;
source_entry->src_surface = cairo_surface_reference (params->src_surface);
source_entry->regions_id = params->regions_id;
if (_cairo_surface_is_recording (source_entry->src_surface) && source_entry->regions_id != 0)
_cairo_recording_surface_region_array_reference (source_entry->src_surface, source_entry->regions_id);
source_entry->src_surface_extents = *params->src_surface_extents;
source_entry->src_surface_bounded = params->src_surface_bounded;
source_entry->required_extents = *params->src_op_extents;
@ -3662,11 +3671,13 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) params->src_surface;
status = _cairo_ps_surface_emit_recording_surface (surface,
sub->target,
params->regions_id,
&sub->extents,
TRUE);
} else {
status = _cairo_ps_surface_emit_recording_surface (surface,
params->src_surface,
params->regions_id,
params->src_op_extents,
FALSE);
}
@ -3709,6 +3720,7 @@ _cairo_ps_form_emit (void *entry, void *closure)
cairo_output_stream_t *old_stream;
params.src_surface = form->src_surface;
params.regions_id = form->regions_id;
params.op = CAIRO_OPERATOR_OVER;
params.src_surface_extents = &form->src_surface_extents;
params.src_surface_bounded = form->src_surface_bounded;
@ -3850,11 +3862,17 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
cairo_path_fixed_t path;
cairo_emit_surface_params_t params;
cairo_image_surface_t *image = NULL;
unsigned int region_id = 0;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
return status;
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
region_id = surface_pattern->region_array_id;
}
status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
pattern,
extents,
@ -3940,6 +3958,7 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
cairo_matrix_translate (&ps_p2d, x_offset, y_offset);
params.src_surface = image ? &image->base : source_surface;
params.regions_id = image ? 0 : region_id;
params.op = op;
params.src_surface_extents = &src_surface_extents;
params.src_surface_bounded = src_surface_bounded;
@ -3994,12 +4013,18 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
cairo_rectangle_int_t src_op_extents;
cairo_emit_surface_params_t params;
cairo_extend_t extend = cairo_pattern_get_extend (pattern);
unsigned int region_id = 0;
cairo_p2d = pattern->matrix;
status = cairo_matrix_invert (&cairo_p2d);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
region_id = surface_pattern->region_array_id;
}
status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
pattern,
extents,
@ -4093,6 +4118,7 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
old_paint_proc = surface->paint_proc;
surface->paint_proc = TRUE;
params.src_surface = image ? &image->base : source_surface;
params.regions_id = image ? 0 : region_id;
params.op = op;
params.src_surface_extents = &pattern_extents;
params.src_surface_bounded = bounded;

View file

@ -735,7 +735,8 @@ _cairo_surface_to_cgimage (cairo_surface_t *source,
status = _cairo_recording_surface_replay_with_clip (source,
matrix,
&image_surface->base,
NULL);
NULL,
FALSE);
if (unlikely (status)) {
cairo_surface_destroy (&image_surface->base);
return status;

View file

@ -1,3 +1,4 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
@ -55,14 +56,19 @@ typedef enum {
} cairo_command_type_t;
typedef enum {
CAIRO_RECORDING_REGION_ALL,
CAIRO_RECORDING_REGION_ALL = 0,
CAIRO_RECORDING_REGION_NATIVE,
CAIRO_RECORDING_REGION_IMAGE_FALLBACK
} cairo_recording_region_type_t;
typedef enum {
CAIRO_RECORDING_REPLAY,
CAIRO_RECORDING_CREATE_REGIONS,
CAIRO_RECORDING_REPLAY_REGION
} cairo_recording_replay_type_t;
typedef struct _cairo_command_header {
cairo_command_type_t type;
cairo_recording_region_type_t region;
cairo_operator_t op;
cairo_rectangle_int_t extents;
cairo_clip_t *clip;
@ -155,8 +161,27 @@ typedef struct _cairo_recording_surface {
struct bbtree *left, *right;
cairo_command_header_t *chain;
} bbtree;
/* The mutex protects modification to all subsequent fields. */
cairo_mutex_t mutex;
cairo_list_t region_array_list;
} cairo_recording_surface_t;
typedef struct _cairo_recording_region_element {
cairo_recording_region_type_t region;
unsigned int source_id;
unsigned int mask_id;
} cairo_recording_region_element_t;
typedef struct _cairo_recording_region_array {
unsigned int id;
cairo_reference_count_t ref_count;
cairo_array_t regions; /* cairo_recording_region_element_t */
cairo_list_t link;
} cairo_recording_regions_array_t;
slim_hidden_proto (cairo_recording_surface_create);
cairo_private cairo_int_status_t
@ -182,18 +207,21 @@ cairo_private cairo_status_t
_cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
const cairo_matrix_t *surface_transform,
cairo_surface_t *target,
const cairo_clip_t *target_clip);
const cairo_clip_t *target_clip,
cairo_bool_t surface_is_unbounded);
cairo_private cairo_status_t
_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
unsigned int regions_id,
const cairo_matrix_t *surface_transform,
cairo_surface_t *target,
cairo_bool_t surface_is_unbounded);
cairo_surface_t *target,
cairo_bool_t surface_is_unbounded);
cairo_private cairo_status_t
_cairo_recording_surface_replay_region (cairo_surface_t *surface,
const cairo_rectangle_int_t *surface_extents,
unsigned int regions_id,
const cairo_rectangle_int_t *surface_extents,
cairo_surface_t *target,
cairo_recording_region_type_t region);
cairo_recording_region_type_t region);
cairo_private cairo_status_t
_cairo_recording_surface_get_bbox (cairo_recording_surface_t *recording,
@ -211,4 +239,23 @@ _cairo_recording_surface_has_only_bilevel_alpha (cairo_recording_surface_t *surf
cairo_private cairo_bool_t
_cairo_recording_surface_has_only_op_over (cairo_recording_surface_t *surface);
cairo_private cairo_status_t
_cairo_recording_surface_region_array_attach (cairo_surface_t *surface,
unsigned int *id);
cairo_private void
_cairo_recording_surface_region_array_reference (cairo_surface_t *surface,
unsigned int id);
cairo_private void
_cairo_recording_surface_region_array_remove (cairo_surface_t *surface,
unsigned int id);
cairo_private void
_cairo_debug_print_recording_surface (FILE *file,
cairo_surface_t *surface,
unsigned int regions_id,
int indent,
cairo_bool_t recurse);
#endif /* CAIRO_RECORDING_SURFACE_H */

View file

@ -86,16 +86,12 @@
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
#include "cairo-list-inline.h"
#include "cairo-recording-surface-inline.h"
#include "cairo-surface-snapshot-inline.h"
#include "cairo-surface-wrapper-private.h"
#include "cairo-traps-private.h"
typedef enum {
CAIRO_RECORDING_REPLAY,
CAIRO_RECORDING_CREATE_REGIONS
} cairo_recording_replay_type_t;
typedef struct _cairo_recording_surface_replay_params {
const cairo_rectangle_int_t *surface_extents;
const cairo_matrix_t *surface_transform;
@ -104,6 +100,7 @@ typedef struct _cairo_recording_surface_replay_params {
cairo_bool_t surface_is_unbounded;
cairo_recording_replay_type_t type;
cairo_recording_region_type_t region;
unsigned int regions_id;
const cairo_color_t *foreground_color;
cairo_bool_t foreground_used;
} cairo_recording_surface_replay_params_t;
@ -437,6 +434,10 @@ cairo_recording_surface_create (cairo_content_t content,
surface->has_bilevel_alpha = FALSE;
surface->has_only_op_over = FALSE;
CAIRO_MUTEX_INIT (surface->mutex);
cairo_list_init (&surface->region_array_list);
return &surface->base;
}
slim_hidden_def (cairo_recording_surface_create);
@ -454,12 +455,88 @@ _cairo_recording_surface_create_similar (void *abstract_surface,
return cairo_recording_surface_create (content, &extents);
}
static void
destroy_pattern_region_array (const cairo_pattern_t *pattern,
unsigned int region_id)
{
if (region_id != 0) {
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
if (_cairo_surface_is_recording (surface_pattern->surface))
_cairo_recording_surface_region_array_remove (surface_pattern->surface, region_id);
}
}
}
static void
_cairo_recording_surface_region_array_destroy (cairo_recording_surface_t *surface,
cairo_recording_regions_array_t *region_array)
{
cairo_command_t **elements;
cairo_recording_region_element_t *region_elements;
int i, num_elements;
num_elements = surface->commands.num_elements;
elements = _cairo_array_index (&surface->commands, 0);
region_elements = _cairo_array_index (&region_array->regions, 0);
for (i = 0; i < num_elements; i++) {
cairo_command_t *command = elements[i];
cairo_recording_region_element_t *region_element = &region_elements[i];
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
destroy_pattern_region_array (&command->paint.source.base, region_element->source_id);
break;
case CAIRO_COMMAND_MASK:
destroy_pattern_region_array (&command->mask.source.base, region_element->source_id);
destroy_pattern_region_array (&command->mask.mask.base, region_element->mask_id);
break;
case CAIRO_COMMAND_STROKE:
destroy_pattern_region_array (&command->stroke.source.base, region_element->source_id);
break;
case CAIRO_COMMAND_FILL:
destroy_pattern_region_array (&command->fill.source.base, region_element->source_id);
break;
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
destroy_pattern_region_array (&command->show_text_glyphs.source.base, region_element->source_id);
break;
case CAIRO_COMMAND_TAG:
break;
default:
ASSERT_NOT_REACHED;
}
}
_cairo_array_fini (&region_array->regions);
free (region_array);
}
static cairo_status_t
_cairo_recording_surface_finish (void *abstract_surface)
{
cairo_recording_surface_t *surface = abstract_surface;
cairo_command_t **elements;
int i, num_elements;
cairo_recording_regions_array_t *region_array, *region_next;
/* Normally backend surfaces hold a reference to the surface as
* well as the region and free the region before the surface. So
* the regions should already be freed at this point but just in
* case we ensure the regions are freed before destroying the
* surface. */
cairo_list_foreach_entry_safe (region_array, region_next,
cairo_recording_regions_array_t,
&surface->region_array_list, link)
{
cairo_list_del (&region_array->link);
_cairo_recording_surface_region_array_destroy (surface, region_array);
}
num_elements = surface->commands.num_elements;
elements = _cairo_array_index (&surface->commands, 0);
@ -660,7 +737,6 @@ _command_init (cairo_recording_surface_t *surface,
command->type = type;
command->op = op;
command->region = CAIRO_RECORDING_REGION_ALL;
command->extents = composite ? composite->unbounded : _cairo_empty_rectangle;
command->chain = NULL;
@ -1162,7 +1238,6 @@ _command_init_copy (cairo_recording_surface_t *surface,
{
dst->type = src->type;
dst->op = src->op;
dst->region = CAIRO_RECORDING_REGION_ALL;
dst->extents = src->extents;
dst->chain = NULL;
@ -1561,6 +1636,10 @@ _cairo_recording_surface_snapshot (void *abstract_other)
surface->has_bilevel_alpha = other->has_bilevel_alpha;
surface->has_only_op_over = other->has_only_op_over;
CAIRO_MUTEX_INIT (surface->mutex);
cairo_list_init (&surface->region_array_list);
_cairo_array_init (&surface->commands, sizeof (cairo_command_t *));
status = _cairo_recording_surface_copy (surface, other);
if (unlikely (status)) {
@ -1626,6 +1705,123 @@ static const cairo_surface_backend_t cairo_recording_surface_backend = {
_cairo_recording_surface_tag,
};
static unsigned int
_cairo_recording_surface_regions_allocate_unique_id (void)
{
static cairo_atomic_int_t unique_id;
#if CAIRO_NO_MUTEX
if (++unique_id == 0)
unique_id = 1;
return unique_id;
#else
cairo_atomic_int_t old, id;
do {
old = _cairo_atomic_uint_get (&unique_id);
id = old + 1;
if (id == 0)
id = 1;
} while (! _cairo_atomic_uint_cmpxchg (&unique_id, old, id));
return id;
#endif
}
static cairo_recording_regions_array_t *
_cairo_recording_surface_region_array_find (cairo_recording_surface_t *surface,
unsigned int id)
{
cairo_recording_regions_array_t *regions;
cairo_list_foreach_entry (regions, cairo_recording_regions_array_t,
&surface->region_array_list, link)
{
if (regions->id == id)
return regions;
}
return NULL;
}
/* Create and initialize a new #cairo_recording_regions_array_t. Attach
* it to the recording surface and return its id
*/
cairo_status_t
_cairo_recording_surface_region_array_attach (cairo_surface_t *abstract_surface,
unsigned int *id)
{
cairo_recording_regions_array_t *region_array;
cairo_recording_surface_t *surface = (cairo_recording_surface_t *) abstract_surface;
assert (_cairo_surface_is_recording (abstract_surface));
region_array = _cairo_malloc (sizeof (cairo_recording_regions_array_t));
if (region_array == NULL) {
*id = 0;
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
region_array->id = _cairo_recording_surface_regions_allocate_unique_id ();
CAIRO_REFERENCE_COUNT_INIT (&region_array->ref_count, 1);
_cairo_array_init (&region_array->regions, sizeof (cairo_recording_region_element_t));
CAIRO_MUTEX_LOCK (surface->mutex);
cairo_list_add (&region_array->link, &surface->region_array_list);
CAIRO_MUTEX_UNLOCK (surface->mutex);
*id = region_array->id;
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_recording_surface_region_array_remove (cairo_surface_t *abstract_surface,
unsigned int id)
{
cairo_recording_regions_array_t *region_array;
cairo_recording_surface_t *surface = (cairo_recording_surface_t *) abstract_surface;
if (id == 0)
return;
assert (_cairo_surface_is_recording (abstract_surface));
CAIRO_MUTEX_LOCK (surface->mutex);
region_array = _cairo_recording_surface_region_array_find (surface, id);
if (region_array) {
if (_cairo_reference_count_dec_and_test (&region_array->ref_count))
cairo_list_del (&region_array->link);
else
region_array = NULL;
}
CAIRO_MUTEX_UNLOCK (surface->mutex);
if (region_array)
_cairo_recording_surface_region_array_destroy (surface, region_array);
}
void
_cairo_recording_surface_region_array_reference (cairo_surface_t *abstract_surface,
unsigned int id)
{
cairo_recording_regions_array_t *region_array;
cairo_recording_surface_t *surface = (cairo_recording_surface_t *) abstract_surface;
assert (_cairo_surface_is_recording (abstract_surface));
CAIRO_MUTEX_LOCK (surface->mutex);
region_array = _cairo_recording_surface_region_array_find (surface, id);
if (region_array) {
_cairo_reference_count_inc (&region_array->ref_count);
}
CAIRO_MUTEX_UNLOCK (surface->mutex);
}
cairo_int_status_t
_cairo_recording_surface_get_path (cairo_surface_t *abstract_surface,
cairo_path_fixed_t *path)
@ -1799,8 +1995,8 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
{
cairo_surface_wrapper_t wrapper;
cairo_command_t **elements;
cairo_bool_t replay_all =
params->type == CAIRO_RECORDING_CREATE_REGIONS || params->region == CAIRO_RECORDING_REGION_ALL;
cairo_recording_regions_array_t *regions_array = NULL;
cairo_recording_region_element_t *region_elements = NULL;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_rectangle_int_t extents;
cairo_bool_t use_indices = FALSE;
@ -1821,6 +2017,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
assert (_cairo_surface_is_recording (&surface->base));
if (params->regions_id != 0) {
regions_array = _cairo_recording_surface_region_array_find (surface, params->regions_id);
assert (regions_array != NULL);
}
_cairo_surface_wrapper_init (&wrapper, params->target);
if (params->surface_extents)
_cairo_surface_wrapper_intersect_extents (&wrapper, params->surface_extents);
@ -1845,18 +2046,48 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
surface->has_only_op_over = TRUE;
num_elements = surface->commands.num_elements;
if (regions_array) {
if (params->type == CAIRO_RECORDING_CREATE_REGIONS) {
/* Re-running create regions with the same region id is not supported. */
assert (_cairo_array_num_elements (&regions_array->regions) == 0);
void *array_elems;
status = _cairo_array_allocate (&regions_array->regions, num_elements, &array_elems);
if (unlikely (status))
return status;
/* Set regions to CAIRO_RECORDING_REGION_ALL and ids to 0 */
memset (array_elems, 0, num_elements * sizeof (cairo_recording_region_element_t));
} else {
assert (_cairo_array_num_elements (&regions_array->regions) == num_elements);
}
}
elements = _cairo_array_index (&surface->commands, 0);
if (regions_array)
region_elements = _cairo_array_index (&regions_array->regions, 0);
if (extents.width < r->width || extents.height < r->height) {
num_elements =
_cairo_recording_surface_get_visible_commands (surface, &extents);
use_indices = num_elements != surface->commands.num_elements;
}
cairo_bool_t target_is_analysis = _cairo_surface_is_analysis (params->target);
for (i = 0; i < num_elements; i++) {
cairo_command_t *command = elements[use_indices ? surface->indices[i] : i];
cairo_recording_region_element_t *region_element = NULL;
unsigned int source_region_id = 0;
unsigned int mask_region_id = 0;
if (! replay_all && command->header.region != params->region)
if (region_elements)
region_element = &region_elements[use_indices ? surface->indices[i] : i];
if (region_element && params->type == CAIRO_RECORDING_REPLAY_REGION &&
region_element->region != params->region)
{
continue;
}
if (! _cairo_rectangle_intersects (&extents, &command->header.extents)) {
if (command->header.type != CAIRO_COMMAND_TAG)
@ -1865,22 +2096,35 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
if (region_element)
source_region_id = region_element->source_id;
status = _cairo_surface_wrapper_paint (&wrapper,
command->header.op,
&command->paint.source.base,
source_region_id,
command->header.clip);
if (params->type == CAIRO_RECORDING_CREATE_REGIONS) {
_cairo_recording_surface_merge_source_attributes (surface,
command->header.op,
&command->paint.source.base);
if (region_element && target_is_analysis)
region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target);
}
break;
case CAIRO_COMMAND_MASK:
if (region_element) {
source_region_id = region_element->source_id;
mask_region_id = region_element->mask_id;
}
status = _cairo_surface_wrapper_mask (&wrapper,
command->header.op,
&command->mask.source.base,
source_region_id,
&command->mask.mask.base,
mask_region_id,
command->header.clip);
if (params->type == CAIRO_RECORDING_CREATE_REGIONS) {
_cairo_recording_surface_merge_source_attributes (surface,
@ -1889,13 +2133,21 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
_cairo_recording_surface_merge_source_attributes (surface,
command->header.op,
&command->mask.mask.base);
if (region_element && target_is_analysis) {
region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target);
region_element->mask_id = _cairo_analysis_surface_get_mask_region_id (params->target);
}
}
break;
case CAIRO_COMMAND_STROKE:
if (region_element)
source_region_id = region_element->source_id;
status = _cairo_surface_wrapper_stroke (&wrapper,
command->header.op,
&command->stroke.source.base,
source_region_id,
&command->stroke.path,
&command->stroke.style,
&command->stroke.ctm,
@ -1907,23 +2159,39 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
_cairo_recording_surface_merge_source_attributes (surface,
command->header.op,
&command->stroke.source.base);
if (region_element && target_is_analysis)
region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target);
}
break;
case CAIRO_COMMAND_FILL:
status = CAIRO_INT_STATUS_UNSUPPORTED;
if (region_element)
source_region_id = region_element->source_id;
if (_cairo_surface_wrapper_has_fill_stroke (&wrapper)) {
cairo_command_t *stroke_command;
cairo_command_t *stroke_command = NULL;
cairo_recording_region_element_t *stroke_region_element = NULL;
unsigned stroke_region_id = 0;
stroke_command = NULL;
if (params->type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1)
/* The analysis surface does not implement
* fill_stroke. When creating regions the fill and
* stroke commands are tested separately.
*/
if (params->type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1) {
stroke_command = elements[i + 1];
if (region_elements)
stroke_region_element = &region_elements[i + 1];
}
if (stroke_command != NULL &&
params->type == CAIRO_RECORDING_REPLAY &&
if (stroke_region_element)
stroke_region_id = stroke_region_element->source_id;
if (stroke_command && stroke_region_element &&
params->type == CAIRO_RECORDING_REPLAY_REGION &&
params->region != CAIRO_RECORDING_REGION_ALL)
{
if (stroke_command->header.region != params->region)
if (stroke_region_element->region != params->region)
stroke_command = NULL;
}
@ -1937,12 +2205,14 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
status = _cairo_surface_wrapper_fill_stroke (&wrapper,
command->header.op,
&command->fill.source.base,
source_region_id,
command->fill.fill_rule,
command->fill.tolerance,
command->fill.antialias,
&command->fill.path,
stroke_command->header.op,
&stroke_command->stroke.source.base,
stroke_region_id,
&stroke_command->stroke.style,
&stroke_command->stroke.ctm,
&stroke_command->stroke.ctm_inverse,
@ -1964,6 +2234,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
status = _cairo_surface_wrapper_fill (&wrapper,
command->header.op,
&command->fill.source.base,
source_region_id,
&command->fill.path,
command->fill.fill_rule,
command->fill.tolerance,
@ -1973,14 +2244,20 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
_cairo_recording_surface_merge_source_attributes (surface,
command->header.op,
&command->fill.source.base);
if (region_element && target_is_analysis)
region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target);
}
}
break;
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
if (region_element)
source_region_id = region_element->source_id;
status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
command->header.op,
&command->show_text_glyphs.source.base,
source_region_id,
command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
command->show_text_glyphs.glyphs, command->show_text_glyphs.num_glyphs,
command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
@ -1991,6 +2268,9 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
_cairo_recording_surface_merge_source_attributes (surface,
command->header.op,
&command->show_text_glyphs.source.base);
if (region_element && target_is_analysis)
region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target);
}
break;
@ -2009,11 +2289,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
status = CAIRO_INT_STATUS_SUCCESS;
if (params->type == CAIRO_RECORDING_CREATE_REGIONS && command->header.region != CAIRO_RECORDING_REGION_NATIVE) {
if (params->type == CAIRO_RECORDING_CREATE_REGIONS && region_element) {
if (status == CAIRO_INT_STATUS_SUCCESS) {
command->header.region = CAIRO_RECORDING_REGION_NATIVE;
region_element->region = CAIRO_RECORDING_REGION_NATIVE;
} else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
command->header.region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK;
region_element->region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK;
status = CAIRO_INT_STATUS_SUCCESS;
} else {
assert (_cairo_int_status_is_error (status));
@ -2042,7 +2322,7 @@ _cairo_recording_surface_replay_one (cairo_recording_surface_t *surface,
{
cairo_surface_wrapper_t wrapper;
cairo_command_t **elements, *command;
cairo_int_status_t status;
cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
if (unlikely (surface->base.status))
return surface->base.status;
@ -2071,6 +2351,7 @@ _cairo_recording_surface_replay_one (cairo_recording_surface_t *surface,
status = _cairo_surface_wrapper_paint (&wrapper,
command->header.op,
&command->paint.source.base,
0,
command->header.clip);
break;
@ -2078,7 +2359,9 @@ _cairo_recording_surface_replay_one (cairo_recording_surface_t *surface,
status = _cairo_surface_wrapper_mask (&wrapper,
command->header.op,
&command->mask.source.base,
0,
&command->mask.mask.base,
0,
command->header.clip);
break;
@ -2086,6 +2369,7 @@ _cairo_recording_surface_replay_one (cairo_recording_surface_t *surface,
status = _cairo_surface_wrapper_stroke (&wrapper,
command->header.op,
&command->stroke.source.base,
0,
&command->stroke.path,
&command->stroke.style,
&command->stroke.ctm,
@ -2099,6 +2383,7 @@ _cairo_recording_surface_replay_one (cairo_recording_surface_t *surface,
status = _cairo_surface_wrapper_fill (&wrapper,
command->header.op,
&command->fill.source.base,
0,
&command->fill.path,
command->fill.fill_rule,
command->fill.tolerance,
@ -2110,6 +2395,7 @@ _cairo_recording_surface_replay_one (cairo_recording_surface_t *surface,
status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
command->header.op,
&command->show_text_glyphs.source.base,
0,
command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
command->show_text_glyphs.glyphs, command->show_text_glyphs.num_glyphs,
command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
@ -2157,6 +2443,7 @@ _cairo_recording_surface_replay (cairo_surface_t *surface,
params.surface_is_unbounded = FALSE;
params.type = CAIRO_RECORDING_REPLAY;
params.region = CAIRO_RECORDING_REGION_ALL;
params.regions_id = 0;
params.foreground_color = NULL;
return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
@ -2178,6 +2465,7 @@ _cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surf
params.surface_is_unbounded = FALSE;
params.type = CAIRO_RECORDING_REPLAY;
params.region = CAIRO_RECORDING_REGION_ALL;
params.regions_id = 0;
params.foreground_color = foreground_color;
params.foreground_used = FALSE;
@ -2191,7 +2479,8 @@ cairo_status_t
_cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
const cairo_matrix_t *surface_transform,
cairo_surface_t *target,
const cairo_clip_t *target_clip)
const cairo_clip_t *target_clip,
cairo_bool_t surface_is_unbounded)
{
cairo_recording_surface_replay_params_t params;
@ -2199,9 +2488,10 @@ _cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
params.surface_transform = surface_transform;
params.target = target;
params.target_clip = target_clip;
params.surface_is_unbounded = FALSE;
params.surface_is_unbounded = surface_is_unbounded;
params.type = CAIRO_RECORDING_REPLAY;
params.region = CAIRO_RECORDING_REGION_ALL;
params.regions_id = 0;
params.foreground_color = NULL;
return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
@ -2215,6 +2505,7 @@ _cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
*/
cairo_status_t
_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
unsigned int regions_id,
const cairo_matrix_t *surface_transform,
cairo_surface_t *target,
cairo_bool_t surface_is_unbounded)
@ -2228,6 +2519,7 @@ _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
params.surface_is_unbounded = surface_is_unbounded;
params.type = CAIRO_RECORDING_CREATE_REGIONS;
params.region = CAIRO_RECORDING_REGION_ALL;
params.regions_id = regions_id;
params.foreground_color = NULL;
return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
@ -2235,6 +2527,7 @@ _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
cairo_status_t
_cairo_recording_surface_replay_region (cairo_surface_t *surface,
unsigned int regions_id,
const cairo_rectangle_int_t *surface_extents,
cairo_surface_t *target,
cairo_recording_region_type_t region)
@ -2246,8 +2539,9 @@ _cairo_recording_surface_replay_region (cairo_surface_t *surface,
params.target = target;
params.target_clip = NULL;
params.surface_is_unbounded = FALSE;
params.type = CAIRO_RECORDING_REPLAY;
params.type = CAIRO_RECORDING_REPLAY_REGION;
params.region = region;
params.regions_id = regions_id;
params.foreground_color = NULL;
return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
@ -2263,7 +2557,7 @@ _recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
cairo_status_t status;
null_surface = _cairo_null_surface_create (surface->base.content);
analysis_surface = _cairo_analysis_surface_create (null_surface);
analysis_surface = _cairo_analysis_surface_create (null_surface, FALSE);
cairo_surface_destroy (null_surface);
status = analysis_surface->status;
@ -2395,3 +2689,186 @@ _cairo_recording_surface_has_only_op_over (cairo_recording_surface_t *surface)
{
return surface->has_only_op_over;
}
static void
print_indent (FILE *file, int indent)
{
fprintf (file, "%*s", indent * 2, "");
}
static void
print_pattern (FILE *file,
const cairo_pattern_t *pattern,
unsigned int region_id,
int indent,
cairo_bool_t recurse)
{
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID: {
cairo_solid_pattern_t *p = (cairo_solid_pattern_t *) pattern;
if (pattern->is_userfont_foreground) {
fprintf (file, "solid foreground\n");
} else {
fprintf (file, "solid rgba: %f %f %f %f\n",
p->color.red,
p->color.green,
p->color.blue,
p->color.alpha);
}
} break;
case CAIRO_PATTERN_TYPE_SURFACE: {
cairo_surface_pattern_t *p = (cairo_surface_pattern_t *) pattern;
fprintf (file, "surface ");
if (p->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
fprintf (file, "recording id: %d\n", p->surface->unique_id);
if (recurse) {
_cairo_debug_print_recording_surface (file, p->surface,
region_id,
indent + 1, recurse);
}
} else if (p->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
cairo_image_surface_t *image = (cairo_image_surface_t *)p->surface;
fprintf (file, "image format: ");
switch (image->format) {
case CAIRO_FORMAT_INVALID: fputs ("INVALID", file); break;
case CAIRO_FORMAT_ARGB32: fputs ("ARGB32", file); break;
case CAIRO_FORMAT_RGB24: fputs ("RGB24", file); break;
case CAIRO_FORMAT_A8: fputs ("A8", file); break;
case CAIRO_FORMAT_A1: fputs ("A1", file); break;
case CAIRO_FORMAT_RGB16_565: fputs ("RGB16_565", file); break;
case CAIRO_FORMAT_RGB30: fputs ("RGB30", file); break;
case CAIRO_FORMAT_RGB96F: fputs ("RGB96F", file); break;
case CAIRO_FORMAT_RGBA128F: fputs ("RGBA128F", file); break;
}
fprintf (file, " width: %d height: %d\n", image->width, image->height);
} else {
fprintf (file, "type %d\n", p->surface->type);
}
} break;
case CAIRO_PATTERN_TYPE_LINEAR:
fprintf (file, "linear\n");
break;
case CAIRO_PATTERN_TYPE_RADIAL:
fprintf (file, "radial\n");
break;
case CAIRO_PATTERN_TYPE_MESH:
fprintf (file, "mesh\n");
break;
case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
fprintf (file, "raster\n");
break;
}
}
void
_cairo_debug_print_recording_surface (FILE *file,
cairo_surface_t *surface,
unsigned int regions_id,
int indent,
cairo_bool_t recurse)
{
cairo_command_t **elements;
cairo_recording_region_element_t *region_elements = NULL;
unsigned int i, num_elements;
cairo_recording_surface_t *recording_surface;
cairo_surface_t *free_me = NULL;
char common[100];
if (_cairo_surface_is_snapshot (surface))
free_me = surface = _cairo_surface_snapshot_get_target (surface);
assert (_cairo_surface_is_recording (surface));
recording_surface = (cairo_recording_surface_t *)surface;
print_indent (file, indent);
indent++;
fprintf(file, "recording surface id: %d regions id: %d\n", recording_surface->base.unique_id, regions_id);
num_elements = recording_surface->commands.num_elements;
elements = _cairo_array_index (&recording_surface->commands, 0);
if (regions_id != 0) {
cairo_recording_regions_array_t *regions_array;
regions_array = _cairo_recording_surface_region_array_find (recording_surface, regions_id);
assert (regions_array != NULL);
assert (_cairo_array_num_elements (&regions_array->regions) == num_elements);
region_elements = _cairo_array_index (&regions_array->regions, 0);
}
for (i = 0; i < num_elements; i++) {
cairo_command_t *command = elements[i];
unsigned int source_region_id = 0;
unsigned int mask_region_id = 0;
common[0] = 0;
if (region_elements) {
cairo_recording_region_element_t *region_element = &region_elements[i];
strcpy (common, "region: ");
switch (region_element->region) {
case CAIRO_RECORDING_REGION_ALL: strcat (common, "all"); break;
case CAIRO_RECORDING_REGION_NATIVE: strcat (common, "native"); break;
case CAIRO_RECORDING_REGION_IMAGE_FALLBACK: strcat (common, "fallback"); break;
}
source_region_id = region_element->source_id;
mask_region_id = region_element->mask_id;
}
sprintf (common + strlen(common), " op: %s", _cairo_debug_operator_to_string (command->header.op));
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
print_indent (file, indent);
fprintf(file, "%d PAINT %s source: ", i, common);
print_pattern (file, &command->paint.source.base, source_region_id, indent + 1, recurse);
break;
case CAIRO_COMMAND_MASK:
print_indent (file, indent);
fprintf(file, "%d MASK %s\n", i, common);
print_indent (file, indent + 1);
fprintf(file, "source: ");
print_pattern (file, &command->mask.source.base, source_region_id, indent + 1, recurse);
print_indent (file, indent + 1);
fprintf(file, "mask: ");
print_pattern (file, &command->mask.mask.base, mask_region_id, indent + 1, recurse);
break;
case CAIRO_COMMAND_STROKE:
print_indent (file, indent);
fprintf(file, "%d STROKE %s source:", i, common);
print_pattern (file, &command->stroke.source.base, source_region_id, indent + 1, recurse);
break;
case CAIRO_COMMAND_FILL:
print_indent (file, indent);
fprintf(file, "%d FILL %s source: ", i, common);
print_pattern (file, &command->fill.source.base, source_region_id, indent + 1, recurse);
break;
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
print_indent (file, indent);
fprintf(file, "%d SHOW_TEXT_GLYPHS %s font_type: ", i, common);
switch (command->show_text_glyphs.scaled_font->backend->type) {
case CAIRO_FONT_TYPE_TOY: fputs ("toy", file); break;
case CAIRO_FONT_TYPE_FT: fputs ("ft", file); break;
case CAIRO_FONT_TYPE_WIN32: fputs ("win32", file); break;
case CAIRO_FONT_TYPE_QUARTZ: fputs ("quartz", file); break;
case CAIRO_FONT_TYPE_USER: fputs ("user", file); break;
case CAIRO_FONT_TYPE_DWRITE: fputs ("dwrite", file); break;
}
fprintf (file, " glyphs:");
for (unsigned j = 0; j < command->show_text_glyphs.num_glyphs; j++)
fprintf (file, " %ld", command->show_text_glyphs.glyphs[j].index);
fprintf (file, " source:");
print_pattern (file, &command->show_text_glyphs.source.base, source_region_id, indent + 1, recurse);
break;
case CAIRO_COMMAND_TAG:
print_indent (file, indent);
fprintf(file, "%d TAG\n", i);
break;
default:
ASSERT_NOT_REACHED;
}
}
cairo_surface_destroy (free_me);
}

View file

@ -2509,7 +2509,7 @@ _cairo_script_surface_paint (void *abstract_surface,
if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
return _cairo_surface_wrapper_paint (&surface->wrapper,
op, source, clip);
op, source, 0, clip);
}
return CAIRO_STATUS_SUCCESS;
@ -2566,7 +2566,7 @@ _cairo_script_surface_mask (void *abstract_surface,
if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
return _cairo_surface_wrapper_mask (&surface->wrapper,
op, source, mask, clip);
op, source, 0, mask, 0, clip);
}
return CAIRO_STATUS_SUCCESS;
@ -2653,7 +2653,7 @@ _cairo_script_surface_stroke (void *abstract_surface,
if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
return _cairo_surface_wrapper_stroke (&surface->wrapper,
op, source, path,
op, source, 0, path,
style,
ctm, ctm_inverse,
tolerance, antialias,
@ -2734,7 +2734,7 @@ _cairo_script_surface_fill (void *abstract_surface,
if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
return _cairo_surface_wrapper_fill (&surface->wrapper,
op, source, path,
op, source, 0, path,
fill_rule,
tolerance,
antialias,
@ -3585,7 +3585,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
if (_cairo_surface_wrapper_is_active (&surface->wrapper)){
return _cairo_surface_wrapper_show_text_glyphs (&surface->wrapper,
op, source,
op, source, 0,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,

View file

@ -612,7 +612,7 @@ composite_aligned_boxes (const cairo_spans_compositor_t *compositor,
recording_clip = _cairo_clip_from_boxes (boxes);
status = _cairo_recording_surface_replay_with_clip (unwrap_source (source),
m, dst, recording_clip);
m, dst, recording_clip, FALSE);
_cairo_clip_destroy (recording_clip);
return status;

View file

@ -1,3 +1,4 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
@ -41,6 +42,7 @@
#include "cairoint.h"
#include "cairo-types-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-surface-backend-private.h"
CAIRO_BEGIN_DECLS
@ -54,6 +56,9 @@ struct _cairo_surface_wrapper {
cairo_rectangle_int_t extents;
const cairo_clip_t *clip;
unsigned int source_region_id;
unsigned int mask_region_id;
cairo_bool_t needs_transform;
};
@ -95,60 +100,68 @@ _cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
cairo_private cairo_status_t
_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip);
cairo_operator_t op,
const cairo_pattern_t *source,
unsigned int source_region_id,
const cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_clip_t *clip);
cairo_operator_t op,
const cairo_pattern_t *source,
unsigned int source_region_id,
const cairo_pattern_t *mask,
unsigned int mask_region_id,
const cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
const cairo_clip_t *clip);
_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
unsigned int source_region_id,
const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
const cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t fill_op,
const cairo_pattern_t *fill_source,
cairo_fill_rule_t fill_rule,
double fill_tolerance,
cairo_antialias_t fill_antialias,
const cairo_path_fixed_t*path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *stroke_ctm,
const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
const cairo_clip_t *clip);
_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t fill_op,
const cairo_pattern_t *fill_source,
unsigned int fill_region_id,
cairo_fill_rule_t fill_rule,
double fill_tolerance,
cairo_antialias_t fill_antialias,
const cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
unsigned int stroke_region_id,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *stroke_ctm,
const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
const cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
const cairo_clip_t *clip);
_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
unsigned int source_region_id,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
const cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
unsigned int source_region_id,
const char *utf8,
int utf8_len,
const cairo_glyph_t *glyphs,

View file

@ -1,3 +1,4 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
@ -47,12 +48,18 @@
static void
_copy_transformed_pattern (cairo_pattern_t *pattern,
const cairo_pattern_t *original,
const cairo_matrix_t *ctm_inverse)
const cairo_matrix_t *ctm_inverse,
unsigned int region_id)
{
_cairo_pattern_init_static_copy (pattern, original);
if (! _cairo_matrix_is_identity (ctm_inverse))
_cairo_pattern_transform (pattern, ctm_inverse);
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
surface_pattern->region_array_id = region_id;
}
}
cairo_status_t
@ -129,9 +136,10 @@ _cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t *wrapper,
cairo_status_t
_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_clip_t *clip)
cairo_operator_t op,
const cairo_pattern_t *source,
unsigned int source_region_id,
const cairo_clip_t *clip)
{
cairo_status_t status;
cairo_clip_t *dev_clip;
@ -144,7 +152,7 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (wrapper->needs_transform) {
if (wrapper->needs_transform || source_region_id != 0) {
cairo_matrix_t m;
_cairo_surface_wrapper_get_transform (wrapper, &m);
@ -152,7 +160,7 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
_copy_transformed_pattern (&source_copy.base, source, &m);
_copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
source = &source_copy.base;
}
@ -162,13 +170,14 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
return status;
}
cairo_status_t
_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
const cairo_clip_t *clip)
cairo_operator_t op,
const cairo_pattern_t *source,
unsigned int source_region_id,
const cairo_pattern_t *mask,
unsigned int mask_region_id,
const cairo_clip_t *clip)
{
cairo_status_t status;
cairo_clip_t *dev_clip;
@ -182,7 +191,7 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (wrapper->needs_transform) {
if (wrapper->needs_transform || source_region_id != 0 || mask_region_id != 0) {
cairo_matrix_t m;
_cairo_surface_wrapper_get_transform (wrapper, &m);
@ -190,10 +199,10 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
_copy_transformed_pattern (&source_copy.base, source, &m);
_copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
source = &source_copy.base;
_copy_transformed_pattern (&mask_copy.base, mask, &m);
_copy_transformed_pattern (&mask_copy.base, mask, &m, mask_region_id);
mask = &mask_copy.base;
}
@ -204,16 +213,17 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
}
cairo_status_t
_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
const cairo_clip_t *clip)
_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
unsigned int source_region_id,
const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
const cairo_clip_t *clip)
{
cairo_status_t status;
cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path;
@ -229,7 +239,7 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (wrapper->needs_transform) {
if (wrapper->needs_transform || source_region_id != 0) {
cairo_matrix_t m;
_cairo_surface_wrapper_get_transform (wrapper, &m);
@ -248,7 +258,7 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
_copy_transformed_pattern (&source_copy.base, source, &m);
_copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
source = &source_copy.base;
}
@ -266,21 +276,23 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
}
cairo_status_t
_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t fill_op,
const cairo_pattern_t *fill_source,
cairo_fill_rule_t fill_rule,
double fill_tolerance,
cairo_antialias_t fill_antialias,
const cairo_path_fixed_t*path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *stroke_ctm,
const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
const cairo_clip_t *clip)
_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t fill_op,
const cairo_pattern_t *fill_source,
unsigned int fill_region_id,
cairo_fill_rule_t fill_rule,
double fill_tolerance,
cairo_antialias_t fill_antialias,
const cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
unsigned int stroke_region_id,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *stroke_ctm,
const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
const cairo_clip_t *clip)
{
cairo_status_t status;
cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *)path;
@ -297,7 +309,7 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (wrapper->needs_transform) {
if (wrapper->needs_transform || fill_region_id != 0 || stroke_region_id != 0) {
cairo_matrix_t m;
_cairo_surface_wrapper_get_transform (wrapper, &m);
@ -316,10 +328,10 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
_copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m);
_copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m, fill_region_id);
stroke_source = &stroke_source_copy.base;
_copy_transformed_pattern (&fill_source_copy.base, fill_source, &m);
_copy_transformed_pattern (&fill_source_copy.base, fill_source, &m, stroke_region_id);
fill_source = &fill_source_copy.base;
}
@ -341,14 +353,15 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
}
cairo_status_t
_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
const cairo_clip_t *clip)
_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
unsigned int source_region_id,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
const cairo_clip_t *clip)
{
cairo_status_t status;
cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path;
@ -362,7 +375,7 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (wrapper->needs_transform) {
if (wrapper->needs_transform || source_region_id != 0) {
cairo_matrix_t m;
_cairo_surface_wrapper_get_transform (wrapper, &m);
@ -377,7 +390,7 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
_copy_transformed_pattern (&source_copy.base, source, &m);
_copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
source = &source_copy.base;
}
@ -394,9 +407,10 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
}
cairo_status_t
_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
unsigned int source_region_id,
const char *utf8,
int utf8_len,
const cairo_glyph_t *glyphs,
@ -425,7 +439,7 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
cairo_surface_get_font_options (wrapper->target, &options);
cairo_font_options_merge (&options, &scaled_font->options);
if (wrapper->needs_transform) {
if (wrapper->needs_transform || source_region_id != 0) {
cairo_matrix_t m;
int i;
@ -460,7 +474,7 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
_copy_transformed_pattern (&source_copy.base, source, &m);
_copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
source = &source_copy.base;
} else {
if (! cairo_font_options_equal (&options, &scaled_font->options)) {
@ -622,6 +636,8 @@ _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
wrapper->has_extents = FALSE;
wrapper->extents.x = wrapper->extents.y = 0;
wrapper->clip = NULL;
wrapper->source_region_id = 0;
wrapper->mask_region_id = 0;
wrapper->needs_transform = FALSE;
if (target) {

View file

@ -1240,7 +1240,7 @@ composite_aligned_boxes (const cairo_traps_compositor_t *compositor,
recording_clip = _cairo_clip_from_boxes (boxes);
status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (source),
m, dst, recording_clip);
m, dst, recording_clip, FALSE);
_cairo_clip_destroy (recording_clip);
return status;

View file

@ -1112,7 +1112,8 @@ record_to_picture (cairo_surface_t *target,
status = _cairo_recording_surface_replay_with_clip (source,
&matrix, tmp,
NULL);
NULL,
FALSE);
if (unlikely (status)) {
cairo_surface_destroy (tmp);
return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);

View file

@ -920,7 +920,8 @@ record_source (cairo_xlib_surface_t *dst,
recording = recording_pattern_get_surface (&pattern->base),
status = _cairo_recording_surface_replay_with_clip (recording,
&matrix, &src->base,
NULL);
NULL,
FALSE);
cairo_surface_destroy (recording);
if (unlikely (status)) {
cairo_surface_destroy (&src->base);

View file

@ -1855,6 +1855,12 @@ _cairo_debug_print_matrix (FILE *file, const cairo_matrix_t *matrix);
cairo_private void
_cairo_debug_print_rect (FILE *file, const cairo_rectangle_int_t *rect);
cairo_private const char *
_cairo_debug_operator_to_string (cairo_operator_t op);
cairo_private const char *
_cairo_debug_status_to_string (cairo_int_status_t status);
cairo_private cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps,
const cairo_polygon_t *polygon,

View file

@ -654,6 +654,7 @@ _cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_printing_surf
SaveDC (surface->win32.dc); /* Allow clip path to be reset during replay */
status = _cairo_recording_surface_replay_region (&recording_surface->base,
pattern->region_array_id,
is_subsurface ? &recording_extents : NULL,
&surface->win32.base,
CAIRO_RECORDING_REGION_NATIVE);