# HG changeset patch
# User Robert O'Callahan <robert@ocallahan.org>
# 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;
 }
