[cairo-commit] 3 commits - src/cairoint.h src/cairo-pattern.c src/cairo-pdf-surface.c src/cairo-pdf-surface-private.h src/cairo-types-private.h

Adrian Johnson ajohnson at kemper.freedesktop.org
Mon Sep 5 05:10:24 PDT 2011


 src/cairo-pattern.c             |   44 ++++++
 src/cairo-pdf-surface-private.h |    3 
 src/cairo-pdf-surface.c         |  258 ++++++++++++++++++++++++++--------------
 src/cairo-types-private.h       |    5 
 src/cairoint.h                  |    4 
 5 files changed, 225 insertions(+), 89 deletions(-)

New commits:
commit 42fecf37dc2e8f63fbe4c9560f224fe141c59f3b
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Sep 4 22:39:57 2011 +0930

    pdf: use ink extents in content stream XObjects

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 424d0b7..c475ddd 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1622,9 +1622,10 @@ _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_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_status_t status;
 
@@ -1636,21 +1637,25 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t  *surface,
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     if (is_form) {
+	assert (bbox != NULL);
+
 	status =
 	    _cairo_pdf_surface_open_stream (surface,
 					    resource,
 					    surface->compress_content,
 					    "   /Type /XObject\n"
 					    "   /Subtype /Form\n"
-					    "   /BBox [ 0 0 %f %f ]\n"
+					    "   /BBox [ %f %f %f %f ]\n"
 					    "   /Group <<\n"
 					    "      /Type /Group\n"
 					    "      /S /Transparency\n"
 					    "      /CS /DeviceRGB\n"
 					    "   >>\n"
 					    "   /Resources %d 0 R\n",
-					    surface->width,
-					    surface->height,
+					    bbox->p1.x,
+					    bbox->p1.y,
+					    bbox->p2.x,
+					    bbox->p2.y,
 					    surface->content_resources.id);
     } else {
 	status =
@@ -1845,9 +1850,14 @@ _cairo_pdf_surface_has_fallback_images (void		*abstract_surface,
 {
     cairo_status_t status;
     cairo_pdf_surface_t *surface = abstract_surface;
+    cairo_box_double_t bbox;
 
     surface->has_fallback_images = has_fallbacks;
-    status = _cairo_pdf_surface_open_content_stream (surface, NULL, has_fallbacks);
+    bbox.p1.x = 0;
+    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);
     if (unlikely (status))
 	return status;
 
@@ -2409,32 +2419,20 @@ BAIL:
 
 
 static cairo_status_t
-_cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t  *surface,
-					   cairo_surface_t      *source,
-					   cairo_pdf_resource_t  resource)
+_cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t        *surface,
+					   cairo_pdf_source_surface_t *pdf_source)
 {
     double old_width, old_height;
     cairo_paginated_mode_t old_paginated_mode;
     cairo_surface_clipper_t old_clipper;
-    cairo_rectangle_int_t recording_extents;
+    cairo_box_double_t bbox;
     cairo_int_status_t status;
     int alpha = 0;
+    cairo_surface_t *source = pdf_source->surface;
 
     if (_cairo_surface_is_snapshot (source))
 	source = _cairo_surface_snapshot_get_target (source);
 
-    if (! _cairo_surface_get_extents (source, &recording_extents)) {
-	cairo_box_t bbox;
-
-	status =
-	    _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) source,
-					       &bbox, NULL);
-	if (unlikely (status))
-	    return status;
-
-	_cairo_box_round_to_rectangle (&bbox, &recording_extents);
-    }
-
     old_width = surface->width;
     old_height = surface->height;
     old_paginated_mode = surface->paginated_mode;
@@ -2443,15 +2441,16 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t  *surface,
 				 _cairo_pdf_surface_clipper_intersect_clip_path);
 
     _cairo_pdf_surface_set_size_internal (surface,
-					  recording_extents.width,
-					  recording_extents.height);
+					  pdf_source->hash_entry->width,
+					  pdf_source->hash_entry->height);
     /* Patterns are emitted after fallback images. The paginated mode
      * needs to be set to _RENDER while the recording surface is replayed
      * back to this surface.
      */
     surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER;
     _cairo_pdf_group_resources_clear (&surface->resources);
-    status = _cairo_pdf_surface_open_content_stream (surface, &resource, TRUE);
+    _get_bbox_from_extents (pdf_source->hash_entry->height, &pdf_source->hash_entry->extents, &bbox);
+    status = _cairo_pdf_surface_open_content_stream (surface, &bbox, &pdf_source->hash_entry->surface_res, TRUE);
     if (unlikely (status))
 	return status;
 
@@ -2496,6 +2495,7 @@ _cairo_pdf_surface_emit_recording_subsurface (cairo_pdf_surface_t  *surface,
     double old_width, old_height;
     cairo_paginated_mode_t old_paginated_mode;
     cairo_surface_clipper_t old_clipper;
+    cairo_box_double_t bbox;
     cairo_int_status_t status;
     int alpha = 0;
 
@@ -2515,7 +2515,8 @@ _cairo_pdf_surface_emit_recording_subsurface (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, &resource, TRUE);
+    _get_bbox_from_extents (extents->height, extents, &bbox);
+    status = _cairo_pdf_surface_open_content_stream (surface, &bbox, &resource, TRUE);
     if (unlikely (status))
 	return status;
 
@@ -2564,8 +2565,7 @@ _cairo_pdf_surface_emit_surface (cairo_pdf_surface_t        *surface,
 								 src_surface->hash_entry->surface_res);
 	} else {
 	    return _cairo_pdf_surface_emit_recording_surface (surface,
-							      src_surface->surface,
-							      src_surface->hash_entry->surface_res);
+							      src_surface);
 	}
     } else {
 	return _cairo_pdf_surface_emit_image_surface (surface,
@@ -5555,7 +5555,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, FALSE);
+	status = _cairo_pdf_surface_open_content_stream (surface, NULL, NULL, FALSE);
 	if (unlikely (status))
 	    return status;
 
@@ -5808,6 +5808,7 @@ _cairo_pdf_surface_operation_supported (cairo_pdf_surface_t  *surface,
 static cairo_int_status_t
 _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
 {
+    cairo_box_double_t bbox;
     cairo_status_t status;
 
     status = _cairo_pdf_surface_close_content_stream (surface);
@@ -5819,7 +5820,11 @@ _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, NULL, TRUE);
+    bbox.p1.x = 0;
+    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);
 }
 
 /* A PDF stencil mask is an A1 mask used with the current color */
commit d1f146b54f2c13c8786e389eb4d731dfc33d8bb7
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Sep 4 20:52:02 2011 +0930

    pdf: use ink extents for pattern bbox

diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index 64bf7f0..139c1c6 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -74,6 +74,7 @@ typedef struct _cairo_pdf_source_surface_entry {
     cairo_pdf_resource_t surface_res;
     int width;
     int height;
+    cairo_rectangle_int_t extents;
 } cairo_pdf_source_surface_entry_t;
 
 typedef struct _cairo_pdf_source_surface {
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index b4d48a4..424d0b7 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1105,10 +1105,10 @@ _get_jpeg_image_info (cairo_surface_t		 *source,
 static cairo_int_status_t
 _get_source_surface_size (cairo_surface_t         *source,
 			  int                     *width,
-			  int                     *height)
+			  int                     *height,
+			  cairo_rectangle_int_t   *extents)
 {
     cairo_int_status_t status;
-    cairo_rectangle_int_t extents;
     cairo_image_info_t info;
     const unsigned char *mime_data;
     unsigned long mime_data_length;
@@ -1117,33 +1117,39 @@ _get_source_surface_size (cairo_surface_t         *source,
 	if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
 	     cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
 
-	    *width  = sub->extents.width;
-	    *height = sub->extents.height;
-
+	     *extents = sub->extents;
+	     *width  = extents->width;
+	     *height = extents->height;
 	} else {
-	    cairo_recording_surface_t *recording_surface;
-	    cairo_box_t bbox;
+	    cairo_rectangle_int_t surf_extents;
+	    double x, y, w, h;
+	    cairo_bool_t bounded;
 
 	    if (_cairo_surface_is_snapshot (source))
 		source = _cairo_surface_snapshot_get_target (source);
 
-	    recording_surface = (cairo_recording_surface_t *) source;
-	    status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
-	    if (unlikely (status))
-		return status;
-
-	    _cairo_box_round_to_rectangle (&bbox, &extents);
-
-	    *width = extents.width;
-	    *height = extents.height;
+	    cairo_recording_surface_ink_extents (source, &x, &y,&w, &h);
+	    extents->x = floor (x);
+	    extents->y = floor (y);
+	    extents->width = ceil (x + w) - extents->x;
+	    extents->height = ceil (y + h) - extents->y;
+	    bounded = _cairo_surface_get_extents (source, &surf_extents);
+	    *width = surf_extents.width;
+	    *height = surf_extents.height;
 	}
+
 	return CAIRO_STATUS_SUCCESS;
     }
 
+    extents->x = 0;
+    extents->y = 0;
+
     status = _get_jpx_image_info (source, &info, &mime_data, &mime_data_length);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
 	*width = info.width;
 	*height = info.height;
+	extents->width = info.width;
+	extents->height = info.height;
 	return status;
     }
 
@@ -1151,14 +1157,16 @@ _get_source_surface_size (cairo_surface_t         *source,
     if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
 	*width = info.width;
 	*height = info.height;
+	extents->width = info.width;
+	extents->height = info.height;
 	return status;
     }
 
-    if (! _cairo_surface_get_extents (source, &extents))
+    if (! _cairo_surface_get_extents (source, extents))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    *width = extents.width;
-    *height = extents.height;
+    *width = extents->width;
+    *height = extents->height;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1170,7 +1178,8 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t	*surface,
 				       cairo_bool_t              mask,
 				       cairo_pdf_resource_t	*surface_res,
 				       int                      *width,
-				       int                      *height)
+				       int                      *height,
+				       cairo_rectangle_int_t    *extents)
 {
     cairo_pdf_source_surface_t src_surface;
     cairo_pdf_source_surface_entry_t surface_key;
@@ -1205,6 +1214,7 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t	*surface,
 	*surface_res = surface_entry->surface_res;
 	*width = surface_entry->width;
 	*height = surface_entry->height;
+	*extents = surface_entry->extents;
 
 	return CAIRO_STATUS_SUCCESS;
     }
@@ -1243,8 +1253,10 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t	*surface,
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
 
-    status = _get_source_surface_size (source, &surface_entry->width,
-				       &surface_entry->height);
+    status = _get_source_surface_size (source,
+				       &surface_entry->width,
+				       &surface_entry->height,
+				       &surface_entry->extents);
 
     status = _cairo_array_append (&surface->page_surfaces, &src_surface);
     if (unlikely (status)) {
@@ -1259,6 +1271,7 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t	*surface,
     *surface_res = surface_entry->surface_res;
     *width = surface_entry->width;
     *height = surface_entry->height;
+    *extents = surface_entry->extents;
 
     return status;
 }
@@ -2573,12 +2586,13 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	*surface,
     cairo_matrix_t cairo_p2d, pdf_p2d;
     cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base);
     double xstep, ystep;
+    cairo_rectangle_int_t pattern_extents;
     int pattern_width = 0; /* squelch bogus compiler warning */
     int pattern_height = 0; /* squelch bogus compiler warning */
     int origin_x = 0; /* squelch bogus compiler warning */
     int origin_y = 0; /* squelch bogus compiler warning */
-    int bbox_x, bbox_y;
     char draw_surface[200];
+    cairo_box_double_t     bbox;
 
     if (pattern->base.extend == CAIRO_EXTEND_PAD &&
 	pattern->surface->type != CAIRO_SURFACE_TYPE_RECORDING)
@@ -2590,6 +2604,10 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	*surface,
 							       &pattern_height,
 							       &origin_x,
 							       &origin_y);
+	pattern_extents.x = 0;
+	pattern_extents.y = 0;
+	pattern_extents.width = pattern_width;
+	pattern_extents.height = pattern_height;
     }
     else
     {
@@ -2599,13 +2617,12 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	*surface,
 							FALSE,
 							&pattern_resource,
 							&pattern_width,
-							&pattern_height);
+							&pattern_height,
+							&pattern_extents);
     }
     if (unlikely (status))
 	return status;
 
-    bbox_x = pattern_width;
-    bbox_y = pattern_height;
     switch (extend) {
     case CAIRO_EXTEND_PAD:
     case CAIRO_EXTEND_NONE:
@@ -2641,10 +2658,12 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	*surface,
 	ystep = pattern_height;
 	break;
     case CAIRO_EXTEND_REFLECT:
-	bbox_x = pattern_width*2;
-	bbox_y = pattern_height*2;
-	xstep = bbox_x;
-	ystep = bbox_y;
+	pattern_extents.x = 0;
+	pattern_extents.y = 0;
+	pattern_extents.width = pattern_width*2;
+	pattern_extents.height = pattern_height*2;
+	xstep = pattern_width*2;
+	ystep = pattern_height*2;
 	break;
 	/* All the rest (if any) should have been analyzed away, so this
 	 * case should be unreachable. */
@@ -2691,19 +2710,20 @@ _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);
 
+    _get_bbox_from_extents (pattern_height, &pattern_extents, &bbox);
     _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res);
     status = _cairo_pdf_surface_open_stream (surface,
 				             &pdf_pattern->pattern_res,
 					     FALSE,
 					     "   /PatternType 1\n"
-					     "   /BBox [0 0 %d %d]\n"
+					     "   /BBox [ %f %f %f %f ]\n"
 					     "   /XStep %f\n"
 					     "   /YStep %f\n"
 					     "   /TilingType 1\n"
 					     "   /PaintType 1\n"
 					     "   /Matrix [ %f %f %f %f %f %f ]\n"
 					     "   /Resources << /XObject << /x%d %d 0 R >> >>\n",
-					     bbox_x, bbox_y,
+					     bbox.p1.x, bbox.p1.y, bbox.p2.x, bbox.p2.y,
 					     xstep, ystep,
 					     pdf_p2d.xx, pdf_p2d.yx,
 					     pdf_p2d.xy, pdf_p2d.yy,
@@ -3648,6 +3668,7 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t     *surface,
     cairo_matrix_t cairo_p2d, pdf_p2d;
     cairo_status_t status;
     int alpha;
+    cairo_rectangle_int_t extents;
 
     status = _cairo_pdf_surface_add_source_surface (surface,
 						    source->surface,
@@ -3655,7 +3676,8 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t     *surface,
 						    mask,
 						    &surface_res,
 						    &width,
-						    &height);
+						    &height,
+						    &extents);
     if (unlikely (status))
 	return status;
 
@@ -5500,6 +5522,7 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
     _cairo_pdf_group_resources_clear (&surface->resources);
     if (surface->has_fallback_images) {
 	cairo_rectangle_int_t extents;
+	cairo_box_double_t    bbox;
 
 	extents.x = 0;
 	extents.y = 0;
commit 37a22669d80cf970dab3aa3e7a8ec673c1462342
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Sep 4 20:43:07 2011 +0930

    pdf: use ink extents for smask bbox
    
    There are some inkscape bugs reporting very slow rendering of inkscape
    generated PDFs (inkscape uses cairo for PDF output). These bugs are
    caused by cairo specifying a page sized bounding box in XObjects and
    Patterns. PDF renderers usually use the BBox as the image size when
    compositing. As PDFs generated from SVG tends to use a lot of XObjects
    and Patterns this can lead to very long rendering times.
    
    These three patches tighten up all the BBoxes in PDF output.

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 3438454..19aa978 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -4376,6 +4376,50 @@ _cairo_pattern_get_extents (const cairo_pattern_t         *pattern,
     return;
 }
 
+/**
+ * _cairo_pattern_get_ink_extents:
+ *
+ * Return the "target-space" inked extents of @pattern in @extents.
+ **/
+void
+_cairo_pattern_get_ink_extents (const cairo_pattern_t         *pattern,
+				cairo_rectangle_int_t         *extents)
+{
+    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE &&
+	pattern->extend == CAIRO_EXTEND_NONE)
+    {
+	const cairo_surface_pattern_t *surface_pattern =
+	    (const cairo_surface_pattern_t *) pattern;
+	cairo_surface_t *surface = surface_pattern->surface;
+
+	if (surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
+	    cairo_matrix_t imatrix;
+	    double x1, y1, x2, y2, width, height;
+	    cairo_status_t status;
+
+	    cairo_recording_surface_ink_extents (surface, &x1, &y1, &width, &height);
+	    imatrix = pattern->matrix;
+	    status = cairo_matrix_invert (&imatrix);
+	    /* cairo_pattern_set_matrix ensures the matrix is invertible */
+	    assert (status == CAIRO_STATUS_SUCCESS);
+
+	    x2 = x1 + width;
+	    y2 = y1 + height;
+	    _cairo_matrix_transform_bounding_box (&imatrix,
+						  &x1, &y1, &x2, &y2,
+						  NULL);
+	    x1 = floor (x1);
+	    y1 = floor (y1);
+	    x2 = ceil (x2);
+	    y2 = ceil (y2);
+	    extents->x = x1; extents->width  = x2 - x1;
+	    extents->y = y1; extents->height = y2 - y1;
+	    return;
+	}
+    }
+
+    return _cairo_pattern_get_extents (pattern, extents);
+}
 
 static unsigned long
 _cairo_solid_pattern_hash (unsigned long hash,
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index dd1c77c..64bf7f0 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -101,6 +101,7 @@ typedef enum _cairo_pdf_operation {
 typedef struct _cairo_pdf_smask_group {
     double		  width;
     double		  height;
+    cairo_rectangle_int_t extents;
     cairo_pdf_resource_t  group_res;
     cairo_pdf_operation_t operation;
     cairo_pattern_t	 *source;
@@ -174,6 +175,7 @@ struct _cairo_pdf_surface {
 	cairo_output_stream_t *mem_stream;
 	cairo_output_stream_t *old_output;
 	cairo_pdf_resource_t   resource;
+	cairo_box_double_t     bbox;
 	cairo_bool_t is_knockout;
     } group_stream;
 
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 9f15aee..b4d48a4 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -992,7 +992,8 @@ _cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t         *surface,
 }
 
 static cairo_pdf_smask_group_t *
-_cairo_pdf_surface_create_smask_group (cairo_pdf_surface_t	*surface)
+_cairo_pdf_surface_create_smask_group (cairo_pdf_surface_t	    *surface,
+				       const cairo_rectangle_int_t  *extents)
 {
     cairo_pdf_smask_group_t	*group;
 
@@ -1010,6 +1011,15 @@ _cairo_pdf_surface_create_smask_group (cairo_pdf_surface_t	*surface)
     }
     group->width = surface->width;
     group->height = surface->height;
+    if (extents != NULL) {
+	group->extents = *extents;
+    } else {
+	group->extents.x = 0;
+	group->extents.y = 0;
+	group->extents.width = surface->width;
+	group->extents.height = surface->height;
+    }
+    group->extents = *extents;
 
     return group;
 }
@@ -1322,6 +1332,18 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t		*surface,
     return CAIRO_STATUS_SUCCESS;
 }
 
+/* Get BBox in PDF coordinates from extents in cairo coordinates */
+static void
+_get_bbox_from_extents (double                       surface_height,
+		       const cairo_rectangle_int_t *extents,
+		       cairo_box_double_t          *bbox)
+{
+    bbox->p1.x = extents->x;
+    bbox->p1.y = surface_height - (extents->y + extents->height);
+    bbox->p2.x = extents->x + extents->width;
+    bbox->p2.y = surface_height - extents->y;
+}
+
 static cairo_status_t
 _cairo_pdf_surface_open_stream (cairo_pdf_surface_t	*surface,
 				cairo_pdf_resource_t    *resource,
@@ -1443,7 +1465,8 @@ _cairo_pdf_surface_write_memory_stream (cairo_pdf_surface_t         *surface,
 					cairo_output_stream_t       *mem_stream,
 					cairo_pdf_resource_t         resource,
 					cairo_pdf_group_resources_t *resources,
-					cairo_bool_t                 is_knockout_group)
+					cairo_bool_t                 is_knockout_group,
+					const cairo_box_double_t    *bbox)
 {
     _cairo_pdf_surface_update_object (surface, resource);
 
@@ -1461,13 +1484,12 @@ _cairo_pdf_surface_write_memory_stream (cairo_pdf_surface_t         *surface,
 
     _cairo_output_stream_printf (surface->output,
 				 "   /Subtype /Form\n"
-				 "   /BBox [ 0 0 %f %f ]\n"
+				 "   /BBox [ %f %f %f %f ]\n"
 				 "   /Group <<\n"
 				 "      /Type /Group\n"
 				 "      /S /Transparency\n"
 				 "      /CS /DeviceRGB\n",
-				 surface->width,
-				 surface->height);
+				 bbox->p1.x, bbox->p1.y, bbox->p2.x, bbox->p2.y);
 
     if (is_knockout_group)
         _cairo_output_stream_printf (surface->output,
@@ -1487,8 +1509,9 @@ _cairo_pdf_surface_write_memory_stream (cairo_pdf_surface_t         *surface,
 }
 
 static cairo_status_t
-_cairo_pdf_surface_open_group (cairo_pdf_surface_t  *surface,
-			       cairo_pdf_resource_t *resource)
+_cairo_pdf_surface_open_group (cairo_pdf_surface_t         *surface,
+			       const cairo_box_double_t    *bbox,
+			       cairo_pdf_resource_t        *resource)
 {
     cairo_status_t status;
 
@@ -1523,16 +1546,18 @@ _cairo_pdf_surface_open_group (cairo_pdf_surface_t  *surface,
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
     surface->group_stream.is_knockout = FALSE;
+    surface->group_stream.bbox = *bbox;
 
     return status;
 }
 
 static cairo_status_t
-_cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t  *surface)
+_cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t         *surface,
+					const cairo_box_double_t    *bbox)
 {
     cairo_status_t status;
 
-    status = _cairo_pdf_surface_open_group (surface, NULL);
+    status = _cairo_pdf_surface_open_group (surface, bbox, NULL);
     if (unlikely (status))
 	return status;
 
@@ -1568,7 +1593,8 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
 					    surface->group_stream.mem_stream,
 					    surface->group_stream.resource,
 					    &surface->resources,
-					    surface->group_stream.is_knockout);
+					    surface->group_stream.is_knockout,
+					    &surface->group_stream.bbox);
     if (group)
 	*group = surface->group_stream.resource;
 
@@ -5182,9 +5208,11 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t	*surface,
     cairo_pdf_smask_group_t *smask_group;
     cairo_pdf_resource_t pattern_res, gstate_res;
     cairo_status_t status;
+    cairo_box_double_t bbox;
 
     /* Create mask group */
-    status = _cairo_pdf_surface_open_group (surface, NULL);
+    _get_bbox_from_extents (group->height, &group->extents, &bbox);
+    status = _cairo_pdf_surface_open_group (surface, &bbox, NULL);
     if (unlikely (status))
 	return status;
 
@@ -5196,10 +5224,12 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t	*surface,
 	return status;
 
     if (gstate_res.id != 0) {
-	smask_group = _cairo_pdf_surface_create_smask_group (surface);
+	smask_group = _cairo_pdf_surface_create_smask_group (surface, &group->extents);
 	if (unlikely (smask_group == NULL))
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
+	smask_group->width = group->width;
+	smask_group->height = group->height;
 	smask_group->operation = PDF_PAINT;
 	smask_group->source = cairo_pattern_reference (group->mask);
 	smask_group->source_res = pattern_res;
@@ -5227,8 +5257,11 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t	*surface,
 	    return status;
 
 	_cairo_output_stream_printf (surface->output,
-				     "0 0 %f %f re f\n",
-				     surface->width, surface->height);
+				     "%f %f %f %f re f\n",
+				     bbox.p1.x,
+				     bbox.p1.y,
+				     bbox.p2.x - bbox.p1.x,
+				     bbox.p2.y - bbox.p1.y);
 
 	status = _cairo_pdf_surface_unselect_pattern (surface);
 	if (unlikely (status))
@@ -5240,7 +5273,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t	*surface,
 	return status;
 
     /* Create source group */
-    status = _cairo_pdf_surface_open_group (surface, &group->source_res);
+    status = _cairo_pdf_surface_open_group (surface, &bbox, &group->source_res);
     if (unlikely (status))
 	return status;
 
@@ -5252,7 +5285,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t	*surface,
 	return status;
 
     if (gstate_res.id != 0) {
-	smask_group = _cairo_pdf_surface_create_smask_group (surface);
+	smask_group = _cairo_pdf_surface_create_smask_group (surface, &group->extents);
 	if (unlikely (smask_group == NULL))
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
@@ -5283,8 +5316,11 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t	*surface,
 	    return status;
 
 	_cairo_output_stream_printf (surface->output,
-				     "0 0 %f %f re f\n",
-				     surface->width, surface->height);
+				     "%f %f %f %f re f\n",
+				     bbox.p1.x,
+				     bbox.p1.y,
+				     bbox.p2.x - bbox.p1.x,
+				     bbox.p2.y - bbox.p1.y);
 
 	status = _cairo_pdf_surface_unselect_pattern (surface);
 	if (unlikely (status))
@@ -5333,6 +5369,7 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t     *surface,
 {
     double old_width, old_height;
     cairo_status_t status;
+    cairo_box_double_t bbox;
 
     old_width = surface->width;
     old_height = surface->height;
@@ -5346,7 +5383,8 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t     *surface,
 	goto RESTORE_SIZE;
     }
 
-    status = _cairo_pdf_surface_open_group (surface, &group->group_res);
+    _get_bbox_from_extents (group->height, &group->extents, &bbox);
+    status = _cairo_pdf_surface_open_group (surface, &bbox, &group->group_res);
     if (unlikely (status))
 	return status;
 
@@ -5461,7 +5499,14 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
 
     _cairo_pdf_group_resources_clear (&surface->resources);
     if (surface->has_fallback_images) {
-	status = _cairo_pdf_surface_open_knockout_group (surface);
+	cairo_rectangle_int_t extents;
+
+	extents.x = 0;
+	extents.y = 0;
+	extents.width = ceil (surface->width);
+	extents.height = ceil (surface->height);
+	_get_bbox_from_extents (surface->height, &extents, &bbox);
+	status = _cairo_pdf_surface_open_knockout_group (surface, &bbox);
 	if (unlikely (status))
 	    return status;
 
@@ -5899,7 +5944,7 @@ _cairo_pdf_surface_paint (void			*abstract_surface,
 	goto cleanup;
 
     if (gstate_res.id != 0) {
-	group = _cairo_pdf_surface_create_smask_group (surface);
+	group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded);
 	if (unlikely (group == NULL)) {
 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	    goto cleanup;
@@ -6001,6 +6046,13 @@ _cairo_pdf_surface_mask (void			*abstract_surface,
     assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
     assert (_cairo_pdf_surface_operation_supported (surface, op, mask, &extents.bounded));
 
+    /* get the accurate extents */
+    _cairo_pattern_get_ink_extents (source, &extents.source);
+    _cairo_pattern_get_ink_extents (mask, &extents.mask);
+    extents.bounded = extents.source;
+    if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
+	return CAIRO_STATUS_SUCCESS;
+
     status = _cairo_pdf_surface_set_clip (surface, &extents);
     if (unlikely (status))
 	goto cleanup;
@@ -6014,7 +6066,7 @@ _cairo_pdf_surface_mask (void			*abstract_surface,
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	goto cleanup;
 
-    group = _cairo_pdf_surface_create_smask_group (surface);
+    group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded);
     if (unlikely (group == NULL)) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	goto cleanup;
@@ -6139,7 +6191,7 @@ _cairo_pdf_surface_stroke (void			*abstract_surface,
 	goto cleanup;
 
     if (gstate_res.id != 0) {
-	group = _cairo_pdf_surface_create_smask_group (surface);
+	group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded);
 	if (unlikely (group == NULL)) {
 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	    goto cleanup;
@@ -6303,7 +6355,7 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
 	goto cleanup;
 
     if (gstate_res.id != 0) {
-	group = _cairo_pdf_surface_create_smask_group (surface);
+	group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded);
 	if (unlikely (group == NULL)) {
 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	    goto cleanup;
@@ -6587,7 +6639,7 @@ _cairo_pdf_surface_show_text_glyphs (void			*abstract_surface,
 	goto cleanup;
 
     if (gstate_res.id != 0) {
-	group = _cairo_pdf_surface_create_smask_group (surface);
+	group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded);
 	if (unlikely (group == NULL)) {
 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	    goto cleanup;
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 966cd8f..f18a20e 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -271,6 +271,11 @@ typedef struct _cairo_distance_double {
     double dy;
 } cairo_distance_double_t;
 
+typedef struct _cairo_box_double {
+    cairo_point_double_t p1;
+    cairo_point_double_t p2;
+} cairo_box_double_t;
+
 typedef struct _cairo_line {
     cairo_point_t p1;
     cairo_point_t p2;
diff --git a/src/cairoint.h b/src/cairoint.h
index df2071b..5ae8b7a 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -407,6 +407,10 @@ _cairo_user_data_array_foreach (cairo_user_data_array_t     *array,
 cairo_private unsigned long
 _cairo_hash_string (const char *c);
 
+cairo_private void
+_cairo_pattern_get_ink_extents (const cairo_pattern_t	    *pattern,
+				cairo_rectangle_int_t       *extents);
+
 cairo_private unsigned long
 _cairo_hash_bytes (unsigned long hash,
 		   const void *bytes,


More information about the cairo-commit mailing list