diff options
Diffstat (limited to 'src/cairo-recording-surface.c')
-rw-r--r-- | src/cairo-recording-surface.c | 574 |
1 files changed, 541 insertions, 33 deletions
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c index 065e62c46..2912f5ede 100644 --- a/src/cairo-recording-surface.c +++ b/src/cairo-recording-surface.c @@ -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,7 +100,9 @@ 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; static const cairo_surface_backend_t cairo_recording_surface_backend; @@ -366,7 +364,10 @@ _cairo_recording_surface_create_bbtree (cairo_recording_surface_t *surface) return CAIRO_STATUS_SUCCESS; cleanup: - bbtree_del (&surface->bbtree); + if (surface->bbtree.left) + bbtree_del (surface->bbtree.left); + if (surface->bbtree.right) + bbtree_del (surface->bbtree.right); return status; } @@ -436,6 +437,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); @@ -453,12 +458,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 (®ion_array->regions, 0); + for (i = 0; i < num_elements; i++) { + cairo_command_t *command = elements[i]; + cairo_recording_region_element_t *region_element = ®ion_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 (®ion_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 (®ion_array->link); + _cairo_recording_surface_region_array_destroy (surface, region_array); + } num_elements = surface->commands.num_elements; elements = _cairo_array_index (&surface->commands, 0); @@ -614,7 +695,8 @@ _cairo_recording_surface_acquire_source_image (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } - assert (! surface->unbounded); + if (surface->unbounded) + return CAIRO_INT_STATUS_UNSUPPORTED; image = _cairo_image_surface_create_with_content (surface->base.content, surface->extents.width, surface->extents.height); @@ -658,7 +740,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; @@ -1153,6 +1234,14 @@ _cairo_recording_surface_tag (void *abstract_surface, return status; } +static cairo_bool_t +_cairo_recording_surface_supports_color_glyph (void *abstract_surface, + cairo_scaled_font_t *scaled_font, + unsigned long glyph_index) +{ + return TRUE; +} + static void _command_init_copy (cairo_recording_surface_t *surface, cairo_command_header_t *dst, @@ -1160,7 +1249,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; @@ -1559,6 +1647,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)) { @@ -1622,8 +1714,126 @@ static const cairo_surface_backend_t cairo_recording_surface_backend = { _cairo_recording_surface_show_text_glyphs, NULL, /* get_supported_mime_types */ _cairo_recording_surface_tag, + _cairo_recording_surface_supports_color_glyph, }; +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 (®ion_array->ref_count, 1); + + _cairo_array_init (®ion_array->regions, sizeof (cairo_recording_region_element_t)); + + CAIRO_MUTEX_LOCK (surface->mutex); + cairo_list_add (®ion_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 (®ion_array->ref_count)) + cairo_list_del (®ion_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 (®ion_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) @@ -1797,8 +2007,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; @@ -1819,6 +2029,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); @@ -1829,7 +2044,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface, } _cairo_surface_wrapper_set_inverse_transform (&wrapper, params->surface_transform); _cairo_surface_wrapper_set_clip (&wrapper, params->target_clip); - _cairo_surface_wrapper_set_foreground_color (&wrapper, params->foreground_color); + + if (params->foreground_color) { + params->target->foreground_source = _cairo_pattern_create_solid (params->foreground_color); + params->target->foreground_used = FALSE; + } /* Compute the extents of the target clip in recorded device space */ if (! _cairo_surface_wrapper_get_target_extents (&wrapper, params->surface_is_unbounded, &extents)) @@ -1839,18 +2058,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 (®ions_array->regions) == 0); + void *array_elems; + status = _cairo_array_allocate (®ions_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 (®ions_array->regions) == num_elements); + } + } + elements = _cairo_array_index (&surface->commands, 0); + if (regions_array) + region_elements = _cairo_array_index (®ions_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 (region_elements) + region_element = ®ion_elements[use_indices ? surface->indices[i] : i]; - if (! replay_all && command->header.region != params->region) + 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) @@ -1859,22 +2108,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, @@ -1883,13 +2145,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, @@ -1901,23 +2171,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 (_cairo_surface_wrapper_has_fill_stroke (&wrapper)) { - cairo_command_t *stroke_command; + if (region_element) + source_region_id = region_element->source_id; - stroke_command = NULL; - if (params->type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1) + if (_cairo_surface_wrapper_has_fill_stroke (&wrapper)) { + cairo_command_t *stroke_command = NULL; + cairo_recording_region_element_t *stroke_region_element = NULL; + unsigned stroke_region_id = 0; + + /* 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 = ®ion_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; } @@ -1931,12 +2217,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, @@ -1958,6 +2246,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, @@ -1967,14 +2256,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, @@ -1985,6 +2280,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; @@ -2003,11 +2301,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)); @@ -2019,6 +2317,12 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface, } done: + if (params->foreground_color) { + cairo_pattern_destroy (params->target->foreground_source); + params->target->foreground_source = NULL; + params->foreground_used = params->target->foreground_used; + } + _cairo_surface_wrapper_fini (&wrapper); return _cairo_surface_set_error (&surface->base, status); } @@ -2030,7 +2334,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; @@ -2059,6 +2363,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; @@ -2066,7 +2371,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; @@ -2074,6 +2381,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, @@ -2087,6 +2395,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, @@ -2098,6 +2407,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, @@ -2145,17 +2455,20 @@ _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, ¶ms); } cairo_status_t -_cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface, - cairo_surface_t *target, - const cairo_color_t *color) +_cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface, + cairo_surface_t *target, + const cairo_color_t *foreground_color, + cairo_bool_t *foreground_used) { cairo_recording_surface_replay_params_t params; + cairo_status_t status; params.surface_extents = NULL; params.surface_transform = NULL; @@ -2164,16 +2477,22 @@ _cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface, params.surface_is_unbounded = FALSE; params.type = CAIRO_RECORDING_REPLAY; params.region = CAIRO_RECORDING_REGION_ALL; - params.foreground_color = color; + params.regions_id = 0; + params.foreground_color = foreground_color; + params.foreground_used = FALSE; - return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms); + status = _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms); + *foreground_used = params.foreground_used; + + return status; } 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; @@ -2181,9 +2500,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, ¶ms); @@ -2197,6 +2517,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) @@ -2210,6 +2531,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, ¶ms); @@ -2217,6 +2539,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) @@ -2228,8 +2551,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, ¶ms); @@ -2245,7 +2569,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; @@ -2309,6 +2633,7 @@ DONE: if (height) *height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y); } +slim_hidden_def (cairo_recording_surface_ink_extents); cairo_status_t _cairo_recording_surface_get_bbox (cairo_recording_surface_t *surface, @@ -2376,3 +2701,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_foreground_marker) { + 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 (®ions_array->regions) == num_elements); + region_elements = _cairo_array_index (®ions_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 = ®ion_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); +} |