[cairo-commit] 4 commits - boilerplate/cairo-boilerplate.c src/cairo-analysis-surface.c src/cairo-meta-surface.c src/cairo-meta-surface-private.h src/cairo-pdf-surface.c src/cairo-types-private.h

Carl Worth cworth at kemper.freedesktop.org
Wed Sep 5 14:48:32 PDT 2007


 boilerplate/cairo-boilerplate.c  |   11 -
 src/cairo-analysis-surface.c     |   66 +++++++++
 src/cairo-meta-surface-private.h |    4 
 src/cairo-meta-surface.c         |   61 ++++++--
 src/cairo-pdf-surface.c          |  282 ++++++++++++++++++++++++++++-----------
 src/cairo-types-private.h        |    3 
 6 files changed, 326 insertions(+), 101 deletions(-)

New commits:
diff-tree 3c01efb0ee0c8911fba7627d056ec3b53dfab6e3 (from parents)
Merge: 0682b9a9c18640c284c7cc8ba8792a329414998e 1e21220f0e2540e3befa66e4764f75589d0eef82
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Sep 5 14:38:40 2007 -0700

    Merge branch adrianj/pdf-meta-surface-pattern into cairo
    
    This does introduce some reported failures from the cairo-pdf backend
    into the test suite. However, in all cases the output PDF files look
    fine when viewed with acroread. It looks like all of the problems
    could be fixed by using cairo_rectangle;cairo_fill along with
    CAIRO_EXTEND_PAD when drawing images with cairo inside poppler.
    
    However, I'm not yet filing a bug against poppler and disabling these
    tests because we need to _implement_ CAIRO_EXTEND_PAD before we can
    tell poppler to start using it.

diff-tree 1e21220f0e2540e3befa66e4764f75589d0eef82 (from 875e32178e5d990a09f3c41262d890888035f04f)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Wed Sep 5 22:53:43 2007 +0930

    Create meta-surface source image with same content type as the
    meta-surface

diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index e9635a2..5fcbf26 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -192,9 +192,9 @@ _cairo_meta_surface_acquire_source_image
     cairo_meta_surface_t *surface = abstract_surface;
     cairo_surface_t *image;
 
-    image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-					surface->width_pixels,
-					surface->height_pixels);
+    image = _cairo_image_surface_create_with_content (surface->content,
+						      surface->width_pixels,
+						      surface->height_pixels);
 
     status = _cairo_meta_surface_replay (&surface->base, image);
     if (status) {
diff-tree 875e32178e5d990a09f3c41262d890888035f04f (from d24f019101dd014983aeb0bf186fe2011694e2ed)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Wed Sep 5 22:51:13 2007 +0930

    Eliminate unclipped CLEAR from meta-surface playback
    
    The optimization that avoids replaying commands prior to an unclipped
    CLEAR operation now starts playback from the first command after the
    CLEAR. This avoids the need to handle the unclipped CLEAR in the PDF
    surface.

diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index 63f6a9c..e9635a2 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -251,12 +251,6 @@ _cairo_meta_surface_paint (void			*abstr
     cairo_meta_surface_t *meta = abstract_surface;
     cairo_command_paint_t *command;
 
-    /* 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)
-	meta->replay_start_idx = meta->commands.num_elements;
-
     command = malloc (sizeof (cairo_command_paint_t));
     if (command == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
@@ -273,6 +267,12 @@ _cairo_meta_surface_paint (void			*abstr
     if (status)
 	goto CLEANUP_SOURCE;
 
+    /* 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)
+	meta->replay_start_idx = meta->commands.num_elements;
+
     return CAIRO_STATUS_SUCCESS;
 
   CLEANUP_SOURCE:
diff-tree d24f019101dd014983aeb0bf186fe2011694e2ed (from b85032584b32af968dc8d8a0fcfc9f3e1d2770a0)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Wed Sep 5 22:26:16 2007 +0930

    Add support for PDF meta-surface patterns

diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index 9479284..34846d2 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -284,16 +284,7 @@ static cairo_boilerplate_target_t target
       _cairo_boilerplate_pdf_surface_write_to_png,
       _cairo_boilerplate_pdf_cleanup,
       NULL, TRUE },
-
-    /* XXX: We expect type image here only due to a limitation in
-     * the current PDF/meta-surface code. A PDF surface is
-     * "naturally" COLOR_ALPHA, so the COLOR-only variant goes
-     * through create_similar in _cairo_boilerplate_pdf_create_surface which results
-     * in the similar surface being used as a source. We do not yet
-     * have source support for PDF/meta-surfaces, so the
-     * create_similar path for all paginated surfaces currently
-     * returns an image surface.*/
-    { "pdf", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR, 0,
+    { "pdf", CAIRO_INTERNAL_SURFACE_TYPE_META, CAIRO_CONTENT_COLOR, 0,
       _cairo_boilerplate_pdf_create_surface,
       _cairo_boilerplate_pdf_surface_write_to_png,
       _cairo_boilerplate_pdf_cleanup,
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index afbd30f..f738a6d 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -39,6 +39,7 @@
 #include "cairo-analysis-surface-private.h"
 #include "cairo-paginated-private.h"
 #include "cairo-region-private.h"
+#include "cairo-meta-surface-private.h"
 
 typedef struct {
     cairo_surface_t base;
@@ -57,6 +58,33 @@ typedef struct {
 } cairo_analysis_surface_t;
 
 static cairo_int_status_t
+_cairo_analysis_surface_analyze_meta_surface_pattern (cairo_analysis_surface_t *surface,
+						      cairo_pattern_t	       *pattern)
+{
+    cairo_surface_pattern_t *surface_pattern;
+    cairo_surface_t *meta_surface;
+    cairo_surface_t *analysis;
+    cairo_status_t status;
+
+    assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
+    surface_pattern = (cairo_surface_pattern_t *) pattern;
+    assert (_cairo_surface_is_meta (surface_pattern->surface));
+
+    meta_surface = surface_pattern->surface;
+    analysis = _cairo_analysis_surface_create (surface->target,
+					       surface->width, surface->height);
+    if (analysis == NULL)
+	return CAIRO_STATUS_NO_MEMORY;
+
+    status = _cairo_meta_surface_replay_analyze_meta_pattern (meta_surface, analysis);
+    if (status == CAIRO_STATUS_SUCCESS)
+	    status = analysis->status;
+    cairo_surface_destroy (analysis);
+
+    return status;
+}
+
+static cairo_int_status_t
 _cairo_analysis_surface_add_operation  (cairo_analysis_surface_t *surface,
 					cairo_rectangle_int_t    *rect,
 					cairo_int_status_t        backend_status)
@@ -186,6 +214,10 @@ _cairo_analysis_surface_paint (void			*a
 	backend_status = (*surface->target->backend->paint) (surface->target, op,
                                                              source);
 
+    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
+	backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
+									       source);
+
     status = _cairo_surface_get_extents (&surface->base, &extents);
     if (status)
 	return status;
@@ -222,6 +254,28 @@ _cairo_analysis_surface_mask (void		*abs
 	backend_status = (*surface->target->backend->mask) (surface->target, op,
                                                             source, mask);
 
+    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) {
+	if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	    cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
+	    if (_cairo_surface_is_meta (surface_pattern->surface))
+		backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
+										       source);
+	    if (backend_status != CAIRO_STATUS_SUCCESS &&
+		backend_status != CAIRO_INT_STATUS_IMAGE_FALLBACK)
+		return backend_status;
+	}
+
+	if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	    cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
+	    if (_cairo_surface_is_meta (surface_pattern->surface))
+		backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
+										       mask);
+	    if (backend_status != CAIRO_STATUS_SUCCESS &&
+		backend_status != CAIRO_INT_STATUS_IMAGE_FALLBACK)
+		return backend_status;
+	}
+    }
+
     status = _cairo_surface_get_extents (&surface->base, &extents);
     if (status)
 	return status;
@@ -273,6 +327,10 @@ _cairo_analysis_surface_stroke (void			*
 							      ctm, ctm_inverse,
 							      tolerance, antialias);
 
+    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
+	backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
+									       source);
+
     status = _cairo_surface_get_extents (&surface->base, &extents);
     if (status)
 	return status;
@@ -342,6 +400,10 @@ _cairo_analysis_surface_fill (void			*ab
 						    source, path, fill_rule,
 						    tolerance, antialias);
 
+    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
+	backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
+									       source);
+
     status = _cairo_surface_get_extents (&surface->base, &extents);
     if (status)
 	return status;
@@ -409,6 +471,10 @@ _cairo_analysis_surface_show_glyphs (voi
 							   glyphs, num_glyphs,
 							   scaled_font);
 
+    if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
+	backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
+									       source);
+
     status = _cairo_surface_get_extents (&surface->base, &extents);
     if (status)
 	return status;
diff --git a/src/cairo-meta-surface-private.h b/src/cairo-meta-surface-private.h
index b6d5730..a3360e6 100644
--- a/src/cairo-meta-surface-private.h
+++ b/src/cairo-meta-surface-private.h
@@ -164,6 +164,10 @@ _cairo_meta_surface_replay (cairo_surfac
 			    cairo_surface_t *target);
 
 cairo_private cairo_status_t
+_cairo_meta_surface_replay_analyze_meta_pattern (cairo_surface_t *surface,
+						 cairo_surface_t *target);
+
+cairo_private cairo_status_t
 _cairo_meta_surface_replay_and_create_regions (cairo_surface_t *surface,
 					       cairo_surface_t *target);
 cairo_private cairo_status_t
diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index d8f5064..63f6a9c 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -59,6 +59,12 @@
 #include "cairo-meta-surface-private.h"
 #include "cairo-clip-private.h"
 
+typedef enum {
+    CAIRO_META_REPLAY,
+    CAIRO_META_CREATE_REGIONS,
+    CAIRO_META_ANALYZE_META_PATTERN
+} cairo_meta_replay_type_t;
+
 static const cairo_surface_backend_t cairo_meta_surface_backend;
 
 /* Currently all meta surfaces do have a size which should be passed
@@ -650,7 +656,7 @@ _cairo_command_get_path (cairo_command_t
 static cairo_status_t
 _cairo_meta_surface_replay_internal (cairo_surface_t	     *surface,
 				     cairo_surface_t	     *target,
-				     cairo_bool_t	      create_regions,
+				     cairo_meta_replay_type_t type,
 				     cairo_meta_region_type_t region)
 {
     cairo_meta_surface_t *meta;
@@ -675,7 +681,7 @@ _cairo_meta_surface_replay_internal (cai
     for (i = meta->replay_start_idx; i < num_elements; i++) {
 	command = elements[i];
 
-	if (!create_regions && region != CAIRO_META_REGION_ALL) {
+	if (type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL) {
 	    if (command->header.region != region)
 		continue;
         }
@@ -834,7 +840,7 @@ _cairo_meta_surface_replay_internal (cai
 	if (dev_path == &path_copy)
 	    _cairo_path_fixed_fini (&path_copy);
 
-	if (create_regions) {
+	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) {
@@ -842,6 +848,12 @@ _cairo_meta_surface_replay_internal (cai
 		status = CAIRO_STATUS_SUCCESS;
 	    }
 	}
+
+	if (type == CAIRO_META_ANALYZE_META_PATTERN) {
+	    if (status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
+		status = CAIRO_STATUS_SUCCESS;
+	}
+
 	if (status)
 	    break;
     }
@@ -855,7 +867,20 @@ cairo_status_t
 _cairo_meta_surface_replay (cairo_surface_t *surface,
 			    cairo_surface_t *target)
 {
-    return _cairo_meta_surface_replay_internal (surface, target, FALSE, CAIRO_META_REGION_ALL);
+    return _cairo_meta_surface_replay_internal (surface,
+						target,
+						CAIRO_META_REPLAY,
+						CAIRO_META_REGION_ALL);
+}
+
+cairo_status_t
+_cairo_meta_surface_replay_analyze_meta_pattern (cairo_surface_t *surface,
+						 cairo_surface_t *target)
+{
+    return _cairo_meta_surface_replay_internal (surface,
+						target,
+						CAIRO_META_ANALYZE_META_PATTERN,
+						CAIRO_META_REGION_ALL);
 }
 
 /* Replay meta to surface. When the return status of each operation is
@@ -868,7 +893,10 @@ cairo_status_t
 _cairo_meta_surface_replay_and_create_regions (cairo_surface_t *surface,
 					       cairo_surface_t *target)
 {
-    return _cairo_meta_surface_replay_internal (surface, target, TRUE, CAIRO_META_REGION_ALL);
+    return _cairo_meta_surface_replay_internal (surface,
+						target,
+						CAIRO_META_CREATE_REGIONS,
+						CAIRO_META_REGION_ALL);
 }
 
 cairo_status_t
@@ -876,5 +904,8 @@ _cairo_meta_surface_replay_region (cairo
 				   cairo_surface_t          *target,
 				   cairo_meta_region_type_t  region)
 {
-    return _cairo_meta_surface_replay_internal (surface, target, FALSE, region);
+    return _cairo_meta_surface_replay_internal (surface,
+						target,
+						CAIRO_META_REPLAY,
+						region);
 }
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 3d9ebba..1bca1f3 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -45,6 +45,7 @@
 #include "cairo-paginated-private.h"
 #include "cairo-path-fixed-private.h"
 #include "cairo-output-stream-private.h"
+#include "cairo-meta-surface-private.h"
 
 #include <time.h>
 #include <zlib.h>
@@ -235,6 +236,9 @@ _cairo_pdf_surface_open_stream (cairo_pd
 static cairo_status_t
 _cairo_pdf_surface_close_stream (cairo_pdf_surface_t	*surface);
 
+static cairo_status_t
+_cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
+
 static void
 _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface);
 
@@ -1036,6 +1040,15 @@ _cairo_pdf_group_element_array_finish (c
     }
 }
 
+static cairo_surface_t *
+_cairo_pdf_surface_create_similar (void			*abstract_surface,
+				   cairo_content_t	 content,
+				   int			 width,
+				   int			 height)
+{
+    return _cairo_meta_surface_create (content, width, height);
+}
+
 static cairo_status_t
 _cairo_pdf_surface_finish (void *abstract_surface)
 {
@@ -1308,14 +1321,120 @@ _cairo_pdf_surface_emit_image (cairo_pdf
     _cairo_output_stream_printf (surface->output, "\r\n");
     status = _cairo_pdf_surface_close_stream (surface);
 
- CLEANUP_COMPRESSED:
+CLEANUP_COMPRESSED:
     free (compressed);
- CLEANUP_RGB:
+CLEANUP_RGB:
     free (rgb);
- CLEANUP:
+CLEANUP:
     return status;
 }
 
+static cairo_status_t
+_cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t     *surface,
+				       cairo_surface_pattern_t *pattern,
+				       cairo_pdf_resource_t    *resource,
+				       int                     *width,
+				       int                     *height)
+{
+    cairo_surface_t *pat_surface;
+    cairo_surface_attributes_t pat_attr;
+    cairo_image_surface_t *image;
+    void *image_extra;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+    status = _cairo_pattern_acquire_surface ((cairo_pattern_t *)pattern,
+					     (cairo_surface_t *)surface,
+					     0, 0, -1, -1,
+					     &pat_surface, &pat_attr);
+    if (status)
+	return status;
+
+    status = _cairo_surface_acquire_source_image (pat_surface, &image, &image_extra);
+    if (status)
+	goto BAIL2;
+
+    status = _cairo_pdf_surface_emit_image (surface, image, resource);
+    if (status)
+	goto BAIL;
+
+    *width = image->width;
+    *height = image->height;
+
+BAIL:
+    _cairo_surface_release_source_image (pat_surface, image, image_extra);
+BAIL2:
+    _cairo_pattern_release_surface ((cairo_pattern_t *)pattern, pat_surface, &pat_attr);
+
+    return status;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
+				      cairo_surface_t      *meta_surface,
+				      cairo_pdf_resource_t *resource)
+{
+    cairo_array_t group;
+    cairo_array_t *old_group;
+    double old_width, old_height;
+    cairo_matrix_t old_cairo_to_pdf;
+    cairo_rectangle_int16_t meta_extents;
+    cairo_status_t status;
+    int alpha = 0;
+
+    status = _cairo_surface_get_extents (meta_surface, &meta_extents);
+    if (status)
+	return status;
+
+    _cairo_pdf_surface_resume_content_stream (surface);
+    _cairo_pdf_surface_stop_content_stream (surface);
+
+    _cairo_array_init (&group, sizeof (cairo_pdf_group_element_t));
+    old_group = surface->current_group;
+    old_width = surface->width;
+    old_height = surface->height;
+    old_cairo_to_pdf = surface->cairo_to_pdf;
+    surface->current_group = &group;
+    surface->width = meta_extents.width;
+    surface->height = meta_extents.height;
+    cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, -1, 0, surface->height);
+
+    _cairo_pdf_surface_start_content_stream (surface);
+
+    if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
+	status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
+	if (status)
+	    return status;
+	_cairo_output_stream_printf (surface->output,
+				     "q /a%d gs 0 0 0 rg 0 0 %f %f re f Q\r\n",
+				     alpha,
+				     surface->width,
+				     surface->height);
+    }
+
+    status = _cairo_meta_surface_replay (meta_surface, &surface->base);
+    if (status)
+	return status;
+    _cairo_pdf_surface_stop_content_stream (surface);
+
+    _cairo_pdf_surface_open_group (surface);
+    _cairo_pdf_surface_write_group_list (surface, &group);
+    _cairo_pdf_surface_close_group (surface, resource);
+
+    surface->current_group = old_group;
+    surface->width = old_width;
+    surface->height = old_height;
+    surface->cairo_to_pdf = old_cairo_to_pdf;
+
+    _cairo_pdf_surface_start_content_stream (surface);
+
+    _cairo_pdf_group_element_array_finish (&group);
+    _cairo_array_fini (&group);
+
+    _cairo_pdf_surface_pause_content_stream (surface);
+
+    return 0;
+}
+
 static void
 _cairo_pdf_surface_emit_solid_pattern (cairo_pdf_surface_t   *surface,
 				       cairo_solid_pattern_t *pattern)
@@ -1331,81 +1450,84 @@ _cairo_pdf_surface_emit_solid_pattern (c
 
 static cairo_status_t
 _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	 *surface,
-                                         cairo_surface_pattern_t *pattern)
+					 cairo_surface_pattern_t *pattern)
 {
     cairo_pdf_resource_t stream;
-    cairo_surface_t *pat_surface;
-    cairo_surface_attributes_t pat_attr;
-    cairo_image_surface_t *image;
-    void *image_extra;
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
-    cairo_pdf_resource_t image_resource = {0}; /* squelch bogus compiler warning */
+    cairo_pdf_resource_t pattern_resource = {0}; /* squelch bogus compiler warning */
     cairo_matrix_t cairo_p2d, pdf_p2d;
     cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base);
     double xstep, ystep;
-    cairo_rectangle_int_t surface_extents;
-
-    /* XXX: Should do something clever here for PDF source surfaces ? */
+    cairo_rectangle_int16_t surface_extents;
+    int pattern_width = 0; /* squelch bogus compiler warning */
+    int pattern_height = 0; /* squelch bogus compiler warning */
 
     _cairo_pdf_surface_pause_content_stream (surface);
 
-    status = _cairo_pattern_acquire_surface ((cairo_pattern_t *)pattern,
-					     (cairo_surface_t *)surface,
-					     0, 0, -1, -1,
-					     &pat_surface, &pat_attr);
+    if (_cairo_surface_is_meta (pattern->surface)) {
+	cairo_surface_t *meta_surface = pattern->surface;
+	cairo_rectangle_int16_t pattern_extents;
+
+	status = _cairo_pdf_surface_emit_meta_surface (surface,
+						       meta_surface,
+						       &pattern_resource);
+	status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
+	if (status)
+	    return status;
+	pattern_width = pattern_extents.width;
+	pattern_height = pattern_extents.height;
+    } else {
+	status = _cairo_pdf_surface_emit_image_surface (surface,
+							pattern,
+							&pattern_resource,
+							&pattern_width,
+							&pattern_height);
+    }
     if (status)
 	return status;
 
-    status = _cairo_surface_acquire_source_image (pat_surface, &image, &image_extra);
-    if (status)
-	goto BAIL2;
-
-    status = _cairo_pdf_surface_emit_image (surface, image, &image_resource);
-    if (status)
-	goto BAIL;
-
     status = _cairo_surface_get_extents (&surface->base, &surface_extents);
     if (status)
-	goto BAIL;
+	return status;
 
     switch (extend) {
-    /* We implement EXTEND_PAD like EXTEND_NONE for now */
+	/* We implement EXTEND_PAD like EXTEND_NONE for now */
     case CAIRO_EXTEND_PAD:
     case CAIRO_EXTEND_NONE:
-        {
-	    /* In PS/PDF, (as far as I can tell), all patterns are
-	     * repeating. So we support cairo's EXTEND_NONE semantics
-	     * by setting the repeat step size to a size large enough
-	     * to guarantee that no more than a single occurrence will
-	     * be visible.
-	     *
-	     * First, map the surface extents into pattern space (since
-	     * xstep and ystep are in pattern space).  Then use an upper
-	     * bound on the length of the diagonal of the pattern image
-	     * and the surface as repeat size.  This guarantees to never
-	     * repeat visibly.
-	     */
-	    double x1 = 0.0, y1 = 0.0;
-	    double x2 = surface->width, y2 = surface->height;
-	    _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
-						  &x1, &y1, &x2, &y2,
-						  NULL);
-
-	    /* Rather than computing precise bounds of the union, just
-	     * add the surface extents unconditionally. We only
-	     * required an answer that's large enough, we don't really
-	     * care if it's not as tight as possible.*/
-	    xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
-				  image->width + image->height);
-	}
-	break;
+    {
+	/* In PS/PDF, (as far as I can tell), all patterns are
+	 * repeating. So we support cairo's EXTEND_NONE semantics
+	 * by setting the repeat step size to a size large enough
+	 * to guarantee that no more than a single occurrence will
+	 * be visible.
+	 *
+	 * First, map the surface extents into pattern space (since
+	 * xstep and ystep are in pattern space).  Then use an upper
+	 * bound on the length of the diagonal of the pattern image
+	 * and the surface as repeat size.  This guarantees to never
+	 * repeat visibly.
+	 */
+	double x1 = 0.0, y1 = 0.0;
+	double x2 = surface->width, y2 = surface->height;
+	_cairo_matrix_transform_bounding_box (&pattern->base.matrix,
+					      &x1, &y1, &x2, &y2,
+					      NULL);
+
+	/* Rather than computing precise bounds of the union, just
+	 * add the surface extents unconditionally. We only
+	 * required an answer that's large enough, we don't really
+	 * care if it's not as tight as possible.*/
+	xstep = ystep = ceil ((x2 - x1) + (y2 - y1) +
+			      pattern_width + pattern_height);
+    }
+    break;
     case CAIRO_EXTEND_REPEAT:
     case CAIRO_EXTEND_REFLECT:
-	xstep = image->width;
-	ystep = image->height;
+	xstep = pattern_width;
+	ystep = pattern_height;
 	break;
-    /* All the rest (if any) should have been analyzed away, so this
-     * case should be unreachable. */
+	/* All the rest (if any) should have been analyzed away, so this
+	 * case should be unreachable. */
     default:
 	ASSERT_NOT_REACHED;
 	xstep = 0;
@@ -1448,11 +1570,11 @@ _cairo_pdf_surface_emit_surface_pattern 
     cairo_matrix_translate (&pdf_p2d, 0.0, surface_extents.height);
     cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
     cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d);
-    cairo_matrix_translate (&pdf_p2d, 0.0, image->height);
+    cairo_matrix_translate (&pdf_p2d, 0.0, pattern_height);
     cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
 
     stream = _cairo_pdf_surface_open_stream (surface,
-                                             FALSE,
+					     FALSE,
 					     "   /BBox [0 0 %d %d]\r\n"
 					     "   /XStep %f\r\n"
 					     "   /YStep %f\r\n"
@@ -1460,23 +1582,29 @@ _cairo_pdf_surface_emit_surface_pattern 
 					     "   /TilingType 1\r\n"
 					     "   /PaintType 1\r\n"
 					     "   /Matrix [ %f %f %f %f %f %f ]\r\n"
-					     "   /Resources << /XObject << /res%d %d 0 R >> >>\r\n",
-					     image->width, image->height,
+					     "   /Resources << /XObject << /x%d %d 0 R >> >>\r\n",
+					     pattern_width, pattern_height,
 					     xstep, ystep,
 					     pdf_p2d.xx, pdf_p2d.yx,
 					     pdf_p2d.xy, pdf_p2d.yy,
 					     pdf_p2d.x0, pdf_p2d.y0,
-					     image_resource.id,
-					     image_resource.id);
+					     pattern_resource.id,
+					     pattern_resource.id);
 
-    _cairo_output_stream_printf (surface->output,
-				 "q %d 0 0 %d 0 0 cm /res%d Do Q\r\n",
-				 image->width, image->height,
-				 image_resource.id);
+    if (_cairo_surface_is_meta (pattern->surface)) {
+	_cairo_output_stream_printf (surface->output,
+				     "/x%d Do\r\n",
+				     pattern_resource.id);
+    } else {
+	_cairo_output_stream_printf (surface->output,
+				     "q %d 0 0 %d 0 0 cm /x%d Do Q\r\n",
+				     pattern_width, pattern_height,
+				     pattern_resource.id);
+    }
 
     status = _cairo_pdf_surface_close_stream (surface);
     if (status)
-	goto BAIL;
+	return status;
 
     _cairo_pdf_surface_resume_content_stream (surface);
 
@@ -1485,11 +1613,6 @@ _cairo_pdf_surface_emit_surface_pattern 
     surface->emitted_pattern.pattern = stream;
     surface->emitted_pattern.alpha = 1.0;
 
- BAIL:
-    _cairo_surface_release_source_image (pat_surface, image, image_extra);
- BAIL2:
-    _cairo_pattern_release_surface ((cairo_pattern_t *)pattern, pat_surface, &pat_attr);
-
     return status;
 }
 
@@ -3436,6 +3559,9 @@ _surface_pattern_supported (cairo_surfac
 {
     cairo_extend_t extend;
 
+    if (_cairo_surface_is_meta (pattern->surface))
+	return TRUE;
+
     if (pattern->surface->backend->acquire_source_image == NULL)
 	return FALSE;
 
@@ -3524,8 +3650,14 @@ _cairo_pdf_surface_analyze_operation (ca
     if (! _pattern_supported (pattern))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    if (op == CAIRO_OPERATOR_OVER)
+    if (op == CAIRO_OPERATOR_OVER) {
+	if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	    cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
+	    if ( _cairo_surface_is_meta (surface_pattern->surface))
+	    return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
+	}
 	return CAIRO_STATUS_SUCCESS;
+    }
 
     /* The SOURCE operator is only supported for the fallback images. */
     if (op == CAIRO_OPERATOR_SOURCE &&
@@ -4089,7 +4221,7 @@ _cairo_pdf_surface_set_paginated_mode (v
 
 static const cairo_surface_backend_t cairo_pdf_surface_backend = {
     CAIRO_SURFACE_TYPE_PDF,
-    NULL, /* create_similar */
+    _cairo_pdf_surface_create_similar,
     _cairo_pdf_surface_finish,
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index e63dccd..45491f7 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -136,7 +136,8 @@ typedef enum _cairo_int_status {
     CAIRO_INT_STATUS_NOTHING_TO_DO,
     CAIRO_INT_STATUS_CACHE_EMPTY,
     CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY,
-    CAIRO_INT_STATUS_IMAGE_FALLBACK
+    CAIRO_INT_STATUS_IMAGE_FALLBACK,
+    CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN,
 } cairo_int_status_t;
 
 typedef enum _cairo_internal_surface_type {


More information about the cairo-commit mailing list