[cairo-commit] 6 commits - src/cairo-pdf-surface.c src/cairo-ps-surface.c src/cairo-surface-wrapper.c src/win32 test/reference

Adrian Johnson ajohnson at kemper.freedesktop.org
Sat Oct 17 01:05:26 PDT 2015


 src/cairo-pdf-surface.c                  |   33 +
 src/cairo-ps-surface.c                   |   36 +-
 src/cairo-surface-wrapper.c              |    6 
 src/win32/cairo-win32-printing-surface.c |  523 +++++++++++++++++++++++--------
 src/win32/cairo-win32-private.h          |    1 
 test/reference/raster-source.ps.ref.png  |binary
 6 files changed, 444 insertions(+), 155 deletions(-)

New commits:
commit 6656cafebfdac3365e8f903eb408043507a5e551
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat Oct 17 18:33:01 2015 +1030

    win32-print: support raster_source patterns

diff --git a/src/win32/cairo-win32-printing-surface.c b/src/win32/cairo-win32-printing-surface.c
index 05964e5..ad54a4c 100644
--- a/src/win32/cairo-win32-printing-surface.c
+++ b/src/win32/cairo-win32-printing-surface.c
@@ -51,10 +51,12 @@
 #include "cairo-paginated-private.h"
 
 #include "cairo-clip-private.h"
+#include "cairo-composite-rectangles-private.h"
 #include "cairo-win32-private.h"
 #include "cairo-recording-surface-inline.h"
 #include "cairo-scaled-font-subsets-private.h"
 #include "cairo-image-info-private.h"
+#include "cairo-image-surface-inline.h"
 #include "cairo-image-surface-private.h"
 #include "cairo-surface-backend-private.h"
 #include "cairo-surface-clipper-private.h"
@@ -170,20 +172,145 @@ _cairo_win32_printing_surface_init_language_pack (cairo_win32_printing_surface_t
     }
 }
 
+/**
+ * _cairo_win32_printing_surface_acquire_image_pattern:
+ * @surface: the win32 printing surface
+ * @pattern: A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source
+ * @extents: extents of the operation that is using this source
+ * @image_pattern: returns pattern containing acquired image. The matrix (adjusted for
+ * the device offset of raster source) is copied from the pattern.
+ * @width: returns width of the pattern
+ * @height: returns height of  pattern
+ * @image_extra: returns image extra for image type surface
+ *
+ * Acquire source surface or raster source pattern.
+ **/
+static cairo_status_t
+_cairo_win32_printing_surface_acquire_image_pattern (
+    cairo_win32_printing_surface_t  *surface,
+    const cairo_pattern_t           *pattern,
+    const cairo_rectangle_int_t     *extents,
+    cairo_surface_pattern_t         *image_pattern,
+    int                             *width,
+    int                             *height,
+    void                           **image_extra)
+{
+    cairo_status_t          status;
+    cairo_image_surface_t  *image;
+    cairo_matrix_t tm;
+    double x = 0;
+    double y = 0;
+
+    switch (pattern->type) {
+    case CAIRO_PATTERN_TYPE_SURFACE: {
+	cairo_surface_t *surf = ((cairo_surface_pattern_t *) pattern)->surface;
+
+	status =  _cairo_surface_acquire_source_image (surf, &image, image_extra);
+	if (unlikely (status))
+	    return status;
+
+	*width = image->width;
+	*height = image->height;
+    } break;
+
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE: {
+	cairo_surface_t *surf;
+	cairo_box_t box;
+	cairo_rectangle_int_t rect;
+	cairo_raster_source_pattern_t *raster;
+
+	/* get the operation extents in pattern space */
+	_cairo_box_from_rectangle (&box, extents);
+	_cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &box, NULL);
+	_cairo_box_round_to_rectangle (&box, &rect);
+	surf = _cairo_raster_source_pattern_acquire (pattern, &surface->win32.base, &rect);
+	if (!surf)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+
+	assert (_cairo_surface_is_image (surf));
+	image = (cairo_image_surface_t *) surf;
+	cairo_surface_get_device_offset (surf, &x, &y);
+
+	raster = (cairo_raster_source_pattern_t *) pattern;
+	*width = raster->extents.width;
+	*height = raster->extents.height;
+    } break;
+
+    case CAIRO_PATTERN_TYPE_SOLID:
+    case CAIRO_PATTERN_TYPE_LINEAR:
+    case CAIRO_PATTERN_TYPE_RADIAL:
+    case CAIRO_PATTERN_TYPE_MESH:
+    default:
+	ASSERT_NOT_REACHED;
+	break;
+    }
+
+    _cairo_pattern_init_for_surface (image_pattern, &image->base);
+    image_pattern->base.extend = pattern->extend;
+    cairo_matrix_init_translate (&tm, x, y);
+    status = cairo_matrix_invert (&tm);
+    /* translation matrices are invertibile */
+    assert (status == CAIRO_STATUS_SUCCESS);
+
+    image_pattern->base.matrix = pattern->matrix;
+    cairo_matrix_multiply (&image_pattern->base.matrix, &image_pattern->base.matrix, &tm);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_win32_printing_surface_release_image_pattern (cairo_win32_printing_surface_t *surface,
+						     const cairo_pattern_t          *pattern,
+						     cairo_surface_pattern_t        *image_pattern,
+						     void                           *image_extra)
+{
+    cairo_surface_t *surf = image_pattern->surface;
+
+    _cairo_pattern_fini (&image_pattern->base);
+    switch (pattern->type) {
+    case CAIRO_PATTERN_TYPE_SURFACE: {
+	cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) pattern;
+	cairo_image_surface_t *image = (cairo_image_surface_t *) surf;
+	_cairo_surface_release_source_image (surf_pat->surface, image, image_extra);
+    } break;
+
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	_cairo_raster_source_pattern_release (pattern, surf);
+	break;
+
+    case CAIRO_PATTERN_TYPE_SOLID:
+    case CAIRO_PATTERN_TYPE_LINEAR:
+    case CAIRO_PATTERN_TYPE_RADIAL:
+    case CAIRO_PATTERN_TYPE_MESH:
+    default:
+	ASSERT_NOT_REACHED;
+	break;
+    }
+}
+
 static cairo_int_status_t
-analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern)
+analyze_surface_pattern_transparency (cairo_win32_printing_surface_t *surface,
+				      const cairo_pattern_t          *pattern,
+				      const cairo_rectangle_int_t    *extents)
 {
+    cairo_surface_pattern_t image_pattern;
     cairo_image_surface_t  *image;
     void		   *image_extra;
     cairo_int_status_t      status;
     cairo_image_transparency_t transparency;
-
-    status = _cairo_surface_acquire_source_image (pattern->surface,
-						  &image,
-						  &image_extra);
+    int pattern_width, pattern_height;
+
+    status = _cairo_win32_printing_surface_acquire_image_pattern (surface,
+								  pattern,
+								  extents,
+								  &image_pattern,
+								  &pattern_width,
+								  &pattern_height,
+								  &image_extra);
     if (status)
 	return status;
 
+    image = (cairo_image_surface_t *)(image_pattern.surface);
     transparency = _cairo_image_analyze_transparency (image);
     switch (transparency) {
     case CAIRO_IMAGE_UNKNOWN:
@@ -198,7 +325,7 @@ analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern)
 	break;
     }
 
-    _cairo_surface_release_source_image (pattern->surface, image, image_extra);
+    _cairo_win32_printing_surface_release_image_pattern (surface, pattern, &image_pattern, image_extra);
 
     return status;
 }
@@ -209,8 +336,7 @@ surface_pattern_supported (const cairo_surface_pattern_t *pattern)
     if (_cairo_surface_is_recording (pattern->surface))
 	return TRUE;
 
-    if (cairo_surface_get_type (pattern->surface) != CAIRO_SURFACE_TYPE_WIN32 &&
-	pattern->surface->backend->acquire_source_image == NULL)
+    if (pattern->surface->backend->acquire_source_image == NULL)
     {
 	return FALSE;
     }
@@ -221,22 +347,34 @@ surface_pattern_supported (const cairo_surface_pattern_t *pattern)
 static cairo_bool_t
 pattern_supported (cairo_win32_printing_surface_t *surface, const cairo_pattern_t *pattern)
 {
-    if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
+    switch (pattern->type) {
+    case CAIRO_PATTERN_TYPE_SOLID:
 	return TRUE;
 
-    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
-	return surface_pattern_supported ((const cairo_surface_pattern_t *) pattern);
-
-    if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR)
+    case CAIRO_PATTERN_TYPE_LINEAR:
 	return surface->win32.flags & CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT;
 
-    return FALSE;
+    case CAIRO_PATTERN_TYPE_RADIAL:
+    case CAIRO_PATTERN_TYPE_MESH:
+	return FALSE;
+
+    case CAIRO_PATTERN_TYPE_SURFACE:
+	return surface_pattern_supported ((cairo_surface_pattern_t *) pattern);
+
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	return TRUE;
+
+    default:
+	ASSERT_NOT_REACHED;
+	return FALSE;
+    }
 }
 
 static cairo_int_status_t
 _cairo_win32_printing_surface_analyze_operation (cairo_win32_printing_surface_t *surface,
-                                                 cairo_operator_t       op,
-                                                 const cairo_pattern_t *pattern)
+                                                 cairo_operator_t                op,
+                                                 const cairo_pattern_t          *pattern,
+						 const cairo_rectangle_int_t    *extents)
 {
     if (! pattern_supported (surface, pattern))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -267,11 +405,8 @@ _cairo_win32_printing_surface_analyze_operation (cairo_win32_printing_surface_t
      * background to convert the pattern to opaque.
      */
 
-    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
-	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
-
-	return analyze_surface_pattern_transparency (surface_pattern);
-    }
+    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE || pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE)
+	return analyze_surface_pattern_transparency (surface, pattern, extents);
 
     if (_cairo_pattern_is_opaque (pattern, NULL))
 	return CAIRO_STATUS_SUCCESS;
@@ -281,10 +416,11 @@ _cairo_win32_printing_surface_analyze_operation (cairo_win32_printing_surface_t
 
 static cairo_bool_t
 _cairo_win32_printing_surface_operation_supported (cairo_win32_printing_surface_t *surface,
-                                                   cairo_operator_t       op,
-                                                   const cairo_pattern_t *pattern)
+                                                   cairo_operator_t                op,
+                                                   const cairo_pattern_t          *pattern,
+						   const cairo_rectangle_int_t    *extents)
 {
-    if (_cairo_win32_printing_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED)
+    if (_cairo_win32_printing_surface_analyze_operation (surface, op, pattern, extents) != CAIRO_INT_STATUS_UNSUPPORTED)
 	return TRUE;
     else
 	return FALSE;
@@ -605,11 +741,12 @@ _cairo_win32_printing_surface_check_png (cairo_win32_printing_surface_t   *surfa
 }
 
 static cairo_status_t
-_cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_t   *surface,
-						   cairo_surface_pattern_t *pattern)
+_cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_t *surface,
+						   const cairo_pattern_t          *pattern,
+						   const cairo_rectangle_int_t    *extents)
 {
     cairo_int_status_t status;
-    cairo_extend_t extend;
+    cairo_surface_pattern_t image_pattern;
     cairo_image_surface_t *image;
     void *image_extra;
     cairo_image_surface_t *opaque_image = NULL;
@@ -618,6 +755,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_
     int oldmode;
     XFORM xform;
     int x_tile, y_tile, left, right, top, bottom;
+    int pattern_width, pattern_height;
     RECT clip;
     const cairo_color_t *background_color;
     const unsigned char *mime_data;
@@ -637,13 +775,17 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_
     else
 	background_color = CAIRO_COLOR_BLACK;
 
-    extend = cairo_pattern_get_extend (&pattern->base);
-
-    status = _cairo_surface_acquire_source_image (pattern->surface,
-						  &image, &image_extra);
+    status = _cairo_win32_printing_surface_acquire_image_pattern (surface,
+								  pattern,
+								  extents,
+								  &image_pattern,
+								  &pattern_width,
+								  &pattern_height,
+								  &image_extra);
     if (status)
 	return status;
 
+    image = (cairo_image_surface_t *)(image_pattern.surface);
     if (image->base.status) {
 	status = image->base.status;
 	goto CLEANUP_IMAGE;
@@ -656,14 +798,14 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_
 
     mime_type = BI_JPEG;
     status = _cairo_win32_printing_surface_check_jpeg (surface,
-						       pattern->surface,
+						       image_pattern.surface,
 						       &mime_data,
 						       &mime_size,
 						       &mime_info);
     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
 	mime_type = BI_PNG;
 	status = _cairo_win32_printing_surface_check_png (surface,
-							  pattern->surface,
+							  image_pattern.surface,
 							  &mime_data,
 							  &mime_size,
 							  &mime_info);
@@ -721,7 +863,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_
     bi.bmiHeader.biClrUsed = 0;
     bi.bmiHeader.biClrImportant = 0;
 
-    m = pattern->base.matrix;
+    m = image_pattern.base.matrix;
     status = cairo_matrix_invert (&m);
     /* _cairo_pattern_set_matrix guarantees invertibility */
     assert (status == CAIRO_INT_STATUS_SUCCESS);
@@ -739,7 +881,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_
     oldmode = SetStretchBltMode(surface->win32.dc, HALFTONE);
 
     GetClipBox (surface->win32.dc, &clip);
-    if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) {
+    if (pattern->extend == CAIRO_EXTEND_REPEAT || pattern->extend == CAIRO_EXTEND_REFLECT) {
 	left = floor ( clip.left / (double) opaque_image->width);
 	right = ceil (clip.right / (double) opaque_image->width);
 	top = floor (clip.top / (double) opaque_image->height);
@@ -779,24 +921,11 @@ CLEANUP_OPAQUE_IMAGE:
     if (opaque_image != image)
 	cairo_surface_destroy (&opaque_image->base);
 CLEANUP_IMAGE:
-    _cairo_surface_release_source_image (pattern->surface, image, image_extra);
+    _cairo_win32_printing_surface_release_image_pattern (surface, pattern, &image_pattern, image_extra);
 
     return status;
 }
 
-static cairo_status_t
-_cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_printing_surface_t   *surface,
-                                                     cairo_surface_pattern_t *pattern)
-{
-    if (_cairo_surface_is_recording (pattern->surface)) {
-	return _cairo_win32_printing_surface_paint_recording_pattern (surface,
-								      pattern);
-    } else {
-	return _cairo_win32_printing_surface_paint_image_pattern (surface,
-								  pattern);
-    }
-}
-
 static void
 vertex_set_color (TRIVERTEX *vert, cairo_color_stop_t *color)
 {
@@ -955,7 +1084,8 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_printing_surface
 
 static cairo_int_status_t
 _cairo_win32_printing_surface_paint_pattern (cairo_win32_printing_surface_t *surface,
-                                             const cairo_pattern_t *pattern)
+                                             const cairo_pattern_t          *pattern,
+					     const cairo_rectangle_int_t    *extents)
 {
     cairo_status_t status;
 
@@ -966,9 +1096,20 @@ _cairo_win32_printing_surface_paint_pattern (cairo_win32_printing_surface_t *sur
 	    return status;
 	break;
 
-    case CAIRO_PATTERN_TYPE_SURFACE:
-	status = _cairo_win32_printing_surface_paint_surface_pattern (surface,
-                                                                      (cairo_surface_pattern_t *) pattern);
+    case CAIRO_PATTERN_TYPE_SURFACE: {
+	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
+
+	if ( _cairo_surface_is_recording (surface_pattern->surface))
+	    status = _cairo_win32_printing_surface_paint_recording_pattern (surface, surface_pattern);
+	else
+	    status = _cairo_win32_printing_surface_paint_image_pattern (surface, pattern, extents);
+
+	if (status)
+	    return status;
+	break;
+    }
+    case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+	status = _cairo_win32_printing_surface_paint_image_pattern (surface, pattern, extents);
 	if (status)
 	    return status;
 	break;
@@ -1198,24 +1339,37 @@ _cairo_win32_printing_surface_paint (void			*abstract_surface,
 {
     cairo_win32_printing_surface_t *surface = abstract_surface;
     cairo_solid_pattern_t clear;
+    cairo_composite_rectangles_t extents;
     cairo_status_t status;
 
-    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
-    if (status)
+    status = _cairo_composite_rectangles_init_for_paint (&extents,
+							 &surface->win32.base,
+							 op, source, clip);
+    if (unlikely (status))
 	return status;
 
+    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+    if (unlikely (status))
+	goto cleanup_composite;
+
     if (op == CAIRO_OPERATOR_CLEAR) {
 	_cairo_win32_printing_surface_init_clear_color (surface, &clear);
 	source = (cairo_pattern_t*) &clear;
 	op = CAIRO_OPERATOR_SOURCE;
     }
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-	return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	status = _cairo_win32_printing_surface_analyze_operation (surface, op, source, &extents.bounded);
+	goto cleanup_composite;
+    }
+
+    assert (_cairo_win32_printing_surface_operation_supported (surface, op, source, &extents.bounded));
 
-    assert (_cairo_win32_printing_surface_operation_supported (surface, op, source));
+    status = _cairo_win32_printing_surface_paint_pattern (surface, source, &extents.bounded);
 
-    return _cairo_win32_printing_surface_paint_pattern (surface, source);
+  cleanup_composite:
+    _cairo_composite_rectangles_fini (&extents);
+    return status;
 }
 
 static int
@@ -1292,10 +1446,37 @@ _cairo_win32_printing_surface_stroke (void			*abstract_surface,
     cairo_solid_pattern_t clear;
     cairo_matrix_t mat;
     double scale;
+    cairo_composite_rectangles_t extents;
+
+    status = _cairo_composite_rectangles_init_for_stroke (&extents,
+							  &surface->win32.base,
+							  op, source,
+							  path, style, stroke_ctm,
+							  clip);
+    if (unlikely (status))
+	return status;
+
+    /* use the more accurate extents */
+    {
+	cairo_rectangle_int_t r;
+	cairo_box_t b;
+
+	status = _cairo_path_fixed_stroke_extents (path, style,
+						   stroke_ctm, stroke_ctm_inverse,
+						   tolerance,
+						   &r);
+	if (unlikely (status))
+	    goto cleanup_composite;
+
+	_cairo_box_from_rectangle (&b, &r);
+	status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b);
+	if (unlikely (status))
+	    goto cleanup_composite;
+    }
 
     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
-    if (status)
-	return status;
+    if (unlikely (status))
+	goto cleanup_composite;
 
     if (op == CAIRO_OPERATOR_CLEAR) {
 	_cairo_win32_printing_surface_init_clear_color (surface, &clear);
@@ -1306,12 +1487,14 @@ _cairo_win32_printing_surface_stroke (void			*abstract_surface,
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
 	/* Win32 does not support a dash offset. */
 	if (style->num_dashes > 0 && style->dash_offset != 0.0)
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
+	    status = CAIRO_INT_STATUS_UNSUPPORTED;
+	else
+	    status = _cairo_win32_printing_surface_analyze_operation (surface, op, source, &extents.bounded);
 
-	return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
+	goto cleanup_composite;
     }
 
-    assert (_cairo_win32_printing_surface_operation_supported (surface, op, source));
+    assert (_cairo_win32_printing_surface_operation_supported (surface, op, source, &extents.bounded));
     assert (!(style->num_dashes > 0 && style->dash_offset != 0.0));
 
     cairo_matrix_multiply (&mat, stroke_ctm, &surface->ctm);
@@ -1350,17 +1533,22 @@ _cairo_win32_printing_surface_stroke (void			*abstract_surface,
 		       &brush,
 		       style->num_dashes,
 		       dash_array);
-    if (pen == NULL)
-	return _cairo_win32_print_gdi_error ("_win32_surface_stroke:ExtCreatePen");
+    if (pen == NULL) {
+	status = _cairo_win32_print_gdi_error ("_win32_surface_stroke:ExtCreatePen");
+	goto cleanup_composite;
+    }
+
     obj = SelectObject (surface->win32.dc, pen);
-    if (obj == NULL)
-	return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectObject");
+    if (obj == NULL) {
+	status = _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectObject");
+	goto cleanup_composite;
+    }
 
     BeginPath (surface->win32.dc);
     status = _cairo_win32_printing_surface_emit_path (surface, path);
     EndPath (surface->win32.dc);
-    if (status)
-	return status;
+    if (unlikely (status))
+	goto cleanup_composite;
 
     /*
      * Switch to user space to set line parameters
@@ -1371,27 +1559,37 @@ _cairo_win32_printing_surface_stroke (void			*abstract_surface,
     xform.eDx = 0.0f;
     xform.eDy = 0.0f;
 
-    if (!ModifyWorldTransform (surface->win32.dc, &xform, MWT_LEFTMULTIPLY))
-	return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SetWorldTransform");
+    if (!ModifyWorldTransform (surface->win32.dc, &xform, MWT_LEFTMULTIPLY)) {
+	status = _cairo_win32_print_gdi_error ("_win32_surface_stroke:SetWorldTransform");
+	goto cleanup_composite;
+    }
 
     if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
 	StrokePath (surface->win32.dc);
     } else {
-	if (!WidenPath (surface->win32.dc))
-	    return _cairo_win32_print_gdi_error ("_win32_surface_stroke:WidenPath");
-	if (!SelectClipPath (surface->win32.dc, RGN_AND))
-	    return _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectClipPath");
+	if (!WidenPath (surface->win32.dc)) {
+	    status = _cairo_win32_print_gdi_error ("_win32_surface_stroke:WidenPath");
+	    goto cleanup_composite;
+	}
+	if (!SelectClipPath (surface->win32.dc, RGN_AND)) {
+	    status = _cairo_win32_print_gdi_error ("_win32_surface_stroke:SelectClipPath");
+	    goto cleanup_composite;
+	}
 
 	/* Return to device space to paint the pattern */
 	_cairo_matrix_to_win32_xform (&surface->gdi_ctm, &xform);
-	if (!SetWorldTransform (surface->win32.dc, &xform))
-	    return _cairo_win32_print_gdi_error ("_win32_surface_stroke:ModifyWorldTransform");
-	status = _cairo_win32_printing_surface_paint_pattern (surface, source);
+	if (!SetWorldTransform (surface->win32.dc, &xform)) {
+	    status = _cairo_win32_print_gdi_error ("_win32_surface_stroke:ModifyWorldTransform");
+	    goto cleanup_composite;
+	}
+	status = _cairo_win32_printing_surface_paint_pattern (surface, source, &extents.bounded);
     }
     RestoreDC (surface->win32.dc, -1);
     DeleteObject (pen);
     free (dash_array);
 
+cleanup_composite:
+    _cairo_composite_rectangles_fini (&extents);
     return status;
 }
 
@@ -1408,21 +1606,47 @@ _cairo_win32_printing_surface_fill (void		        *abstract_surface,
     cairo_win32_printing_surface_t *surface = abstract_surface;
     cairo_int_status_t status;
     cairo_solid_pattern_t clear;
+    cairo_composite_rectangles_t extents;
 
-    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
-    if (status)
+    status = _cairo_composite_rectangles_init_for_fill (&extents,
+							&surface->win32.base,
+							op, source, path,
+							clip);
+    if (unlikely (status))
 	return status;
 
+    /* use the more accurate extents */
+    {
+	cairo_rectangle_int_t r;
+	cairo_box_t b;
+
+	_cairo_path_fixed_fill_extents (path,
+					fill_rule,
+					tolerance,
+					&r);
+
+	_cairo_box_from_rectangle (&b, &r);
+	status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b);
+	if (unlikely (status))
+	    goto cleanup_composite;
+    }
+
+    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+    if (unlikely (status))
+	goto cleanup_composite;
+
     if (op == CAIRO_OPERATOR_CLEAR) {
 	_cairo_win32_printing_surface_init_clear_color (surface, &clear);
 	source = (cairo_pattern_t*) &clear;
 	op = CAIRO_OPERATOR_SOURCE;
     }
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-	return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	status = _cairo_win32_printing_surface_analyze_operation (surface, op, source, &extents.bounded);
+	goto cleanup_composite;
+    }
 
-    assert (_cairo_win32_printing_surface_operation_supported (surface, op, source));
+    assert (_cairo_win32_printing_surface_operation_supported (surface, op, source, &extents.bounded));
 
     surface->path_empty = TRUE;
     BeginPath (surface->win32.dc);
@@ -1442,20 +1666,22 @@ _cairo_win32_printing_surface_fill (void		        *abstract_surface,
 
     if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
 	status = _cairo_win32_printing_surface_select_solid_brush (surface, source);
-	if (status)
-	    return status;
+	if (unlikely (status))
+	    goto cleanup_composite;
 
 	FillPath (surface->win32.dc);
 	_cairo_win32_printing_surface_done_solid_brush (surface);
     } else if (surface->path_empty == FALSE) {
 	SaveDC (surface->win32.dc);
 	SelectClipPath (surface->win32.dc, RGN_AND);
-	status = _cairo_win32_printing_surface_paint_pattern (surface, source);
+	status = _cairo_win32_printing_surface_paint_pattern (surface, source, &extents.bounded);
 	RestoreDC (surface->win32.dc, -1);
     }
 
     fflush(stderr);
 
+cleanup_composite:
+    _cairo_composite_rectangles_fini (&extents);
     return status;
 }
 
@@ -1560,10 +1786,22 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
     cairo_matrix_t old_ctm;
     cairo_bool_t old_has_ctm;
     cairo_solid_pattern_t clear;
+    cairo_composite_rectangles_t extents;
+    cairo_bool_t overlap;
+
+    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+							  &surface->win32.base,
+							  op, source,
+							  scaled_font,
+							  glyphs, num_glyphs,
+							  clip,
+							  &overlap);
+    if (unlikely (status))
+	return status;
 
     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
-    if (status)
-	return status;
+    if (unlikely (status))
+	goto cleanup_composite;
 
     if (op == CAIRO_OPERATOR_CLEAR) {
 	_cairo_win32_printing_surface_init_clear_color (surface, &clear);
@@ -1583,10 +1821,13 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
 	 */
 #if CAIRO_HAS_WIN32_FONT
 	if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32) {
-	    if (_cairo_win32_scaled_font_is_bitmap (scaled_font))
-		return CAIRO_INT_STATUS_UNSUPPORTED;
-	    else
-		return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
+	    if (_cairo_win32_scaled_font_is_bitmap (scaled_font)) {
+		status = CAIRO_INT_STATUS_UNSUPPORTED;
+		goto cleanup_composite;
+	    } else {
+		status = _cairo_win32_printing_surface_analyze_operation (surface, op, source, &extents.bounded);
+		goto cleanup_composite;
+	    }
 	}
 #endif
 
@@ -1606,10 +1847,11 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
                 break;
 	}
         _cairo_scaled_font_thaw_cache (scaled_font);
-        if (status)
-            return status;
+	if (unlikely (status))
+	    goto cleanup_composite;
 
-	return _cairo_win32_printing_surface_analyze_operation (surface, op, source);
+	status = _cairo_win32_printing_surface_analyze_operation (surface, op, source, &extents.bounded);
+	goto cleanup_composite;
     }
 
     if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
@@ -1621,8 +1863,10 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
 	opaque = cairo_pattern_create_rgb (GetRValue (color) / 255.0,
 					   GetGValue (color) / 255.0,
 					   GetBValue (color) / 255.0);
-	if (opaque->status)
-	    return opaque->status;
+	if (unlikely (opaque->status)) {
+	    status = opaque->status;
+	    goto cleanup_composite;
+	}
 	source = opaque;
     }
 
@@ -1630,13 +1874,14 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
     if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32 &&
 	source->type == CAIRO_PATTERN_TYPE_SOLID)
     {
-	return _cairo_win32_printing_surface_emit_win32_glyphs (surface,
-								op,
-								source,
-								glyphs,
-								num_glyphs,
-								scaled_font,
-								clip);
+	status = _cairo_win32_printing_surface_emit_win32_glyphs (surface,
+								  op,
+								  source,
+								  glyphs,
+								  num_glyphs,
+								  scaled_font,
+								  clip);
+	goto cleanup_composite;
     }
 #endif
 
@@ -1665,15 +1910,15 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
     if (status == CAIRO_STATUS_SUCCESS && surface->path_empty == FALSE) {
 	if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
 	    status = _cairo_win32_printing_surface_select_solid_brush (surface, source);
-	    if (status)
-		return status;
+	    if (unlikely (status))
+		goto cleanup_composite;
 
 	    SetPolyFillMode (surface->win32.dc, WINDING);
 	    FillPath (surface->win32.dc);
 	    _cairo_win32_printing_surface_done_solid_brush (surface);
 	} else {
 	    SelectClipPath (surface->win32.dc, RGN_AND);
-	    status = _cairo_win32_printing_surface_paint_pattern (surface, source);
+	    status = _cairo_win32_printing_surface_paint_pattern (surface, source, &extents.bounded);
 	}
     }
     RestoreDC (surface->win32.dc, -1);
@@ -1681,6 +1926,8 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
     if (opaque)
 	cairo_pattern_destroy (opaque);
 
+cleanup_composite:
+    _cairo_composite_rectangles_fini (&extents);
     return status;
 }
 
commit 9fcb42f7fe530da40d96dbc56ea7a8423fa3505a
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat Oct 17 18:32:59 2015 +1030

    win32-print: fix warnings

diff --git a/src/win32/cairo-win32-printing-surface.c b/src/win32/cairo-win32-printing-surface.c
index 4d3b8ce..05964e5 100644
--- a/src/win32/cairo-win32-printing-surface.c
+++ b/src/win32/cairo-win32-printing-surface.c
@@ -402,7 +402,7 @@ _cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_printing_surf
     cairo_matrix_t old_ctm;
     cairo_bool_t old_has_ctm;
     cairo_rectangle_int_t recording_extents;
-    cairo_status_t status;
+    cairo_int_status_t status;
     cairo_extend_t extend;
     cairo_matrix_t p2d;
     XFORM xform;
@@ -416,7 +416,7 @@ _cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_printing_surf
     p2d = pattern->base.matrix;
     status = cairo_matrix_invert (&p2d);
     /* _cairo_pattern_set_matrix guarantees invertibility */
-    assert (status == CAIRO_STATUS_SUCCESS);
+    assert (status == CAIRO_INT_STATUS_SUCCESS);
 
     old_ctm = surface->ctm;
     old_has_ctm = surface->has_ctm;
@@ -608,7 +608,7 @@ static cairo_status_t
 _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_t   *surface,
 						   cairo_surface_pattern_t *pattern)
 {
-    cairo_status_t status;
+    cairo_int_status_t status;
     cairo_extend_t extend;
     cairo_image_surface_t *image;
     void *image_extra;
@@ -668,10 +668,10 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_
 							  &mime_size,
 							  &mime_info);
     }
-    if (_cairo_status_is_error (status))
+    if (_cairo_int_status_is_error (status))
 	return status;
 
-    use_mime = (status == CAIRO_STATUS_SUCCESS);
+    use_mime = (status == CAIRO_INT_STATUS_SUCCESS);
 
     if (!use_mime && image->format != CAIRO_FORMAT_RGB24) {
 	cairo_surface_t *opaque_surface;
@@ -724,7 +724,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_
     m = pattern->base.matrix;
     status = cairo_matrix_invert (&m);
     /* _cairo_pattern_set_matrix guarantees invertibility */
-    assert (status == CAIRO_STATUS_SUCCESS);
+    assert (status == CAIRO_INT_STATUS_SUCCESS);
 
     cairo_matrix_multiply (&m, &m, &surface->ctm);
     cairo_matrix_multiply (&m, &m, &surface->gdi_ctm);
commit 2c45fdfc15a81eae6196f92c9768f3d895bd0819
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat Oct 17 18:32:57 2015 +1030

    win32-print: Fix the page extents
    
    As the page size can be changed between pages, set the extents in
    _start_page. The extents are invalidated in _show_page since the
    page size on the DC may be changed after this call. The only thing that
    uses the extents between _show_page and _start_page (and before the first
    _start_page) is the creation of the recording surface in the paginated
    surface. In this case, when the paginated surface can't get the extents,
    it will create an unbounded recording surface.
    
    The extents x,y is always set to 0 to prevent the replay from translating
    the page.

diff --git a/src/win32/cairo-win32-printing-surface.c b/src/win32/cairo-win32-printing-surface.c
index cce7040..4d3b8ce 100644
--- a/src/win32/cairo-win32-printing-surface.c
+++ b/src/win32/cairo-win32-printing-surface.c
@@ -1116,6 +1116,11 @@ _cairo_win32_printing_surface_show_page (void *abstract_surface)
     /* Undo both SaveDC's that we did in start_page */
     RestoreDC (surface->win32.dc, -2);
 
+    /* Invalidate extents since the size of the next page is not known at
+     * this point.
+     */
+    surface->extents_valid = FALSE;
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -1161,6 +1166,18 @@ _cairo_win32_printing_surface_clipper_intersect_clip_path (cairo_surface_clipper
     return status;
 }
 
+static cairo_bool_t
+_cairo_win32_printing_surface_get_extents (void		          *abstract_surface,
+					   cairo_rectangle_int_t  *rectangle)
+{
+    cairo_win32_printing_surface_t *surface = abstract_surface;
+
+    if (surface->extents_valid)
+	*rectangle = surface->win32.extents;
+
+    return surface->extents_valid;
+}
+
 static void
 _cairo_win32_printing_surface_get_font_options (void                  *abstract_surface,
                                                 cairo_font_options_t  *options)
@@ -1706,6 +1723,27 @@ _cairo_win32_printing_surface_start_page (void *abstract_surface)
     double x_res, y_res;
     cairo_matrix_t inverse_ctm;
     cairo_status_t status;
+    RECT rect;
+
+    /* Since the page size may be changed after _show_page() and before the
+     * next drawing command, the extents are set in _start_page() and invalidated
+     * in _show_page(). The paginated surface will obtain the extents immediately
+     * after calling _show_page() and before any drawing commands. At this point
+     * the next page will not have been setup on the DC so we return invalid
+     * extents and the paginated surface will create an unbounded recording surface.
+     * Prior to replay of the record surface, the paginated surface will call
+     * _start_page and we setup the correct extents.
+     *
+     * Note that we always set the extents x,y to 0 so prevent replay from translating
+     * the coordinates of objects. Windows will clip anything outside of the page clip
+     * area.
+     */
+    GetClipBox(surface->win32.dc, &rect);
+    surface->win32.extents.x = 0;
+    surface->win32.extents.y = 0;
+    surface->win32.extents.width = rect.right;
+    surface->win32.extents.height = rect.bottom;
+    surface->extents_valid = TRUE;
 
     SaveDC (surface->win32.dc); /* Save application context first, before doing MWT */
 
@@ -1823,7 +1861,6 @@ cairo_win32_printing_surface_create (HDC hdc)
 {
     cairo_win32_printing_surface_t *surface;
     cairo_surface_t *paginated;
-    RECT rect;
 
     surface = malloc (sizeof (cairo_win32_printing_surface_t));
     if (surface == NULL)
@@ -1843,6 +1880,7 @@ cairo_win32_printing_surface_create (HDC hdc)
     surface->content = CAIRO_CONTENT_COLOR_ALPHA;
 
     surface->win32.dc = hdc;
+    surface->extents_valid = FALSE;
 
     surface->brush = NULL;
     surface->old_brush = NULL;
@@ -1852,12 +1890,6 @@ cairo_win32_printing_surface_create (HDC hdc)
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     }
 
-    GetClipBox(hdc, &rect);
-    surface->win32.extents.x = rect.left;
-    surface->win32.extents.y = rect.top;
-    surface->win32.extents.width = rect.right - rect.left;
-    surface->win32.extents.height = rect.bottom - rect.top;
-
     surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc);
     surface->win32.flags |= CAIRO_WIN32_SURFACE_FOR_PRINTING;
 
@@ -1898,7 +1930,7 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
     NULL, /* copy_page */
     _cairo_win32_printing_surface_show_page,
 
-    _cairo_win32_surface_get_extents,
+    _cairo_win32_printing_surface_get_extents,
     _cairo_win32_printing_surface_get_font_options,
 
     NULL, /* flush */
diff --git a/src/win32/cairo-win32-private.h b/src/win32/cairo-win32-private.h
index b6c2431..6fdf96f 100644
--- a/src/win32/cairo-win32-private.h
+++ b/src/win32/cairo-win32-private.h
@@ -139,6 +139,7 @@ typedef struct _cairo_win32_printing_surface {
     cairo_matrix_t ctm;
     cairo_bool_t has_gdi_ctm;
     cairo_matrix_t gdi_ctm;
+    cairo_bool_t extents_valid;
     HBRUSH brush, old_brush;
     cairo_scaled_font_subsets_t *font_subsets;
 } cairo_win32_printing_surface_t;
commit 094f0e0fa0153f290061635eed51e8d1dbe2cf4a
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat Oct 17 16:50:50 2015 +1030

    pdf: fix subsurface recordings

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 4bc2947..1733a86 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1249,21 +1249,22 @@ _get_source_surface_size (cairo_surface_t         *source,
     unsigned long mime_data_length;
 
     if (source->type == CAIRO_SURFACE_TYPE_RECORDING) {
+	cairo_surface_t *free_me = NULL;
+
+	if (_cairo_surface_is_snapshot (source))
+	    free_me = source = _cairo_surface_snapshot_get_target (source);
+
 	if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
-	     cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
+	    cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
 
-	     *extents = sub->extents;
-	     *width  = extents->width;
-	     *height = extents->height;
+	    *extents = sub->extents;
+	    *width  = extents->width;
+	    *height = extents->height;
 	} else {
-	    cairo_surface_t *free_me = NULL;
 	    cairo_rectangle_int_t surf_extents;
 	    cairo_box_t box;
 	    cairo_bool_t bounded;
 
-	    if (_cairo_surface_is_snapshot (source))
-		free_me = source = _cairo_surface_snapshot_get_target (source);
-
 	    status = _cairo_recording_surface_get_ink_bbox ((cairo_recording_surface_t *)source,
 							    &box, NULL);
 	    if (unlikely (status)) {
@@ -1272,13 +1273,13 @@ _get_source_surface_size (cairo_surface_t         *source,
 	    }
 
 	    bounded = _cairo_surface_get_extents (source, &surf_extents);
-	    cairo_surface_destroy (free_me);
 
 	    *width = surf_extents.width;
 	    *height = surf_extents.height;
 
 	    _cairo_box_round_to_rectangle (&box, extents);
 	}
+	cairo_surface_destroy (free_me);
 
 	return CAIRO_STATUS_SUCCESS;
     }
@@ -3010,9 +3011,10 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t        *surface,
     height = pdf_source->hash_entry->height;
     is_subsurface = FALSE;
     source = pdf_source->surface;
-    if (_cairo_surface_is_snapshot (source)) {
+    if (_cairo_surface_is_snapshot (source))
 	free_me = source = _cairo_surface_snapshot_get_target (source);
-    } else if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
+
+    if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
 	cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
 
 	source = sub->target;
@@ -3040,7 +3042,14 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t        *surface,
      */
     surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER;
     _cairo_pdf_group_resources_clear (&surface->resources);
-    _get_bbox_from_extents (height, extents, &bbox);
+    if (is_subsurface) {
+	bbox.p1.x = 0;
+	bbox.p1.y = 0;
+	bbox.p2.x = extents->width;
+	bbox.p2.y = extents->height;
+    } else {
+	_get_bbox_from_extents (height, extents, &bbox);
+    }
 
     /* We can optimize away the transparency group allowing the viewer
      * to replay the group in place when all operators are OVER and the
commit 2215b4e0c0f90a90f659aa0cfc28fc02dfce3339
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat Oct 17 16:25:16 2015 +1030

    ps: fix subsurface recordings

diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 557daca..cd03e1a 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1739,32 +1739,33 @@ _cairo_ps_surface_acquire_source_surface_from_pattern (cairo_ps_surface_t
     cairo_image_surface_t  *image;
 
     *x_offset = *y_offset = 0;
+    *image_extra = NULL;
     switch (pattern->type) {
     case CAIRO_PATTERN_TYPE_SURFACE: {
 	cairo_surface_t *surf = ((cairo_surface_pattern_t *) pattern)->surface;
 
 	if (surf->type == CAIRO_SURFACE_TYPE_RECORDING) {
+	    if (_cairo_surface_is_snapshot (surf)) {
+		surf = _cairo_surface_snapshot_get_target (surf);
+		*image_extra = surf;
+	    }
 	    if (surf->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
 		cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surf;
 
 		*width  = sub->extents.width;
 		*height = sub->extents.height;
 	    } else {
-		cairo_surface_t *free_me = NULL;
 		cairo_recording_surface_t *recording_surface;
 		cairo_box_t bbox;
 		cairo_rectangle_int_t extents;
 
 		recording_surface = (cairo_recording_surface_t *) surf;
-		if (_cairo_surface_is_snapshot (&recording_surface->base)) {
-		    free_me = _cairo_surface_snapshot_get_target (&recording_surface->base);
-		    recording_surface = (cairo_recording_surface_t *) free_me;
-		}
 
 		status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
-		cairo_surface_destroy (free_me);
-		if (unlikely (status))
+		if (unlikely (status)) {
+		    cairo_surface_destroy (*image_extra);
 		    return status;
+		}
 
 		_cairo_box_round_to_rectangle (&bbox, &extents);
 		*width  = extents.width;
@@ -1775,8 +1776,10 @@ _cairo_ps_surface_acquire_source_surface_from_pattern (cairo_ps_surface_t
 	    return CAIRO_STATUS_SUCCESS;
 	} else {
 	    status =  _cairo_surface_acquire_source_image (surf, &image, image_extra);
-	    if (unlikely (status))
+	    if (unlikely (status)) {
+		cairo_surface_destroy (*image_extra);
 		return status;
+	    }
 	}
     } break;
 
@@ -1821,7 +1824,9 @@ _cairo_ps_surface_release_source_surface_from_pattern (cairo_ps_surface_t
     switch (pattern->type) {
     case CAIRO_PATTERN_TYPE_SURFACE: {
 	cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) pattern;
-	if (surf_pat->surface->type != CAIRO_SURFACE_TYPE_RECORDING) {
+	if (surf_pat->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
+	    cairo_surface_destroy (image_extra);
+	} else {
 	    cairo_image_surface_t *image  = (cairo_image_surface_t *) source;
 	    _cairo_surface_release_source_image (surf_pat->surface, image, image_extra);
 	}
@@ -2924,7 +2929,6 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t          *surface,
     cairo_matrix_t old_cairo_to_ps;
     cairo_content_t old_content;
     cairo_rectangle_int_t old_page_bbox;
-    cairo_surface_t *free_me = NULL;
     cairo_surface_clipper_t old_clipper;
     cairo_box_t bbox;
     cairo_int_status_t status;
@@ -2938,9 +2942,6 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t          *surface,
     _cairo_surface_clipper_init (&surface->clipper,
 				 _cairo_ps_surface_clipper_intersect_clip_path);
 
-    if (_cairo_surface_is_snapshot (recording_surface))
-	free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface);
-
     if (subsurface) {
 	surface->page_bbox.x = surface->page_bbox.y = 0;
 	surface->page_bbox.width = surface->width  = extents->width;
@@ -2960,7 +2961,7 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t          *surface,
 					       &bbox,
 					       NULL);
 	if (unlikely (status))
-	    goto err;
+	    return status;
 
 	surface->width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
 	surface->height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
@@ -2999,11 +3000,11 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t          *surface,
 						     CAIRO_RECORDING_REGION_NATIVE);
     assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
     if (unlikely (status))
-	goto err;
+	return status;
 
     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
     if (unlikely (status))
-	goto err;
+	return status;
 
     _cairo_output_stream_printf (surface->stream, "  Q\n");
 
@@ -3020,8 +3021,6 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t          *surface,
     _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
 						  &surface->cairo_to_ps);
 
-err:
-    cairo_surface_destroy (free_me);
     return status;
 }
 
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index 9236c8b..64e2d1e 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -119,14 +119,14 @@ _cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t *wrapper,
 				 const cairo_clip_t *clip)
 {
     cairo_clip_t *copy;
+    cairo_matrix_t m;
 
     copy = _cairo_clip_copy (clip);
     if (wrapper->has_extents) {
 	copy = _cairo_clip_intersect_rectangle (copy, &wrapper->extents);
     }
-    copy = _cairo_clip_transform (copy, &wrapper->transform);
-    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform))
-	copy = _cairo_clip_transform (copy, &wrapper->target->device_transform);
+    _cairo_surface_wrapper_get_transform (wrapper, &m);
+    copy = _cairo_clip_transform (copy, &m);
     if (wrapper->clip)
 	copy = _cairo_clip_intersect_clip (copy, wrapper->clip);
 
commit 6952e03262717751716f48114e6a921b62a0ecee
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat Oct 17 13:15:56 2015 +1030

    ps: fix raster source patterns

diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 12b682b..557daca 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1794,6 +1794,7 @@ _cairo_ps_surface_acquire_source_surface_from_pattern (cairo_ps_surface_t
 	    return CAIRO_INT_STATUS_UNSUPPORTED;
 	assert (_cairo_surface_is_image (surf));
 	image = (cairo_image_surface_t *) surf;
+	cairo_surface_get_device_offset (surf, x_offset, y_offset);
     } break;
 
     case CAIRO_PATTERN_TYPE_SOLID:
diff --git a/test/reference/raster-source.ps.ref.png b/test/reference/raster-source.ps.ref.png
index 2ffc114..524477d 100644
Binary files a/test/reference/raster-source.ps.ref.png and b/test/reference/raster-source.ps.ref.png differ


More information about the cairo-commit mailing list