[cairo-commit] 16 commits - cairo-version.h src/cairo-clip-surface.c src/cairo-default-context.c src/cairo-gl-traps-compositor.c src/cairo-gstate.c src/cairo.h src/cairo-image-source.c src/cairoint.h src/cairo-mask-compositor.c src/cairo-paginated-surface.c src/cairo-pattern.c src/cairo-pattern-private.h src/cairo-shape-mask-compositor.c src/cairo-spans-compositor.c src/cairo-surface.c src/cairo-surface-subsurface.c src/cairo-surface-wrapper.c src/cairo-traps-compositor.c src/cairo-xcb-surface-render.c src/cairo-xlib-source.c test/cairo-test.c test/cairo-test-private.h test/cairo-test-runner.c util/cairo-script util/cairo-trace

Chris Wilson ickle at kemper.freedesktop.org
Thu Sep 5 08:16:47 PDT 2013


 cairo-version.h                            |    4 
 src/cairo-clip-surface.c                   |   20 +-
 src/cairo-default-context.c                |   37 ++---
 src/cairo-gl-traps-compositor.c            |   18 +-
 src/cairo-gstate.c                         |   25 ++-
 src/cairo-image-source.c                   |   65 ++++++++-
 src/cairo-mask-compositor.c                |   14 +-
 src/cairo-paginated-surface.c              |    2 
 src/cairo-pattern-private.h                |    4 
 src/cairo-pattern.c                        |   10 +
 src/cairo-shape-mask-compositor.c          |   27 ++-
 src/cairo-spans-compositor.c               |   23 ++-
 src/cairo-surface-subsurface.c             |   30 +++-
 src/cairo-surface-wrapper.c                |    9 -
 src/cairo-surface.c                        |  198 ++++++++++++++++-------------
 src/cairo-traps-compositor.c               |   48 ++++---
 src/cairo-xcb-surface-render.c             |   20 +-
 src/cairo-xlib-source.c                    |   36 ++---
 src/cairo.h                                |   10 +
 src/cairoint.h                             |   23 +--
 test/cairo-test-private.h                  |    2 
 test/cairo-test-runner.c                   |   88 +++++++-----
 test/cairo-test.c                          |   66 +++++----
 util/cairo-script/cairo-script-operators.c |   48 +++++++
 util/cairo-trace/trace.c                   |   12 +
 25 files changed, 539 insertions(+), 300 deletions(-)

New commits:
commit 0266cb821fbf0bdd307af7bbcbbd22c4a14201fc
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Sep 5 16:13:56 2013 +0100

    script: Add support for replaying device-scale
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index d423fe5..aae6bea 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -4850,6 +4850,30 @@ _set_device_offset (csi_t *ctx)
 }
 
 static csi_status_t
+_set_device_scale (csi_t *ctx)
+{
+    csi_status_t status;
+    cairo_surface_t *surface;
+    double x, y;
+
+    check (3);
+
+    status = _csi_ostack_get_number (ctx, 0,  &y);
+    if (_csi_unlikely (status))
+	return status;
+    status = _csi_ostack_get_number (ctx, 1, &x);
+    if (_csi_unlikely (status))
+	return status;
+    status = _csi_ostack_get_surface (ctx, 2, &surface);
+    if (_csi_unlikely (status))
+	return status;
+
+    cairo_surface_set_device_scale (surface, x, y);
+    pop (2);
+    return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
 _set_extend (csi_t *ctx)
 {
     csi_status_t status;
@@ -6103,6 +6127,29 @@ _surface (csi_t *ctx)
 	}
     }
 
+    status = csi_name_new_static (ctx, &key, "device-scale");
+    if (_csi_unlikely (status)) {
+	cairo_surface_destroy (surface);
+	return status;
+    }
+    if (csi_dictionary_has (dict, key.datum.name)) {
+	status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
+	if (_csi_unlikely (status))
+	    return status;
+
+	if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) {
+	    csi_array_t *array = obj.datum.array;
+
+	    if (array->stack.len == 2) {
+		cairo_surface_set_device_scale (surface,
+						csi_number_get_value
+						(&array->stack.objects[0]),
+						csi_number_get_value
+						(&array->stack.objects[1]));
+	    }
+	}
+    }
+
     obj.type = CSI_OBJECT_TYPE_SURFACE;
     obj.datum.surface = surface;
     pop (1);
@@ -6539,6 +6586,7 @@ _defs[] = {
     { "set-antialias", _set_antialias },
     { "set-dash", _set_dash },
     { "set-device-offset", _set_device_offset },
+    { "set-device-scale", _set_device_scale },
     { "set-extend", _set_extend },
     { "set-fallback-resolution", _set_fallback_resolution },
     { "set-fill-rule", _set_fill_rule },
commit a4164142f2a21fb005533d1c5b3cf668c99d1259
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Sep 5 16:12:26 2013 +0100

    trace: Record set-device-scale
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 085059f..05e97d2 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -3884,6 +3884,18 @@ cairo_surface_set_device_offset (cairo_surface_t *surface, double x_offset, doub
 }
 
 void
+cairo_surface_set_device_scale (cairo_surface_t *surface, double x_offset, double y_offset)
+{
+    _enter_trace ();
+    _emit_line_info ();
+    _emit_surface_op (surface, "%g %g set-device-scale\n",
+		      x_offset, y_offset);
+    DLCALL (cairo_surface_set_device_scale, surface, x_offset, y_offset);
+    _exit_trace ();
+}
+
+
+void
 cairo_surface_set_fallback_resolution (cairo_surface_t *surface, double x_pixels_per_inch, double y_pixels_per_inch)
 {
     _enter_trace ();
commit 935c64a43409a80d9b19d491f9133004152de9bb
Author: Alexander Larsson <alexl at redhat.com>
Date:   Tue Aug 27 15:10:38 2013 +0200

    surface: Inherit device scale in cairo_surface_create_similar()
    
    Without this most code that uses similar surfaces for offscreen
    rendering will render in a pixelized fashion if the final
    target uses a device scale.

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index cdd75b8..f2f2ef6 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -507,6 +507,10 @@ cairo_surface_create_similar (cairo_surface_t  *other,
         if (unlikely (other->status))
 	return _cairo_surface_create_in_error (other->status);
 
+    /* We inherit the device scale, so create a larger surface */
+    width = width * other->device_transform.xx;
+    height = height * other->device_transform.yy;
+
     surface = NULL;
     if (other->backend->create_similar)
 	surface = other->backend->create_similar (other, content, width, height);
@@ -519,6 +523,9 @@ cairo_surface_create_similar (cairo_surface_t  *other,
 	return surface;
 
     _cairo_surface_copy_similar_properties (surface, other);
+    cairo_surface_set_device_scale (surface,
+				    other->device_transform.xx,
+				    other->device_transform.yy);
 
     if (unlikely (surface->status))
 	return surface;
commit bc792a5e0e196dd9761649b14c9206465b42ef1d
Author: Alexander Larsson <alexl at redhat.com>
Date:   Tue Aug 27 14:46:16 2013 +0200

    surface: Merge scratch construction into _cairo_surface_create_scratch
    
    We merge _cairo_surface_create_similar_scratch and
    _cairo_surface_create_similar_solid into a single function named
    _cairo_surface_create_scratch, to avoid confusion with
    cairo_surface_create_similar which now will have a different
    behaviour wrt the sizes and the device-scale.
    
    _create_scratch assumes the width and height are in backend
    coordinates, while create_similar does not.

diff --git a/src/cairo-clip-surface.c b/src/cairo-clip-surface.c
index fff9724..85feaa6 100644
--- a/src/cairo-clip-surface.c
+++ b/src/cairo-clip-surface.c
@@ -132,11 +132,11 @@ _cairo_clip_get_surface (const cairo_clip_t *clip,
 	cairo_path_fixed_t path;
 	int i;
 
-	surface = _cairo_surface_create_similar_solid (target,
-						       CAIRO_CONTENT_ALPHA,
-						       clip->extents.width,
-						       clip->extents.height,
-						       CAIRO_COLOR_TRANSPARENT);
+	surface = _cairo_surface_create_scratch (target,
+						 CAIRO_CONTENT_ALPHA,
+						 clip->extents.width,
+						 clip->extents.height,
+						 CAIRO_COLOR_TRANSPARENT);
 	if (unlikely (surface->status))
 	    return surface;
 
@@ -162,11 +162,11 @@ _cairo_clip_get_surface (const cairo_clip_t *clip,
 	    return _cairo_surface_create_in_error (status);
 	}
     } else {
-	surface = _cairo_surface_create_similar_solid (target,
-						       CAIRO_CONTENT_ALPHA,
-						       clip->extents.width,
-						       clip->extents.height,
-						       CAIRO_COLOR_WHITE);
+	surface = _cairo_surface_create_scratch (target,
+						 CAIRO_CONTENT_ALPHA,
+						 clip->extents.width,
+						 clip->extents.height,
+						 CAIRO_COLOR_WHITE);
 	if (unlikely (surface->status))
 	    return surface;
     }
diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c
index 8964244..1e5067b 100644
--- a/src/cairo-default-context.c
+++ b/src/cairo-default-context.c
@@ -170,11 +170,11 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
 	    group_surface = cairo_recording_surface_create (content, NULL);
 	    extents.x = extents.y = 0;
 	} else {
-	    group_surface = _cairo_surface_create_similar_solid (parent_surface,
-								 content,
-								 extents.width,
-								 extents.height,
-								 CAIRO_COLOR_TRANSPARENT);
+	    group_surface = _cairo_surface_create_scratch (parent_surface,
+							   content,
+							   extents.width,
+							   extents.height,
+							   CAIRO_COLOR_TRANSPARENT);
 	}
 	status = group_surface->status;
 	if (unlikely (status))
diff --git a/src/cairo-gl-traps-compositor.c b/src/cairo-gl-traps-compositor.c
index ec478ee..125ed4e 100644
--- a/src/cairo-gl-traps-compositor.c
+++ b/src/cairo-gl-traps-compositor.c
@@ -333,10 +333,11 @@ traps_to_operand (void *_dst,
 	}
     }
 
-    mask = _cairo_surface_create_similar_scratch (_dst,
-						  CAIRO_CONTENT_COLOR_ALPHA,
-						  extents->width,
-						  extents->height);
+    mask = _cairo_surface_create_scratch (_dst,
+					  CAIRO_CONTENT_COLOR_ALPHA,
+					  extents->width,
+					  extents->height,
+					  NULL);
     if (unlikely (mask->status)) {
 	cairo_surface_destroy (image);
 	return mask->status;
@@ -445,10 +446,11 @@ tristrip_to_surface (void *_dst,
 	return (cairo_gl_surface_t *)image;
     }
 
-    mask = _cairo_surface_create_similar_scratch (_dst,
-						  CAIRO_CONTENT_COLOR_ALPHA,
-						  extents->width,
-						  extents->height);
+    mask = _cairo_surface_create_scratch (_dst,
+					  CAIRO_CONTENT_COLOR_ALPHA,
+					  extents->width,
+					  extents->height,
+					  NULL);
     if (unlikely (mask->status)) {
 	cairo_surface_destroy (image);
 	return (cairo_gl_surface_t *)mask;
diff --git a/src/cairo-mask-compositor.c b/src/cairo-mask-compositor.c
index d0be144..4d6b118 100644
--- a/src/cairo-mask-compositor.c
+++ b/src/cairo-mask-compositor.c
@@ -163,9 +163,10 @@ create_composite_mask (const cairo_mask_compositor_t *compositor,
     struct blt_in info;
     int i;
 
-    surface = _cairo_surface_create_similar_scratch (dst, CAIRO_CONTENT_ALPHA,
-						     extents->bounded.width,
-						     extents->bounded.height);
+    surface = _cairo_surface_create_scratch (dst, CAIRO_CONTENT_ALPHA,
+					     extents->bounded.width,
+					     extents->bounded.height,
+					     NULL);
     if (unlikely (surface->status))
 	return surface;
 
@@ -346,9 +347,10 @@ clip_and_composite_combine (const cairo_mask_compositor_t *compositor,
     cairo_status_t status;
     int clip_x, clip_y;
 
-    tmp = _cairo_surface_create_similar_scratch (dst, dst->content,
-						 extents->bounded.width,
-						 extents->bounded.height);
+    tmp = _cairo_surface_create_scratch (dst, dst->content,
+					 extents->bounded.width,
+					 extents->bounded.height,
+					 NULL);
     if (unlikely (tmp->status))
 	return tmp->status;
 
diff --git a/src/cairo-shape-mask-compositor.c b/src/cairo-shape-mask-compositor.c
index c2425b0..3117267 100644
--- a/src/cairo-shape-mask-compositor.c
+++ b/src/cairo-shape-mask-compositor.c
@@ -62,10 +62,11 @@ _cairo_shape_mask_compositor_stroke (const cairo_compositor_t *_compositor,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
-    mask = _cairo_surface_create_similar_scratch (extents->surface,
-						  CAIRO_CONTENT_ALPHA,
-						  extents->bounded.width,
-						  extents->bounded.height);
+    mask = _cairo_surface_create_scratch (extents->surface,
+					  CAIRO_CONTENT_ALPHA,
+					  extents->bounded.width,
+					  extents->bounded.height,
+					  NULL);
     if (unlikely (mask->status))
 	return mask->status;
 
@@ -156,10 +157,11 @@ _cairo_shape_mask_compositor_fill (const cairo_compositor_t *_compositor,
     if (! extents->is_bounded)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    mask = _cairo_surface_create_similar_scratch (extents->surface,
-						  CAIRO_CONTENT_ALPHA,
-						  extents->bounded.width,
-						  extents->bounded.height);
+    mask = _cairo_surface_create_scratch (extents->surface,
+					  CAIRO_CONTENT_ALPHA,
+					  extents->bounded.width,
+					  extents->bounded.height,
+					  NULL);
     if (unlikely (mask->status))
 	return mask->status;
 
@@ -248,10 +250,11 @@ _cairo_shape_mask_compositor_glyphs (const cairo_compositor_t *_compositor,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
-    mask = _cairo_surface_create_similar_scratch (extents->surface,
-						  CAIRO_CONTENT_ALPHA,
-						  extents->bounded.width,
-						  extents->bounded.height);
+    mask = _cairo_surface_create_scratch (extents->surface,
+					  CAIRO_CONTENT_ALPHA,
+					  extents->bounded.width,
+					  extents->bounded.height,
+					  NULL);
     if (unlikely (mask->status))
 	return mask->status;
 
diff --git a/src/cairo-spans-compositor.c b/src/cairo-spans-compositor.c
index 1a46ea3..efbae25 100644
--- a/src/cairo-spans-compositor.c
+++ b/src/cairo-spans-compositor.c
@@ -95,11 +95,11 @@ get_clip_surface (const cairo_spans_compositor_t *compositor,
 
     assert (clip->path);
 
-    surface = _cairo_surface_create_similar_solid (dst,
-						   CAIRO_CONTENT_ALPHA,
-						   extents->width,
-						   extents->height,
-						   CAIRO_COLOR_TRANSPARENT);
+    surface = _cairo_surface_create_scratch (dst,
+					     CAIRO_CONTENT_ALPHA,
+					     extents->width,
+					     extents->height,
+					     CAIRO_COLOR_TRANSPARENT);
 
     _cairo_box_from_rectangle (&box, extents);
     _cairo_polygon_init (&polygon, &box, 1);
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 0efb963..b7dfd9d 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -351,10 +351,11 @@ _cairo_surface_subsurface_snapshot (void *abstract_surface)
 
     TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, surface->target->unique_id));
 
-    clone = _cairo_surface_create_similar_scratch (surface->target,
-						   surface->target->content,
-						   surface->extents.width,
-						   surface->extents.height);
+    clone = _cairo_surface_create_scratch (surface->target,
+					   surface->target->content,
+					   surface->extents.width,
+					   surface->extents.height,
+					   NULL);
     if (unlikely (clone->status))
 	return clone;
 
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index 030de67..9236c8b 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -513,8 +513,8 @@ _cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
 				       int		width,
 				       int		height)
 {
-    return _cairo_surface_create_similar_scratch (wrapper->target,
-						  content, width, height);
+    return _cairo_surface_create_scratch (wrapper->target,
+					  content, width, height, NULL);
 }
 
 cairo_bool_t
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 9caacbb..cdd75b8 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -454,33 +454,6 @@ _cairo_surface_copy_similar_properties (cairo_surface_t *surface,
 					   other->y_fallback_resolution);
 }
 
-cairo_surface_t *
-_cairo_surface_create_similar_scratch (cairo_surface_t *other,
-				       cairo_content_t	content,
-				       int		width,
-				       int		height)
-{
-    cairo_surface_t *surface;
-
-    if (unlikely (other->status))
-	return _cairo_surface_create_in_error (other->status);
-
-    surface = NULL;
-    if (other->backend->create_similar)
-	surface = other->backend->create_similar (other, content, width, height);
-    if (surface == NULL)
-	surface = cairo_surface_create_similar_image (other,
-						      _cairo_format_from_content (content),
-						      width, height);
-
-    if (unlikely (surface->status))
-	return surface;
-
-    _cairo_surface_copy_similar_properties (surface, other);
-
-    return surface;
-}
-
 /**
  * cairo_surface_create_similar:
  * @other: an existing surface used to select the backend of the new surface
@@ -879,29 +852,45 @@ error:
 }
 
 cairo_surface_t *
-_cairo_surface_create_similar_solid (cairo_surface_t	 *other,
-				     cairo_content_t	  content,
-				     int		  width,
-				     int		  height,
-				     const cairo_color_t *color)
+_cairo_surface_create_scratch (cairo_surface_t	 *other,
+			       cairo_content_t	  content,
+			       int		  width,
+			       int		  height,
+			       const cairo_color_t *color)
 {
-    cairo_status_t status;
     cairo_surface_t *surface;
+    cairo_status_t status;
     cairo_solid_pattern_t pattern;
 
-    surface = _cairo_surface_create_similar_scratch (other, content,
-						     width, height);
+    if (unlikely (other->status))
+	return _cairo_surface_create_in_error (other->status);
+
+    surface = NULL;
+    if (other->backend->create_similar)
+	surface = other->backend->create_similar (other, content, width, height);
+    if (surface == NULL)
+	surface = cairo_surface_create_similar_image (other,
+						      _cairo_format_from_content (content),
+						      width, height);
+
     if (unlikely (surface->status))
 	return surface;
 
-    _cairo_pattern_init_solid (&pattern, color);
-    status = _cairo_surface_paint (surface,
-				   color == CAIRO_COLOR_TRANSPARENT ?
-				   CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
-				   &pattern.base, NULL);
-    if (unlikely (status)) {
-	cairo_surface_destroy (surface);
-	surface = _cairo_surface_create_in_error (status);
+    _cairo_surface_copy_similar_properties (surface, other);
+
+    if (unlikely (surface->status))
+	return surface;
+
+    if (color) {
+	_cairo_pattern_init_solid (&pattern, color);
+	status = _cairo_surface_paint (surface,
+				       color == CAIRO_COLOR_TRANSPARENT ?
+				       CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
+				       &pattern.base, NULL);
+	if (unlikely (status)) {
+	    cairo_surface_destroy (surface);
+	    surface = _cairo_surface_create_in_error (status);
+	}
     }
 
     return surface;
diff --git a/src/cairo-traps-compositor.c b/src/cairo-traps-compositor.c
index 631e172..8d67965 100644
--- a/src/cairo-traps-compositor.c
+++ b/src/cairo-traps-compositor.c
@@ -307,10 +307,11 @@ __clip_to_surface (const cairo_traps_compositor_t *compositor,
     if (unlikely (status))
 	return status;
 
-    mask = _cairo_surface_create_similar_scratch (composite->surface,
-						  CAIRO_CONTENT_ALPHA,
-						  extents->width,
-						  extents->height);
+    mask = _cairo_surface_create_scratch (composite->surface,
+					  CAIRO_CONTENT_ALPHA,
+					  extents->width,
+					  extents->height,
+					  NULL);
     if (unlikely (mask->status)) {
 	_cairo_traps_fini (&traps);
 	return status;
@@ -371,11 +372,11 @@ traps_get_clip_surface (const cairo_traps_compositor_t *compositor,
 
     status = __clip_to_surface (compositor, composite, extents, &surface);
     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	surface = _cairo_surface_create_similar_solid (composite->surface,
-						       CAIRO_CONTENT_ALPHA,
-						       extents->width,
-						       extents->height,
-						       CAIRO_COLOR_WHITE);
+	surface = _cairo_surface_create_scratch (composite->surface,
+						 CAIRO_CONTENT_ALPHA,
+						 extents->width,
+						 extents->height,
+						 CAIRO_COLOR_WHITE);
 	if (unlikely (surface->status))
 	    return surface;
 
@@ -430,9 +431,10 @@ create_composite_mask (const cairo_traps_compositor_t *compositor,
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
 
-    surface = _cairo_surface_create_similar_scratch (dst, CAIRO_CONTENT_ALPHA,
-						     extents->bounded.width,
-						     extents->bounded.height);
+    surface = _cairo_surface_create_scratch (dst, CAIRO_CONTENT_ALPHA,
+					     extents->bounded.width,
+					     extents->bounded.height,
+					     NULL);
     if (unlikely (surface->status))
 	return surface;
 
@@ -590,9 +592,10 @@ clip_and_composite_combine (const cairo_traps_compositor_t *compositor,
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
 
-    tmp = _cairo_surface_create_similar_scratch (dst, dst->content,
-						 extents->bounded.width,
-						 extents->bounded.height);
+    tmp = _cairo_surface_create_scratch (dst, dst->content,
+					 extents->bounded.width,
+					 extents->bounded.height,
+					 NULL);
     if (unlikely (tmp->status))
 	return tmp->status;
 
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 2d52be9..99efe87 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -1101,11 +1101,11 @@ record_to_picture (cairo_surface_t *target,
 	return _cairo_xcb_transparent_picture ((cairo_xcb_surface_t *) target);
 
     /* Now draw the recording surface to an xcb surface */
-    tmp = _cairo_surface_create_similar_solid (target,
-					       source->content,
-					       limit.width,
-					       limit.height,
-					       CAIRO_COLOR_TRANSPARENT);
+    tmp = _cairo_surface_create_scratch (target,
+                                         source->content,
+                                         limit.width,
+                                         limit.height,
+                                         CAIRO_COLOR_TRANSPARENT);
     if (tmp->status != CAIRO_STATUS_SUCCESS) {
 	return (cairo_xcb_picture_t *) tmp;
     }
@@ -1693,11 +1693,11 @@ get_clip_surface (const cairo_clip_t *clip,
     cairo_surface_t *surface;
     cairo_status_t status;
 
-    surface = _cairo_surface_create_similar_solid (&target->base,
-						   CAIRO_CONTENT_ALPHA,
-						   clip->extents.width,
-						   clip->extents.height,
-						   CAIRO_COLOR_WHITE);
+    surface = _cairo_surface_create_scratch (&target->base,
+					    CAIRO_CONTENT_ALPHA,
+					    clip->extents.width,
+					    clip->extents.height,
+					    CAIRO_COLOR_WHITE);
     if (unlikely (surface->status))
 	return (cairo_xcb_surface_t *) surface;
 
diff --git a/src/cairo-xlib-source.c b/src/cairo-xlib-source.c
index 746001e..8275da3 100644
--- a/src/cairo-xlib-source.c
+++ b/src/cairo-xlib-source.c
@@ -288,10 +288,11 @@ render_pattern (cairo_xlib_surface_t *dst,
     cairo_rectangle_int_t map_extents;
 
     src = (cairo_xlib_surface_t *)
-	_cairo_surface_create_similar_scratch (&dst->base,
-					       is_mask ? CAIRO_CONTENT_ALPHA : CAIRO_CONTENT_COLOR_ALPHA,
-					       extents->width,
-					       extents->height);
+	_cairo_surface_create_scratch (&dst->base,
+				       is_mask ? CAIRO_CONTENT_ALPHA : CAIRO_CONTENT_COLOR_ALPHA,
+				       extents->width,
+				       extents->height,
+				       NULL);
     if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
 	cairo_surface_destroy (&src->base);
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
@@ -750,10 +751,11 @@ subsurface_source (cairo_xlib_surface_t *dst,
 	source = &src->embedded_source;
     } else {
 	src = (cairo_xlib_surface_t *)
-	    _cairo_surface_create_similar_scratch (&dst->base,
-						   sub->base.content,
-						   sub->extents.width,
-						   sub->extents.height);
+	    _cairo_surface_create_scratch (&dst->base,
+					   sub->base.content,
+					   sub->extents.width,
+					   sub->extents.height,
+					   NULL);
 	if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
 	    cairo_surface_destroy (&src->base);
 	    return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
@@ -898,10 +900,11 @@ record_source (cairo_xlib_surface_t *dst,
     }
 
     src = (cairo_xlib_surface_t *)
-	_cairo_surface_create_similar_scratch (&dst->base,
-					       pattern->surface->content,
-					       upload.width,
-					       upload.height);
+	_cairo_surface_create_scratch (&dst->base,
+				       pattern->surface->content,
+				       upload.width,
+				       upload.height,
+				       NULL);
     if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
 	cairo_surface_destroy (&src->base);
 	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
@@ -1001,10 +1004,11 @@ surface_source (cairo_xlib_surface_t *dst,
     }
 
     xsrc = (cairo_xlib_surface_t *)
-	    _cairo_surface_create_similar_scratch (&dst->base,
-						   src->content,
-						   upload.width,
-						   upload.height);
+	    _cairo_surface_create_scratch (&dst->base,
+					   src->content,
+					   upload.width,
+					   upload.height,
+					   NULL);
     if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
 	cairo_surface_destroy (src);
 	cairo_surface_destroy (&xsrc->base);
diff --git a/src/cairoint.h b/src/cairoint.h
index 84e6026..d31e07b 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1288,21 +1288,15 @@ _cairo_surface_set_resolution (cairo_surface_t *surface,
                                double y_res);
 
 cairo_private cairo_surface_t *
-_cairo_surface_create_similar_scratch (cairo_surface_t *other,
-				       cairo_content_t	content,
-				       int		width,
-				       int		height);
-
-cairo_private cairo_surface_t *
 _cairo_surface_create_for_rectangle_int (cairo_surface_t *target,
 					 const cairo_rectangle_int_t *extents);
 
 cairo_private cairo_surface_t *
-_cairo_surface_create_similar_solid (cairo_surface_t	    *other,
-				     cairo_content_t	     content,
-				     int		     width,
-				     int		     height,
-				     const cairo_color_t    *color);
+_cairo_surface_create_scratch (cairo_surface_t	    *other,
+			       cairo_content_t	     content,
+			       int		     width,
+			       int		     height,
+			       const cairo_color_t  *color);
 
 cairo_private void
 _cairo_surface_init (cairo_surface_t			*surface,
commit bdccf4fe51bca785f73205ccd26c4d020669e312
Author: Alexander Larsson <alexl at redhat.com>
Date:   Tue Aug 27 14:33:14 2013 +0200

    surface: Opencode create_similar
    
    We copy the _cairo_surface_create_similar_solid code into
    cairo_surface_create_similar so that we can separate these later
    as one wants to use backend sizes and one not.

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index f07a0f6..9caacbb 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -518,6 +518,8 @@ cairo_surface_create_similar (cairo_surface_t  *other,
 			      int		height)
 {
     cairo_surface_t *surface;
+    cairo_status_t status;
+    cairo_solid_pattern_t pattern;
 
     if (unlikely (other->status))
 	return _cairo_surface_create_in_error (other->status);
@@ -529,9 +531,34 @@ cairo_surface_create_similar (cairo_surface_t  *other,
     if (unlikely (! CAIRO_CONTENT_VALID (content)))
 	return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT);
 
-    surface = _cairo_surface_create_similar_solid (other,
-						   content, width, height,
-						   CAIRO_COLOR_TRANSPARENT);
+        if (unlikely (other->status))
+	return _cairo_surface_create_in_error (other->status);
+
+    surface = NULL;
+    if (other->backend->create_similar)
+	surface = other->backend->create_similar (other, content, width, height);
+    if (surface == NULL)
+	surface = cairo_surface_create_similar_image (other,
+						      _cairo_format_from_content (content),
+						      width, height);
+
+    if (unlikely (surface->status))
+	return surface;
+
+    _cairo_surface_copy_similar_properties (surface, other);
+
+    if (unlikely (surface->status))
+	return surface;
+
+    _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_TRANSPARENT);
+    status = _cairo_surface_paint (surface,
+				   CAIRO_OPERATOR_CLEAR,
+				   &pattern.base, NULL);
+    if (unlikely (status)) {
+	cairo_surface_destroy (surface);
+	surface = _cairo_surface_create_in_error (status);
+    }
+
     assert (surface->is_clear);
 
     return surface;
commit 5f70148467ff2767dc3c6d45f4af1223d7daa301
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Jun 3 15:20:05 2013 +0100

    test: Allow CAIRO_TEST_MODE to independently enable extended testing
    
    Such as CAIRO_TEST_MODE=scale for testing application of
    cairo_surface_set_device_offset.
    
    CAIRO_TEST_MODE=similar - test rendering through similar surfaces
    CAIRO_TEST_MODE=offset - test rendering with a device offset
    CAIRO_TEST_MODE=scale - test rendering with a device scale

diff --git a/test/cairo-test-runner.c b/test/cairo-test-runner.c
index 71107f3..3fb3ae5 100644
--- a/test/cairo-test-runner.c
+++ b/test/cairo-test-runner.c
@@ -358,7 +358,7 @@ _parse_cmdline (cairo_test_runner_t *runner, int *argc, char **argv[])
 
 	switch (c) {
 	case 'a':
-	    runner->full_test = TRUE;
+	    runner->full_test = ~0;
 	    break;
 	case 'f':
 	    runner->foreground = TRUE;
@@ -691,6 +691,9 @@ _has_required_rsvg_version (const char *str)
     return TRUE;
 }
 
+#define TEST_SIMILAR	0x1
+#define TEST_OFFSET	0x2
+#define TEST_SCALE	0x4
 int
 main (int argc, char **argv)
 {
@@ -722,7 +725,16 @@ main (int argc, char **argv)
 	const char *env = getenv ("CAIRO_TEST_MODE");
 
 	if (strstr (env, "full")) {
-	    runner.full_test = TRUE;
+	    runner.full_test = ~0;
+	}
+	if (strstr (env, "similar")) {
+	    runner.full_test |= TEST_SIMILAR;
+	}
+	if (strstr (env, "offset")) {
+	    runner.full_test |= TEST_OFFSET;
+	}
+	if (strstr (env, "scale")) {
+	    runner.full_test |= TEST_SCALE;
 	}
 	if (strstr (env, "foreground")) {
 	    runner.foreground = TRUE;
@@ -743,8 +755,10 @@ main (int argc, char **argv)
     cairo_tests_env = getenv("CAIRO_TESTS");
     append_argv (&argc, &argv, cairo_tests_env);
 
-    if (runner.full_test) {
+    if (runner.full_test & TEST_OFFSET) {
 	runner.num_device_offsets = 2;
+    }
+    if (runner.full_test & TEST_SCALE) {
 	runner.num_device_scales = 2;
     }
 
@@ -910,7 +924,7 @@ main (int argc, char **argv)
 
 	    target = ctx.targets_to_test[n];
 
-	    has_similar = runner.full_test ?
+	    has_similar = runner.full_test & TEST_SIMILAR ?
 			  cairo_test_target_has_similar (&ctx, target) :
 			  DIRECT;
 	    for (m = 0; m < runner.num_device_offsets; m++) {
commit 690c61aa54c27e4d35b04d0173abd5931fce507d
Author: Alexander Larsson <alexl at redhat.com>
Date:   Mon Jun 3 15:38:22 2013 +0200

    tests: Add device scale test to "full" testrun similar to offsets

diff --git a/test/cairo-test-private.h b/test/cairo-test-private.h
index 3e40324..cfd22de 100644
--- a/test/cairo-test-private.h
+++ b/test/cairo-test-private.h
@@ -49,7 +49,7 @@ cairo_test_status_t
 _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
 				    const cairo_boilerplate_target_t *target,
 				    cairo_bool_t similar,
-				    int dev_offset);
+				    int dev_offset, int dev_scale);
 
 void
 _cairo_test_context_init_for_test (cairo_test_context_t *ctx,
diff --git a/test/cairo-test-runner.c b/test/cairo-test-runner.c
index a5c6705..71107f3 100644
--- a/test/cairo-test-runner.c
+++ b/test/cairo-test-runner.c
@@ -69,6 +69,7 @@ typedef struct _cairo_test_runner {
     cairo_test_context_t base;
 
     unsigned int num_device_offsets;
+    unsigned int num_device_scales;
 
     cairo_bool_t passed;
     int num_passed;
@@ -232,7 +233,7 @@ _cairo_test_runner_draw (cairo_test_runner_t *runner,
 			 cairo_test_context_t *ctx,
 			 const cairo_boilerplate_target_t *target,
 			 cairo_bool_t similar,
-			 int device_offset)
+			 int device_offset, int device_scale)
 {
 #if SHOULD_FORK
     if (! runner->foreground) {
@@ -244,7 +245,7 @@ _cairo_test_runner_draw (cairo_test_runner_t *runner,
 
 	case 0: /* child */
 	    exit (_cairo_test_context_run_for_target (ctx, target,
-						      similar, device_offset));
+						      similar, device_offset, device_scale));
 
 	default:
 	    return _cairo_test_wait (pid);
@@ -252,7 +253,7 @@ _cairo_test_runner_draw (cairo_test_runner_t *runner,
     }
 #endif
     return _cairo_test_context_run_for_target (ctx, target,
-					       similar, device_offset);
+					       similar, device_offset, device_scale);
 }
 
 static void
@@ -696,7 +697,7 @@ main (int argc, char **argv)
     cairo_test_runner_t runner;
     cairo_test_list_t *test_list;
     cairo_test_status_t *target_status;
-    unsigned int n, m;
+    unsigned int n, m, k;
     char targets[4096];
     int len;
     char *cairo_tests_env;
@@ -712,6 +713,7 @@ main (int argc, char **argv)
 
     memset (&runner, 0, sizeof (runner));
     runner.num_device_offsets = 1;
+    runner.num_device_scales = 1;
 
     if (is_running_under_debugger ())
 	runner.foreground = TRUE;
@@ -743,6 +745,7 @@ main (int argc, char **argv)
 
     if (runner.full_test) {
 	runner.num_device_offsets = 2;
+	runner.num_device_scales = 2;
     }
 
     target_status = NULL; /* silence the compiler */
@@ -911,32 +914,35 @@ main (int argc, char **argv)
 			  cairo_test_target_has_similar (&ctx, target) :
 			  DIRECT;
 	    for (m = 0; m < runner.num_device_offsets; m++) {
-		int dev_offset = m * 25;
-		cairo_test_similar_t similar;
-
-		for (similar = DIRECT; similar <= has_similar; similar++) {
-		    status = _cairo_test_runner_draw (&runner, &ctx, target,
-						      similar, dev_offset);
-		    switch (status) {
-		    case CAIRO_TEST_SUCCESS:
-			target_skipped = FALSE;
-			break;
-		    case CAIRO_TEST_XFAILURE:
-			target_xfailed = TRUE;
-			break;
-		    case CAIRO_TEST_NEW:
-		    case CAIRO_TEST_FAILURE:
-			target_failed = TRUE;
-			break;
-		    case CAIRO_TEST_ERROR:
-			target_error = TRUE;
-			break;
-		    case CAIRO_TEST_NO_MEMORY:
-		    case CAIRO_TEST_CRASHED:
-			target_crashed = TRUE;
-			break;
-		    case CAIRO_TEST_UNTESTED:
-			break;
+		for (k = 0; k < runner.num_device_scales; k++) {
+		    int dev_offset = m * 25;
+		    int dev_scale = k + 1;
+		    cairo_test_similar_t similar;
+
+		    for (similar = DIRECT; similar <= has_similar; similar++) {
+			status = _cairo_test_runner_draw (&runner, &ctx, target,
+							  similar, dev_offset, dev_scale);
+			switch (status) {
+			case CAIRO_TEST_SUCCESS:
+			    target_skipped = FALSE;
+			    break;
+			case CAIRO_TEST_XFAILURE:
+			    target_xfailed = TRUE;
+			    break;
+			case CAIRO_TEST_NEW:
+			case CAIRO_TEST_FAILURE:
+			    target_failed = TRUE;
+			    break;
+			case CAIRO_TEST_ERROR:
+			    target_error = TRUE;
+			    break;
+			case CAIRO_TEST_NO_MEMORY:
+			case CAIRO_TEST_CRASHED:
+			    target_crashed = TRUE;
+			    break;
+			case CAIRO_TEST_UNTESTED:
+			    break;
+			}
 		    }
 		}
 	    }
diff --git a/test/cairo-test.c b/test/cairo-test.c
index a3a587a..7bcb0ba 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -101,6 +101,7 @@ static cairo_bool_t print_fail_on_stdout;
 static int cairo_test_timeout = 60;
 
 #define NUM_DEVICE_OFFSETS 2
+#define NUM_DEVICE_SCALE 2
 
 static cairo_bool_t
 _cairo_test_mkdir (const char *path)
@@ -430,8 +431,8 @@ cairo_test_target_has_similar (const cairo_test_context_t *ctx,
 						target->content,
 						ctx->test->width,
 						ctx->test->height,
-						ctx->test->width + 25 * NUM_DEVICE_OFFSETS,
-						ctx->test->height + 25 * NUM_DEVICE_OFFSETS,
+						ctx->test->width* NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS,
+						ctx->test->height* NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS,
 						CAIRO_BOILERPLATE_MODE_TEST,
 						&closure);
 	    if (surface == NULL)
@@ -628,6 +629,7 @@ static cairo_test_status_t
 cairo_test_for_target (cairo_test_context_t		 *ctx,
 		       const cairo_boilerplate_target_t	 *target,
 		       int				  dev_offset,
+		       int				  dev_scale,
 		       cairo_bool_t                       similar)
 {
     cairo_test_status_t status;
@@ -635,6 +637,7 @@ cairo_test_for_target (cairo_test_context_t		 *ctx,
     cairo_t *cr;
     const char *empty_str = "";
     char *offset_str;
+    char *scale_str;
     char *base_name, *base_path;
     char *out_png_path;
     char *ref_path = NULL, *ref_png_path, *cmp_png_path = NULL;
@@ -666,15 +669,23 @@ cairo_test_for_target (cairo_test_context_t		 *ctx,
     else
 	offset_str = (char *) empty_str;
 
-    xasprintf (&base_name, "%s.%s.%s%s%s",
+    if (dev_scale != 1)
+	xasprintf (&scale_str, ".x%d", dev_scale);
+    else
+	scale_str = (char *) empty_str;
+
+    xasprintf (&base_name, "%s.%s.%s%s%s%s",
 	       ctx->test_name,
 	       target->name,
 	       format,
 	       similar ? ".similar" : "",
-	       offset_str);
+	       offset_str,
+               scale_str);
 
     if (offset_str != empty_str)
       free (offset_str);
+    if (scale_str != empty_str)
+      free (scale_str);
 
     ref_png_path = cairo_test_reference_filename (ctx,
 						  base_name,
@@ -782,6 +793,8 @@ cairo_test_for_target (cairo_test_context_t		 *ctx,
     width = ctx->test->width;
     height = ctx->test->height;
     if (width && height) {
+	width *= dev_scale;
+	height *= dev_scale;
 	width += dev_offset;
 	height += dev_offset;
     }
@@ -810,8 +823,8 @@ REPEAT:
     surface = (target->create_surface) (base_path,
 					target->content,
 					width, height,
-					ctx->test->width + 25 * NUM_DEVICE_OFFSETS,
-					ctx->test->height + 25 * NUM_DEVICE_OFFSETS,
+					ctx->test->width * NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS,
+					ctx->test->height * NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS,
 					CAIRO_BOILERPLATE_MODE_TEST,
 					&closure);
     if (surface == NULL) {
@@ -878,6 +891,7 @@ REPEAT:
     }
 
     cairo_surface_set_device_offset (surface, dev_offset, dev_offset);
+    cairo_surface_set_device_scale (surface, dev_scale, dev_scale);
 
     cr = cairo_create (surface);
     if (cairo_set_user_data (cr, &_cairo_test_context_key, (void*) ctx, NULL)) {
@@ -1471,7 +1485,7 @@ cairo_test_status_t
 _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
 				    const cairo_boilerplate_target_t *target,
 				    cairo_bool_t similar,
-				    int dev_offset)
+				    int dev_offset, int dev_scale)
 {
     cairo_test_status_t status;
 
@@ -1482,15 +1496,15 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
 	return CAIRO_TEST_UNTESTED;
 
     cairo_test_log (ctx,
-		    "Testing %s with %s%s target (dev offset %d)\n",
+		    "Testing %s with %s%s target (dev offset %d scale: %d)\n",
 		    ctx->test_name,
 		    similar ? " (similar) " : "",
 		    target->name,
-		    dev_offset);
+		    dev_offset, dev_scale);
 
-    printf ("%s.%s.%s [%d]%s:\t", ctx->test_name, target->name,
+    printf ("%s.%s.%s [%dx%d]%s:\t", ctx->test_name, target->name,
 	    cairo_boilerplate_content_name (target->content),
-	    dev_offset,
+	    dev_offset, dev_scale,
 	    similar ? " (similar)": "");
     fflush (stdout);
 
@@ -1519,7 +1533,7 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
 	old_sigalrm_handler = signal (SIGALRM, segfault_handler);
 #endif
 	if (0 == setjmp (jmpbuf))
-	    status = cairo_test_for_target (ctx, target, dev_offset, similar);
+	    status = cairo_test_for_target (ctx, target, dev_offset, dev_scale, similar);
 	else
 	    status = CAIRO_TEST_CRASHED;
 #ifdef SIGSEGV
@@ -1538,17 +1552,17 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
 	signal (SIGALRM, old_sigalrm_handler);
 #endif
     } else {
-	status = cairo_test_for_target (ctx, target, dev_offset, similar);
+	status = cairo_test_for_target (ctx, target, dev_offset, dev_scale, similar);
     }
 #else
-    status = cairo_test_for_target (ctx, target, dev_offset, similar);
+    status = cairo_test_for_target (ctx, target, dev_offset, dev_scale, similar);
 #endif
 
     cairo_test_log (ctx,
-		    "TEST: %s TARGET: %s FORMAT: %s OFFSET: %d SIMILAR: %d RESULT: ",
+		    "TEST: %s TARGET: %s FORMAT: %s OFFSET: %d SCALE: %d SIMILAR: %d RESULT: ",
 		    ctx->test_name, target->name,
 		    cairo_boilerplate_content_name (target->content),
-		    dev_offset, similar);
+		    dev_offset, dev_scale, similar);
     switch (status) {
     case CAIRO_TEST_SUCCESS:
 	printf ("PASS\n");
@@ -1570,9 +1584,9 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
 	    fflush (stdout);
 	}
 	cairo_test_log (ctx, "CRASHED\n");
-	fprintf (stderr, "%s.%s.%s [%d]%s:\t%s!!!CRASHED!!!%s\n",
+	fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%s!!!CRASHED!!!%s\n",
 		 ctx->test_name, target->name,
-		 cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
+		 cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
 		 fail_face, normal_face);
 	break;
 
@@ -1585,9 +1599,9 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
 	    fflush (stdout);
 	}
 	cairo_test_log (ctx, "ERROR\n");
-	fprintf (stderr, "%s.%s.%s [%d]%s:\t%s!!!ERROR!!!%s\n",
+	fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%s!!!ERROR!!!%s\n",
 		 ctx->test_name, target->name,
-		 cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
+		 cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
 		 fail_face, normal_face);
 	break;
 
@@ -1599,9 +1613,9 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
 	    printf ("\r");
 	    fflush (stdout);
 	}
-	fprintf (stderr, "%s.%s.%s [%d]%s:\t%sXFAIL%s\n",
+	fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%sXFAIL%s\n",
 		 ctx->test_name, target->name,
-		 cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
+		 cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
 		 xfail_face, normal_face);
 	cairo_test_log (ctx, "XFAIL\n");
 	break;
@@ -1614,9 +1628,9 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
 	    printf ("\r");
 	    fflush (stdout);
 	}
-	fprintf (stderr, "%s.%s.%s [%d]%s:\t%sNEW%s\n",
+	fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%sNEW%s\n",
 		 ctx->test_name, target->name,
-		 cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
+		 cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
 		 fail_face, normal_face);
 	cairo_test_log (ctx, "NEW\n");
 	break;
@@ -1630,9 +1644,9 @@ _cairo_test_context_run_for_target (cairo_test_context_t *ctx,
 	    printf ("\r");
 	    fflush (stdout);
 	}
-	fprintf (stderr, "%s.%s.%s [%d]%s:\t%sFAIL%s\n",
+	fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%sFAIL%s\n",
 		 ctx->test_name, target->name,
-		 cairo_boilerplate_content_name (target->content), dev_offset, similar ? " (similar)" : "",
+		 cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "",
 		 fail_face, normal_face);
 	cairo_test_log (ctx, "FAIL\n");
 	break;
commit 7ab34f302be72d9dda54d936b6d69bc7c534c885
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu May 30 19:45:59 2013 +0200

    surface: expose the device scale
    
    This adds the new public functions
    cairo_surface_set_device_scale and cairo_surface_get_device_scale and
    updates old users of the internal functions.

diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c
index 078135b..8964244 100644
--- a/src/cairo-default-context.c
+++ b/src/cairo-default-context.c
@@ -189,9 +189,9 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
 					 parent_surface->device_transform.x0 - extents.x,
 					 parent_surface->device_transform.y0 - extents.y);
 
-	_cairo_surface_set_device_scale (group_surface,
-					 parent_surface->device_transform.xx,
-					 parent_surface->device_transform.yy);
+	cairo_surface_set_device_scale (group_surface,
+					parent_surface->device_transform.xx,
+					parent_surface->device_transform.yy);
 
 	/* If we have a current path, we need to adjust it to compensate for
 	 * the device offset just applied. */
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index fe9ccee..68e4e0e 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -308,7 +308,7 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
     image = _cairo_paginated_surface_create_image_surface (surface,
 							   ceil (width  * x_scale),
 							   ceil (height * y_scale));
-    _cairo_surface_set_device_scale (image, x_scale, y_scale);
+    cairo_surface_set_device_scale (image, x_scale, y_scale);
     /* set_device_offset just sets the x0/y0 components of the matrix;
      * so we have to do the scaling manually. */
     cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 712c0fe..0efb963 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -500,9 +500,9 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target,
 
     surface->snapshot = NULL;
 
-    _cairo_surface_set_device_scale (&surface->base,
-                                     target->device_transform.xx,
-                                     target->device_transform.yy);
+    cairo_surface_set_device_scale (&surface->base,
+                                    target->device_transform.xx,
+                                    target->device_transform.yy);
 
     return &surface->base;
 }
@@ -542,9 +542,9 @@ _cairo_surface_create_for_rectangle_int (cairo_surface_t *target,
 
     surface->snapshot = NULL;
 
-    _cairo_surface_set_device_scale (&surface->base,
-                                     target->device_transform.xx,
-                                     target->device_transform.yy);
+    cairo_surface_set_device_scale (&surface->base,
+                                    target->device_transform.xx,
+                                    target->device_transform.yy);
 
     return &surface->base;
 }
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 79b2f2e..f07a0f6 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1624,26 +1624,28 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
 slim_hidden_def (cairo_surface_mark_dirty_rectangle);
 
 /**
- * _cairo_surface_set_device_scale:
+ * cairo_surface_set_device_scale:
  * @surface: a #cairo_surface_t
  * @sx: a scale factor in the X direction
  * @sy: a scale factor in the Y direction
  *
- * Private function for setting an extra scale factor to affect all
- * drawing to a surface. This is used, for example, when replaying a
- * recording surface to an image fallback intended for an eventual
- * vector-oriented backend. Since the recording surface will record
- * coordinates in one backend space, but the image fallback uses a
- * different backend space, (differing by the fallback resolution
- * scale factors), we need a scale factor correction.
+ * Sets an scale that is multiplied to the device coordinates determined
+ * by the CTM when drawing to @surface. One common use for this is to
+ * render to very high resolution display devices at a scale factor, so
+ * that code that assumes 1 pixel will be a certain size will still work.
+ * Setting a transformation via cairo_translate() isn't
+ * sufficient to do this, since functions like
+ * cairo_device_to_user() will expose the hidden scale.
+ *
+ * Note that the scale affects drawing to the surface as well as
+ * using the surface in a source pattern.
  *
- * Caution: Not all places we use device transform correctly handle
- * both a translate and a scale.  An audit would be nice.
+ * Since: 1.14
  **/
 void
-_cairo_surface_set_device_scale (cairo_surface_t *surface,
-				 double		  sx,
-				 double		  sy)
+cairo_surface_set_device_scale (cairo_surface_t *surface,
+				double		 sx,
+				double		 sy)
 {
     cairo_status_t status;
 
@@ -1675,6 +1677,30 @@ _cairo_surface_set_device_scale (cairo_surface_t *surface,
 
     _cairo_observers_notify (&surface->device_transform_observers, surface);
 }
+slim_hidden_def (cairo_surface_set_device_scale);
+
+/**
+ * cairo_surface_get_device_scale:
+ * @surface: a #cairo_surface_t
+ * @x_scale: the scale in the X direction, in device units
+ * @y_scale: the scale in the Y direction, in device units
+ *
+ * This function returns the previous device offset set by
+ * cairo_surface_set_device_scale().
+ *
+ * Since: 1.14
+ **/
+void
+cairo_surface_get_device_scale (cairo_surface_t *surface,
+				double          *x_scale,
+				double          *y_scale)
+{
+    if (x_scale)
+	*x_scale = surface->device_transform.xx;
+    if (y_scale)
+	*y_scale = surface->device_transform.yy;
+}
+slim_hidden_def (cairo_surface_get_device_scale);
 
 /**
  * cairo_surface_set_device_offset:
diff --git a/src/cairo.h b/src/cairo.h
index a2f5aa3..de35126 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -2456,6 +2456,16 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
 				    int              height);
 
 cairo_public void
+cairo_surface_set_device_scale (cairo_surface_t *surface,
+				double           x_scale,
+				double           y_scale);
+
+cairo_public void
+cairo_surface_get_device_scale (cairo_surface_t *surface,
+				double          *x_scale,
+				double          *y_scale);
+
+cairo_public void
 cairo_surface_set_device_offset (cairo_surface_t *surface,
 				 double           x_offset,
 				 double           y_offset);
diff --git a/src/cairoint.h b/src/cairoint.h
index 861e2f7..84e6026 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1420,11 +1420,6 @@ cairo_private_no_warn cairo_bool_t
 _cairo_surface_get_extents (cairo_surface_t         *surface,
 			    cairo_rectangle_int_t   *extents);
 
-cairo_private void
-_cairo_surface_set_device_scale (cairo_surface_t *surface,
-				 double		  sx,
-				 double		  sy);
-
 cairo_private cairo_bool_t
 _cairo_surface_has_device_transform (cairo_surface_t *surface) cairo_pure;
 
@@ -1955,6 +1950,7 @@ slim_hidden_proto (cairo_surface_destroy);
 slim_hidden_proto (cairo_surface_finish);
 slim_hidden_proto (cairo_surface_flush);
 slim_hidden_proto (cairo_surface_get_device_offset);
+slim_hidden_proto (cairo_surface_get_device_scale);
 slim_hidden_proto (cairo_surface_get_font_options);
 slim_hidden_proto (cairo_surface_get_mime_data);
 slim_hidden_proto (cairo_surface_has_show_text_glyphs);
@@ -1962,6 +1958,7 @@ slim_hidden_proto (cairo_surface_mark_dirty);
 slim_hidden_proto (cairo_surface_mark_dirty_rectangle);
 slim_hidden_proto_no_warn (cairo_surface_reference);
 slim_hidden_proto (cairo_surface_set_device_offset);
+slim_hidden_proto (cairo_surface_set_device_scale);
 slim_hidden_proto (cairo_surface_set_fallback_resolution);
 slim_hidden_proto (cairo_surface_set_mime_data);
 slim_hidden_proto (cairo_surface_show_page);
commit 38217d67fc2226778dde8d05817cb916691d4d22
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Jun 3 20:32:45 2013 +0100

    spans,traps: Undo device transform from source matrix for recording replays
    
    As the replay of the recording surface applies the device_transform of
    the matrix once again to all its operations, we end up with a repeated
    transform through the source matrix of the recording surface. We need to
    remove one of these, and the easiest way to do that appears to be to
    undo the application to the source matrix.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-spans-compositor.c b/src/cairo-spans-compositor.c
index 6eb9b42..1a46ea3 100644
--- a/src/cairo-spans-compositor.c
+++ b/src/cairo-spans-compositor.c
@@ -585,6 +585,8 @@ composite_aligned_boxes (const cairo_spans_compositor_t		*compositor,
     {
 	cairo_clip_t *recording_clip;
 	const cairo_pattern_t *source = &extents->source_pattern.base;
+	const cairo_matrix_t *m;
+	cairo_matrix_t matrix;
 
 	/* XXX could also do tiling repeat modes... */
 
@@ -600,10 +602,17 @@ composite_aligned_boxes (const cairo_spans_compositor_t		*compositor,
 	    dst->is_clear = TRUE;
 	}
 
+	m = &source->matrix;
+	if (_cairo_surface_has_device_transform (dst)) {
+	    cairo_matrix_multiply (&matrix,
+				   &source->matrix,
+				   &dst->device_transform);
+	    m = &matrix;
+	}
+
 	recording_clip = _cairo_clip_from_boxes (boxes);
 	status = _cairo_recording_surface_replay_with_clip (unwrap_source (source),
-							    &source->matrix,
-							    dst, recording_clip);
+							    m, dst, recording_clip);
 	_cairo_clip_destroy (recording_clip);
 
 	return status;
diff --git a/src/cairo-traps-compositor.c b/src/cairo-traps-compositor.c
index 988d23c..631e172 100644
--- a/src/cairo-traps-compositor.c
+++ b/src/cairo-traps-compositor.c
@@ -1206,7 +1206,9 @@ composite_aligned_boxes (const cairo_traps_compositor_t *compositor,
 					   &extents->source_sample_area))
     {
 	cairo_clip_t *recording_clip;
-	cairo_pattern_t *source = &extents->source_pattern.base;
+	const cairo_pattern_t *source = &extents->source_pattern.base;
+	const cairo_matrix_t *m;
+	cairo_matrix_t matrix;
 
 	/* XXX could also do tiling repeat modes... */
 
@@ -1225,10 +1227,17 @@ composite_aligned_boxes (const cairo_traps_compositor_t *compositor,
 		return status;
 	}
 
+	m = &source->matrix;
+	if (_cairo_surface_has_device_transform (dst)) {
+	    cairo_matrix_multiply (&matrix,
+				   &source->matrix,
+				   &dst->device_transform);
+	    m = &matrix;
+	}
+
 	recording_clip = _cairo_clip_from_boxes (boxes);
 	status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (source),
-							    &source->matrix,
-							    dst, recording_clip);
+							    m, dst, recording_clip);
 	_cairo_clip_destroy (recording_clip);
 
 	return status;
commit f0e2cd4494b1ac9a351d095fbeb53d702342d35c
Author: Alexander Larsson <alexl at redhat.com>
Date:   Fri May 31 16:44:29 2013 +0200

    gstate: Handle device scale on surface as source
    
    When creating a transformed pattern we must apply the device
    transform *before* the transform set on the pattern itself, otherwise
    e.g. its translation will not be affected by the device scale.
    
    We also fix up the device_transform related handling in
    _cairo_default_context_pop_group().  With a device scale we can
    no longer just use the device_transform_inverse to unset the
    device offset for the extents, so we make that a simple translate
    instead.
    
    We also remove some weird code that tries to handle the device
    transform but seems unnecessary (maybe a workaround for applying
    the device transform in the wrong order?). With that code removed
    things work fine, but with it things get translated wrongly when
    there is a scale.

diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c
index 77b6eef..078135b 100644
--- a/src/cairo-default-context.c
+++ b/src/cairo-default-context.c
@@ -218,7 +218,8 @@ _cairo_default_context_pop_group (void *abstract_cr)
     cairo_default_context_t *cr = abstract_cr;
     cairo_surface_t *group_surface;
     cairo_pattern_t *group_pattern;
-    cairo_matrix_t group_matrix, device_transform_matrix;
+    cairo_surface_t *parent_surface;
+    cairo_matrix_t group_matrix;
     cairo_status_t status;
 
     /* Verify that we are at the right nesting level */
@@ -232,29 +233,21 @@ _cairo_default_context_pop_group (void *abstract_cr)
     status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist);
     assert (status == CAIRO_STATUS_SUCCESS);
 
+    parent_surface = _cairo_gstate_get_target (cr->gstate);
+
     group_pattern = cairo_pattern_create_for_surface (group_surface);
     status = group_pattern->status;
     if (unlikely (status))
         goto done;
 
     _cairo_gstate_get_matrix (cr->gstate, &group_matrix);
-    /* Transform by group_matrix centered around device_transform so that when
-     * we call _cairo_gstate_copy_transformed_pattern the result is a pattern
-     * with a matrix equivalent to the device_transform of group_surface. */
-    if (_cairo_surface_has_device_transform (group_surface)) {
-	cairo_pattern_set_matrix (group_pattern, &group_surface->device_transform);
-	_cairo_pattern_transform (group_pattern, &group_matrix);
-	_cairo_pattern_transform (group_pattern, &group_surface->device_transform_inverse);
-    } else {
-	cairo_pattern_set_matrix (group_pattern, &group_matrix);
-    }
+    cairo_pattern_set_matrix (group_pattern, &group_matrix);
 
     /* If we have a current path, we need to adjust it to compensate for
      * the device offset just removed. */
-    cairo_matrix_multiply (&device_transform_matrix,
-                           &_cairo_gstate_get_target (cr->gstate)->device_transform,
-			   &group_surface->device_transform_inverse);
-    _cairo_path_fixed_transform (cr->path, &device_transform_matrix);
+    _cairo_path_fixed_translate (cr->path,
+				 _cairo_fixed_from_int (parent_surface->device_transform.x0 - group_surface->device_transform.x0),
+				 _cairo_fixed_from_int (parent_surface->device_transform.y0 - group_surface->device_transform.y0));
 
 done:
     cairo_surface_destroy (group_surface);
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 8ddb3af..b4e988e 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -954,7 +954,7 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t  *gstate,
         surface = surface_pattern->surface;
 
 	if (_cairo_surface_has_device_transform (surface))
-	    _cairo_pattern_transform (pattern, &surface->device_transform);
+	    _cairo_pattern_pretransform (pattern, &surface->device_transform);
     }
 
     if (! _cairo_matrix_is_identity (ctm_inverse))
diff --git a/src/cairo-pattern-private.h b/src/cairo-pattern-private.h
index dfd843f..bbcfadd 100644
--- a/src/cairo-pattern-private.h
+++ b/src/cairo-pattern-private.h
@@ -237,6 +237,10 @@ cairo_private void
 _cairo_pattern_transform (cairo_pattern_t      *pattern,
 			  const cairo_matrix_t *ctm_inverse);
 
+cairo_private void
+_cairo_pattern_pretransform (cairo_pattern_t      *pattern,
+                             const cairo_matrix_t *ctm);
+
 cairo_private cairo_bool_t
 _cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern);
 
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 940227d..57b930b 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -2128,6 +2128,16 @@ cairo_pattern_get_extend (cairo_pattern_t *pattern)
 slim_hidden_def (cairo_pattern_get_extend);
 
 void
+_cairo_pattern_pretransform (cairo_pattern_t	*pattern,
+			     const cairo_matrix_t  *ctm)
+{
+    if (pattern->status)
+	return;
+
+    cairo_matrix_multiply (&pattern->matrix, &pattern->matrix, ctm);
+}
+
+void
 _cairo_pattern_transform (cairo_pattern_t	*pattern,
 			  const cairo_matrix_t  *ctm_inverse)
 {
commit 900fc4a890026e46a3b0a00967632f57074b8b93
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu May 30 20:53:29 2013 +0200

    gstate: Move device-scale font scaling to gstate
    
    If we do this in surface it will be applied twice then
    we chain to a different surface, like e.g. a subsurface.
    
    We also remove a hack in cairo-surface-wrapper where it compensated
    for the device scale not being applied.
    
    v2: Compute the backend CTM in ensure_scaled_font().

diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 56e961e..8ddb3af 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1842,6 +1842,7 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate)
     cairo_status_t status;
     cairo_font_options_t options;
     cairo_scaled_font_t *scaled_font;
+    cairo_matrix_t font_ctm;
 
     if (gstate->scaled_font != NULL)
 	return gstate->scaled_font->status;
@@ -1853,9 +1854,13 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate)
     cairo_surface_get_font_options (gstate->target, &options);
     cairo_font_options_merge (&options, &gstate->font_options);
 
+    cairo_matrix_multiply (&font_ctm,
+			   &gstate->ctm,
+			   &gstate->target->device_transform);
+
     scaled_font = cairo_scaled_font_create (gstate->font_face,
 				            &gstate->font_matrix,
-					    &gstate->ctm,
+					    &font_ctm,
 					    &options);
 
     status = cairo_scaled_font_status (scaled_font);
@@ -2005,6 +2010,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t		   *gstate,
     if (cairo_surface_has_show_text_glyphs (gstate->target) ||
 	_cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240)
     {
+
 	if (info != NULL) {
 	    status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
 						      info->utf8, info->utf8_len,
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index 578e8e2..030de67 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -437,12 +437,11 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
 
 	_cairo_surface_wrapper_get_transform (wrapper, &m);
 
-	if (! _cairo_matrix_is_translation (&wrapper->transform)) {
+	if (! _cairo_matrix_is_translation (&m)) {
 	    cairo_matrix_t ctm;
 
-	    /* XXX No device-transform? A bug in the tangle of layers? */
 	    _cairo_matrix_multiply (&ctm,
-				    &wrapper->transform,
+				    &m,
 				    &scaled_font->ctm);
 	    dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
 							&scaled_font->font_matrix,
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 5e18b07..79b2f2e 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -2459,7 +2459,6 @@ _cairo_surface_show_text_glyphs (cairo_surface_t	    *surface,
 				 const cairo_clip_t		*clip)
 {
     cairo_int_status_t status;
-    cairo_scaled_font_t *dev_scaled_font = scaled_font;
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
     if (unlikely (surface->status))
@@ -2484,25 +2483,6 @@ _cairo_surface_show_text_glyphs (cairo_surface_t	    *surface,
     if (unlikely (status))
 	return status;
 
-    if (_cairo_surface_has_device_transform (surface) &&
-	! _cairo_matrix_is_integer_translation (&surface->device_transform, NULL, NULL))
-    {
-	cairo_font_options_t font_options;
-	cairo_matrix_t dev_ctm, font_matrix;
-
-	cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix);
-	cairo_scaled_font_get_ctm (scaled_font, &dev_ctm);
-	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &surface->device_transform);
-	cairo_scaled_font_get_font_options (scaled_font, &font_options);
-	dev_scaled_font = cairo_scaled_font_create (cairo_scaled_font_get_font_face (scaled_font),
-						    &font_matrix,
-						    &dev_ctm,
-						    &font_options);
-    }
-    status = cairo_scaled_font_status (dev_scaled_font);
-    if (unlikely (status))
-	return _cairo_surface_set_error (surface, status);
-
     status = CAIRO_INT_STATUS_UNSUPPORTED;
 
     /* The logic here is duplicated in _cairo_analysis_surface show_glyphs and
@@ -2516,7 +2496,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t	    *surface,
 							 utf8, utf8_len,
 							 glyphs, num_glyphs,
 							 clusters, num_clusters, cluster_flags,
-							 dev_scaled_font,
+							 scaled_font,
 							 clip);
 	}
 	if (status == CAIRO_INT_STATUS_UNSUPPORTED &&
@@ -2525,7 +2505,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t	    *surface,
 	    status = surface->backend->show_glyphs (surface, op,
 						    source,
 						    glyphs, num_glyphs,
-						    dev_scaled_font,
+						    scaled_font,
 						    clip);
 	}
     } else {
@@ -2534,7 +2514,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t	    *surface,
 	    status = surface->backend->show_glyphs (surface, op,
 						    source,
 						    glyphs, num_glyphs,
-						    dev_scaled_font,
+						    scaled_font,
 						    clip);
 	} else if (surface->backend->show_text_glyphs != NULL) {
 	    /* Intentionally only try show_text_glyphs method for show_glyphs
@@ -2550,14 +2530,11 @@ _cairo_surface_show_text_glyphs (cairo_surface_t	    *surface,
 							 utf8, utf8_len,
 							 glyphs, num_glyphs,
 							 clusters, num_clusters, cluster_flags,
-							 dev_scaled_font,
+							 scaled_font,
 							 clip);
 	}
     }
 
-    if (dev_scaled_font != scaled_font)
-	cairo_scaled_font_destroy (dev_scaled_font);
-
     if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
 	surface->is_clear = FALSE;
 	surface->serial++;
commit 25eaec0a3874a2090e1bb97547a328eb5c00b0b1
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu May 30 20:53:15 2013 +0200

    subsurface: Handle device scales

diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 051e95f..712c0fe 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -465,7 +465,12 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target,
     if (unlikely (surface == NULL))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    assert (_cairo_matrix_is_translation (&target->device_transform));
+    x *= target->device_transform.xx;
+    y *= target->device_transform.yy;
+
+    width *= target->device_transform.xx;
+    height *= target->device_transform.yy;
+
     x += target->device_transform.x0;
     y += target->device_transform.y0;
 
@@ -495,6 +500,10 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target,
 
     surface->snapshot = NULL;
 
+    _cairo_surface_set_device_scale (&surface->base,
+                                     target->device_transform.xx,
+                                     target->device_transform.yy);
+
     return &surface->base;
 }
 
@@ -515,14 +524,16 @@ _cairo_surface_create_for_rectangle_int (cairo_surface_t *target,
     if (unlikely (surface == NULL))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    assert (_cairo_matrix_is_translation (&target->device_transform));
-
     _cairo_surface_init (&surface->base,
 			 &_cairo_surface_subsurface_backend,
 			 NULL, /* device */
 			 target->content);
 
     surface->extents = *extents;
+    surface->extents.x *= target->device_transform.xx;
+    surface->extents.y *= target->device_transform.yy;
+    surface->extents.width *= target->device_transform.xx;
+    surface->extents.height *= target->device_transform.yy;
     surface->extents.x += target->device_transform.x0;
     surface->extents.y += target->device_transform.y0;
 
@@ -531,6 +542,10 @@ _cairo_surface_create_for_rectangle_int (cairo_surface_t *target,
 
     surface->snapshot = NULL;
 
+    _cairo_surface_set_device_scale (&surface->base,
+                                     target->device_transform.xx,
+                                     target->device_transform.yy);
+
     return &surface->base;
 }
 /* XXX observe mark-dirty */
commit 633d573889ad685c8f07e9ee72f6a1d240dfacf2
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu May 30 19:48:33 2013 +0200

    default-context: Inherit device scale in push_group surface
    
    Without this we will only render to part of the newly created
    surface and then copy+scale that part back, which causes fuzziness.

diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c
index aec5b10..77b6eef 100644
--- a/src/cairo-default-context.c
+++ b/src/cairo-default-context.c
@@ -189,6 +189,10 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
 					 parent_surface->device_transform.x0 - extents.x,
 					 parent_surface->device_transform.y0 - extents.y);
 
+	_cairo_surface_set_device_scale (group_surface,
+					 parent_surface->device_transform.xx,
+					 parent_surface->device_transform.yy);
+
 	/* If we have a current path, we need to adjust it to compensate for
 	 * the device offset just applied. */
 	_cairo_path_fixed_translate (cr->path,
commit db7e551a6bf06a0aa7e2e6b3744b7663807d003f
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu May 30 19:47:19 2013 +0200

    gstate: Respect device transform in stroke
    
    We need to apply the device transform to the ctm when stroking, as
    otherwise line widths are not affected by the device scale.

diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index b8caa63..56e961e 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1155,6 +1155,8 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
     cairo_stroke_style_t style;
     double dash[2];
     cairo_status_t status;
+    cairo_matrix_t aggregate_transform;
+    cairo_matrix_t aggregate_transform_inverse;
 
     status = _cairo_gstate_get_pattern_status (gstate->source);
     if (unlikely (status))
@@ -1171,8 +1173,15 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
 
     assert (gstate->opacity == 1.0);
 
+    cairo_matrix_multiply (&aggregate_transform,
+                           &gstate->ctm,
+                           &gstate->target->device_transform);
+    cairo_matrix_multiply (&aggregate_transform_inverse,
+                           &gstate->target->device_transform_inverse,
+                           &gstate->ctm_inverse);
+
     memcpy (&style, &gstate->stroke_style, sizeof (gstate->stroke_style));
-    if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance)) {
+    if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &aggregate_transform, gstate->tolerance)) {
         style.dash = dash;
         _cairo_stroke_style_dash_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance,
 					      &style.dash_offset,
@@ -1187,8 +1196,8 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
 				  &source_pattern.base,
 				  path,
 				  &style,
-				  &gstate->ctm,
-				  &gstate->ctm_inverse,
+				  &aggregate_transform,
+				  &aggregate_transform_inverse,
 				  gstate->tolerance,
 				  gstate->antialias,
 				  gstate->clip);
commit fb57ea13e04d82866cbc8e86c83261148bb3e231
Author: Krzysztof Kosiński <tweenk.pl at gmail.com>
Date:   Thu Sep 5 16:02:14 2013 +0100

    image: Use convolution filters for sample reconstruction when downscaling
    
    I had a look at how complex would it be to add correct downscaling to
    Cairo now that Pixman supports convolution filters. It turns out it
    this is rather easy. Here is an initial, minimal attempt. It uses
    convolution filters only if the image is being downscaled by more than
    half a pixel in at least one dimension.
    
    Some discussion:
    
    1. The sampling and reconstruction kernels are picked in a way that
    gives comparable quality when upscaling and downscaling. I paired box
    sampling with bilinear reconstruction and impulse (point) sampling
    with box reconstruction. This gives the expected result for NEAREST
    filter. BEST filter uses Lanczos3 for both kernels.
    
    > Do we need to use a reconstruction filter for NEAREST at all? Or maybe
    > differentiate between NEAREST and FAST in that case?
    
    If impulse (point) sampling is used, there must be some reconstruction
    filter, otherwise no image is produced. That's because the sampling
    grid does not match the data grid, and since there is no
    reconstruction filter, values between data points are undefined. The
    alternative is to use box sampling + no reconstruction.
    
    2. Subsampling bits are always set to 1, since this doesn't seem to
    affect quality at all.
    
    3. I am not sure whether this code works correctly for matrices with a
    skew component. It should be OK for any combination of scale, rotation
    and translation.
    
    4. This patch causes new failures in the test suite:
    - recording-surface*: possibly an effect of improved quality.
    - surface-pattern-scale-down*, surface-pattern-big-scale-down: the
    reference images should be updated.
    - pthread-same-source: I have no idea why this is failing, since this
    test shouldn't even trigger the new code.
    - large-source-roi: this test attempts to downscale an image which is
    30000 pixels wide down to 7 pixels. The filter parameters seem to be
    created correctly, but they might trigger an overflow somewhere in the
    convolution code; the output rectangle is white instead of red, as if
    nothing was drawn.
    - device-offset-scale: there are subtle differences which look like
    convolution-related smoothing; I'm not sure whether this is OK or not.

diff --git a/src/cairo-image-source.c b/src/cairo-image-source.c
index c5bd228..661bc10 100644
--- a/src/cairo-image-source.c
+++ b/src/cairo-image-source.c
@@ -554,24 +554,42 @@ _pixman_image_set_properties (pixman_image_t *pixman_image,
     }
     else
     {
+	double scale_x, scale_y;
+	int shrink_x, shrink_y;
 	pixman_filter_t pixman_filter;
+	pixman_kernel_t pixman_kernel_sample, pixman_kernel_reconstruct;
+
+	/* Compute scale factors as the length of basis vectors transformed by
+	 * the pattern matrix. These scale factors are from user to pattern space,
+	 * and as such they are greater than 1.0 for downscaling and less than 1.0
+	 * for upscaling.
+	 * TODO: this approach may not be completely correct if the matrix
+	 * contains a skew component. */
+	scale_x = hypot (pattern->matrix.xx, pattern->matrix.yx);
+	scale_y = hypot (pattern->matrix.yx, pattern->matrix.yy);
+
+	/* Use convolution filtering if the transformation shrinks the image
+	 * by more than half a pixel */
+	shrink_x = (extents->width / scale_x - extents->width) < -0.5;
+	shrink_y = (extents->height / scale_y - extents->height) < -0.5;
 
 	switch (pattern->filter) {
 	case CAIRO_FILTER_FAST:
-	    pixman_filter = PIXMAN_FILTER_FAST;
-	    break;
-	case CAIRO_FILTER_GOOD:
-	    pixman_filter = PIXMAN_FILTER_GOOD;
-	    break;
-	case CAIRO_FILTER_BEST:
-	    pixman_filter = PIXMAN_FILTER_BEST;
-	    break;
 	case CAIRO_FILTER_NEAREST:
 	    pixman_filter = PIXMAN_FILTER_NEAREST;
+	    pixman_kernel_sample = PIXMAN_KERNEL_IMPULSE;
+	    pixman_kernel_reconstruct = PIXMAN_KERNEL_BOX;
 	    break;
+	case CAIRO_FILTER_GOOD:
 	case CAIRO_FILTER_BILINEAR:
 	    pixman_filter = PIXMAN_FILTER_BILINEAR;
+	    pixman_kernel_sample = PIXMAN_KERNEL_BOX;
+	    pixman_kernel_reconstruct = PIXMAN_KERNEL_LINEAR;
 	    break;
+	case CAIRO_FILTER_BEST:
+	    pixman_filter = PIXMAN_FILTER_BEST;
+	    pixman_kernel_sample = PIXMAN_KERNEL_LANCZOS3;
+	    pixman_kernel_reconstruct = PIXMAN_KERNEL_LANCZOS3;
 	case CAIRO_FILTER_GAUSSIAN:
 	    /* XXX: The GAUSSIAN value has no implementation in cairo
 	     * whatsoever, so it was really a mistake to have it in the
@@ -579,10 +597,37 @@ _pixman_image_set_properties (pixman_image_t *pixman_image,
 	     * else inventing semantics and providing an actual
 	     * implementation for it. */
 	default:
-	    pixman_filter = PIXMAN_FILTER_BEST;
+	    pixman_filter = PIXMAN_FILTER_BILINEAR;
+	    pixman_kernel_sample = PIXMAN_KERNEL_BOX;
+	    pixman_kernel_reconstruct = PIXMAN_KERNEL_LINEAR;
 	}
 
-	pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
+	if (pixman_filter != PIXMAN_FILTER_NEAREST && (shrink_x || shrink_y)) {
+	    pixman_kernel_t sampling_kernel_x, sampling_kernel_y;
+	    int n_params;
+	    pixman_fixed_t *params;
+
+	    sampling_kernel_x = shrink_x ? pixman_kernel_sample : PIXMAN_KERNEL_IMPULSE;
+	    sampling_kernel_y = shrink_y ? pixman_kernel_sample : PIXMAN_KERNEL_IMPULSE;
+
+	    n_params = 0;
+	    params = pixman_filter_create_separable_convolution (&n_params,
+								 scale_x * 65536.0 + 0.5,
+								 scale_y * 65536.0 + 0.5,
+								 pixman_kernel_reconstruct,
+								 pixman_kernel_reconstruct,
+								 sampling_kernel_x,
+								 sampling_kernel_y,
+								 1, 1);
+
+	    pixman_image_set_filter (pixman_image,
+				     PIXMAN_FILTER_SEPARABLE_CONVOLUTION,
+				     params, n_params);
+
+	    free (params);
+	} else {
+	    pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
+	}
     }
 
     {
commit 28ad0f9f3bec65e462e29a1d0b1757a86d16c129
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Sep 5 15:56:55 2013 +0100

    Bump version for new development tree, 1.13.1

diff --git a/cairo-version.h b/cairo-version.h
index 046a614..df272d1 100644
--- a/cairo-version.h
+++ b/cairo-version.h
@@ -2,7 +2,7 @@
 #define CAIRO_VERSION_H
 
 #define CAIRO_VERSION_MAJOR 1
-#define CAIRO_VERSION_MINOR 12
-#define CAIRO_VERSION_MICRO 17
+#define CAIRO_VERSION_MINOR 13
+#define CAIRO_VERSION_MICRO 1
 
 #endif


More information about the cairo-commit mailing list