diff options
Diffstat (limited to 'src/cairo-meta-surface.c')
-rw-r--r-- | src/cairo-meta-surface.c | 550 |
1 files changed, 244 insertions, 306 deletions
diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c index 4fb2722c..f091a59f 100644 --- a/src/cairo-meta-surface.c +++ b/src/cairo-meta-surface.c @@ -50,6 +50,12 @@ * that would have been obtained if the original operations applied to * the meta surface had instead been applied to the target surface. * + * A meta surface is logically unbounded, i.e. it has no implicit constraint + * on the size of the drawing surface. However, in practice this is rarely + * useful as you wish to replay against a particular target surface with + * known bounds. For this case, it is more efficient to specify the target + * extents to the meta surface upon creation. + * * The recording phase of the meta surface is careful to snapshot all * necessary objects (paths, patterns, etc.), in order to achieve * accurate replay. The efficiency of the meta surface could be @@ -58,10 +64,13 @@ * copy-on-write implementation for _cairo_surface_snapshot. */ +/* XXX Rename to recording surface */ + #include "cairoint.h" #include "cairo-analysis-surface-private.h" #include "cairo-meta-surface-private.h" #include "cairo-clip-private.h" +#include "cairo-surface-wrapper-private.h" typedef enum { CAIRO_META_REPLAY, @@ -82,8 +91,8 @@ static const cairo_surface_backend_t cairo_meta_surface_backend; /** * cairo_meta_surface_create: * @content: the content of the meta surface - * @width_pixels: width of the surface, in pixels - * @height_pixels: height of the surface, in pixels + * @extents_pixels: the extents to record in pixels, can be %NULL to record + * unbounded operations. * * Creates a meta-surface which can be used to record all drawing operations * at the highest level (that is, the level of paint, mask, stroke, fill @@ -105,50 +114,45 @@ static const cairo_surface_backend_t cairo_meta_surface_backend; * Since 1.10 **/ cairo_surface_t * -cairo_meta_surface_create (cairo_content_t content, - double width_pixels, - double height_pixels) +cairo_meta_surface_create (cairo_content_t content, + const cairo_rectangle_t *extents) { cairo_meta_surface_t *meta; + cairo_status_t status; meta = malloc (sizeof (cairo_meta_surface_t)); if (unlikely (meta == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - _cairo_surface_init (&meta->base, &cairo_meta_surface_backend, - content); + _cairo_surface_init (&meta->base, &cairo_meta_surface_backend, content); meta->content = content; - meta->width_pixels = width_pixels; - meta->height_pixels = height_pixels; /* unbounded -> 'infinite' extents */ - if (width_pixels < 0) { - meta->extents.x = CAIRO_RECT_INT_MIN; - meta->extents.width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN; - } else { - meta->extents.x = 0; - if (ceil (width_pixels) > CAIRO_RECT_INT_MAX) - meta->extents.width = CAIRO_RECT_INT_MAX; - else - meta->extents.width = ceil (width_pixels); - } + if (extents != NULL) { + meta->extents_pixels = *extents; - if (height_pixels < 0) { - meta->extents.y = CAIRO_RECT_INT_MIN; - meta->extents.height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN; + /* XXX check for overflow */ + meta->extents.x = floor (extents->x); + meta->extents.y = floor (extents->y); + meta->extents.width = ceil (extents->x + extents->width) - meta->extents.x; + meta->extents.height = ceil (extents->y + extents->height) - meta->extents.y; + + status = _cairo_clip_init_rectangle (&meta->clip, &meta->extents); + if (unlikely (status)) { + free (meta); + return _cairo_surface_create_in_error (status); + } + + meta->unbounded = FALSE; } else { - meta->extents.y = 0; - if (ceil (height_pixels) > CAIRO_RECT_INT_MAX) - meta->extents.height = CAIRO_RECT_INT_MAX; - else - meta->extents.height = ceil (height_pixels); + meta->unbounded = TRUE; + _cairo_clip_init (&meta->clip); } _cairo_array_init (&meta->commands, sizeof (cairo_command_t *)); meta->commands_owner = NULL; - meta->is_clipped = FALSE; meta->replay_start_idx = 0; return &meta->base; @@ -161,14 +165,17 @@ _cairo_meta_surface_create_similar (void *abstract_surface, int width, int height) { - return cairo_meta_surface_create (content, width, height); + cairo_rectangle_t extents; + extents.x = extents.y = 0; + extents.width = width; + extents.height = height; + return cairo_meta_surface_create (content, &extents); } static cairo_status_t _cairo_meta_surface_finish (void *abstract_surface) { cairo_meta_surface_t *meta = abstract_surface; - cairo_command_t *command; cairo_command_t **elements; int i, num_elements; @@ -180,11 +187,11 @@ _cairo_meta_surface_finish (void *abstract_surface) num_elements = meta->commands.num_elements; elements = _cairo_array_index (&meta->commands, 0); for (i = 0; i < num_elements; i++) { - command = elements[i]; - switch (command->header.type) { + cairo_command_t *command = elements[i]; - /* 5 basic drawing operations */ + _cairo_clip_reset (&command->header.clip); + switch (command->header.type) { case CAIRO_COMMAND_PAINT: _cairo_pattern_fini_snapshot (&command->paint.source.base); free (command); @@ -218,19 +225,13 @@ _cairo_meta_surface_finish (void *abstract_surface) free (command); break; - /* Other junk. */ - case CAIRO_COMMAND_INTERSECT_CLIP_PATH: - if (command->intersect_clip_path.path_pointer) - _cairo_path_fixed_fini (&command->intersect_clip_path.path); - free (command); - break; - default: ASSERT_NOT_REACHED; } } _cairo_array_fini (&meta->commands); + _cairo_clip_reset (&meta->clip); return CAIRO_STATUS_SUCCESS; } @@ -254,8 +255,12 @@ _cairo_meta_surface_acquire_source_image (void *abstract_surface, } image = _cairo_image_surface_create_with_content (surface->content, - ceil (surface->width_pixels), - ceil (surface->height_pixels)); + surface->extents.width, + surface->extents.height); + + cairo_surface_set_device_offset (image, + -surface->extents.x, + -surface->extents.y); status = cairo_meta_surface_replay (&surface->base, image); if (unlikely (status)) { @@ -282,21 +287,30 @@ _cairo_meta_surface_release_source_image (void *abstract_surface, cairo_surface_destroy (&image->base); } -static void -_draw_command_init (cairo_command_header_t *command, - cairo_command_type_t type, - cairo_meta_surface_t *meta) +static cairo_status_t +_command_init (cairo_meta_surface_t *meta, + cairo_command_header_t *command, + cairo_command_type_t type, + cairo_operator_t op, + cairo_clip_t *clip) { + cairo_status_t status = CAIRO_STATUS_SUCCESS; + command->type = type; + command->op = op; command->region = CAIRO_META_REGION_ALL; - command->extents = meta->extents; + _cairo_clip_init_copy (&command->clip, clip); + if (meta->clip.path != NULL) + status = _cairo_clip_apply_clip (&command->clip, &meta->clip); + + return status; } static cairo_int_status_t -_cairo_meta_surface_paint (void *abstract_surface, - cairo_operator_t op, +_cairo_meta_surface_paint (void *abstract_surface, + cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; @@ -306,8 +320,10 @@ _cairo_meta_surface_paint (void *abstract_surface, if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - _draw_command_init (&command->header, CAIRO_COMMAND_PAINT, meta); - command->op = op; + status = _command_init (meta, + &command->header, CAIRO_COMMAND_PAINT, op, clip); + if (unlikely (status)) + goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (status)) @@ -320,7 +336,7 @@ _cairo_meta_surface_paint (void *abstract_surface, /* An optimisation that takes care to not replay what was done * before surface is cleared. We don't erase recorded commands * since we may have earlier snapshots of this surface. */ - if (op == CAIRO_OPERATOR_CLEAR && !meta->is_clipped) + if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) meta->replay_start_idx = meta->commands.num_elements; return CAIRO_STATUS_SUCCESS; @@ -337,7 +353,7 @@ _cairo_meta_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; @@ -347,8 +363,10 @@ _cairo_meta_surface_mask (void *abstract_surface, if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - _draw_command_init (&command->header, CAIRO_COMMAND_MASK, meta); - command->op = op; + status = _command_init (meta, + &command->header, CAIRO_COMMAND_MASK, op, clip); + if (unlikely (status)) + goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (status)) @@ -383,7 +401,7 @@ _cairo_meta_surface_stroke (void *abstract_surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; @@ -393,8 +411,10 @@ _cairo_meta_surface_stroke (void *abstract_surface, if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - _draw_command_init (&command->header, CAIRO_COMMAND_STROKE, meta); - command->op = op; + status = _command_init (meta, + &command->header, CAIRO_COMMAND_STROKE, op, clip); + if (unlikely (status)) + goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (status)) @@ -438,7 +458,7 @@ _cairo_meta_surface_fill (void *abstract_surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; @@ -448,8 +468,10 @@ _cairo_meta_surface_fill (void *abstract_surface, if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - _draw_command_init (&command->header, CAIRO_COMMAND_FILL, meta); - command->op = op; + status =_command_init (meta, + &command->header, CAIRO_COMMAND_FILL, op, clip); + if (unlikely (status)) + goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (status)) @@ -496,7 +518,7 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; @@ -506,8 +528,11 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface, if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - _draw_command_init (&command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS, meta); - command->op = op; + status = _command_init (meta, + &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS, + op, clip); + if (unlikely (status)) + goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (status)) @@ -594,82 +619,31 @@ _cairo_meta_surface_snapshot (void *abstract_other) _cairo_surface_init (&meta->base, &cairo_meta_surface_backend, other->base.content); - meta->width_pixels = other->width_pixels; - meta->height_pixels = other->height_pixels; + meta->extents_pixels = other->extents_pixels; meta->extents = other->extents; + meta->unbounded = other->unbounded; meta->replay_start_idx = other->replay_start_idx; meta->content = other->content; _cairo_array_init_snapshot (&meta->commands, &other->commands); meta->commands_owner = cairo_surface_reference (&other->base); - return &meta->base; -} - -static cairo_int_status_t -_cairo_meta_surface_intersect_clip_path (void *dst, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) -{ - cairo_meta_surface_t *meta = dst; - cairo_command_intersect_clip_path_t *command; - cairo_status_t status; - - command = malloc (sizeof (cairo_command_intersect_clip_path_t)); - if (unlikely (command == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - command->header.type = CAIRO_COMMAND_INTERSECT_CLIP_PATH; - command->header.region = CAIRO_META_REGION_ALL; - - if (path) { - status = _cairo_path_fixed_init_copy (&command->path, path); - if (unlikely (status)) { - free (command); - return status; - } - command->path_pointer = &command->path; - meta->is_clipped = TRUE; - } else { - command->path_pointer = NULL; - meta->is_clipped = FALSE; - } - command->fill_rule = fill_rule; - command->tolerance = tolerance; - command->antialias = antialias; - - status = _cairo_array_append (&meta->commands, &command); - if (unlikely (status)) { - if (path) - _cairo_path_fixed_fini (&command->path); - free (command); - return status; - } + _cairo_clip_init_copy (&meta->clip, &other->clip); - return CAIRO_STATUS_SUCCESS; + return &meta->base; } -/* Currently, we're using as the "size" of a meta surface the largest - * surface size against which the meta-surface is expected to be - * replayed, (as passed in to cairo_meta_surface_create()). - */ -static cairo_int_status_t +static cairo_bool_t _cairo_meta_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle) { cairo_meta_surface_t *surface = abstract_surface; - if (surface->width_pixels < 0 || surface->height_pixels < 0) - return CAIRO_INT_STATUS_UNSUPPORTED; - - rectangle->x = 0; - rectangle->y = 0; - rectangle->width = ceil (surface->width_pixels); - rectangle->height = ceil (surface->height_pixels); + if (surface->unbounded) + return FALSE; - return CAIRO_STATUS_SUCCESS; + *rectangle = surface->extents; + return TRUE; } /** @@ -702,8 +676,6 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = { NULL, /* check_span_renderer */ NULL, /* copy_page */ NULL, /* show_page */ - NULL, /* set_clip_region */ - _cairo_meta_surface_intersect_clip_path, _cairo_meta_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ @@ -726,7 +698,6 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = { _cairo_meta_surface_snapshot, NULL, /* is_similar */ - NULL, /* reset */ NULL, /* fill_stroke */ NULL, /* create_solid_pattern_surface */ NULL, /* can_repaint_solid_pattern_surface */ @@ -735,32 +706,12 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = { _cairo_meta_surface_show_text_glyphs }; -static cairo_path_fixed_t * -_cairo_command_get_path (cairo_command_t *command) -{ - switch (command->header.type) { - case CAIRO_COMMAND_PAINT: - case CAIRO_COMMAND_MASK: - case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: - return NULL; - case CAIRO_COMMAND_STROKE: - return &command->stroke.path; - case CAIRO_COMMAND_FILL: - return &command->fill.path; - case CAIRO_COMMAND_INTERSECT_CLIP_PATH: - return command->intersect_clip_path.path_pointer; - } - - ASSERT_NOT_REACHED; - return NULL; -} - cairo_int_status_t _cairo_meta_surface_get_path (cairo_surface_t *surface, cairo_path_fixed_t *path) { cairo_meta_surface_t *meta; - cairo_command_t *command, **elements; + cairo_command_t **elements; int i, num_elements; cairo_int_status_t status; @@ -773,12 +724,11 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface, num_elements = meta->commands.num_elements; elements = _cairo_array_index (&meta->commands, 0); for (i = meta->replay_start_idx; i < num_elements; i++) { - command = elements[i]; + cairo_command_t *command = elements[i]; switch (command->header.type) { case CAIRO_COMMAND_PAINT: case CAIRO_COMMAND_MASK: - case CAIRO_COMMAND_INTERSECT_CLIP_PATH: status = CAIRO_INT_STATUS_UNSUPPORTED; break; @@ -804,7 +754,9 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface, } case CAIRO_COMMAND_FILL: { - status = _cairo_path_fixed_append (path, &command->fill.path, CAIRO_DIRECTION_FORWARD); + status = _cairo_path_fixed_append (path, + &command->fill.path, CAIRO_DIRECTION_FORWARD, + 0, 0); break; } case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: @@ -827,6 +779,7 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface, return _cairo_surface_set_error (surface, status); } +#define _clip(c) ((c)->header.clip.path ? &(c)->header.clip : NULL) static cairo_status_t _cairo_meta_surface_replay_internal (cairo_surface_t *surface, cairo_surface_t *target, @@ -834,209 +787,155 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, cairo_meta_region_type_t region) { cairo_meta_surface_t *meta; - cairo_command_t *command, **elements; + cairo_command_t **elements; int i, num_elements; - cairo_int_status_t status, status2; - cairo_clip_t clip, *old_clip; - cairo_bool_t has_device_transform = _cairo_surface_has_device_transform (target); - cairo_matrix_t *device_transform = &target->device_transform; - cairo_path_fixed_t path_copy, *dev_path; + cairo_int_status_t status; + cairo_surface_wrapper_t wrapper; - if (surface->status) + if (unlikely (surface->status)) return surface->status; - if (target->status) + if (unlikely (target->status)) return _cairo_surface_set_error (surface, target->status); + _cairo_surface_wrapper_init (&wrapper, target); + meta = (cairo_meta_surface_t *) surface; status = CAIRO_STATUS_SUCCESS; - _cairo_clip_init (&clip, target); - old_clip = _cairo_surface_get_clip (target); - num_elements = meta->commands.num_elements; elements = _cairo_array_index (&meta->commands, 0); for (i = meta->replay_start_idx; i < num_elements; i++) { - command = elements[i]; + cairo_command_t *command = elements[i]; if (type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL) { if (command->header.region != region) continue; } - /* For all commands except intersect_clip_path, we have to - * ensure the current clip gets set on the surface. */ - if (command->header.type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) { - status = _cairo_surface_set_clip (target, &clip); - if (unlikely (status)) - break; - } - - dev_path = _cairo_command_get_path (command); - if (dev_path && has_device_transform) { - status = _cairo_path_fixed_init_copy (&path_copy, dev_path); - if (unlikely (status)) - break; - _cairo_path_fixed_transform (&path_copy, device_transform); - dev_path = &path_copy; - } - switch (command->header.type) { case CAIRO_COMMAND_PAINT: - status = _cairo_surface_paint (target, - command->paint.op, - &command->paint.source.base, &command->header.extents); + status = _cairo_surface_wrapper_paint (&wrapper, + command->header.op, + &command->paint.source.base, + _clip (command)); break; + case CAIRO_COMMAND_MASK: - status = _cairo_surface_mask (target, - command->mask.op, - &command->mask.source.base, - &command->mask.mask.base, &command->header.extents); + status = _cairo_surface_wrapper_mask (&wrapper, + command->header.op, + &command->mask.source.base, + &command->mask.mask.base, + _clip (command)); break; + case CAIRO_COMMAND_STROKE: { - cairo_matrix_t dev_ctm = command->stroke.ctm; - cairo_matrix_t dev_ctm_inverse = command->stroke.ctm_inverse; - - if (has_device_transform) { - cairo_matrix_multiply (&dev_ctm, &dev_ctm, device_transform); - cairo_matrix_multiply (&dev_ctm_inverse, - &target->device_transform_inverse, - &dev_ctm_inverse); - } - - status = _cairo_surface_stroke (target, - command->stroke.op, - &command->stroke.source.base, - dev_path, - &command->stroke.style, - &dev_ctm, - &dev_ctm_inverse, - command->stroke.tolerance, - command->stroke.antialias, &command->header.extents); + status = _cairo_surface_wrapper_stroke (&wrapper, + command->header.op, + &command->stroke.source.base, + &command->stroke.path, + &command->stroke.style, + &command->stroke.ctm, + &command->stroke.ctm_inverse, + command->stroke.tolerance, + command->stroke.antialias, + _clip (command)); break; } case CAIRO_COMMAND_FILL: { cairo_command_t *stroke_command; - if (type != CAIRO_META_CREATE_REGIONS) - stroke_command = (i < num_elements - 1) ? elements[i + 1] : NULL; - else - stroke_command = NULL; + stroke_command = NULL; + if (type != CAIRO_META_CREATE_REGIONS && i < num_elements - 1) + stroke_command = elements[i + 1]; if (stroke_command != NULL && - type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL) + type == CAIRO_META_REPLAY && + region != CAIRO_META_REGION_ALL) { if (stroke_command->header.region != region) stroke_command = NULL; } + if (stroke_command != NULL && stroke_command->header.type == CAIRO_COMMAND_STROKE && - _cairo_path_fixed_is_equal (dev_path, _cairo_command_get_path (stroke_command))) { - cairo_matrix_t dev_ctm; - cairo_matrix_t dev_ctm_inverse; - - dev_ctm = stroke_command->stroke.ctm; - dev_ctm_inverse = stroke_command->stroke.ctm_inverse; - - if (has_device_transform) { - cairo_matrix_multiply (&dev_ctm, &dev_ctm, device_transform); - cairo_matrix_multiply (&dev_ctm_inverse, - &surface->device_transform_inverse, - &dev_ctm_inverse); - } - - status = _cairo_surface_fill_stroke (target, - command->fill.op, - &command->fill.source.base, - command->fill.fill_rule, - command->fill.tolerance, - command->fill.antialias, - dev_path, - stroke_command->stroke.op, - &stroke_command->stroke.source.base, - &stroke_command->stroke.style, - &dev_ctm, - &dev_ctm_inverse, - stroke_command->stroke.tolerance, - stroke_command->stroke.antialias, - &stroke_command->header.extents); + _cairo_path_fixed_is_equal (&command->fill.path, + &stroke_command->stroke.path)) + { + status = _cairo_surface_wrapper_fill_stroke (&wrapper, + command->header.op, + &command->fill.source.base, + command->fill.fill_rule, + command->fill.tolerance, + command->fill.antialias, + &command->fill.path, + stroke_command->header.op, + &stroke_command->stroke.source.base, + &stroke_command->stroke.style, + &stroke_command->stroke.ctm, + &stroke_command->stroke.ctm_inverse, + stroke_command->stroke.tolerance, + stroke_command->stroke.antialias, + _clip (command)); i++; - } else - status = _cairo_surface_fill (target, - command->fill.op, - &command->fill.source.base, - dev_path, - command->fill.fill_rule, - command->fill.tolerance, - command->fill.antialias, &command->header.extents); + } + else + { + status = _cairo_surface_wrapper_fill (&wrapper, + command->header.op, + &command->fill.source.base, + &command->fill.path, + command->fill.fill_rule, + command->fill.tolerance, + command->fill.antialias, + _clip (command)); + } break; } case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: { cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs; - cairo_glyph_t *dev_glyphs; - int i, num_glyphs = command->show_text_glyphs.num_glyphs; + cairo_glyph_t *glyphs_copy; + int num_glyphs = command->show_text_glyphs.num_glyphs; /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed * to modify the glyph array that's passed in. We must always * copy the array before handing it to the backend. */ - dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); - if (unlikely (dev_glyphs == NULL)) { + glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); + if (unlikely (glyphs_copy == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); break; } - if (has_device_transform) { - for (i = 0; i < num_glyphs; i++) { - dev_glyphs[i] = glyphs[i]; - cairo_matrix_transform_point (device_transform, - &dev_glyphs[i].x, - &dev_glyphs[i].y); - } - } else { - memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs); - } - - status = _cairo_surface_show_text_glyphs (target, - command->show_text_glyphs.op, - &command->show_text_glyphs.source.base, - command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len, - dev_glyphs, num_glyphs, - command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters, - command->show_text_glyphs.cluster_flags, - command->show_text_glyphs.scaled_font, &command->header.extents); - - free (dev_glyphs); + memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs); + + status = _cairo_surface_wrapper_show_text_glyphs (&wrapper, + command->header.op, + &command->show_text_glyphs.source.base, + command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len, + glyphs_copy, num_glyphs, + command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters, + command->show_text_glyphs.cluster_flags, + command->show_text_glyphs.scaled_font, + _clip (command)); + free (glyphs_copy); break; } - case CAIRO_COMMAND_INTERSECT_CLIP_PATH: - /* XXX Meta surface clipping is broken and requires some - * cairo-gstate.c rewriting. Work around it for now. */ - if (dev_path == NULL) - _cairo_clip_reset (&clip); - else - status = _cairo_clip_clip (&clip, dev_path, - command->intersect_clip_path.fill_rule, - command->intersect_clip_path.tolerance, - command->intersect_clip_path.antialias, - target); - break; default: ASSERT_NOT_REACHED; } - if (dev_path == &path_copy) - _cairo_path_fixed_fini (&path_copy); - if (type == CAIRO_META_CREATE_REGIONS) { if (status == CAIRO_STATUS_SUCCESS) { command->header.region = CAIRO_META_REGION_NATIVE; } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) { command->header.region = CAIRO_META_REGION_IMAGE_FALLBACK; status = CAIRO_STATUS_SUCCESS; + } else { + assert (_cairo_status_is_error (status)); } } @@ -1044,10 +943,14 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface, break; } - _cairo_clip_reset (&clip); - status2 = _cairo_surface_set_clip (target, old_clip); - if (status == CAIRO_STATUS_SUCCESS) - status = status2; + /* free up any caches */ + for (i = meta->replay_start_idx; i < num_elements; i++) { + cairo_command_t *command = elements[i]; + + _cairo_clip_drop_cache (&command->header.clip); + } + + _cairo_surface_wrapper_fini (&wrapper); return _cairo_surface_set_error (surface, status); } @@ -1104,6 +1007,33 @@ _cairo_meta_surface_replay_region (cairo_surface_t *surface, region); } +static cairo_status_t +_meta_surface_get_ink_bbox (cairo_meta_surface_t *surface, + cairo_box_t *bbox, + const cairo_matrix_t *transform) +{ + cairo_surface_t *null_surface; + cairo_surface_t *analysis_surface; + cairo_status_t status; + + null_surface = _cairo_null_surface_create (surface->content); + analysis_surface = _cairo_analysis_surface_create (null_surface); + cairo_surface_destroy (null_surface); + + status = analysis_surface->status; + if (unlikely (status)) + return status; + + if (transform != NULL) + _cairo_analysis_surface_set_ctm (analysis_surface, transform); + + status = cairo_meta_surface_replay (&surface->base, analysis_surface); + _cairo_analysis_surface_get_bounding_box (analysis_surface, bbox); + cairo_surface_destroy (analysis_surface); + + return status; +} + /** * cairo_meta_surface_ink_extents: * @surface: a #cairo_meta_surface_t @@ -1114,7 +1044,7 @@ _cairo_meta_surface_replay_region (cairo_surface_t *surface, * * Measures the extents of the operations stored within the meta-surface. * This is useful to compute the required size of an image surface (or - * equivalent) into which to replay the full sequence of drawing operaitions. + * equivalent) into which to replay the full sequence of drawing operations. * * Since: 1.10 **/ @@ -1125,8 +1055,6 @@ cairo_meta_surface_ink_extents (cairo_surface_t *surface, double *width, double *height) { - cairo_surface_t *null_surface; - cairo_surface_t *analysis_surface; cairo_status_t status; cairo_box_t bbox; @@ -1137,17 +1065,11 @@ cairo_meta_surface_ink_extents (cairo_surface_t *surface, goto DONE; } - null_surface = _cairo_null_surface_create (CAIRO_CONTENT_COLOR_ALPHA); - analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1); - cairo_surface_destroy (null_surface); - - status = analysis_surface->status; + status = _meta_surface_get_ink_bbox ((cairo_meta_surface_t *) surface, + &bbox, + NULL); if (unlikely (status)) - goto DONE; - - status = cairo_meta_surface_replay (surface, analysis_surface); - _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox); - cairo_surface_destroy (analysis_surface); + status = _cairo_surface_set_error (surface, status); DONE: if (x0) @@ -1159,3 +1081,19 @@ DONE: if (height) *height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y); } + +cairo_status_t +_cairo_meta_surface_get_bbox (cairo_meta_surface_t *surface, + cairo_box_t *bbox, + const cairo_matrix_t *transform) +{ + if (! surface->unbounded) { + _cairo_box_from_rectangle (bbox, &surface->extents); + if (transform != NULL) + _cairo_matrix_transform_bounding_box_fixed (transform, bbox, NULL); + + return CAIRO_STATUS_SUCCESS; + } + + return _meta_surface_get_ink_bbox (surface, bbox, transform); +} |