# HG changeset patch # User Robert O'Callahan # Date 1294019288 -46800 # Node ID bacc54d452a9fddb5a0d6a1442ec7be4de81ffa7 # Parent ccba8826be1451d0e61d0df38363dadffb20ba48 Bug 593604. Part 2: When compositing a tee surface into another tee surface, try to compose the subsurfaces pointwise. r=jrmuizel,a=blocking diff --git a/gfx/cairo/cairo/src/cairo-tee-surface.c b/gfx/cairo/cairo/src/cairo-tee-surface.c --- a/gfx/cairo/cairo/src/cairo-tee-surface.c +++ b/gfx/cairo/cairo/src/cairo-tee-surface.c @@ -186,35 +186,72 @@ static void _cairo_tee_surface_get_font_options (void *abstract_surface, cairo_font_options_t *options) { cairo_tee_surface_t *surface = abstract_surface; _cairo_surface_wrapper_get_font_options (&surface->master, options); } +static const cairo_pattern_t * +_cairo_tee_surface_match_source (cairo_tee_surface_t *surface, + const cairo_pattern_t *source, + int index, + cairo_surface_wrapper_t *dest, + cairo_surface_pattern_t *temp) +{ + cairo_surface_t *s; + cairo_status_t status = cairo_pattern_get_surface ((cairo_pattern_t *)source, &s); + if (status == CAIRO_STATUS_SUCCESS && + cairo_surface_get_type (s) == CAIRO_SURFACE_TYPE_TEE) { + cairo_surface_t *tee_surf = cairo_tee_surface_index (s, index); + if (tee_surf->status == CAIRO_STATUS_SUCCESS && + tee_surf->backend == dest->target->backend) { + status = _cairo_pattern_init_copy (&temp->base, source); + if (status == CAIRO_STATUS_SUCCESS) { + cairo_surface_destroy (temp->surface); + temp->surface = tee_surf; + cairo_surface_reference (temp->surface); + return &temp->base; + } + } + } + + return source; +} + static cairo_int_status_t _cairo_tee_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_clip_t *clip) { cairo_tee_surface_t *surface = abstract_surface; cairo_surface_wrapper_t *slaves; int n, num_slaves; cairo_status_t status; + const cairo_pattern_t *matched_source; + cairo_surface_pattern_t temp; - status = _cairo_surface_wrapper_paint (&surface->master, op, source, clip); + matched_source = _cairo_tee_surface_match_source (surface, source, 0, &surface->master, &temp); + status = _cairo_surface_wrapper_paint (&surface->master, op, matched_source, clip); + if (matched_source == &temp.base) { + _cairo_pattern_fini (&temp.base); + } if (unlikely (status)) return status; num_slaves = _cairo_array_num_elements (&surface->slaves); slaves = _cairo_array_index (&surface->slaves, 0); for (n = 0; n < num_slaves; n++) { - status = _cairo_surface_wrapper_paint (&slaves[n], op, source, clip); + matched_source = _cairo_tee_surface_match_source (surface, source, n + 1, &slaves[n], &temp); + status = _cairo_surface_wrapper_paint (&slaves[n], op, matched_source, clip); + if (matched_source == &temp.base) { + _cairo_pattern_fini (&temp.base); + } if (unlikely (status)) return status; } return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t @@ -223,27 +260,37 @@ _cairo_tee_surface_mask (void *abstrac const cairo_pattern_t *source, const cairo_pattern_t *mask, cairo_clip_t *clip) { cairo_tee_surface_t *surface = abstract_surface; cairo_surface_wrapper_t *slaves; int n, num_slaves; cairo_status_t status; + const cairo_pattern_t *matched_source; + cairo_surface_pattern_t temp; + matched_source = _cairo_tee_surface_match_source (surface, source, 0, &surface->master, &temp); status = _cairo_surface_wrapper_mask (&surface->master, - op, source, mask, clip); + op, matched_source, mask, clip); + if (matched_source == &temp.base) { + _cairo_pattern_fini (&temp.base); + } if (unlikely (status)) return status; num_slaves = _cairo_array_num_elements (&surface->slaves); slaves = _cairo_array_index (&surface->slaves, 0); for (n = 0; n < num_slaves; n++) { + matched_source = _cairo_tee_surface_match_source (surface, source, n + 1, &slaves[n], &temp); status = _cairo_surface_wrapper_mask (&slaves[n], - op, source, mask, clip); + op, matched_source, mask, clip); + if (matched_source == &temp.base) { + _cairo_pattern_fini (&temp.base); + } if (unlikely (status)) return status; } return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t @@ -257,35 +304,45 @@ _cairo_tee_surface_stroke (void *abst double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) { cairo_tee_surface_t *surface = abstract_surface; cairo_surface_wrapper_t *slaves; int n, num_slaves; cairo_status_t status; + const cairo_pattern_t *matched_source; + cairo_surface_pattern_t temp; + matched_source = _cairo_tee_surface_match_source (surface, source, 0, &surface->master, &temp); status = _cairo_surface_wrapper_stroke (&surface->master, - op, source, + op, matched_source, path, style, ctm, ctm_inverse, tolerance, antialias, clip); + if (matched_source == &temp.base) { + _cairo_pattern_fini (&temp.base); + } if (unlikely (status)) return status; num_slaves = _cairo_array_num_elements (&surface->slaves); slaves = _cairo_array_index (&surface->slaves, 0); for (n = 0; n < num_slaves; n++) { + matched_source = _cairo_tee_surface_match_source (surface, source, n + 1, &slaves[n], &temp); status = _cairo_surface_wrapper_stroke (&slaves[n], - op, source, + op, matched_source, path, style, ctm, ctm_inverse, tolerance, antialias, clip); + if (matched_source == &temp.base) { + _cairo_pattern_fini (&temp.base); + } if (unlikely (status)) return status; } return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t @@ -297,33 +354,43 @@ _cairo_tee_surface_fill (void *abstra double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) { cairo_tee_surface_t *surface = abstract_surface; cairo_surface_wrapper_t *slaves; int n, num_slaves; cairo_status_t status; + const cairo_pattern_t *matched_source; + cairo_surface_pattern_t temp; + matched_source = _cairo_tee_surface_match_source (surface, source, 0, &surface->master, &temp); status = _cairo_surface_wrapper_fill (&surface->master, - op, source, + op, matched_source, path, fill_rule, tolerance, antialias, clip); + if (matched_source == &temp.base) { + _cairo_pattern_fini (&temp.base); + } if (unlikely (status)) return status; num_slaves = _cairo_array_num_elements (&surface->slaves); slaves = _cairo_array_index (&surface->slaves, 0); for (n = 0; n < num_slaves; n++) { + matched_source = _cairo_tee_surface_match_source (surface, source, n + 1, &slaves[n], &temp); status = _cairo_surface_wrapper_fill (&slaves[n], - op, source, + op, matched_source, path, fill_rule, tolerance, antialias, clip); + if (matched_source == &temp.base) { + _cairo_pattern_fini (&temp.base); + } if (unlikely (status)) return status; } return CAIRO_STATUS_SUCCESS; } static cairo_bool_t @@ -346,46 +413,56 @@ _cairo_tee_surface_show_text_glyphs (voi cairo_scaled_font_t *scaled_font, cairo_clip_t *clip) { cairo_tee_surface_t *surface = abstract_surface; cairo_surface_wrapper_t *slaves; int n, num_slaves; cairo_status_t status; cairo_glyph_t *glyphs_copy; + const cairo_pattern_t *matched_source; + cairo_surface_pattern_t temp; /* XXX: This copying is ugly. */ glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); if (unlikely (glyphs_copy == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs); + matched_source = _cairo_tee_surface_match_source (surface, source, 0, &surface->master, &temp); status = _cairo_surface_wrapper_show_text_glyphs (&surface->master, op, - source, + matched_source, utf8, utf8_len, glyphs_copy, num_glyphs, clusters, num_clusters, cluster_flags, scaled_font, clip); + if (matched_source == &temp.base) { + _cairo_pattern_fini (&temp.base); + } if (unlikely (status)) goto CLEANUP; num_slaves = _cairo_array_num_elements (&surface->slaves); slaves = _cairo_array_index (&surface->slaves, 0); for (n = 0; n < num_slaves; n++) { memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs); + matched_source = _cairo_tee_surface_match_source (surface, source, n + 1, &slaves[n], &temp); status = _cairo_surface_wrapper_show_text_glyphs (&slaves[n], op, - source, + matched_source, utf8, utf8_len, glyphs_copy, num_glyphs, clusters, num_clusters, cluster_flags, scaled_font, clip); + if (matched_source == &temp.base) { + _cairo_pattern_fini (&temp.base); + } if (unlikely (status)) goto CLEANUP; } CLEANUP: free (glyphs_copy); return status; }