[cairo-commit] src/cairo-pdf-surface.c src/cairo-pdf-surface-private.h src/cairo-recording-surface.c src/cairo-recording-surface-private.h

Adrian Johnson ajohnson at kemper.freedesktop.org
Wed Sep 11 04:50:56 PDT 2013


 src/cairo-pdf-surface-private.h       |    2 
 src/cairo-pdf-surface.c               |  125 +++++++++++++++++++++++++---------
 src/cairo-recording-surface-private.h |    8 ++
 src/cairo-recording-surface.c         |  113 ++++++++++++++++++++++++++++++
 4 files changed, 215 insertions(+), 33 deletions(-)

New commits:
commit 8addb4798c918000eaa6f6dab138e0abb0efa946
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Apr 8 10:57:23 2012 +0930

    pdf: avoid making groups a transparency group if not required
    
    If the group contains only a combination of clear and opaque alpha and
    only OPERATOR_OVER is used in the group and to paint the group, a
    transparency group is not required. This allows the pdf viewer to
    replay the group in place.

diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index d9f65d8..dfeb1aa 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -70,6 +70,7 @@ typedef struct _cairo_pdf_source_surface_entry {
     unsigned int id;
     unsigned char *unique_id;
     unsigned long unique_id_length;
+    cairo_operator_t operator;
     cairo_bool_t interpolate;
     cairo_bool_t stencil_mask;
     cairo_pdf_resource_t surface_res;
@@ -92,6 +93,7 @@ typedef struct _cairo_pdf_pattern {
     cairo_pattern_t *pattern;
     cairo_pdf_resource_t pattern_res;
     cairo_pdf_resource_t gstate_res;
+    cairo_operator_t operator;
     cairo_bool_t is_shading;
 } cairo_pdf_pattern_t;
 
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 6580d5b..9ff1503 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1282,6 +1282,7 @@ _get_source_surface_size (cairo_surface_t         *source,
  * @surface: the pdf surface
  * @source_surface: A #cairo_surface_t to use as the source surface
  * @source_pattern: A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source
+ * @op: the operator used to composite this source
  * @filter: filter type of the source pattern
  * @stencil_mask: if true, the surface will be written to the PDF as an /ImageMask
  * @extents: extents of the operation that is using this source
@@ -1306,6 +1307,7 @@ static cairo_int_status_t
 _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t	    *surface,
 				       cairo_surface_t	            *source_surface,
 				       const cairo_pattern_t	    *source_pattern,
+				       cairo_operator_t              op,
 				       cairo_filter_t		     filter,
 				       cairo_bool_t                  stencil_mask,
 				       const cairo_rectangle_int_t  *extents,
@@ -1406,6 +1408,7 @@ release_source:
     }
 
     surface_entry->id = surface_key.id;
+    surface_entry->operator = op;
     surface_entry->interpolate = interpolate;
     surface_entry->stencil_mask = stencil_mask;
     surface_entry->unique_id_length = unique_id_length;
@@ -1466,6 +1469,7 @@ fail1:
 static cairo_int_status_t
 _cairo_pdf_surface_add_pdf_pattern_or_shading (cairo_pdf_surface_t	   *surface,
 					       const cairo_pattern_t	   *pattern,
+					       cairo_operator_t	            op,
 					       const cairo_rectangle_int_t *extents,
 					       cairo_bool_t                 is_shading,
 					       cairo_pdf_resource_t	   *pattern_res,
@@ -1475,6 +1479,7 @@ _cairo_pdf_surface_add_pdf_pattern_or_shading (cairo_pdf_surface_t	   *surface,
     cairo_int_status_t status;
 
     pdf_pattern.is_shading = is_shading;
+    pdf_pattern.operator = op;
 
     /* Solid colors are emitted into the content stream */
     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
@@ -1550,12 +1555,14 @@ _get_bbox_from_extents (double                       surface_height,
 static cairo_int_status_t
 _cairo_pdf_surface_add_pdf_shading (cairo_pdf_surface_t		*surface,
 				    const cairo_pattern_t	*pattern,
+				    cairo_operator_t	         op,
 				    const cairo_rectangle_int_t	*extents,
 				    cairo_pdf_resource_t	*shading_res,
 				    cairo_pdf_resource_t	*gstate_res)
 {
     return _cairo_pdf_surface_add_pdf_pattern_or_shading (surface,
 							  pattern,
+							  op,
 							  extents,
 							  TRUE,
 							  shading_res,
@@ -1565,12 +1572,14 @@ _cairo_pdf_surface_add_pdf_shading (cairo_pdf_surface_t		*surface,
 static cairo_int_status_t
 _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t		*surface,
 				    const cairo_pattern_t	*pattern,
+				    cairo_operator_t	         op,
 				    const cairo_rectangle_int_t	*extents,
 				    cairo_pdf_resource_t	*pattern_res,
 				    cairo_pdf_resource_t	*gstate_res)
 {
     return _cairo_pdf_surface_add_pdf_pattern_or_shading (surface,
 							  pattern,
+							  op,
 							  extents,
 							  FALSE,
 							  pattern_res,
@@ -1846,7 +1855,8 @@ static cairo_int_status_t
 _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t       *surface,
 					const cairo_box_double_t  *bbox,
 					cairo_pdf_resource_t      *resource,
-					cairo_bool_t               is_form)
+					cairo_bool_t               is_form,
+					cairo_bool_t               is_group)
 {
     cairo_int_status_t status;
 
@@ -1860,25 +1870,41 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t       *surface,
     if (is_form) {
 	assert (bbox != NULL);
 
-	status =
-	    _cairo_pdf_surface_open_stream (surface,
-					    resource,
-					    surface->compress_content,
-					    "   /Type /XObject\n"
-					    "   /Subtype /Form\n"
-					    "   /BBox [ %f %f %f %f ]\n"
-					    "   /Group <<\n"
-					    "      /Type /Group\n"
-					    "      /S /Transparency\n"
-					    "      /I true\n"
-					    "      /CS /DeviceRGB\n"
-					    "   >>\n"
-					    "   /Resources %d 0 R\n",
-					    bbox->p1.x,
-					    bbox->p1.y,
-					    bbox->p2.x,
-					    bbox->p2.y,
-					    surface->content_resources.id);
+	if (is_group) {
+	    status =
+		_cairo_pdf_surface_open_stream (surface,
+						resource,
+						surface->compress_content,
+						"   /Type /XObject\n"
+						"   /Subtype /Form\n"
+						"   /BBox [ %f %f %f %f ]\n"
+						"   /Group <<\n"
+						"      /Type /Group\n"
+						"      /S /Transparency\n"
+						"      /I true\n"
+						"      /CS /DeviceRGB\n"
+						"   >>\n"
+						"   /Resources %d 0 R\n",
+						bbox->p1.x,
+						bbox->p1.y,
+						bbox->p2.x,
+						bbox->p2.y,
+						surface->content_resources.id);
+	} else {
+	    status =
+		_cairo_pdf_surface_open_stream (surface,
+						resource,
+						surface->compress_content,
+						"   /Type /XObject\n"
+						"   /Subtype /Form\n"
+						"   /BBox [ %f %f %f %f ]\n"
+						"   /Resources %d 0 R\n",
+						bbox->p1.x,
+						bbox->p1.y,
+						bbox->p2.x,
+						bbox->p2.y,
+						surface->content_resources.id);
+	}
     } else {
 	status =
 	    _cairo_pdf_surface_open_stream (surface,
@@ -2079,7 +2105,7 @@ _cairo_pdf_surface_has_fallback_images (void		*abstract_surface,
     bbox.p1.y = 0;
     bbox.p2.x = surface->width;
     bbox.p2.y = surface->height;
-    status = _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, has_fallbacks);
+    status = _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, has_fallbacks, has_fallbacks);
     if (unlikely (status))
 	return status;
 
@@ -2154,6 +2180,7 @@ _cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t          *surfa
     status = _cairo_pdf_surface_add_source_surface (surface,
 						    pad_image,
 						    NULL,
+						    FALSE,
 						    source->filter,
 						    FALSE,
 						    extents,
@@ -2686,6 +2713,8 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t        *surface,
     int width;
     int height;
     cairo_bool_t is_subsurface;
+    cairo_bool_t transparency_group;
+    cairo_recording_surface_t *recording;
 
     assert (pdf_source->type == CAIRO_PATTERN_TYPE_SURFACE);
     extents = &pdf_source->hash_entry->extents;
@@ -2705,6 +2734,9 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t        *surface,
 	is_subsurface = TRUE;
     }
 
+    assert (source->type == CAIRO_SURFACE_TYPE_RECORDING);
+    recording = (cairo_recording_surface_t *) source;
+
     old_width = surface->width;
     old_height = surface->height;
     old_paginated_mode = surface->paginated_mode;
@@ -2721,7 +2753,16 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t        *surface,
     surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER;
     _cairo_pdf_group_resources_clear (&surface->resources);
     _get_bbox_from_extents (height, extents, &bbox);
-    status = _cairo_pdf_surface_open_content_stream (surface, &bbox, &pdf_source->hash_entry->surface_res, TRUE);
+
+    /* We can optimize away the transparency group allowing the viewer
+     * to replay the group in place when all operators are OVER and the
+     * recording contains only opaque and/or clear alpha.
+     */
+    transparency_group = !(pdf_source->hash_entry->operator == CAIRO_OPERATOR_OVER &&
+			   _cairo_recording_surface_has_only_bilevel_alpha (recording) &&
+			   _cairo_recording_surface_has_only_op_over (recording));
+    status = _cairo_pdf_surface_open_content_stream (surface, &bbox, &pdf_source->hash_entry->surface_res,
+						     TRUE, transparency_group);
     if (unlikely (status))
 	goto err;
 
@@ -2805,6 +2846,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	*surface,
 	status = _cairo_pdf_surface_add_source_surface (surface,
 							NULL,
 							pattern,
+							pdf_pattern->operator,
 							pattern->filter,
 							FALSE,
 							&pdf_pattern->extents,
@@ -3909,6 +3951,7 @@ _cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern
 
 static cairo_int_status_t
 _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t          *surface,
+					  cairo_operator_t              op,
 					  const cairo_pattern_t        *source,
 					  const cairo_rectangle_int_t  *extents,
 					  cairo_bool_t                  stencil_mask)
@@ -3938,6 +3981,7 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t          *surface,
 	status = _cairo_pdf_surface_add_source_surface (surface,
 							NULL,
 							source,
+							op,
 							source->filter,
 							stencil_mask,
 							extents,
@@ -3999,6 +4043,7 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t          *surface,
 
 static cairo_int_status_t
 _cairo_pdf_surface_paint_gradient (cairo_pdf_surface_t         *surface,
+				   cairo_operator_t             op,
 				   const cairo_pattern_t       *source,
 				   const cairo_rectangle_int_t *extents)
 {
@@ -4008,7 +4053,7 @@ _cairo_pdf_surface_paint_gradient (cairo_pdf_surface_t         *surface,
     int alpha;
 
     status = _cairo_pdf_surface_add_pdf_shading (surface, source,
-						 extents,
+						 op, extents,
 						 &shading_res, &gstate_res);
     if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
 	return CAIRO_INT_STATUS_SUCCESS;
@@ -4062,6 +4107,7 @@ _cairo_pdf_surface_paint_gradient (cairo_pdf_surface_t         *surface,
 
 static cairo_int_status_t
 _cairo_pdf_surface_paint_pattern (cairo_pdf_surface_t          *surface,
+				  cairo_operator_t              op,
 				  const cairo_pattern_t        *source,
 				  const cairo_rectangle_int_t  *extents,
 				  cairo_bool_t                  mask)
@@ -4070,6 +4116,7 @@ _cairo_pdf_surface_paint_pattern (cairo_pdf_surface_t          *surface,
     case CAIRO_PATTERN_TYPE_SURFACE:
     case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
 	return _cairo_pdf_surface_paint_surface_pattern (surface,
+							 op,
 							 source,
 							 extents,
 							 mask);
@@ -4077,6 +4124,7 @@ _cairo_pdf_surface_paint_pattern (cairo_pdf_surface_t          *surface,
     case CAIRO_PATTERN_TYPE_RADIAL:
     case CAIRO_PATTERN_TYPE_MESH:
 	return _cairo_pdf_surface_paint_gradient (surface,
+						  op,
 						  source,
 						  extents);
 
@@ -5701,6 +5749,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t	*surface,
     if (_can_paint_pattern (group->mask)) {
 	_cairo_output_stream_printf (surface->output, "q\n");
 	status = _cairo_pdf_surface_paint_pattern (surface,
+						   CAIRO_OPERATOR_OVER,
 						   group->mask,
 						   &group->extents,
 						   FALSE);
@@ -5711,7 +5760,9 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t	*surface,
     } else {
 	pattern_res.id = 0;
 	gstate_res.id = 0;
-	status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask, NULL,
+	status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask,
+						     CAIRO_OPERATOR_OVER,
+						     NULL,
 						     &pattern_res, &gstate_res);
 	if (unlikely (status))
 	    return status;
@@ -5774,6 +5825,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t	*surface,
     if (_can_paint_pattern (group->source)) {
 	_cairo_output_stream_printf (surface->output, "q\n");
 	status = _cairo_pdf_surface_paint_pattern (surface,
+						   CAIRO_OPERATOR_OVER,
 						   group->source,
 						   &group->extents,
 						   FALSE);
@@ -5784,7 +5836,9 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t	*surface,
     } else {
 	pattern_res.id = 0;
 	gstate_res.id = 0;
-	status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source, NULL,
+	status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source,
+						     CAIRO_OPERATOR_OVER,
+						     NULL,
 						     &pattern_res, &gstate_res);
 	if (unlikely (status))
 	    return status;
@@ -6039,7 +6093,7 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
 	    return status;
 
 	_cairo_pdf_group_resources_clear (&surface->resources);
-	status = _cairo_pdf_surface_open_content_stream (surface, NULL, NULL, FALSE);
+	status = _cairo_pdf_surface_open_content_stream (surface, NULL, NULL, FALSE, FALSE);
 	if (unlikely (status))
 	    return status;
 
@@ -6327,12 +6381,13 @@ _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
     bbox.p1.y = 0;
     bbox.p2.x = surface->width;
     bbox.p2.y = surface->height;
-    return _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, TRUE);
+    return _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, TRUE, TRUE);
 }
 
 /* A PDF stencil mask is an A1 mask used with the current color */
 static cairo_int_status_t
 _cairo_pdf_surface_emit_stencil_mask (cairo_pdf_surface_t         *surface,
+				      cairo_operator_t	           op,
 				      const cairo_pattern_t       *source,
 				      const cairo_pattern_t       *mask,
 				      const cairo_rectangle_int_t *extents)
@@ -6379,7 +6434,7 @@ _cairo_pdf_surface_emit_stencil_mask (cairo_pdf_surface_t         *surface,
 	return status;
 
     _cairo_output_stream_printf (surface->output, "q\n");
-    status = _cairo_pdf_surface_paint_surface_pattern (surface, mask, extents, TRUE);
+    status = _cairo_pdf_surface_paint_surface_pattern (surface, op, mask, extents, TRUE);
     if (unlikely (status))
 	return status;
 
@@ -6455,6 +6510,7 @@ _cairo_pdf_surface_paint (void			*abstract_surface,
     if (_can_paint_pattern (source)) {
 	_cairo_output_stream_printf (surface->output, "q\n");
 	status = _cairo_pdf_surface_paint_pattern (surface,
+						   op,
 						   source,
 						   &extents.bounded,
 						   FALSE);
@@ -6468,7 +6524,7 @@ _cairo_pdf_surface_paint (void			*abstract_surface,
 
     pattern_res.id = 0;
     gstate_res.id = 0;
-    status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
+    status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op,
 						 &extents.bounded,
 						 &pattern_res, &gstate_res);
     if (unlikely (status))
@@ -6609,7 +6665,7 @@ _cairo_pdf_surface_mask (void			*abstract_surface,
 	goto cleanup;
 
     /* Check if we can use a stencil mask */
-    status = _cairo_pdf_surface_emit_stencil_mask (surface, source, mask, &extents.bounded);
+    status = _cairo_pdf_surface_emit_stencil_mask (surface, op, source, mask, &extents.bounded);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	goto cleanup;
 
@@ -6726,7 +6782,7 @@ _cairo_pdf_surface_stroke (void			*abstract_surface,
 
     pattern_res.id = 0;
     gstate_res.id = 0;
-    status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
+    status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op,
 						 &extents.bounded,
 						 &pattern_res, &gstate_res);
     if (unlikely (status))
@@ -6879,6 +6935,7 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
 	    goto cleanup;
 
 	status = _cairo_pdf_surface_paint_pattern (surface,
+						   op,
 						   source,
 						   &extents.bounded,
 						   FALSE);
@@ -6892,7 +6949,7 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
 
     pattern_res.id = 0;
     gstate_res.id = 0;
-    status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
+    status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op,
 						 &extents.bounded,
 						 &pattern_res, &gstate_res);
     if (unlikely (status))
@@ -7067,6 +7124,7 @@ _cairo_pdf_surface_fill_stroke (void			*abstract_surface,
     fill_pattern_res.id = 0;
     gstate_res.id = 0;
     status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source,
+						 fill_op,
 						 &extents.bounded,
 						 &fill_pattern_res,
 						 &gstate_res);
@@ -7079,6 +7137,7 @@ _cairo_pdf_surface_fill_stroke (void			*abstract_surface,
     gstate_res.id = 0;
     status = _cairo_pdf_surface_add_pdf_pattern (surface,
 						 stroke_source,
+						 stroke_op,
 						 &extents.bounded,
 						 &stroke_pattern_res,
 						 &gstate_res);
@@ -7170,7 +7229,7 @@ _cairo_pdf_surface_show_text_glyphs (void			*abstract_surface,
 
     pattern_res.id = 0;
     gstate_res.id = 0;
-    status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
+    status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op,
 						 &extents.bounded,
 						 &pattern_res, &gstate_res);
     if (unlikely (status))
diff --git a/src/cairo-recording-surface-private.h b/src/cairo-recording-surface-private.h
index 4919481..456c633 100644
--- a/src/cairo-recording-surface-private.h
+++ b/src/cairo-recording-surface-private.h
@@ -136,6 +136,8 @@ typedef struct _cairo_recording_surface {
     unsigned int *indices;
     unsigned int num_indices;
     cairo_bool_t optimize_clears;
+    cairo_bool_t has_bilevel_alpha;
+    cairo_bool_t has_only_op_over;
 
     struct bbtree {
 	cairo_box_t extents;
@@ -184,4 +186,10 @@ _cairo_recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
 				       cairo_box_t *bbox,
 				       const cairo_matrix_t *transform);
 
+cairo_private cairo_bool_t
+_cairo_recording_surface_has_only_bilevel_alpha (cairo_recording_surface_t *surface);
+
+cairo_private cairo_bool_t
+_cairo_recording_surface_has_only_op_over (cairo_recording_surface_t *surface);
+
 #endif /* CAIRO_RECORDING_SURFACE_H */
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 55a98d0..eb9af46 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -87,6 +87,7 @@
 #include "cairo-error-private.h"
 #include "cairo-image-surface-private.h"
 #include "cairo-recording-surface-inline.h"
+#include "cairo-surface-snapshot-inline.h"
 #include "cairo-surface-wrapper-private.h"
 #include "cairo-traps-private.h"
 
@@ -420,6 +421,8 @@ cairo_recording_surface_create (cairo_content_t		 content,
     surface->indices = NULL;
     surface->num_indices = 0;
     surface->optimize_clears = TRUE;
+    surface->has_bilevel_alpha = FALSE;
+    surface->has_only_op_over = FALSE;
 
     return &surface->base;
 }
@@ -1603,6 +1606,65 @@ _cairo_recording_surface_get_visible_commands (cairo_recording_surface_t *surfac
     return num_visible;
 }
 
+static void
+_cairo_recording_surface_merge_source_attributes (cairo_recording_surface_t  *surface,
+						  cairo_operator_t            op,
+						  const cairo_pattern_t      *source)
+{
+    if (op != CAIRO_OPERATOR_OVER)
+	surface->has_only_op_over = FALSE;
+
+    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) source;
+	cairo_surface_t *surf = surf_pat->surface;
+	cairo_surface_t *free_me;
+
+	if (_cairo_surface_is_snapshot (surf))
+	    free_me = surf = _cairo_surface_snapshot_get_target (surf);
+
+	if (surf->type == CAIRO_SURFACE_TYPE_RECORDING) {
+	    cairo_recording_surface_t *rec_surf = (cairo_recording_surface_t *) surf;
+
+	    if (! _cairo_recording_surface_has_only_bilevel_alpha (rec_surf))
+		surface->has_bilevel_alpha = FALSE;
+
+	    if (! _cairo_recording_surface_has_only_op_over (rec_surf))
+		surface->has_only_op_over = FALSE;
+
+	} else if (surf->type == CAIRO_SURFACE_TYPE_IMAGE) {
+	    cairo_image_surface_t *img_surf = (cairo_image_surface_t *) surf;
+
+	    if (_cairo_image_analyze_transparency (img_surf) == CAIRO_IMAGE_HAS_ALPHA)
+		surface->has_bilevel_alpha = FALSE;
+
+	}
+
+	cairo_surface_destroy (free_me);
+	return;
+
+    } else if (source->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
+	cairo_surface_t *image;
+	cairo_surface_t *raster;
+
+	image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+	raster = _cairo_raster_source_pattern_acquire (source, image, NULL);
+	cairo_surface_destroy (image);
+	if (raster) {
+	    if (raster->type == CAIRO_SURFACE_TYPE_IMAGE) {
+		if (_cairo_image_analyze_transparency ((cairo_image_surface_t *)raster) == CAIRO_IMAGE_HAS_ALPHA)
+		    surface->has_bilevel_alpha = FALSE;
+	    }
+
+	    _cairo_raster_source_pattern_release (source, raster);
+	    if (raster->type == CAIRO_SURFACE_TYPE_IMAGE)
+		return;
+	}
+    }
+
+    if (!_cairo_pattern_is_clear (source) && !_cairo_pattern_is_opaque (source, NULL))
+	surface->has_bilevel_alpha = FALSE;
+}
+
 static cairo_status_t
 _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 					  const cairo_rectangle_int_t *surface_extents,
@@ -1652,6 +1714,9 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
     if (! _cairo_surface_wrapper_get_target_extents (&wrapper, &extents))
 	goto done;
 
+    surface->has_bilevel_alpha = TRUE;
+    surface->has_only_op_over = TRUE;
+
     num_elements = surface->commands.num_elements;
     elements = _cairo_array_index (&surface->commands, 0);
     if (extents.width < r->width || extents.height < r->height) {
@@ -1675,6 +1740,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 						   command->header.op,
 						   &command->paint.source.base,
 						   command->header.clip);
+	    if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+		_cairo_recording_surface_merge_source_attributes (surface,
+								  command->header.op,
+								  &command->paint.source.base);
+	    }
 	    break;
 
 	case CAIRO_COMMAND_MASK:
@@ -1683,6 +1753,14 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 						  &command->mask.source.base,
 						  &command->mask.mask.base,
 						  command->header.clip);
+	    if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+		_cairo_recording_surface_merge_source_attributes (surface,
+								  command->header.op,
+								  &command->mask.source.base);
+		_cairo_recording_surface_merge_source_attributes (surface,
+								  command->header.op,
+								  &command->mask.mask.base);
+	    }
 	    break;
 
 	case CAIRO_COMMAND_STROKE:
@@ -1696,6 +1774,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 						    command->stroke.tolerance,
 						    command->stroke.antialias,
 						    command->header.clip);
+	    if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+		_cairo_recording_surface_merge_source_attributes (surface,
+								  command->header.op,
+								  &command->stroke.source.base);
+	    }
 	    break;
 
 	case CAIRO_COMMAND_FILL:
@@ -1737,6 +1820,14 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 								 stroke_command->stroke.tolerance,
 								 stroke_command->stroke.antialias,
 								 command->header.clip);
+		    if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+			_cairo_recording_surface_merge_source_attributes (surface,
+									  command->header.op,
+									  &command->fill.source.base);
+			_cairo_recording_surface_merge_source_attributes (surface,
+									  command->header.op,
+									  &command->stroke.source.base);
+		    }
 		    i++;
 		}
 	    }
@@ -1749,6 +1840,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 						      command->fill.tolerance,
 						      command->fill.antialias,
 						      command->header.clip);
+		if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+		    _cairo_recording_surface_merge_source_attributes (surface,
+								      command->header.op,
+								      &command->fill.source.base);
+		}
 	    }
 	    break;
 
@@ -1762,6 +1858,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 							      command->show_text_glyphs.cluster_flags,
 							      command->show_text_glyphs.scaled_font,
 							      command->header.clip);
+	    if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+		_cairo_recording_surface_merge_source_attributes (surface,
+								  command->header.op,
+								  &command->show_text_glyphs.source.base);
+	    }
 	    break;
 
 	default:
@@ -2070,3 +2171,15 @@ cairo_recording_surface_get_extents (cairo_surface_t *surface,
     *extents = record->extents_pixels;
     return TRUE;
 }
+
+cairo_bool_t
+_cairo_recording_surface_has_only_bilevel_alpha (cairo_recording_surface_t *surface)
+{
+    return surface->has_bilevel_alpha;
+}
+
+cairo_bool_t
+_cairo_recording_surface_has_only_op_over (cairo_recording_surface_t *surface)
+{
+    return surface->has_only_op_over;
+}


More information about the cairo-commit mailing list