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

Adrian Johnson ajohnson at kemper.freedesktop.org
Sat Jun 13 08:13:55 PDT 2009


 src/cairo-pdf-surface-private.h |   21 +
 src/cairo-pdf-surface.c         |  532 ++++++++++++++++++++++++++--------------
 2 files changed, 372 insertions(+), 181 deletions(-)

New commits:
commit 1798bdd322e0d25147195198bf0c5e9506c61a15
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat Jun 13 22:47:41 2009 +0930

    Fix PDF pattern embedding
    
    The PDF snapshot cow patch was reusing a previously emitted surface
    pattern if the surface unique id matched the current surface. This
    resulted in incorrect output as the new pattern may have a different
    pattern matrix.
    
    This patch fixes the PDF backend to always emit a new pattern but
    re-use previously emitted image or metasurface XObjects.

diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index e64b78a..5aedcd0 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -60,19 +60,27 @@ typedef struct _cairo_pdf_group_resources {
     cairo_array_t fonts;
 } cairo_pdf_group_resources_t;
 
-typedef struct _cairo_pdf_pattern_entry {
+typedef struct _cairo_pdf_source_surface_entry {
     cairo_hash_entry_t base;
     unsigned int id;
-    cairo_pdf_resource_t pattern_res;
-    cairo_pdf_resource_t gstate_res;
-} cairo_pdf_pattern_entry_t;
+    cairo_bool_t interpolate;
+    cairo_pdf_resource_t surface_res;
+    int width;
+    int height;
+} cairo_pdf_source_surface_entry_t;
+
+typedef struct _cairo_pdf_source_surface {
+    cairo_surface_t *surface;
+    cairo_pdf_source_surface_entry_t *hash_entry;
+} cairo_pdf_source_surface_t;
 
 typedef struct _cairo_pdf_pattern {
     double width;
     double height;
     cairo_rectangle_int_t extents;
     cairo_pattern_t *pattern;
-    cairo_pdf_pattern_entry_t *hash_entry;
+    cairo_pdf_resource_t pattern_res;
+    cairo_pdf_resource_t gstate_res;
 } cairo_pdf_pattern_t;
 
 typedef enum _cairo_pdf_operation {
@@ -125,7 +133,8 @@ struct _cairo_pdf_surface {
     cairo_array_t rgb_linear_functions;
     cairo_array_t alpha_linear_functions;
     cairo_array_t page_patterns;
-    cairo_hash_table_t *all_patterns;
+    cairo_array_t page_surfaces;
+    cairo_hash_table_t *all_surfaces;
     cairo_array_t smask_groups;
     cairo_array_t knockout_group;
 
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 2918523..961325b 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -195,7 +195,7 @@ static cairo_status_t
 _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface);
 
 static cairo_bool_t
-_cairo_pdf_pattern_equal (const void *key_a, const void *key_b);
+_cairo_pdf_source_surface_equal (const void *key_a, const void *key_b);
 
 static const cairo_surface_backend_t cairo_pdf_surface_backend;
 static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend;
@@ -275,8 +275,9 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
     _cairo_array_init (&surface->knockout_group, sizeof (cairo_pdf_resource_t));
 
     _cairo_array_init (&surface->page_patterns, sizeof (cairo_pdf_pattern_t));
-    surface->all_patterns = _cairo_hash_table_create (_cairo_pdf_pattern_equal);
-    if (unlikely (surface->all_patterns == NULL)) {
+    _cairo_array_init (&surface->page_surfaces, sizeof (cairo_pdf_source_surface_t));
+    surface->all_surfaces = _cairo_hash_table_create (_cairo_pdf_source_surface_equal);
+    if (unlikely (surface->all_surfaces == NULL)) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	goto BAIL0;
     }
@@ -336,7 +337,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
 BAIL2:
     _cairo_scaled_font_subsets_destroy (surface->font_subsets);
 BAIL1:
-    _cairo_hash_table_destroy (surface->all_patterns);
+    _cairo_hash_table_destroy (surface->all_surfaces);
 BAIL0:
     _cairo_array_fini (&surface->objects);
     free (surface);
@@ -582,6 +583,7 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
 {
     int i, size;
     cairo_pdf_pattern_t *pattern;
+    cairo_pdf_source_surface_t *src_surface;
     cairo_pdf_smask_group_t *group;
 
     size = _cairo_array_num_elements (&surface->page_patterns);
@@ -591,6 +593,13 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
     }
     _cairo_array_truncate (&surface->page_patterns, 0);
 
+    size = _cairo_array_num_elements (&surface->page_surfaces);
+    for (i = 0; i < size; i++) {
+	src_surface = (cairo_pdf_source_surface_t *) _cairo_array_index (&surface->page_surfaces, i);
+	cairo_surface_destroy (src_surface->surface);
+    }
+    _cairo_array_truncate (&surface->page_surfaces, 0);
+
     size = _cairo_array_num_elements (&surface->smask_groups);
     for (i = 0; i < size; i++) {
 	_cairo_array_copy_element (&surface->smask_groups, i, &group);
@@ -873,20 +882,175 @@ _cairo_pdf_surface_add_smask_group (cairo_pdf_surface_t     *surface,
 }
 
 static cairo_bool_t
-_cairo_pdf_pattern_equal (const void *key_a, const void *key_b)
+_cairo_pdf_source_surface_equal (const void *key_a, const void *key_b)
 {
-    const cairo_pdf_pattern_entry_t *a = key_a;
-    const cairo_pdf_pattern_entry_t *b = key_b;
+    const cairo_pdf_source_surface_entry_t *a = key_a;
+    const cairo_pdf_source_surface_entry_t *b = key_b;
 
-    return a->id == b->id;
+    return (a->id == b->id) && (a->interpolate == b->interpolate);
 }
 
 static void
-_cairo_pdf_pattern_init_key (cairo_pdf_pattern_entry_t *key)
+_cairo_pdf_source_surface_init_key (cairo_pdf_source_surface_entry_t *key)
 {
     key->base.hash = key->id;
 }
 
+static cairo_int_status_t
+_get_jpx_image_info (cairo_surface_t	 	 *source,
+		     cairo_image_info_t 	 *info,
+		     const unsigned char 	**mime_data,
+		     unsigned int 		 *mime_data_length)
+{
+    cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JP2,
+				 mime_data, mime_data_length);
+    if (*mime_data == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    return _cairo_image_info_get_jpx_info (info, *mime_data, *mime_data_length);
+}
+
+static cairo_int_status_t
+_get_jpeg_image_info (cairo_surface_t	 *source,
+		      cairo_image_info_t 	 *info,
+		      const unsigned char 	**mime_data,
+		      unsigned int 		 *mime_data_length)
+{
+    cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
+				 mime_data, mime_data_length);
+    if (*mime_data == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    return _cairo_image_info_get_jpeg_info (info, *mime_data, *mime_data_length);
+}
+
+static cairo_status_t
+_get_source_surface_size (cairo_surface_t         *source,
+			  int                     *width,
+			  int                     *height)
+{
+    cairo_image_surface_t *image;
+    void *image_extra;
+    cairo_status_t status;
+    cairo_image_info_t info;
+    const unsigned char *mime_data;
+    unsigned int mime_data_length;
+
+    if (_cairo_surface_is_meta (source)) {
+	cairo_rectangle_int_t extents;
+
+	status = _cairo_surface_get_extents (source, &extents);
+	if (unlikely (status))
+	    return status;
+
+	*width = extents.width;
+	*height = extents.height;
+
+	return status;
+    }
+
+    status = _get_jpx_image_info (source, &info, &mime_data, &mime_data_length);
+    if (status == CAIRO_STATUS_SUCCESS) {
+	*width = info.width;
+	*height = info.height;
+    } else if (_cairo_status_is_error (status)) {
+	return status;
+    }
+
+    status = _get_jpeg_image_info (source, &info, &mime_data, &mime_data_length);
+    if (status == CAIRO_STATUS_SUCCESS) {
+	*width = info.width;
+	*height = info.height;
+    } else if (_cairo_status_is_error (status)) {
+	return status;
+    }
+
+    status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
+    if (unlikely (status))
+	return status;
+
+    *width = image->width;
+    *height = image->height;
+
+    _cairo_surface_release_source_image (source, image, image_extra);
+
+    return status;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t	*surface,
+				       cairo_surface_t		*source,
+				       cairo_filter_t		 filter,
+				       cairo_pdf_resource_t	*surface_res,
+				       int                      *width,
+				       int                      *height)
+{
+    cairo_pdf_source_surface_t src_surface;
+    cairo_pdf_source_surface_entry_t surface_key;
+    cairo_pdf_source_surface_entry_t *surface_entry;
+    cairo_status_t status;
+    cairo_bool_t interpolate;
+
+    switch (filter) {
+    case CAIRO_FILTER_GOOD:
+    case CAIRO_FILTER_BEST:
+    case CAIRO_FILTER_BILINEAR:
+	interpolate = TRUE;
+	break;
+    case CAIRO_FILTER_FAST:
+    case CAIRO_FILTER_NEAREST:
+    case CAIRO_FILTER_GAUSSIAN:
+	interpolate = FALSE;
+	break;
+    }
+
+    surface_key.id  = source->unique_id;
+    surface_key.interpolate = interpolate;
+    _cairo_pdf_source_surface_init_key (&surface_key);
+    surface_entry = _cairo_hash_table_lookup (surface->all_surfaces, &surface_key.base);
+    if (surface_entry) {
+	*surface_res = surface_entry->surface_res;
+	*width = surface_entry->width;
+	*height = surface_entry->height;
+
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    surface_entry = malloc (sizeof (cairo_pdf_source_surface_entry_t));
+    if (surface_entry == NULL)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    surface_entry->id = surface_key.id;
+    surface_entry->interpolate = interpolate;
+    _cairo_pdf_source_surface_init_key (surface_entry);
+
+    src_surface.hash_entry = surface_entry;
+    src_surface.surface = cairo_surface_reference (source);
+    surface_entry->surface_res = _cairo_pdf_surface_new_object (surface);
+    if (surface_entry->surface_res.id == 0) {
+	free (surface_entry);
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    status = _get_source_surface_size (source, &surface_entry->width,
+				       &surface_entry->height);
+
+    status = _cairo_array_append (&surface->page_surfaces, &src_surface);
+    if (unlikely (status)) {
+	free (surface_entry);
+	return status;
+    }
+
+    status = _cairo_hash_table_insert (surface->all_surfaces,
+				       &surface_entry->base);
+
+    *surface_res = surface_entry->surface_res;
+    *width = surface_entry->width;
+    *height = surface_entry->height;
+
+    return status;
+}
+
 static cairo_status_t
 _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t		*surface,
 				    const cairo_pattern_t	*pattern,
@@ -895,8 +1059,6 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t		*surface,
 				    cairo_pdf_resource_t	*gstate_res)
 {
     cairo_pdf_pattern_t pdf_pattern;
-    cairo_pdf_pattern_entry_t pdf_pattern_key;
-    cairo_pdf_pattern_entry_t *pdf_pattern_entry;
     cairo_status_t status;
 
     /* Solid colors are emitted into the content stream */
@@ -906,7 +1068,6 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t		*surface,
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    pdf_pattern_key.id = 0;
     if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
         pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
     {
@@ -926,50 +1087,24 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t		*surface,
 	}
     }
 
-    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
-	cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern;
-
-	pdf_pattern_key.id  = surface->surface->unique_id;
-    }
-
-    _cairo_pdf_pattern_init_key (&pdf_pattern_key);
-    if (pdf_pattern_key.base.hash != 0 &&
-	(pdf_pattern_entry = _cairo_hash_table_lookup (surface->all_patterns,
-						       &pdf_pattern_key.base)))
-    {
-	*pattern_res = pdf_pattern_entry->pattern_res;
-	*gstate_res = pdf_pattern_entry->gstate_res;
-
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    pdf_pattern_entry = malloc (sizeof (cairo_pdf_pattern_entry_t));
-    if (pdf_pattern_entry == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    pdf_pattern_entry->id = pdf_pattern_key.id;
-    _cairo_pdf_pattern_init_key (pdf_pattern_entry);
-
-    pdf_pattern.hash_entry = pdf_pattern_entry;
-
     status = _cairo_pattern_create_copy (&pdf_pattern.pattern, pattern);
     if (unlikely (status))
 	return status;
 
-    pdf_pattern_entry->pattern_res = _cairo_pdf_surface_new_object (surface);
-    if (pdf_pattern_entry->pattern_res.id == 0) {
+    pdf_pattern.pattern_res = _cairo_pdf_surface_new_object (surface);
+    if (pdf_pattern.pattern_res.id == 0) {
 	cairo_pattern_destroy (pdf_pattern.pattern);
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
 
-    pdf_pattern_entry->gstate_res.id = 0;
+    pdf_pattern.gstate_res.id = 0;
 
     /* gradient patterns require an smask object to implement transparency */
     if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
         pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
         if (_cairo_pattern_is_opaque (pattern) == FALSE) {
-            pdf_pattern_entry->gstate_res = _cairo_pdf_surface_new_object (surface);
-	    if (pdf_pattern_entry->gstate_res.id == 0) {
+            pdf_pattern.gstate_res = _cairo_pdf_surface_new_object (surface);
+	    if (pdf_pattern.gstate_res.id == 0) {
 		cairo_pattern_destroy (pdf_pattern.pattern);
 		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	    }
@@ -987,8 +1122,8 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t		*surface,
 	pdf_pattern.extents.height = surface->height;
     }
 
-    *pattern_res = pdf_pattern_entry->pattern_res;
-    *gstate_res = pdf_pattern_entry->gstate_res;
+    *pattern_res = pdf_pattern.pattern_res;
+    *gstate_res = pdf_pattern.gstate_res;
 
     status = _cairo_array_append (&surface->page_patterns, &pdf_pattern);
     if (unlikely (status)) {
@@ -996,13 +1131,6 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t		*surface,
 	return status;
     }
 
-    if (pdf_pattern_entry->base.hash != 0) {
-	status = _cairo_hash_table_insert (surface->all_patterns,
-					   &pdf_pattern_entry->base);
-	if (unlikely (status))
-	    return status;
-    }
-
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -1267,6 +1395,7 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
 
 static cairo_status_t
 _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t  *surface,
+					cairo_pdf_resource_t *resource,
 					cairo_bool_t          is_form)
 {
     cairo_status_t status;
@@ -1281,7 +1410,7 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t  *surface,
     if (is_form) {
 	status =
 	    _cairo_pdf_surface_open_stream (surface,
-					    NULL,
+					    resource,
 					    surface->compress_content,
 					    "   /Type /XObject\n"
 					    "   /Subtype /Form\n"
@@ -1298,7 +1427,7 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t  *surface,
     } else {
 	status =
 	    _cairo_pdf_surface_open_stream (surface,
-					    NULL,
+					    resource,
 					    surface->compress_content,
 					    NULL);
     }
@@ -1350,13 +1479,13 @@ _cairo_pdf_surface_create_similar (void			*abstract_surface,
 }
 
 static void
-_cairo_pdf_pattern_entry_pluck (void *entry, void *closure)
+_cairo_pdf_source_surface_entry_pluck (void *entry, void *closure)
 {
-    cairo_pdf_pattern_entry_t *pattern_entry = entry;
+    cairo_pdf_source_surface_entry_t *surface_entry = entry;
     cairo_hash_table_t *patterns = closure;
 
-    _cairo_hash_table_remove (patterns, &pattern_entry->base);
-    free (pattern_entry);
+    _cairo_hash_table_remove (patterns, &surface_entry->base);
+    free (surface_entry);
 }
 
 static cairo_status_t
@@ -1439,10 +1568,11 @@ _cairo_pdf_surface_finish (void *abstract_surface)
     _cairo_array_fini (&surface->rgb_linear_functions);
     _cairo_array_fini (&surface->alpha_linear_functions);
     _cairo_array_fini (&surface->page_patterns);
-    _cairo_hash_table_foreach (surface->all_patterns,
-			       _cairo_pdf_pattern_entry_pluck,
-			       surface->all_patterns);
-    _cairo_hash_table_destroy (surface->all_patterns);
+    _cairo_array_fini (&surface->page_surfaces);
+    _cairo_hash_table_foreach (surface->all_surfaces,
+			       _cairo_pdf_source_surface_entry_pluck,
+			       surface->all_surfaces);
+    _cairo_hash_table_destroy (surface->all_surfaces);
     _cairo_array_fini (&surface->smask_groups);
     _cairo_array_fini (&surface->fonts);
     _cairo_array_fini (&surface->knockout_group);
@@ -1494,7 +1624,7 @@ _cairo_pdf_surface_has_fallback_images (void		*abstract_surface,
     cairo_pdf_surface_t *surface = abstract_surface;
 
     surface->has_fallback_images = has_fallbacks;
-    status = _cairo_pdf_surface_open_content_stream (surface, has_fallbacks);
+    status = _cairo_pdf_surface_open_content_stream (surface, NULL, has_fallbacks);
     if (unlikely (status))
 	return status;
 
@@ -1614,7 +1744,7 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t	*surface,
 static cairo_status_t
 _cairo_pdf_surface_emit_image (cairo_pdf_surface_t     *surface,
                                cairo_image_surface_t   *image,
-                               cairo_pdf_resource_t    *image_ret,
+                               cairo_pdf_resource_t    *image_res,
 			       cairo_filter_t           filter)
 {
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
@@ -1712,7 +1842,7 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t     *surface,
 
     if (need_smask)
 	status = _cairo_pdf_surface_open_stream (surface,
-						 NULL,
+						 image_res,
 						 TRUE,
 						 IMAGE_DICTIONARY
 						 "   /SMask %d 0 R\n",
@@ -1721,7 +1851,7 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t     *surface,
 						 smask.id);
     else
 	status = _cairo_pdf_surface_open_stream (surface,
-						 NULL,
+						 image_res,
 						 TRUE,
 						 IMAGE_DICTIONARY,
 						 image->width, image->height,
@@ -1731,7 +1861,8 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t     *surface,
 
 #undef IMAGE_DICTIONARY
 
-    *image_ret = surface->pdf_stream.self;
+    if (image_res == NULL)
+	*image_res = surface->pdf_stream.self;
     _cairo_output_stream_write (surface->output, rgb, rgb_size);
     status = _cairo_pdf_surface_close_stream (surface);
 
@@ -1744,9 +1875,7 @@ CLEANUP:
 static cairo_int_status_t
 _cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t   *surface,
 				   cairo_surface_t	 *source,
-				   cairo_pdf_resource_t  *res,
-				   int                   *width,
-				   int                   *height)
+				   cairo_pdf_resource_t   res)
 {
     cairo_status_t status;
     const unsigned char *mime_data;
@@ -1766,7 +1895,7 @@ _cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t   *surface,
 	return status;
 
     status = _cairo_pdf_surface_open_stream (surface,
-					     NULL,
+					     &res,
 					     FALSE,
 					     "   /Type /XObject\n"
 					     "   /Subtype /Image\n"
@@ -1779,23 +1908,17 @@ _cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t   *surface,
     if (status)
 	return status;
 
-    *res = surface->pdf_stream.self;
     _cairo_output_stream_write (surface->output, mime_data, mime_data_length);
     _cairo_output_stream_printf (surface->output, "\n");
     status = _cairo_pdf_surface_close_stream (surface);
 
-    *width = info.width;
-    *height = info.height;
-
     return status;
 }
 
 static cairo_int_status_t
 _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t   *surface,
 				    cairo_surface_t	  *source,
-				    cairo_pdf_resource_t  *res,
-				    int                   *width,
-				    int                   *height)
+				    cairo_pdf_resource_t   res)
 {
     cairo_status_t status;
     const unsigned char *mime_data;
@@ -1817,7 +1940,7 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t   *surface,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     status = _cairo_pdf_surface_open_stream (surface,
-					     NULL,
+					     &res,
 					     FALSE,
 					     "   /Type /XObject\n"
 					     "   /Subtype /Image\n"
@@ -1833,90 +1956,129 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t   *surface,
     if (unlikely (status))
 	return status;
 
-    *res = surface->pdf_stream.self;
     _cairo_output_stream_write (surface->output, mime_data, mime_data_length);
     _cairo_output_stream_printf (surface->output, "\n");
     status = _cairo_pdf_surface_close_stream (surface);
 
-    *width = info.width;
-    *height = info.height;
-
     return status;
 }
 
 static cairo_status_t
 _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t     *surface,
-				       cairo_pdf_pattern_t     *pdf_pattern,
-				       cairo_pdf_resource_t    *resource,
-				       int                     *width,
-				       int                     *height,
-				       int 		       *origin_x,
-				       int 		       *origin_y)
+				       cairo_surface_t         *source,
+				       cairo_pdf_resource_t     resource,
+				       cairo_bool_t 		interpolate)
 {
     cairo_image_surface_t *image;
-    cairo_surface_t *pad_image;
     void *image_extra;
     cairo_status_t status;
-    cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern;
-    int x = 0;
-    int y = 0;
 
-    status = _cairo_pdf_surface_emit_jpx_image (surface, pattern->surface,
-						resource, width, height);
+    status = _cairo_pdf_surface_emit_jpx_image (surface, source, resource);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return status;
 
-    status = _cairo_pdf_surface_emit_jpeg_image (surface, pattern->surface,
-						 resource, width, height);
+    status = _cairo_pdf_surface_emit_jpeg_image (surface, source, resource);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return status;
 
-    status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
+    status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
     if (unlikely (status))
 	return status;
 
+    status = _cairo_pdf_surface_emit_image (surface, image,
+					    &resource, interpolate);
+    if (unlikely (status))
+	goto BAIL;
+
+BAIL:
+    _cairo_surface_release_source_image (source, image, image_extra);
+
+    return status;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_emit_padded_image_surface (cairo_pdf_surface_t     *surface,
+					      cairo_pdf_pattern_t     *pdf_pattern,
+					      cairo_pdf_resource_t    *resource,
+					      int                     *width,
+					      int                     *height,
+					      int                     *origin_x,
+					      int                     *origin_y)
+{
+    cairo_image_surface_t *image;
+    cairo_surface_t *pad_image;
+    void *image_extra;
+    cairo_status_t status;
+    cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern;
+    int x = 0;
+    int y = 0;
+    cairo_bool_t interpolate;
+
+    status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
+    if (unlikely (status))
+        return status;
+
     pad_image = &image->base;
     if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD) {
-	cairo_box_t box;
-	cairo_rectangle_int_t rect;
-	cairo_surface_pattern_t pad_pattern;
-
-	/* get the operation extents in pattern space */
-	_cairo_box_from_rectangle (&box, &pdf_pattern->extents);
-	_cairo_matrix_transform_bounding_box_fixed (&pattern->base.matrix, &box, NULL);
-	_cairo_box_round_to_rectangle (&box, &rect);
-	x = -rect.x;
-	y = -rect.y;
-
-	pad_image = _cairo_image_surface_create_with_content (pattern->surface->content,
-							      rect.width,
-							      rect.height);
-	if (pad_image->status) {
-	    status = pad_image->status;
-	    goto BAIL;
-	}
+        cairo_box_t box;
+        cairo_rectangle_int_t rect;
+        cairo_surface_pattern_t pad_pattern;
+
+        /* get the operation extents in pattern space */
+        _cairo_box_from_rectangle (&box, &pdf_pattern->extents);
+        _cairo_matrix_transform_bounding_box_fixed (&pattern->base.matrix, &box, NULL);
+        _cairo_box_round_to_rectangle (&box, &rect);
+        x = -rect.x;
+        y = -rect.y;
+
+        pad_image = _cairo_image_surface_create_with_content (pattern->surface->content,
+                                                              rect.width,
+                                                              rect.height);
+        if (pad_image->status) {
+            status = pad_image->status;
+            goto BAIL;
+        }
 
-	_cairo_pattern_init_for_surface (&pad_pattern, &image->base);
-	cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y);
-	pad_pattern.base.extend = CAIRO_EXTEND_PAD;
-	status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
-					   &pad_pattern.base,
-					   NULL,
-					   pad_image,
-					   0, 0,
-					   0, 0,
-					   0, 0,
-					   rect.width,
-					   rect.height);
-	_cairo_pattern_fini (&pad_pattern.base);
-	if (unlikely (status))
-	    goto BAIL;
+        _cairo_pattern_init_for_surface (&pad_pattern, &image->base);
+        cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y);
+        pad_pattern.base.extend = CAIRO_EXTEND_PAD;
+        status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
+                                           &pad_pattern.base,
+                                           NULL,
+                                           pad_image,
+                                           0, 0,
+                                           0, 0,
+                                           0, 0,
+                                           rect.width,
+                                           rect.height);
+        _cairo_pattern_fini (&pad_pattern.base);
+        if (unlikely (status))
+            goto BAIL;
+    }
+
+    switch (pdf_pattern->pattern->filter) {
+    case CAIRO_FILTER_GOOD:
+    case CAIRO_FILTER_BEST:
+    case CAIRO_FILTER_BILINEAR:
+	interpolate = TRUE;
+	break;
+    case CAIRO_FILTER_FAST:
+    case CAIRO_FILTER_NEAREST:
+    case CAIRO_FILTER_GAUSSIAN:
+	interpolate = FALSE;
+	break;
+    }
+
+    *resource = _cairo_pdf_surface_new_object (surface);
+    if (resource->id == 0) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto BAIL;
     }
 
     status = _cairo_pdf_surface_emit_image (surface, (cairo_image_surface_t *)pad_image,
-					    resource, pattern->base.filter);
+                                            resource, interpolate);
     if (unlikely (status))
-	goto BAIL;
+        goto BAIL;
 
     *width = ((cairo_image_surface_t *)pad_image)->width;
     *height = ((cairo_image_surface_t *)pad_image)->height;
@@ -1925,17 +2087,18 @@ _cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t     *surface,
 
 BAIL:
     if (pad_image != &image->base)
-	cairo_surface_destroy (pad_image);
+        cairo_surface_destroy (pad_image);
 
     _cairo_surface_release_source_image (pattern->surface, image, image_extra);
 
     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_pdf_resource_t  resource)
 {
     double old_width, old_height;
     cairo_paginated_mode_t old_paginated_mode;
@@ -1961,11 +2124,10 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
      */
     surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER;
     _cairo_pdf_group_resources_clear (&surface->resources);
-    status = _cairo_pdf_surface_open_content_stream (surface, TRUE);
+    status = _cairo_pdf_surface_open_content_stream (surface, &resource, TRUE);
     if (unlikely (status))
 	return status;
 
-    *resource = surface->content;
     if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
 	status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
 	if (unlikely (status))
@@ -1999,12 +2161,28 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t  *surface,
 }
 
 static cairo_status_t
+_cairo_pdf_surface_emit_surface (cairo_pdf_surface_t        *surface,
+				 cairo_pdf_source_surface_t *src_surface)
+{
+    if (_cairo_surface_is_meta (src_surface->surface)) {
+	return _cairo_pdf_surface_emit_meta_surface (surface,
+						     src_surface->surface,
+						     src_surface->hash_entry->surface_res);
+    } else {
+	return _cairo_pdf_surface_emit_image_surface (surface,
+						      src_surface->surface,
+						      src_surface->hash_entry->surface_res,
+						      src_surface->hash_entry->interpolate);
+    }
+}
+
+static cairo_status_t
 _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	*surface,
 					 cairo_pdf_pattern_t	*pdf_pattern)
 {
     cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern;
     cairo_status_t status;
-    cairo_pdf_resource_t pattern_resource = {0}; /* squelch bogus compiler warning */
+    cairo_pdf_resource_t pattern_resource = {0};
     cairo_matrix_t cairo_p2d, pdf_p2d;
     cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base);
     double xstep, ystep;
@@ -2016,33 +2194,28 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	*surface,
     int bbox_x, bbox_y;
     char draw_surface[200];
 
-    if (_cairo_surface_is_meta (pattern->surface)) {
-	cairo_surface_t *meta_surface = pattern->surface;
-	cairo_rectangle_int_t pattern_extents;
-
-	status = _cairo_pdf_surface_emit_meta_surface (surface,
-						       meta_surface,
-						       &pattern_resource);
-	if (unlikely (status))
-	    return status;
-
-	status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
-	if (unlikely (status))
-	    return status;
-
-	pattern_width = pattern_extents.width;
-	pattern_height = pattern_extents.height;
-    } else {
-	status = _cairo_pdf_surface_emit_image_surface (surface,
-							pdf_pattern,
+    if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD &&
+	 ! _cairo_surface_is_meta (pattern->surface))
+    {
+	status = _cairo_pdf_surface_emit_padded_image_surface (surface,
+							       pdf_pattern,
+							       &pattern_resource,
+							       &pattern_width,
+							       &pattern_height,
+							       &origin_x,
+							       &origin_y);
+    }
+    else
+    {
+	status = _cairo_pdf_surface_add_source_surface (surface,
+							pattern->surface,
+							pdf_pattern->pattern->filter,
 							&pattern_resource,
 							&pattern_width,
-							&pattern_height,
-							&origin_x,
-							&origin_y);
-	if (unlikely (status))
-	    return status;
+							&pattern_height);
     }
+    if (unlikely (status))
+	return status;
 
     status = _cairo_surface_get_extents (&surface->base, &surface_extents);
     if (unlikely (status))
@@ -2138,9 +2311,9 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	*surface,
     cairo_matrix_translate (&pdf_p2d, 0.0, pattern_height);
     cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
 
-    _cairo_pdf_surface_update_object (surface, pdf_pattern->hash_entry->pattern_res);
+    _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
     status = _cairo_pdf_surface_open_stream (surface,
-				             &pdf_pattern->hash_entry->pattern_res,
+				             &pdf_pattern->pattern_res,
 					     FALSE,
 					     "   /PatternType 1\n"
 					     "   /BBox [0 0 %d %d]\n"
@@ -2755,7 +2928,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t    *surface,
 	}
     }
 
-    _cairo_pdf_surface_update_object (surface, pdf_pattern->hash_entry->pattern_res);
+    _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
     _cairo_output_stream_printf (surface->output,
                                  "%d 0 obj\n"
                                  "<< /Type /Pattern\n"
@@ -2767,7 +2940,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t    *surface,
                                  "         /Coords [ %f %f %f %f ]\n"
                                  "         /Domain [ %f %f ]\n"
                                  "         /Function %d 0 R\n",
-				 pdf_pattern->hash_entry->pattern_res.id,
+				 pdf_pattern->pattern_res.id,
                                  pat_to_pdf.xx, pat_to_pdf.yx,
                                  pat_to_pdf.xy, pat_to_pdf.yy,
                                  pat_to_pdf.x0, pat_to_pdf.y0,
@@ -2791,7 +2964,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t    *surface,
     if (alpha_function.id != 0) {
 	cairo_pdf_resource_t mask_resource;
 
-	assert (pdf_pattern->hash_entry->gstate_res.id != 0);
+	assert (pdf_pattern->gstate_res.id != 0);
 
         /* Create pattern for SMask. */
         mask_resource = _cairo_pdf_surface_new_object (surface);
@@ -2834,7 +3007,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t    *surface,
             return status;
 
 	status = cairo_pdf_surface_emit_transparency_group (surface,
-						            pdf_pattern->hash_entry->gstate_res,
+						            pdf_pattern->gstate_res,
 							    mask_resource);
 	if (unlikely (status))
 	    return status;
@@ -2878,7 +3051,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t    *surface,
     y2 = _cairo_fixed_to_double (pattern->c2.y);
     r2 = _cairo_fixed_to_double (pattern->r2);
 
-    _cairo_pdf_surface_update_object (surface, pdf_pattern->hash_entry->pattern_res);
+    _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
 
     _cairo_output_stream_printf (surface->output,
                                  "%d 0 obj\n"
@@ -2890,7 +3063,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t    *surface,
                                  "         /ColorSpace /DeviceRGB\n"
                                  "         /Coords [ %f %f %f %f %f %f ]\n"
                                  "         /Function %d 0 R\n",
-				 pdf_pattern->hash_entry->pattern_res.id,
+				 pdf_pattern->pattern_res.id,
                                  pat_to_pdf.xx, pat_to_pdf.yx,
                                  pat_to_pdf.xy, pat_to_pdf.yy,
                                  pat_to_pdf.x0, pat_to_pdf.y0,
@@ -2913,7 +3086,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t    *surface,
     if (alpha_function.id != 0) {
 	cairo_pdf_resource_t mask_resource;
 
-	assert (pdf_pattern->hash_entry->gstate_res.id != 0);
+	assert (pdf_pattern->gstate_res.id != 0);
 
 	/* Create pattern for SMask. */
         mask_resource = _cairo_pdf_surface_new_object (surface);
@@ -2951,7 +3124,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t    *surface,
                                      "endobj\n");
 
 	status = cairo_pdf_surface_emit_transparency_group (surface,
-						            pdf_pattern->hash_entry->gstate_res,
+						            pdf_pattern->gstate_res,
 							    mask_resource);
 	if (unlikely (status))
 	    return status;
@@ -4586,7 +4759,8 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface
 {
     cairo_pdf_pattern_t pattern;
     cairo_pdf_smask_group_t *group;
-    int pattern_index, group_index;
+    cairo_pdf_source_surface_t src_surface;
+    int pattern_index, group_index, surface_index;
     cairo_status_t status;
 
     /* Writing out PDF_MASK groups will cause additional smask groups
@@ -4598,6 +4772,7 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface
      */
     pattern_index = 0;
     group_index = 0;
+    surface_index = 0;
     while ((pattern_index < _cairo_array_num_elements (&surface->page_patterns)) ||
 	   (group_index < _cairo_array_num_elements (&surface->smask_groups)))
     {
@@ -4614,6 +4789,13 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface
 	    if (unlikely (status))
 		return status;
 	}
+
+	for (; surface_index < _cairo_array_num_elements (&surface->page_surfaces); surface_index++) {
+	    _cairo_array_copy_element (&surface->page_surfaces, surface_index, &src_surface);
+	    status = _cairo_pdf_surface_emit_surface (surface, &src_surface);
+	    if (unlikely (status))
+		return status;
+	}
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -4654,7 +4836,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, FALSE);
+	status = _cairo_pdf_surface_open_content_stream (surface, NULL, FALSE);
 	if (unlikely (status))
 	    return status;
 
@@ -4911,7 +5093,7 @@ _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
 	return status;
 
     _cairo_pdf_group_resources_clear (&surface->resources);
-    return _cairo_pdf_surface_open_content_stream (surface, TRUE);
+    return _cairo_pdf_surface_open_content_stream (surface, NULL, TRUE);
 }
 
 static cairo_int_status_t


More information about the cairo-commit mailing list