[cairo-commit] 24 commits - src/cairo-clip.c src/cairo-gstate.c src/cairo.h src/cairoint.h src/cairo-path.c src/cairo-ps-surface.c src/cairo-scaled-font.c src/cairo-surface.c src/cairo-surface-fallback.c src/cairo-traps.c src/cairo-xlib-surface.c test/buffer-diff.c test/buffer-diff.h test/cairo-test.c test/.gitignore test/imagediff.c test/linear-gradient.c test/linear-gradient-ref.png test/make-html.pl test/text-pattern.c test/text-pattern-ref.png test/text-pattern-rgb24-ref.png test/xlib-surface.c

Carl Worth cworth at kemper.freedesktop.org
Thu May 4 02:50:44 PDT 2006


 src/cairo-clip.c                |   11 +
 src/cairo-gstate.c              |   59 ++------
 src/cairo-path.c                |   46 ++++++
 src/cairo-ps-surface.c          |    6 
 src/cairo-scaled-font.c         |    8 -
 src/cairo-surface-fallback.c    |   64 +++-----
 src/cairo-surface.c             |  292 ++++++++++++++++++++++++++++++++--------
 src/cairo-traps.c               |   49 ++++++
 src/cairo-xlib-surface.c        |    4 
 src/cairo.h                     |    5 
 src/cairoint.h                  |   19 ++
 test/.gitignore                 |   36 ----
 test/buffer-diff.c              |   94 +++++++++---
 test/buffer-diff.h              |   21 ++
 test/cairo-test.c               |  134 ++++++++++++------
 test/imagediff.c                |   47 +-----
 test/linear-gradient-ref.png    |binary
 test/linear-gradient.c          |    6 
 test/make-html.pl               |  122 +++++++++-------
 test/text-pattern-ref.png       |binary
 test/text-pattern-rgb24-ref.png |binary
 test/text-pattern.c             |    4 
 test/xlib-surface.c             |    4 
 23 files changed, 686 insertions(+), 345 deletions(-)

New commits:
diff-tree 5e708b38e00f6b2066028c60a5526bf5d5e66356 (from parents)
Merge: a6b1b014bbd12be0f20c44d38d8847181be6d3ae 99719bde9ee0697bd43d97f034ccf4058c9484a0
Author: Carl Worth <cworth at cworth.org>
Date:   Thu May 4 01:46:34 2006 -0700

    Merge branch 'device-offset-history' into cairo

diff-tree a6b1b014bbd12be0f20c44d38d8847181be6d3ae (from 40b39dddf9cd919fb2f456a8e296a60cc8296fbf)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu May 4 01:45:41 2006 -0700

    Implement the device_offset functionality at surface, not gstate layer
    
    This is a mega-patch that has the advantage that the entire test suite
    passes both immediately before and immediately after this commit.
    
    The disadvantage of the mega-patch is that it does not reflect the
    development history of the device-offset branch, (with its various
    fumblings and flailings). To capture that history, we will next merge
    in that branch.

diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 0c862a3..7edb915 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -435,6 +435,15 @@ _cairo_clip_clip (cairo_clip_t       *cl
 {
     cairo_status_t status;
     cairo_traps_t traps;
+    cairo_path_fixed_t path_transformed;
+
+    if (_cairo_surface_has_device_offset_or_scale (target)) {
+	_cairo_path_fixed_init_copy (&path_transformed, path);
+	_cairo_path_fixed_offset (&path_transformed,
+				  _cairo_fixed_from_double (target->device_x_offset),
+				  _cairo_fixed_from_double (target->device_y_offset));
+	path = &path_transformed;
+    }
     
     status = _cairo_clip_intersect_path (clip,
 					 path, fill_rule, tolerance,
@@ -458,6 +467,8 @@ _cairo_clip_clip (cairo_clip_t       *cl
 	
  bail:
     _cairo_traps_fini (&traps);
+    if (path == &path_transformed)
+	_cairo_path_fixed_fini (&path_transformed);
 
     return status;
 }
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 10212cc..1a4ca6a 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -501,37 +501,10 @@ _cairo_gstate_get_miter_limit (cairo_gst
     return gstate->stroke_style.miter_limit;
 }
 
-static void
-_cairo_gstate_apply_device_transform (cairo_gstate_t    *gstate,
-				      cairo_matrix_t	*matrix)
-{
-    if (gstate->target->device_x_scale != 1.0 ||
-	gstate->target->device_y_scale != 1.0)
-    {
-	cairo_matrix_scale (matrix,
-			    gstate->target->device_x_scale,
-			    gstate->target->device_y_scale);
-    }
-}
-
-static void
-_cairo_gstate_apply_device_inverse_transform (cairo_gstate_t    *gstate,
-					      cairo_matrix_t	*matrix)
-{
-    if (gstate->target->device_x_scale != 1.0 ||
-	gstate->target->device_y_scale != 1.0)
-    {
-	cairo_matrix_scale (matrix,
-			    1/gstate->target->device_x_scale,
-			    1/gstate->target->device_y_scale);
-    }
-}
-
 void
 _cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
 {
     *matrix = gstate->ctm;
-    _cairo_gstate_apply_device_inverse_transform (gstate, matrix);
 }
 
 cairo_status_t
@@ -617,9 +590,6 @@ _cairo_gstate_set_matrix (cairo_gstate_t
     if (status)
 	return status;
 
-    _cairo_gstate_apply_device_transform (gstate, &gstate->ctm);
-    _cairo_gstate_apply_device_inverse_transform (gstate, &gstate->ctm_inverse);
-
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -631,9 +601,6 @@ _cairo_gstate_identity_matrix (cairo_gst
     cairo_matrix_init_identity (&gstate->ctm);
     cairo_matrix_init_identity (&gstate->ctm_inverse);
 
-    _cairo_gstate_apply_device_transform (gstate, &gstate->ctm);
-    _cairo_gstate_apply_device_inverse_transform (gstate, &gstate->ctm_inverse);
-
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -675,15 +642,11 @@ void
 _cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
 {
     cairo_matrix_transform_point (&gstate->ctm, x, y);
-    *x += gstate->target->device_x_offset;
-    *y += gstate->target->device_y_offset;
 }
 
 void
 _cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
 {
-    *x -= gstate->target->device_x_offset;
-    *y -= gstate->target->device_y_offset;
     cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
 }
 
@@ -704,16 +667,24 @@ _cairo_gstate_copy_transformed_pattern (
 					cairo_pattern_t *original,
 					cairo_matrix_t  *ctm_inverse)
 {
-    cairo_matrix_t tmp_matrix = *ctm_inverse;
-  
+    cairo_surface_pattern_t *surface_pattern;
+    cairo_surface_t *surface;
+    cairo_matrix_t offset_matrix;
+
     _cairo_pattern_init_copy (pattern, original);
+    _cairo_pattern_transform (pattern, ctm_inverse);
 
-    if (gstate->target)
-	cairo_matrix_translate (&tmp_matrix,
-				- gstate->target->device_x_offset,
-				- gstate->target->device_y_offset);
+    if (cairo_pattern_get_type (original) == CAIRO_PATTERN_TYPE_SURFACE) {
+        surface_pattern = (cairo_surface_pattern_t *) original;
+        surface = surface_pattern->surface;
+        if (_cairo_surface_has_device_offset_or_scale (surface)) {
+            cairo_matrix_init_translate (&offset_matrix,
+                                         surface->device_x_offset,
+                                         surface->device_y_offset);
+            _cairo_pattern_transform (pattern, &offset_matrix);
+        }
+    }
 
-    _cairo_pattern_transform (pattern, &tmp_matrix);
 }
 
 static void
diff --git a/src/cairo-path.c b/src/cairo-path.c
index 7358bee..5c94ad9 100644
--- a/src/cairo-path.c
+++ b/src/cairo-path.c
@@ -568,3 +568,49 @@ _cairo_path_fixed_interpret (cairo_path_
 
     return CAIRO_STATUS_SUCCESS;
 }
+
+static void
+_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
+				    cairo_fixed_t offx,
+				    cairo_fixed_t offy,
+				    cairo_fixed_t scalex,
+				    cairo_fixed_t scaley)
+{
+    cairo_path_arg_buf_t *arg_buf = path->arg_buf_head;
+    int i;
+    cairo_int64_t i64temp;
+    cairo_fixed_t fixedtemp;
+
+    while (arg_buf) {
+	 for (i = 0; i < arg_buf->num_points; i++) {
+	     if (scalex == CAIRO_FIXED_ONE) {
+		 arg_buf->points[i].x += offx;
+	     } else {
+		 fixedtemp = arg_buf->points[i].x + offx;
+		 i64temp = _cairo_int32x32_64_mul (fixedtemp, scalex);
+		 arg_buf->points[i].x = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
+	     }
+
+	     if (scaley == CAIRO_FIXED_ONE) {
+		 arg_buf->points[i].y += offy;
+	     } else {
+		 fixedtemp = arg_buf->points[i].y + offy;
+		 i64temp = _cairo_int32x32_64_mul (fixedtemp, scaley);
+		 arg_buf->points[i].y = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
+	     }
+	 }
+
+	 arg_buf = arg_buf->next;
+    }
+}
+
+void
+_cairo_path_fixed_offset (cairo_path_fixed_t *path,
+			  cairo_fixed_t offx,
+			  cairo_fixed_t offy)
+{
+    _cairo_path_fixed_offset_and_scale (path, offx, offy,
+					CAIRO_FIXED_ONE,
+					CAIRO_FIXED_ONE);
+}
+
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index f24e633..8bf46f5 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1194,10 +1194,8 @@ _cairo_ps_surface_start_page (void *abst
 				 (int) ceil (surface->height));
 
     _cairo_output_stream_printf (surface->stream,
-				 "gsave %f %f translate %f %f scale \n",
-				 0.0, surface->height,
-				 1.0/surface->base.device_x_scale,
-				 -1.0/surface->base.device_y_scale);
+				 "gsave %f %f translate 1.0 -1.0 scale \n",
+				 0.0, surface->height);
 
     _cairo_output_stream_printf (surface->stream,
 				 "%%%%EndPageSetup\n");
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 91e6257..3e40c7e 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -920,11 +920,11 @@ _cairo_scaled_font_show_glyphs (cairo_sc
 	
 	/* round glyph locations to the nearest pixel */
 	x = (int) floor (glyphs[i].x + 
-			 glyph_surface->base.device_x_offset +
-			 0.5);
+                         glyph_surface->base.device_x_offset +
+                         0.5);
 	y = (int) floor (glyphs[i].y +
-			 glyph_surface->base.device_y_offset +
-			 0.5);
+                         glyph_surface->base.device_y_offset +
+                         0.5);
 	
 	_cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base);
 
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index a5c723f..5b01039 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -895,7 +895,8 @@ _cairo_surface_old_show_glyphs_draw_func
 					     op, 
 					     src, dst,
 					     extents->x,         extents->y,
-					     extents->x - dst_x, extents->y - dst_y,
+					     extents->x - dst_x,
+					     extents->y - dst_y,
 					     extents->width,     extents->height,
 					     glyph_info->glyphs,
 					     glyph_info->num_glyphs);
@@ -989,6 +990,9 @@ _cairo_surface_fallback_snapshot (cairo_
     _cairo_surface_release_source_image (surface,
 					 image, &image_extra);
 
+    snapshot->device_x_offset = surface->device_x_offset;
+    snapshot->device_y_offset = surface->device_y_offset;
+
     snapshot->is_snapshot = TRUE;
 
     return snapshot;
@@ -1018,12 +1022,17 @@ _cairo_surface_fallback_composite (cairo
 	return status;
     }
 
-    status = state.image->base.backend->composite (op, src, mask,
-						   &state.image->base,
-						   src_x, src_y, mask_x, mask_y,
-						   dst_x - state.image_rect.x,
-						   dst_y - state.image_rect.y,
-						   width, height);
+    /* We know this will never fail with the image backend; but
+     * instead of calling into it directly, we call
+     * _cairo_surface_composite so that we get the correct device
+     * offset handling.
+     */
+    status = _cairo_surface_composite (op, src, mask,
+				       &state.image->base,
+				       src_x, src_y, mask_x, mask_y,
+				       dst_x - state.image_rect.x,
+				       dst_y - state.image_rect.y,
+				       width, height);
     _fallback_fini (&state);
 
     return status;
@@ -1093,9 +1102,9 @@ _cairo_surface_fallback_fill_rectangles 
 	rects = offset_rects;
     }
 
-    status = state.image->base.backend->fill_rectangles (&state.image->base,
-							 op, color,
-							 rects, num_rects);
+    status = _cairo_surface_fill_rectangles (&state.image->base,
+					     op, color,
+					     rects, num_rects);
 
     free (offset_rects);
 
@@ -1122,7 +1131,6 @@ _cairo_surface_fallback_composite_trapez
     fallback_state_t state;
     cairo_trapezoid_t *offset_traps = NULL;
     cairo_status_t status;
-    int i;
 
     status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
     if (status) {
@@ -1134,39 +1142,25 @@ _cairo_surface_fallback_composite_trapez
     /* If the destination image isn't at 0,0, we need to offset the trapezoids */
     
     if (state.image_rect.x != 0 || state.image_rect.y != 0) {
-
-	cairo_fixed_t xoff = _cairo_fixed_from_int (state.image_rect.x);
-	cairo_fixed_t yoff = _cairo_fixed_from_int (state.image_rect.y);
-	
 	offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps);
 	if (!offset_traps) {
 	    status = CAIRO_STATUS_NO_MEMORY;
 	    goto DONE;
 	}
 
-	for (i = 0; i < num_traps; i++) {
-	    offset_traps[i].top = traps[i].top - yoff;
-	    offset_traps[i].bottom = traps[i].bottom - yoff;
-	    offset_traps[i].left.p1.x = traps[i].left.p1.x - xoff;
-	    offset_traps[i].left.p1.y = traps[i].left.p1.y - yoff;
-	    offset_traps[i].left.p2.x = traps[i].left.p2.x - xoff;
-	    offset_traps[i].left.p2.y = traps[i].left.p2.y - yoff;
-	    offset_traps[i].right.p1.x = traps[i].right.p1.x - xoff;
-	    offset_traps[i].right.p1.y = traps[i].right.p1.y - yoff;
-	    offset_traps[i].right.p2.x = traps[i].right.p2.x - xoff;
-	    offset_traps[i].right.p2.y = traps[i].right.p2.y - yoff;
-	}
-
+	_cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps,
+                                                    - state.image_rect.x, - state.image_rect.y,
+                                                    1.0, 1.0);
 	traps = offset_traps;
     }
 
-    state.image->base.backend->composite_trapezoids (op, pattern,
-						     &state.image->base,
-						     antialias,
-						     src_x, src_y,
-						     dst_x - state.image_rect.x,
-						     dst_y - state.image_rect.y,
-						     width, height, traps, num_traps);
+    _cairo_surface_composite_trapezoids (op, pattern,
+					 &state.image->base,
+					 antialias,
+					 src_x, src_y,
+					 dst_x - state.image_rect.x,
+					 dst_y - state.image_rect.y,
+					 width, height, traps, num_traps);
     if (offset_traps)
 	free (offset_traps);
 
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index f905dfd..025f300 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -92,6 +92,14 @@ const cairo_surface_t _cairo_surface_nil
     0					/* current_clip_serial */
 };
 
+/* Helper macros for transforming surface coords to backend coords */
+#define SURFACE_TO_BACKEND_X(_surf, _sx)  ((_sx)+((_surf)->device_x_offset))
+#define SURFACE_TO_BACKEND_Y(_surf, _sy)  ((_sy)+((_surf)->device_y_offset))
+
+static void _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
+                                                         cairo_surface_t *destination,
+                                                         cairo_pattern_t *pattern_out);
+
 /**
  * _cairo_surface_set_error:
  * @surface: a surface
@@ -171,8 +179,6 @@ _cairo_surface_init (cairo_surface_t			*
 
     surface->device_x_offset = 0.0;
     surface->device_y_offset = 0.0;
-    surface->device_x_scale = 1.0;
-    surface->device_y_scale = 1.0;
 
     surface->clip = NULL;
     surface->next_clip_serial = 0;
@@ -556,7 +562,10 @@ cairo_surface_mark_dirty_rectangle (cair
     if (surface->backend->mark_dirty_rectangle) {
 	cairo_status_t status;
 	
-	status = surface->backend->mark_dirty_rectangle (surface, x, y, width, height);
+	status = surface->backend->mark_dirty_rectangle (surface,
+                                                         SURFACE_TO_BACKEND_X(surface, x),
+                                                         SURFACE_TO_BACKEND_Y(surface, y),
+							 width, height);
 	
 	if (status)
 	    _cairo_surface_set_error (surface, status);
@@ -596,8 +605,34 @@ cairo_surface_set_device_offset (cairo_s
 	return;
     }
 
-    surface->device_x_offset = x_offset * surface->device_x_scale;
-    surface->device_y_offset = y_offset * surface->device_y_scale;
+    surface->device_x_offset = x_offset;
+    surface->device_y_offset = y_offset;
+}
+
+/**
+ * cairo_surface_get_device_offset:
+ * @surface: a #cairo_surface_t
+ * @x_offset: the offset in the X direction, in device units
+ * @y_offset: the offset in the Y direction, in device units
+ *
+ * Returns a previous device offset set by
+ * cairo_surface_set_device_offset().
+ *
+ **/
+void
+cairo_surface_get_device_offset (cairo_surface_t *surface,
+				 double          *x_offset,
+				 double          *y_offset)
+{
+    *x_offset = surface->device_x_offset;
+    *y_offset = surface->device_y_offset;
+}
+
+cairo_bool_t
+_cairo_surface_has_device_offset_or_scale (cairo_surface_t *surface)
+{
+    return (surface->device_x_offset != 0.0 ||
+	    surface->device_y_offset != 0.0);
 }
 
 /**
@@ -651,6 +686,7 @@ _cairo_surface_release_source_image (cai
  * @surface: a #cairo_surface_t
  * @interest_rect: area of @surface for which fallback drawing is being done.
  *    A value of %NULL indicates that the entire surface is desired.
+ *    XXXX I'd like to get rid of being able to pass NULL here (nothing seems to)
  * @image_out: location to store a pointer to an image surface that includes at least
  *    the intersection of @interest_rect with the visible area of @surface.
  *    This surface could be @surface itself, a surface held internal to @surface,
@@ -685,7 +721,8 @@ _cairo_surface_acquire_dest_image (cairo
 {
     assert (!surface->finished);
 
-    return surface->backend->acquire_dest_image (surface, interest_rect,
+    return surface->backend->acquire_dest_image (surface,
+						 interest_rect,
 						 image_out, image_rect, image_extra);
 }
 
@@ -747,6 +784,11 @@ _cairo_surface_clone_similar (cairo_surf
 	return CAIRO_INT_STATUS_UNSUPPORTED;
       
     status = surface->backend->clone_similar (surface, src, clone_out);
+    if (status == CAIRO_STATUS_SUCCESS) {
+        (*clone_out)->device_x_offset = src->device_x_offset;
+        (*clone_out)->device_y_offset = src->device_y_offset;
+    }
+
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return status;
 
@@ -755,6 +797,10 @@ _cairo_surface_clone_similar (cairo_surf
 	return status;
 
     status = surface->backend->clone_similar (surface, &image->base, clone_out);
+    if (status == CAIRO_STATUS_SUCCESS) {
+        (*clone_out)->device_x_offset = src->device_x_offset;
+        (*clone_out)->device_y_offset = src->device_y_offset;
+    }
 
     /* If the above failed point, we could implement a full fallback
      * using acquire_dest_image, but that's going to be very
@@ -829,9 +875,9 @@ _cairo_surface_composite (cairo_operator
     if (dst->backend->composite) {
 	status = dst->backend->composite (op,
 					  src, mask, dst,
-					  src_x, src_y,
-					  mask_x, mask_y,
-					  dst_x, dst_y,
+                                          src_x, src_y,
+                                          mask_x, mask_y,
+                                          dst_x, dst_y,
 					  width, height);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
@@ -989,16 +1035,24 @@ _cairo_surface_paint (cairo_surface_t	*s
 		      cairo_pattern_t	*source)
 {
     cairo_status_t status;
+    cairo_pattern_union_t dev_source;
 
     assert (! surface->is_snapshot);
 
+    _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
+
     if (surface->backend->paint) {
-	status = surface->backend->paint (surface, op, source);
+	status = surface->backend->paint (surface, op, &dev_source.base);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+            goto FINISH;
     }
 
-    return _cairo_surface_fallback_paint (surface, op, source);
+    status = _cairo_surface_fallback_paint (surface, op, &dev_source.base);
+
+FINISH:
+    _cairo_pattern_fini (&dev_source.base);
+
+    return status;
 }
 
 cairo_status_t
@@ -1008,16 +1062,27 @@ _cairo_surface_mask (cairo_surface_t	*su
 		     cairo_pattern_t	*mask)
 {
     cairo_status_t status;
+    cairo_pattern_union_t dev_source;
+    cairo_pattern_union_t dev_mask;
 
     assert (! surface->is_snapshot);
 
+    _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
+    _cairo_surface_copy_pattern_for_destination (mask, surface, &dev_mask.base);
+
     if (surface->backend->mask) {
-	status = surface->backend->mask (surface, op, source, mask);
+	status = surface->backend->mask (surface, op, &dev_source.base, &dev_mask.base);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+            goto FINISH;
     }
 
-    return _cairo_surface_fallback_mask (surface, op, source, mask);
+    status = _cairo_surface_fallback_mask (surface, op, &dev_source.base, &dev_mask.base);
+
+FINISH:
+    _cairo_pattern_fini (&dev_source.base);
+    _cairo_pattern_fini (&dev_mask.base);
+
+    return status;
 }
 
 cairo_status_t
@@ -1031,22 +1096,45 @@ _cairo_surface_stroke (cairo_surface_t		
 		       double			 tolerance,
 		       cairo_antialias_t	 antialias)
 {
+    cairo_status_t status;
+    cairo_pattern_union_t dev_source;
+    cairo_path_fixed_t *dev_path = path;
+    cairo_path_fixed_t real_dev_path;
+
     assert (! surface->is_snapshot);
 
+    _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
+
+    if (_cairo_surface_has_device_offset_or_scale (surface))
+    {
+        _cairo_path_fixed_init_copy (&real_dev_path, path);
+        _cairo_path_fixed_offset (&real_dev_path,
+				  _cairo_fixed_from_double (surface->device_x_offset),
+				  _cairo_fixed_from_double (surface->device_y_offset));
+        dev_path = &real_dev_path;
+    }
+
     if (surface->backend->stroke) {
-	cairo_status_t status;
-	status = surface->backend->stroke (surface, op, source,
-					   path, stroke_style,
+	status = surface->backend->stroke (surface, op, &dev_source.base,
+					   dev_path, stroke_style,
 					   ctm, ctm_inverse,
 					   tolerance, antialias);
+
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+            goto FINISH;
     }
 
-    return _cairo_surface_fallback_stroke (surface, op, source,
-					   path, stroke_style,
-					   ctm, ctm_inverse,
-					   tolerance, antialias);
+    status = _cairo_surface_fallback_stroke (surface, op, &dev_source.base,
+                                             dev_path, stroke_style,
+                                             ctm, ctm_inverse,
+                                             tolerance, antialias);
+
+FINISH:
+    if (dev_path == &real_dev_path)
+        _cairo_path_fixed_fini (&real_dev_path);
+    _cairo_pattern_fini (&dev_source.base);
+
+    return status;
 }
 
 cairo_status_t
@@ -1059,20 +1147,42 @@ _cairo_surface_fill (cairo_surface_t	*su
 		     cairo_antialias_t	 antialias)
 {
     cairo_status_t status;
+    cairo_pattern_union_t dev_source;
+    cairo_path_fixed_t *dev_path = path;
+    cairo_path_fixed_t real_dev_path;
 
     assert (! surface->is_snapshot);
 
+    _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
+
+    if (_cairo_surface_has_device_offset_or_scale (surface))
+    {
+        _cairo_path_fixed_init_copy (&real_dev_path, path);
+        _cairo_path_fixed_offset (&real_dev_path,
+				  _cairo_fixed_from_double (surface->device_x_offset),
+				  _cairo_fixed_from_double (surface->device_y_offset));
+        dev_path = &real_dev_path;
+    }
+
     if (surface->backend->fill) {
-	status = surface->backend->fill (surface, op, source,
-					 path, fill_rule,
+	status = surface->backend->fill (surface, op, &dev_source.base,
+					 dev_path, fill_rule,
 					 tolerance, antialias);
+
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+            goto FINISH;
     }
 
-    return _cairo_surface_fallback_fill (surface, op, source,
-					 path, fill_rule,
-					 tolerance, antialias);
+    status = _cairo_surface_fallback_fill (surface, op, &dev_source.base,
+                                           dev_path, fill_rule,
+                                           tolerance, antialias);
+
+FINISH:
+    if (dev_path == &real_dev_path)
+        _cairo_path_fixed_fini (&real_dev_path);
+    _cairo_pattern_fini (&dev_source.base);
+
+    return status;
 }
   
 cairo_status_t
@@ -1109,7 +1219,7 @@ _cairo_surface_composite_trapezoids (cai
 						     pattern, dst,
 						     antialias,
 						     src_x, src_y,
-						     dst_x, dst_y,
+                                                     dst_x, dst_y,
 						     width, height,
 						     traps, num_traps);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
@@ -1258,6 +1368,8 @@ _cairo_surface_set_clip_region (cairo_su
 				pixman_region16_t   *region,
 				unsigned int	    serial)
 {
+    cairo_status_t status;
+
     if (surface->status)
 	return surface->status;
 
@@ -1265,10 +1377,12 @@ _cairo_surface_set_clip_region (cairo_su
 	return CAIRO_STATUS_SURFACE_FINISHED;
     
     assert (surface->backend->set_clip_region != NULL);
-    
+
     surface->current_clip_serial = serial;
 
-    return surface->backend->set_clip_region (surface, region);
+    status = surface->backend->set_clip_region (surface, region);
+
+    return status;
 }
 
 cairo_int_status_t
@@ -1278,6 +1392,9 @@ _cairo_surface_intersect_clip_path (cair
 				    double		tolerance,
 				    cairo_antialias_t	antialias)
 {
+    cairo_path_fixed_t *dev_path = path;
+    cairo_status_t status;
+
     if (surface->status)
 	return surface->status;
 
@@ -1286,11 +1403,13 @@ _cairo_surface_intersect_clip_path (cair
     
     assert (surface->backend->intersect_clip_path != NULL);
 
-    return surface->backend->intersect_clip_path (surface,
-						  path,
-						  fill_rule,
-						  tolerance,
-						  antialias);
+    status = surface->backend->intersect_clip_path (surface,
+						    dev_path,
+						    fill_rule,
+						    tolerance,
+						    antialias);
+
+    return status;
 }
 
 static cairo_status_t
@@ -1306,11 +1425,11 @@ _cairo_surface_set_clip_path_recursive (
     if (status)
 	return status;
 
-    return surface->backend->intersect_clip_path (surface,
-						  &clip_path->path,
-						  clip_path->fill_rule,
-						  clip_path->tolerance,
-						  clip_path->antialias);
+    return _cairo_surface_intersect_clip_path (surface,
+					       &clip_path->path,
+					       clip_path->fill_rule,
+					       clip_path->tolerance,
+					       clip_path->antialias);
 }
 
 /**
@@ -1413,13 +1532,22 @@ cairo_status_t
 _cairo_surface_get_extents (cairo_surface_t   *surface,
 			    cairo_rectangle_t *rectangle)
 {
+    cairo_status_t status;
+
     if (surface->status)
 	return surface->status;
 
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
-    return surface->backend->get_extents (surface, rectangle);
+    status = surface->backend->get_extents (surface, rectangle);
+
+    rectangle->x = SURFACE_TO_BACKEND_X(surface, rectangle->x);
+    rectangle->y = SURFACE_TO_BACKEND_Y(surface, rectangle->y);
+    rectangle->width = rectangle->width - surface->device_x_offset;
+    rectangle->height = rectangle->height - surface->device_y_offset;
+
+    return status;
 }
 
 cairo_status_t
@@ -1431,20 +1559,48 @@ _cairo_surface_show_glyphs (cairo_surfac
 			    cairo_scaled_font_t	*scaled_font)
 {
     cairo_status_t status;
+    cairo_glyph_t *dev_glyphs = (cairo_glyph_t*) glyphs;
+    cairo_pattern_union_t dev_source;
 
     assert (! surface->is_snapshot);
 
+    _cairo_surface_copy_pattern_for_destination (source,
+                                                 surface,
+                                                 &dev_source.base);
+
+    if (_cairo_surface_has_device_offset_or_scale (surface))
+    {
+        int i;
+
+        dev_glyphs = malloc (sizeof(cairo_glyph_t) * num_glyphs);
+        if (!dev_glyphs)
+            return CAIRO_STATUS_NO_MEMORY;
+
+        for (i = 0; i < num_glyphs; i++) {
+            dev_glyphs[i].index = glyphs[i].index;
+            /* XXX: err, we really should scale the size of the glyphs, no? */
+            dev_glyphs[i].x = SURFACE_TO_BACKEND_X(surface, glyphs[i].x);
+            dev_glyphs[i].y = SURFACE_TO_BACKEND_Y(surface, glyphs[i].y);
+        }
+    }
+
     if (surface->backend->show_glyphs) {
-	status = surface->backend->show_glyphs (surface, op, source,
-						glyphs, num_glyphs,
-						scaled_font);
+	status = surface->backend->show_glyphs (surface, op, &dev_source.base,
+						dev_glyphs, num_glyphs,
+                                                scaled_font);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+            goto FINISH;
     }
 
-    return _cairo_surface_fallback_show_glyphs (surface, op, source,
-						glyphs, num_glyphs,
-						scaled_font);
+    status = _cairo_surface_fallback_show_glyphs (surface, op, &dev_source.base,
+                                                  dev_glyphs, num_glyphs,
+                                                  scaled_font);
+
+FINISH:
+    if (dev_glyphs != glyphs)
+        free (dev_glyphs);
+
+    return status;
 }
 
 /* XXX: Previously, we had a function named _cairo_surface_show_glyphs
@@ -1476,14 +1632,14 @@ _cairo_surface_old_show_glyphs (cairo_sc
     if (dst->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
-    if (dst->backend->old_show_glyphs)
+    if (dst->backend->old_show_glyphs) {
 	status = dst->backend->old_show_glyphs (scaled_font,
 						op, pattern, dst,
 						source_x, source_y,
-						dest_x, dest_y,
+                                                dest_x, dest_y,
 						width, height,
 						glyphs, num_glyphs);
-    else
+    } else
 	status = CAIRO_INT_STATUS_UNSUPPORTED;
 
     return status;
@@ -1593,7 +1749,7 @@ _cairo_surface_composite_fixup_unbounded
     cairo_rectangle_t *mask_rectangle = NULL;
 
     assert (! dst->is_snapshot);
-  
+
     /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
      * non-repeating sources and masks. Other sources and masks can be ignored.
      */
@@ -1668,7 +1824,7 @@ _cairo_surface_composite_shape_fixup_unb
     cairo_rectangle_t *mask_rectangle = NULL;
 
     assert (! dst->is_snapshot);
-  
+
     /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
      * non-repeating sources and masks. Other sources and masks can be ignored.
      */
@@ -1729,3 +1885,29 @@ _cairo_surface_is_opaque (const cairo_su
 
     return FALSE;
 }
+
+/**
+ * _cairo_surface_copy_pattern_for_destination
+ * @pattern: the pattern to copy
+ * @destination: the destination surface for which the pattern is being copied
+ * @pattern_out: the location to hold the copy
+ *
+ * Copies the given pattern, taking into account device scale and offsets
+ * of the destination surface.
+ */
+void
+_cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
+                                             cairo_surface_t *destination,
+                                             cairo_pattern_t *pattern_out)
+{
+    _cairo_pattern_init_copy (pattern_out, pattern);
+
+    if (_cairo_surface_has_device_offset_or_scale (destination)) {
+	cairo_matrix_t device_to_surface;
+	cairo_matrix_init_translate (&device_to_surface,
+				     - destination->device_x_offset,
+				     - destination->device_y_offset);
+
+	_cairo_pattern_transform (pattern_out, &device_to_surface);
+    }
+}
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index 6afb499..6733ca5 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -258,6 +258,54 @@ _cairo_traps_translate (cairo_traps_t *t
     }
 }
 
+void
+_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
+                                            cairo_trapezoid_t *src_traps,
+                                            int num_traps,
+                                            double tx, double ty,
+                                            double sx, double sy)
+{
+    int i;
+    cairo_fixed_t xoff = _cairo_fixed_from_double (tx);
+    cairo_fixed_t yoff = _cairo_fixed_from_double (ty);
+
+    if (sx == 1.0 && sy == 1.0) {
+        for (i = 0; i < num_traps; i++) {
+            offset_traps[i].top = src_traps[i].top + yoff;
+            offset_traps[i].bottom = src_traps[i].bottom + yoff;
+            offset_traps[i].left.p1.x = src_traps[i].left.p1.x + xoff;
+            offset_traps[i].left.p1.y = src_traps[i].left.p1.y + yoff;
+            offset_traps[i].left.p2.x = src_traps[i].left.p2.x + xoff;
+            offset_traps[i].left.p2.y = src_traps[i].left.p2.y + yoff;
+            offset_traps[i].right.p1.x = src_traps[i].right.p1.x + xoff;
+            offset_traps[i].right.p1.y = src_traps[i].right.p1.y + yoff;
+            offset_traps[i].right.p2.x = src_traps[i].right.p2.x + xoff;
+            offset_traps[i].right.p2.y = src_traps[i].right.p2.y + yoff;
+        }
+    } else {
+        cairo_fixed_t xsc = _cairo_fixed_from_double (sx);
+        cairo_fixed_t ysc = _cairo_fixed_from_double (sy);
+
+        for (i = 0; i < num_traps; i++) {
+#define FIXED_MUL(_a, _b) \
+            (_cairo_int64_to_int32(_cairo_int64_rsl(_cairo_int32x32_64_mul((_a), (_b)), 16)))
+
+            offset_traps[i].top = FIXED_MUL(src_traps[i].top + yoff, ysc);
+            offset_traps[i].bottom = FIXED_MUL(src_traps[i].bottom + yoff, ysc);
+            offset_traps[i].left.p1.x = FIXED_MUL(src_traps[i].left.p1.x + xoff, xsc);
+            offset_traps[i].left.p1.y = FIXED_MUL(src_traps[i].left.p1.y + yoff, ysc);
+            offset_traps[i].left.p2.x = FIXED_MUL(src_traps[i].left.p2.x + xoff, xsc);
+            offset_traps[i].left.p2.y = FIXED_MUL(src_traps[i].left.p2.y + yoff, ysc);
+            offset_traps[i].right.p1.x = FIXED_MUL(src_traps[i].right.p1.x + xoff, xsc);
+            offset_traps[i].right.p1.y = FIXED_MUL(src_traps[i].right.p1.y + yoff, ysc);
+            offset_traps[i].right.p2.x = FIXED_MUL(src_traps[i].right.p2.x + xoff, xsc);
+            offset_traps[i].right.p2.y = FIXED_MUL(src_traps[i].right.p2.y + yoff, ysc);
+
+#undef FIXED_MUL
+        }
+    }
+}
+
 cairo_status_t
 _cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3])
 {
@@ -859,4 +907,3 @@ _cairo_traps_extract_region (cairo_traps
 
     return CAIRO_STATUS_SUCCESS;
 }
-
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 3245af6..567ef01 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -2151,8 +2151,8 @@ _cairo_xlib_surface_add_glyph (Display *
      *  sitting around for x and y. 
      */
 
-    glyph_info.x = -(int) glyph_surface->base.device_x_offset;
-    glyph_info.y = -(int) glyph_surface->base.device_y_offset;
+    glyph_info.x = - (int) floor(glyph_surface->base.device_x_offset + 0.5);
+    glyph_info.y = - (int) floor(glyph_surface->base.device_y_offset + 0.5);
     glyph_info.width = glyph_surface->width;
     glyph_info.height = glyph_surface->height;
     glyph_info.xOff = 0;
diff --git a/src/cairo.h b/src/cairo.h
index ea4e20b..c1f191c 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1304,6 +1304,11 @@ cairo_surface_set_device_offset (cairo_s
 				 double           x_offset,
 				 double           y_offset);
 
+cairo_public void
+cairo_surface_get_device_offset (cairo_surface_t *surface,
+				 double          *x_offset,
+				 double          *y_offset);
+
 /* Image-surface functions */
 
 /**
diff --git a/src/cairoint.h b/src/cairoint.h
index cfa8b7d..09d2e65 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -861,8 +861,6 @@ struct _cairo_surface {
 
     double device_x_offset;
     double device_y_offset;
-    double device_x_scale;
-    double device_y_scale;
 
     cairo_clip_t *clip;
 
@@ -1058,6 +1056,8 @@ _cairo_restrict_value (double *value, do
 cairo_private cairo_fixed_t
 _cairo_fixed_from_int (int i);
 
+#define CAIRO_FIXED_ONE _cairo_fixed_from_int (1)
+
 cairo_private cairo_fixed_t
 _cairo_fixed_from_double (double d);
 
@@ -1488,6 +1488,11 @@ _cairo_path_fixed_bounds (cairo_path_fix
 			  double *x1, double *y1,
 			  double *x2, double *y2);
 
+cairo_private void
+_cairo_path_fixed_offset (cairo_path_fixed_t *path,
+			  cairo_fixed_t offx,
+			  cairo_fixed_t offy);
+
 /* cairo_path_fill.c */
 cairo_private cairo_status_t
 _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
@@ -1836,6 +1841,9 @@ _cairo_surface_composite_shape_fixup_unb
 cairo_private cairo_bool_t
 _cairo_surface_is_opaque (const cairo_surface_t *surface);
 
+cairo_private cairo_bool_t
+_cairo_surface_has_device_offset_or_scale (cairo_surface_t *surface);
+
 /* cairo_image_surface.c */
 
 #define CAIRO_FORMAT_VALID(format) ((format) >= CAIRO_FORMAT_ARGB32 && \
@@ -2038,6 +2046,13 @@ cairo_private cairo_status_t
 _cairo_traps_extract_region (cairo_traps_t      *tr,
 			     pixman_region16_t **region);
 
+cairo_private void
+_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
+					    cairo_trapezoid_t *src_traps,
+					    int num_traps,
+					    double tx, double ty,
+					    double sx, double sy);
+
 /* cairo_slope.c */
 cairo_private void
 _cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b);
diff --git a/test/buffer-diff.c b/test/buffer-diff.c
index c62c44e..89af811 100644
--- a/test/buffer-diff.c
+++ b/test/buffer-diff.c
@@ -287,9 +287,9 @@ image_diff_flattened (const char *filena
 
     b_flat_surface = cairo_image_surface_create_for_data (b_flat,
 							  CAIRO_FORMAT_ARGB32,
-							  width_a, height_a,
-							  stride_a);
-    /*cairo_surface_set_device_offset (b_flat_surface, -bx, -by);*/
+							  width_b, height_b,
+							  stride_b);
+    cairo_surface_set_device_offset (b_flat_surface, -bx, -by);
 
     cr = cairo_create (b_flat_surface);
 
@@ -306,7 +306,7 @@ image_diff_flattened (const char *filena
                                   b_flat,
                                   buf_diff,
 				  width_a, height_a,
-				  stride_a, stride_a, stride_a);
+                                  stride_a, stride_b, stride_a);
 
     if (pixels_changed) {
 	FILE *png_file = fopen (filename_diff, "wb");
diff --git a/test/cairo-test.c b/test/cairo-test.c
index 6a3d52a..d0052de 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -1181,6 +1181,15 @@ ps_surface_write_to_png (cairo_surface_t
     ps_target_closure_t *ptc = cairo_surface_get_user_data (surface, &ps_closure_key);
     char    command[4096];
 
+    /* Both surface and ptc->target were originally created at the
+     * same dimensions. We want a 1:1 copy here, so we first clear any
+     * device offset on surface.
+     *
+     * In a more realistic use case of device offsets, the target of
+     * this copying would be of a different size than the source, and
+     * the offset would be desirable during the copy operation. */
+    cairo_surface_set_device_offset (surface, 0, 0);
+
     if (ptc->target) {
 	cairo_t *cr;
 	cr = cairo_create (ptc->target);
@@ -1273,6 +1282,15 @@ pdf_surface_write_to_png (cairo_surface_
     pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface, &pdf_closure_key);
     char    command[4096];
 
+    /* Both surface and ptc->target were originally created at the
+     * same dimensions. We want a 1:1 copy here, so we first clear any
+     * device offset on surface.
+     *
+     * In a more realistic use case of device offsets, the target of
+     * this copying would be of a different size than the source, and
+     * the offset would be desirable during the copy operation. */
+    cairo_surface_set_device_offset (surface, 0, 0);
+
     if (ptc->target) {
 	cairo_t *cr;
 	cr = cairo_create (ptc->target);
@@ -1427,6 +1445,11 @@ cairo_test_for_target (cairo_test_t *tes
     else
 	offset_str = strdup("");
     
+    if (dev_offset)
+	xasprintf (&offset_str, "-%d", dev_offset);
+    else
+	offset_str = strdup("");
+
     xasprintf (&png_name, "%s-%s-%s%s%s", test->name,
 	       target->name, format, offset_str, CAIRO_TEST_PNG_SUFFIX);
 
diff-tree 99719bde9ee0697bd43d97f034ccf4058c9484a0 (from ee687d722a315ff9cefd8755ca38b194187a693c)
Author: Carl Worth <cworth at cworth.org>
Date:   Fri Mar 10 14:57:08 2006 -0800

    Move device-offset touchups from the surface layer up to the gstate.
    
    This fixes the self-copy test which was the last one that was really
    failing due to device offsets.

diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 2b2984d..1a4ca6a 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -667,8 +667,24 @@ _cairo_gstate_copy_transformed_pattern (
 					cairo_pattern_t *original,
 					cairo_matrix_t  *ctm_inverse)
 {
+    cairo_surface_pattern_t *surface_pattern;
+    cairo_surface_t *surface;
+    cairo_matrix_t offset_matrix;
+
     _cairo_pattern_init_copy (pattern, original);
     _cairo_pattern_transform (pattern, ctm_inverse);
+
+    if (cairo_pattern_get_type (original) == CAIRO_PATTERN_TYPE_SURFACE) {
+        surface_pattern = (cairo_surface_pattern_t *) original;
+        surface = surface_pattern->surface;
+        if (_cairo_surface_has_device_offset_or_scale (surface)) {
+            cairo_matrix_init_translate (&offset_matrix,
+                                         surface->device_x_offset,
+                                         surface->device_y_offset);
+            _cairo_pattern_transform (pattern, &offset_matrix);
+        }
+    }
+
 }
 
 static void
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 44d8236..025f300 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1910,16 +1910,4 @@ _cairo_surface_copy_pattern_for_destinat
 
 	_cairo_pattern_transform (pattern_out, &device_to_surface);
     }
-
-    if (cairo_pattern_get_type ((cairo_pattern_t *)pattern) == CAIRO_PATTERN_TYPE_SURFACE) {
-	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
-	cairo_surface_t *surface = surface_pattern->surface;
-	if (_cairo_surface_has_device_offset_or_scale (surface)) {
-	    cairo_matrix_t surface_to_pattern;
-	    cairo_matrix_init_translate (&surface_to_pattern,
-					 surface->device_x_offset,
-					 surface->device_y_offset);
-	    _cairo_pattern_transform (pattern_out, &surface_to_pattern);
-	}
-    }
 }
diff-tree ee687d722a315ff9cefd8755ca38b194187a693c (from ea2faa5fae619a6b813348eda925060f3ed16ee3)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Mar 9 14:39:44 2006 -0800

    Add support to handle the device-offset of a source surface.
    
    This change caused all self-copy failures to now pass.
    But, it also causes all previous self-copy passes to now fail.

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 3da20cc..44d8236 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1900,15 +1900,26 @@ _cairo_surface_copy_pattern_for_destinat
                                              cairo_surface_t *destination,
                                              cairo_pattern_t *pattern_out)
 {
-    cairo_matrix_t device_to_surface;
-
     _cairo_pattern_init_copy (pattern_out, pattern);
 
     if (_cairo_surface_has_device_offset_or_scale (destination)) {
+	cairo_matrix_t device_to_surface;
 	cairo_matrix_init_translate (&device_to_surface,
 				     - destination->device_x_offset,
 				     - destination->device_y_offset);
 
 	_cairo_pattern_transform (pattern_out, &device_to_surface);
     }
+
+    if (cairo_pattern_get_type ((cairo_pattern_t *)pattern) == CAIRO_PATTERN_TYPE_SURFACE) {
+	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
+	cairo_surface_t *surface = surface_pattern->surface;
+	if (_cairo_surface_has_device_offset_or_scale (surface)) {
+	    cairo_matrix_t surface_to_pattern;
+	    cairo_matrix_init_translate (&surface_to_pattern,
+					 surface->device_x_offset,
+					 surface->device_y_offset);
+	    _cairo_pattern_transform (pattern_out, &surface_to_pattern);
+	}
+    }
 }
diff-tree ea2faa5fae619a6b813348eda925060f3ed16ee3 (from 0e230727f8f925b85fffd0359195be4a704fed69)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Mar 9 14:38:20 2006 -0800

    Rip out device_{x,y}_scale.
    
    This device scale stuff is currently not being used. However it is also adding
    complexity to the current device-offset rework. And since it's not being tested
    I'm sure we're getting it wrong. It's better to not even have it here rather
    than having it be broken.

diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 3a0c6cc..7edb915 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -439,11 +439,9 @@ _cairo_clip_clip (cairo_clip_t       *cl
 
     if (_cairo_surface_has_device_offset_or_scale (target)) {
 	_cairo_path_fixed_init_copy (&path_transformed, path);
-	_cairo_path_fixed_offset_and_scale (&path_transformed,
-					    _cairo_fixed_from_double (target->device_x_offset),
-					    _cairo_fixed_from_double (target->device_y_offset),
-					    _cairo_fixed_from_double (target->device_x_scale),
-					    _cairo_fixed_from_double (target->device_y_scale));
+	_cairo_path_fixed_offset (&path_transformed,
+				  _cairo_fixed_from_double (target->device_x_offset),
+				  _cairo_fixed_from_double (target->device_y_offset));
 	path = &path_transformed;
     }
     
diff --git a/src/cairo-path.c b/src/cairo-path.c
index 41d87a8..5c94ad9 100644
--- a/src/cairo-path.c
+++ b/src/cairo-path.c
@@ -569,12 +569,12 @@ _cairo_path_fixed_interpret (cairo_path_
     return CAIRO_STATUS_SUCCESS;
 }
 
-void
+static void
 _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
-				     cairo_fixed_t offx,
-				     cairo_fixed_t offy,
-				     cairo_fixed_t scalex,
-				     cairo_fixed_t scaley)
+				    cairo_fixed_t offx,
+				    cairo_fixed_t offy,
+				    cairo_fixed_t scalex,
+				    cairo_fixed_t scaley)
 {
     cairo_path_arg_buf_t *arg_buf = path->arg_buf_head;
     int i;
@@ -583,8 +583,7 @@ _cairo_path_fixed_offset_and_scale (cair
 
     while (arg_buf) {
 	 for (i = 0; i < arg_buf->num_points; i++) {
-	     /* CAIRO_FIXED_ONE? */
-	     if (scalex == 0x00010000) {
+	     if (scalex == CAIRO_FIXED_ONE) {
 		 arg_buf->points[i].x += offx;
 	     } else {
 		 fixedtemp = arg_buf->points[i].x + offx;
@@ -592,7 +591,7 @@ _cairo_path_fixed_offset_and_scale (cair
 		 arg_buf->points[i].x = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
 	     }
 
-	     if (scaley == 0x00010000) {
+	     if (scaley == CAIRO_FIXED_ONE) {
 		 arg_buf->points[i].y += offy;
 	     } else {
 		 fixedtemp = arg_buf->points[i].y + offy;
@@ -605,3 +604,13 @@ _cairo_path_fixed_offset_and_scale (cair
     }
 }
 
+void
+_cairo_path_fixed_offset (cairo_path_fixed_t *path,
+			  cairo_fixed_t offx,
+			  cairo_fixed_t offy)
+{
+    _cairo_path_fixed_offset_and_scale (path, offx, offy,
+					CAIRO_FIXED_ONE,
+					CAIRO_FIXED_ONE);
+}
+
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index f24e633..8bf46f5 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1194,10 +1194,8 @@ _cairo_ps_surface_start_page (void *abst
 				 (int) ceil (surface->height));
 
     _cairo_output_stream_printf (surface->stream,
-				 "gsave %f %f translate %f %f scale \n",
-				 0.0, surface->height,
-				 1.0/surface->base.device_x_scale,
-				 -1.0/surface->base.device_y_scale);
+				 "gsave %f %f translate 1.0 -1.0 scale \n",
+				 0.0, surface->height);
 
     _cairo_output_stream_printf (surface->stream,
 				 "%%%%EndPageSetup\n");
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index 17abcf7..5b01039 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -992,8 +992,6 @@ _cairo_surface_fallback_snapshot (cairo_
 
     snapshot->device_x_offset = surface->device_x_offset;
     snapshot->device_y_offset = surface->device_y_offset;
-    snapshot->device_x_scale = surface->device_x_scale;
-    snapshot->device_y_scale = surface->device_y_scale;
 
     snapshot->is_snapshot = TRUE;
 
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 18b4271..3da20cc 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -92,21 +92,9 @@ const cairo_surface_t _cairo_surface_nil
     0					/* current_clip_serial */
 };
 
-/* N.B.: set_device_offset already transforms the device offsets by the scale
- * before storing in device_[xy]_scale
- */
-
 /* Helper macros for transforming surface coords to backend coords */
-#define SURFACE_TO_BACKEND_X(_surf, _sx)  ((_sx)*((_surf)->device_x_scale)+((_surf)->device_x_offset))
-#define SURFACE_TO_BACKEND_Y(_surf, _sy)  ((_sy)*((_surf)->device_y_scale)+((_surf)->device_y_offset))
-#define SURFACE_TO_BACKEND_WIDTH(_surf, _sw)  ((_sw)*((_surf)->device_x_scale))
-#define SURFACE_TO_BACKEND_HEIGHT(_surf, _sh)  ((_sh)*((_surf)->device_y_scale))
-
-/* Helper macros for transforming backend coords to surface coords */
-#define BACKEND_TO_SURFACE_X(_surf, _bx)  (((_bx)-((_surf)->device_x_offset))/((_surf)->device_x_scale))
-#define BACKEND_TO_SURFACE_Y(_surf, _by)  (((_by)-((_surf)->device_y_offset))/((_surf)->device_y_scale))
-#define BACKEND_TO_SURFACE_WIDTH(_surf, _bw)  ((_bw)/((_surf)->device_x_scale))
-#define BACKEND_TO_SURFACE_HEIGHT(_surf, _bh)  ((_bh)/((_surf)->device_y_scale))
+#define SURFACE_TO_BACKEND_X(_surf, _sx)  ((_sx)+((_surf)->device_x_offset))
+#define SURFACE_TO_BACKEND_Y(_surf, _sy)  ((_sy)+((_surf)->device_y_offset))
 
 static void _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
                                                          cairo_surface_t *destination,
@@ -191,8 +179,6 @@ _cairo_surface_init (cairo_surface_t			*
 
     surface->device_x_offset = 0.0;
     surface->device_y_offset = 0.0;
-    surface->device_x_scale = 1.0;
-    surface->device_y_scale = 1.0;
 
     surface->clip = NULL;
     surface->next_clip_serial = 0;
@@ -619,8 +605,8 @@ cairo_surface_set_device_offset (cairo_s
 	return;
     }
 
-    surface->device_x_offset = x_offset * surface->device_x_scale;
-    surface->device_y_offset = y_offset * surface->device_y_scale;
+    surface->device_x_offset = x_offset;
+    surface->device_y_offset = y_offset;
 }
 
 /**
@@ -646,9 +632,7 @@ cairo_bool_t
 _cairo_surface_has_device_offset_or_scale (cairo_surface_t *surface)
 {
     return (surface->device_x_offset != 0.0 ||
-	    surface->device_y_offset != 0.0 ||
-	    surface->device_x_scale != 1.0 ||
-	    surface->device_y_scale != 1.0);
+	    surface->device_y_offset != 0.0);
 }
 
 /**
@@ -803,8 +787,6 @@ _cairo_surface_clone_similar (cairo_surf
     if (status == CAIRO_STATUS_SUCCESS) {
         (*clone_out)->device_x_offset = src->device_x_offset;
         (*clone_out)->device_y_offset = src->device_y_offset;
-        (*clone_out)->device_x_scale = src->device_x_scale;
-        (*clone_out)->device_y_scale = src->device_y_scale;
     }
 
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
@@ -818,8 +800,6 @@ _cairo_surface_clone_similar (cairo_surf
     if (status == CAIRO_STATUS_SUCCESS) {
         (*clone_out)->device_x_offset = src->device_x_offset;
         (*clone_out)->device_y_offset = src->device_y_offset;
-        (*clone_out)->device_x_scale = src->device_x_scale;
-        (*clone_out)->device_y_scale = src->device_y_scale;
     }
 
     /* If the above failed point, we could implement a full fallback
@@ -1128,11 +1108,9 @@ _cairo_surface_stroke (cairo_surface_t		
     if (_cairo_surface_has_device_offset_or_scale (surface))
     {
         _cairo_path_fixed_init_copy (&real_dev_path, path);
-        _cairo_path_fixed_offset_and_scale (&real_dev_path,
-                                            _cairo_fixed_from_double (surface->device_x_offset),
-                                            _cairo_fixed_from_double (surface->device_y_offset),
-                                            _cairo_fixed_from_double (surface->device_x_scale),
-                                            _cairo_fixed_from_double (surface->device_y_scale));
+        _cairo_path_fixed_offset (&real_dev_path,
+				  _cairo_fixed_from_double (surface->device_x_offset),
+				  _cairo_fixed_from_double (surface->device_y_offset));
         dev_path = &real_dev_path;
     }
 
@@ -1180,11 +1158,9 @@ _cairo_surface_fill (cairo_surface_t	*su
     if (_cairo_surface_has_device_offset_or_scale (surface))
     {
         _cairo_path_fixed_init_copy (&real_dev_path, path);
-        _cairo_path_fixed_offset_and_scale (&real_dev_path,
-                                            _cairo_fixed_from_double (surface->device_x_offset),
-                                            _cairo_fixed_from_double (surface->device_y_offset),
-                                            _cairo_fixed_from_double (surface->device_x_scale),
-                                            _cairo_fixed_from_double (surface->device_y_scale));
+        _cairo_path_fixed_offset (&real_dev_path,
+				  _cairo_fixed_from_double (surface->device_x_offset),
+				  _cairo_fixed_from_double (surface->device_y_offset));
         dev_path = &real_dev_path;
     }
 
@@ -1568,8 +1544,8 @@ _cairo_surface_get_extents (cairo_surfac
 
     rectangle->x = SURFACE_TO_BACKEND_X(surface, rectangle->x);
     rectangle->y = SURFACE_TO_BACKEND_Y(surface, rectangle->y);
-    rectangle->width = SURFACE_TO_BACKEND_WIDTH(surface, rectangle->width) - surface->device_x_offset;
-    rectangle->height = SURFACE_TO_BACKEND_HEIGHT(surface, rectangle->height) - surface->device_y_offset;
+    rectangle->width = rectangle->width - surface->device_x_offset;
+    rectangle->height = rectangle->height - surface->device_y_offset;
 
     return status;
 }
@@ -1924,7 +1900,7 @@ _cairo_surface_copy_pattern_for_destinat
                                              cairo_surface_t *destination,
                                              cairo_pattern_t *pattern_out)
 {
-    cairo_matrix_t device_to_surface, tmp;
+    cairo_matrix_t device_to_surface;
 
     _cairo_pattern_init_copy (pattern_out, pattern);
 
@@ -1932,10 +1908,6 @@ _cairo_surface_copy_pattern_for_destinat
 	cairo_matrix_init_translate (&device_to_surface,
 				     - destination->device_x_offset,
 				     - destination->device_y_offset);
-	cairo_matrix_init_scale (&tmp,
-				 1.0 / destination->device_x_scale,
-				 1.0 / destination->device_y_scale);
-	cairo_matrix_multiply (&device_to_surface, &device_to_surface, &tmp);
 
 	_cairo_pattern_transform (pattern_out, &device_to_surface);
     }
diff --git a/src/cairoint.h b/src/cairoint.h
index 79bf09b..09d2e65 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -861,8 +861,6 @@ struct _cairo_surface {
 
     double device_x_offset;
     double device_y_offset;
-    double device_x_scale;
-    double device_y_scale;
 
     cairo_clip_t *clip;
 
@@ -1058,6 +1056,8 @@ _cairo_restrict_value (double *value, do
 cairo_private cairo_fixed_t
 _cairo_fixed_from_int (int i);
 
+#define CAIRO_FIXED_ONE _cairo_fixed_from_int (1)
+
 cairo_private cairo_fixed_t
 _cairo_fixed_from_double (double d);
 
@@ -1489,11 +1489,9 @@ _cairo_path_fixed_bounds (cairo_path_fix
 			  double *x2, double *y2);
 
 cairo_private void
-_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
-                                    cairo_fixed_t offx,
-                                    cairo_fixed_t offy,
-                                    cairo_fixed_t scalex,
-                                    cairo_fixed_t scaley);
+_cairo_path_fixed_offset (cairo_path_fixed_t *path,
+			  cairo_fixed_t offx,
+			  cairo_fixed_t offy);
 
 /* cairo_path_fill.c */
 cairo_private cairo_status_t
diff-tree 0e230727f8f925b85fffd0359195be4a704fed69 (from f9333e9975cbb3a0e167de1f78076eb779da4317)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Mar 9 14:01:30 2006 -0800

    Prefer classic C style comments rather than C++/C99-style

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 36ce87f..18b4271 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1602,7 +1602,7 @@ _cairo_surface_show_glyphs (cairo_surfac
 
         for (i = 0; i < num_glyphs; i++) {
             dev_glyphs[i].index = glyphs[i].index;
-            // err, we really should scale the size of the glyphs, no?
+            /* XXX: err, we really should scale the size of the glyphs, no? */
             dev_glyphs[i].x = SURFACE_TO_BACKEND_X(surface, glyphs[i].x);
             dev_glyphs[i].y = SURFACE_TO_BACKEND_Y(surface, glyphs[i].y);
         }
diff-tree f9333e9975cbb3a0e167de1f78076eb779da4317 (from f66ce88e0ec1ef91bb85e795fd53a99f71877e4a)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Mar 9 14:01:10 2006 -0800

    Remove dead code from _cairo_surface_{acquire,release}_dest_image

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 0cb0ab6..36ce87f 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -735,26 +735,11 @@ _cairo_surface_acquire_dest_image (cairo
 				   cairo_rectangle_t       *image_rect,
 				   void                   **image_extra)
 {
-    cairo_rectangle_t dev_interest_rect;
-    cairo_status_t status;
-
     assert (!surface->finished);
 
-    if (interest_rect) {
-	dev_interest_rect = *interest_rect;
-        //dev_interest_rect.x = BACKEND_TO_SURFACE_X(surface, dev_interest_rect.x);
-        //dev_interest_rect.y = BACKEND_TO_SURFACE_Y(surface, dev_interest_rect.y);
-    }
-
-    status = surface->backend->acquire_dest_image (surface,
-						   interest_rect ? &dev_interest_rect : NULL,
-						   image_out, image_rect, image_extra);
-
-    /* move image_rect back into surface coordinates from backend device coordinates */
-    //image_rect->x = SURFACE_TO_BACKEND_X(surface, image_rect->x);
-    //image_rect->y = SURFACE_TO_BACKEND_Y(surface, image_rect->y);
-
-    return status;
+    return surface->backend->acquire_dest_image (surface,
+						 interest_rect,
+						 image_out, image_rect, image_extra);
 }
 
 /**
@@ -776,22 +761,10 @@ _cairo_surface_release_dest_image (cairo
 				   cairo_rectangle_t      *image_rect,
 				   void                   *image_extra)
 {
-    cairo_rectangle_t dev_interest_rect;
-
     assert (!surface->finished);
 
-    /* move image_rect into backend device coords (opposite of acquire_dest_image) */
-    //image_rect->x = BACKEND_TO_SURFACE_X(surface, image_rect->x);
-    //image_rect->y = BACKEND_TO_SURFACE_Y(surface, image_rect->y);
-
-    if (interest_rect) {
-	dev_interest_rect = *interest_rect;
-        //dev_interest_rect.x = BACKEND_TO_SURFACE_X(surface, dev_interest_rect.x);
-        //dev_interest_rect.y = BACKEND_TO_SURFACE_Y(surface, dev_interest_rect.y);
-    }
-
     if (surface->backend->release_dest_image)
-	surface->backend->release_dest_image (surface, &dev_interest_rect,
+	surface->backend->release_dest_image (surface, interest_rect,
 					      image, image_rect, image_extra);
 }
 
diff-tree f66ce88e0ec1ef91bb85e795fd53a99f71877e4a (from 460820cb58b9a9e893cdb2d48d1457defe797246)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Mar 9 13:42:16 2006 -0800

    cairo_surface_mark_dirty_rectangle: correct sense of device-offset handling

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 6dbd625..0cb0ab6 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -577,8 +577,8 @@ cairo_surface_mark_dirty_rectangle (cair
 	cairo_status_t status;
 	
 	status = surface->backend->mark_dirty_rectangle (surface,
-                                                         BACKEND_TO_SURFACE_X(surface, x),
-                                                         BACKEND_TO_SURFACE_Y(surface, y),
+                                                         SURFACE_TO_BACKEND_X(surface, x),
+                                                         SURFACE_TO_BACKEND_Y(surface, y),
 							 width, height);
 	
 	if (status)
diff-tree 460820cb58b9a9e893cdb2d48d1457defe797246 (from b0c047ad95957b46922bbb4f6320a4a7b0c32726)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Mar 9 13:39:55 2006 -0800

    Remove undesired device-offset handling during unbounded fixups.
    
    This code was already commented as being suspicious and its removal causes some
    tests to start passing once again.

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 4d4a16f..6dbd625 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1801,14 +1801,6 @@ _cairo_surface_composite_fixup_unbounded
 
     assert (! dst->is_snapshot);
 
-    /* This is a little odd; this function is called from the xlib/image surfaces,
-     * where the coordinates have already been transformed by the device_xy_offset.
-     * We need to undo this before running through this function,
-     * otherwise those offsets get applied twice.
-     */
-    dst_x = SURFACE_TO_BACKEND_X(dst, dst_x);
-    dst_y = SURFACE_TO_BACKEND_Y(dst, dst_y);
-
     /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
      * non-repeating sources and masks. Other sources and masks can be ignored.
      */
@@ -1884,10 +1876,6 @@ _cairo_surface_composite_shape_fixup_unb
 
     assert (! dst->is_snapshot);
 
-    /* See comment at start of _cairo_surface_composite_fixup_unbounded */
-    dst_x = SURFACE_TO_BACKEND_X(dst, dst_x);
-    dst_y = SURFACE_TO_BACKEND_Y(dst, dst_y);
-  
     /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
      * non-repeating sources and masks. Other sources and masks can be ignored.
      */
diff-tree b0c047ad95957b46922bbb4f6320a4a7b0c32726 (from ee1c642cd85fc4d5408d65578cc9ca48ee4b58cc)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Mar 9 13:37:32 2006 -0800

    _cairo_surface_show_glyphs: Fix reversed device-offset handling so text works again.

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 8d0733d..4d4a16f 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1630,8 +1630,8 @@ _cairo_surface_show_glyphs (cairo_surfac
         for (i = 0; i < num_glyphs; i++) {
             dev_glyphs[i].index = glyphs[i].index;
             // err, we really should scale the size of the glyphs, no?
-            dev_glyphs[i].x = BACKEND_TO_SURFACE_X(surface, glyphs[i].x);
-            dev_glyphs[i].y = BACKEND_TO_SURFACE_Y(surface, glyphs[i].y);
+            dev_glyphs[i].x = SURFACE_TO_BACKEND_X(surface, glyphs[i].x);
+            dev_glyphs[i].y = SURFACE_TO_BACKEND_Y(surface, glyphs[i].y);
         }
     }
 
diff-tree ee1c642cd85fc4d5408d65578cc9ca48ee4b58cc (from a5cb54621259d0a6057543bc0e4edd4d16216007)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Mar 9 13:36:30 2006 -0800

    cairo-surface.c: Correct reversed semantics of SURFACE_TO_BACKEND and BACKEND_TO_SURFACE

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index f8e5655..8d0733d 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -97,16 +97,16 @@ const cairo_surface_t _cairo_surface_nil
  */
 
 /* Helper macros for transforming surface coords to backend coords */
-#define BACKEND_TO_SURFACE_X(_surf, _sx)  ((_sx)*((_surf)->device_x_scale)+((_surf)->device_x_offset))
-#define BACKEND_TO_SURFACE_Y(_surf, _sy)  ((_sy)*((_surf)->device_y_scale)+((_surf)->device_y_offset))
-#define BACKEND_TO_SURFACE_WIDTH(_surf, _sw)  ((_sw)*((_surf)->device_x_scale))
-#define BACKEND_TO_SURFACE_HEIGHT(_surf, _sh)  ((_sh)*((_surf)->device_y_scale))
+#define SURFACE_TO_BACKEND_X(_surf, _sx)  ((_sx)*((_surf)->device_x_scale)+((_surf)->device_x_offset))
+#define SURFACE_TO_BACKEND_Y(_surf, _sy)  ((_sy)*((_surf)->device_y_scale)+((_surf)->device_y_offset))
+#define SURFACE_TO_BACKEND_WIDTH(_surf, _sw)  ((_sw)*((_surf)->device_x_scale))
+#define SURFACE_TO_BACKEND_HEIGHT(_surf, _sh)  ((_sh)*((_surf)->device_y_scale))
 
 /* Helper macros for transforming backend coords to surface coords */
-#define SURFACE_TO_BACKEND_X(_surf, _bx)  (((_bx)-((_surf)->device_x_offset))/((_surf)->device_x_scale))
-#define SURFACE_TO_BACKEND_Y(_surf, _by)  (((_by)-((_surf)->device_y_offset))/((_surf)->device_y_scale))
-#define SURFACE_TO_BACKEND_WIDTH(_surf, _bw)  ((_bw)/((_surf)->device_x_scale))
-#define SURFACE_TO_BACKEND_HEIGHT(_surf, _bh)  ((_bh)/((_surf)->device_y_scale))
+#define BACKEND_TO_SURFACE_X(_surf, _bx)  (((_bx)-((_surf)->device_x_offset))/((_surf)->device_x_scale))
+#define BACKEND_TO_SURFACE_Y(_surf, _by)  (((_by)-((_surf)->device_y_offset))/((_surf)->device_y_scale))
+#define BACKEND_TO_SURFACE_WIDTH(_surf, _bw)  ((_bw)/((_surf)->device_x_scale))
+#define BACKEND_TO_SURFACE_HEIGHT(_surf, _bh)  ((_bh)/((_surf)->device_y_scale))
 
 static void _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
                                                          cairo_surface_t *destination,
@@ -577,8 +577,8 @@ cairo_surface_mark_dirty_rectangle (cair
 	cairo_status_t status;
 	
 	status = surface->backend->mark_dirty_rectangle (surface,
-                                                         SURFACE_TO_BACKEND_X(surface, x),
-                                                         SURFACE_TO_BACKEND_Y(surface, y),
+                                                         BACKEND_TO_SURFACE_X(surface, x),
+                                                         BACKEND_TO_SURFACE_Y(surface, y),
 							 width, height);
 	
 	if (status)
@@ -742,8 +742,8 @@ _cairo_surface_acquire_dest_image (cairo
 
     if (interest_rect) {
 	dev_interest_rect = *interest_rect;
-        //dev_interest_rect.x = SURFACE_TO_BACKEND_X(surface, dev_interest_rect.x);
-        //dev_interest_rect.y = SURFACE_TO_BACKEND_Y(surface, dev_interest_rect.y);
+        //dev_interest_rect.x = BACKEND_TO_SURFACE_X(surface, dev_interest_rect.x);
+        //dev_interest_rect.y = BACKEND_TO_SURFACE_Y(surface, dev_interest_rect.y);
     }
 
     status = surface->backend->acquire_dest_image (surface,
@@ -751,8 +751,8 @@ _cairo_surface_acquire_dest_image (cairo
 						   image_out, image_rect, image_extra);
 
     /* move image_rect back into surface coordinates from backend device coordinates */
-    //image_rect->x = BACKEND_TO_SURFACE_X(surface, image_rect->x);
-    //image_rect->y = BACKEND_TO_SURFACE_Y(surface, image_rect->y);
+    //image_rect->x = SURFACE_TO_BACKEND_X(surface, image_rect->x);
+    //image_rect->y = SURFACE_TO_BACKEND_Y(surface, image_rect->y);
 
     return status;
 }
@@ -781,13 +781,13 @@ _cairo_surface_release_dest_image (cairo
     assert (!surface->finished);
 
     /* move image_rect into backend device coords (opposite of acquire_dest_image) */
-    //image_rect->x = SURFACE_TO_BACKEND_X(surface, image_rect->x);
-    //image_rect->y = SURFACE_TO_BACKEND_Y(surface, image_rect->y);
+    //image_rect->x = BACKEND_TO_SURFACE_X(surface, image_rect->x);
+    //image_rect->y = BACKEND_TO_SURFACE_Y(surface, image_rect->y);
 
     if (interest_rect) {
 	dev_interest_rect = *interest_rect;
-        //dev_interest_rect.x = SURFACE_TO_BACKEND_X(surface, dev_interest_rect.x);
-        //dev_interest_rect.y = SURFACE_TO_BACKEND_Y(surface, dev_interest_rect.y);
+        //dev_interest_rect.x = BACKEND_TO_SURFACE_X(surface, dev_interest_rect.x);
+        //dev_interest_rect.y = BACKEND_TO_SURFACE_Y(surface, dev_interest_rect.y);
     }
 
     if (surface->backend->release_dest_image)
@@ -1593,10 +1593,10 @@ _cairo_surface_get_extents (cairo_surfac
 
     status = surface->backend->get_extents (surface, rectangle);
 
-    rectangle->x = BACKEND_TO_SURFACE_X(surface, rectangle->x);
-    rectangle->y = BACKEND_TO_SURFACE_Y(surface, rectangle->y);
-    rectangle->width = BACKEND_TO_SURFACE_WIDTH(surface, rectangle->width) - surface->device_x_offset;
-    rectangle->height = BACKEND_TO_SURFACE_HEIGHT(surface, rectangle->height) - surface->device_y_offset;
+    rectangle->x = SURFACE_TO_BACKEND_X(surface, rectangle->x);
+    rectangle->y = SURFACE_TO_BACKEND_Y(surface, rectangle->y);
+    rectangle->width = SURFACE_TO_BACKEND_WIDTH(surface, rectangle->width) - surface->device_x_offset;
+    rectangle->height = SURFACE_TO_BACKEND_HEIGHT(surface, rectangle->height) - surface->device_y_offset;
 
     return status;
 }
@@ -1630,8 +1630,8 @@ _cairo_surface_show_glyphs (cairo_surfac
         for (i = 0; i < num_glyphs; i++) {
             dev_glyphs[i].index = glyphs[i].index;
             // err, we really should scale the size of the glyphs, no?
-            dev_glyphs[i].x = SURFACE_TO_BACKEND_X(surface, glyphs[i].x);
-            dev_glyphs[i].y = SURFACE_TO_BACKEND_Y(surface, glyphs[i].y);
+            dev_glyphs[i].x = BACKEND_TO_SURFACE_X(surface, glyphs[i].x);
+            dev_glyphs[i].y = BACKEND_TO_SURFACE_Y(surface, glyphs[i].y);
         }
     }
 
@@ -1806,8 +1806,8 @@ _cairo_surface_composite_fixup_unbounded
      * We need to undo this before running through this function,
      * otherwise those offsets get applied twice.
      */
-    dst_x = BACKEND_TO_SURFACE_X(dst, dst_x);
-    dst_y = BACKEND_TO_SURFACE_Y(dst, dst_y);
+    dst_x = SURFACE_TO_BACKEND_X(dst, dst_x);
+    dst_y = SURFACE_TO_BACKEND_Y(dst, dst_y);
 
     /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
      * non-repeating sources and masks. Other sources and masks can be ignored.
@@ -1885,8 +1885,8 @@ _cairo_surface_composite_shape_fixup_unb
     assert (! dst->is_snapshot);
 
     /* See comment at start of _cairo_surface_composite_fixup_unbounded */
-    dst_x = BACKEND_TO_SURFACE_X(dst, dst_x);
-    dst_y = BACKEND_TO_SURFACE_Y(dst, dst_y);
+    dst_x = SURFACE_TO_BACKEND_X(dst, dst_x);
+    dst_y = SURFACE_TO_BACKEND_Y(dst, dst_y);
   
     /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
      * non-repeating sources and masks. Other sources and masks can be ignored.
diff-tree a5cb54621259d0a6057543bc0e4edd4d16216007 (from 69affa5fafe41edf6c88af7722538b550804284c)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Mar 8 15:02:35 2006 -0800

    _cairo_surface_set_clip_region: Remove device-offset handling that is
    
    now taken care of in _cairo_clip_clip.

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 786081f..f8e5655 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1419,7 +1419,6 @@ _cairo_surface_set_clip_region (cairo_su
 				pixman_region16_t   *region,
 				unsigned int	    serial)
 {
-    pixman_region16_t *dev_region = NULL;
     cairo_status_t status;
 
     if (surface->status)
@@ -1430,45 +1429,10 @@ _cairo_surface_set_clip_region (cairo_su
     
     assert (surface->backend->set_clip_region != NULL);
 
-    if (_cairo_surface_has_device_offset_or_scale (surface))
-    {
-	dev_region = pixman_region_create ();
-	if (surface->device_x_scale == 1.0 &&
-	    surface->device_y_scale == 1.0)
-	{
-	    pixman_region_copy (dev_region, region);
-	    pixman_region_translate (dev_region, surface->device_x_offset, surface->device_y_offset);
-	} else {
-	    int i, nr = pixman_region_num_rects (region);
-	    pixman_box16_t *rects = pixman_region_rects (region);
-	    for (i = 0; i < nr; i++) {
-		pixman_box16_t tmpb;
-		pixman_region16_t *tmpr;
-
-		tmpb.x1 = SURFACE_TO_BACKEND_X(surface, rects[i].x1);
-		tmpb.y1 = SURFACE_TO_BACKEND_Y(surface, rects[i].y1);
-		tmpb.x2 = SURFACE_TO_BACKEND_X(surface, rects[i].x2);
-		tmpb.y2 = SURFACE_TO_BACKEND_Y(surface, rects[i].y2);
-
-		tmpr = pixman_region_create_simple (&tmpb);
-
-		pixman_region_append (dev_region, tmpr);
-		pixman_region_destroy (tmpr);
-	    }
-
-	    pixman_region_validate (dev_region, &i);
-	}
-
-	region = dev_region;
-    }
-
     surface->current_clip_serial = serial;
 
     status = surface->backend->set_clip_region (surface, region);
 
-    if (dev_region)
-	pixman_region_destroy (dev_region);
-
     return status;
 }
 
diff-tree 69affa5fafe41edf6c88af7722538b550804284c (from 50dcd4d1ac3d4b90bcea04e53836d73b8e7c1aa4)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Mar 8 14:51:57 2006 -0800

    Move device-offset handling for clipping from _cairo_surface_interesect_clip_path
    
    to the more general _cairo_clip_clip to handle more cases correctly.

diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 0c862a3..3a0c6cc 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -435,6 +435,17 @@ _cairo_clip_clip (cairo_clip_t       *cl
 {
     cairo_status_t status;
     cairo_traps_t traps;
+    cairo_path_fixed_t path_transformed;
+
+    if (_cairo_surface_has_device_offset_or_scale (target)) {
+	_cairo_path_fixed_init_copy (&path_transformed, path);
+	_cairo_path_fixed_offset_and_scale (&path_transformed,
+					    _cairo_fixed_from_double (target->device_x_offset),
+					    _cairo_fixed_from_double (target->device_y_offset),
+					    _cairo_fixed_from_double (target->device_x_scale),
+					    _cairo_fixed_from_double (target->device_y_scale));
+	path = &path_transformed;
+    }
     
     status = _cairo_clip_intersect_path (clip,
 					 path, fill_rule, tolerance,
@@ -458,6 +469,8 @@ _cairo_clip_clip (cairo_clip_t       *cl
 	
  bail:
     _cairo_traps_fini (&traps);
+    if (path == &path_transformed)
+	_cairo_path_fixed_fini (&path_transformed);
 
     return status;
 }
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index bc103da..786081f 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -642,7 +642,7 @@ cairo_surface_get_device_offset (cairo_s
     *y_offset = surface->device_y_offset;
 }
 
-static cairo_bool_t
+cairo_bool_t
 _cairo_surface_has_device_offset_or_scale (cairo_surface_t *surface)
 {
     return (surface->device_x_offset != 0.0 ||
@@ -1480,7 +1480,6 @@ _cairo_surface_intersect_clip_path (cair
 				    cairo_antialias_t	antialias)
 {
     cairo_path_fixed_t *dev_path = path;
-    cairo_path_fixed_t real_dev_path;
     cairo_status_t status;
 
     if (surface->status)
@@ -1491,26 +1490,12 @@ _cairo_surface_intersect_clip_path (cair
     
     assert (surface->backend->intersect_clip_path != NULL);
 
-    if (_cairo_surface_has_device_offset_or_scale (surface))
-    {
-	_cairo_path_fixed_init_copy (&real_dev_path, path);
-	_cairo_path_fixed_offset_and_scale (&real_dev_path,
-					    _cairo_fixed_from_double (surface->device_x_offset),
-					    _cairo_fixed_from_double (surface->device_y_offset),
-					    _cairo_fixed_from_double (surface->device_x_scale),
-					    _cairo_fixed_from_double (surface->device_y_scale));
-	dev_path = &real_dev_path;
-    }
-
     status = surface->backend->intersect_clip_path (surface,
 						    dev_path,
 						    fill_rule,
 						    tolerance,
 						    antialias);
 
-    if (dev_path == &real_dev_path)
-	_cairo_path_fixed_fini (&real_dev_path);
-
     return status;
 }
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 529fae0..79bf09b 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1843,6 +1843,9 @@ _cairo_surface_composite_shape_fixup_unb
 cairo_private cairo_bool_t
 _cairo_surface_is_opaque (const cairo_surface_t *surface);
 
+cairo_private cairo_bool_t
+_cairo_surface_has_device_offset_or_scale (cairo_surface_t *surface);
+
 /* cairo_image_surface.c */
 
 #define CAIRO_FORMAT_VALID(format) ((format) >= CAIRO_FORMAT_ARGB32 && \
diff-tree 50dcd4d1ac3d4b90bcea04e53836d73b8e7c1aa4 (from 6d212c9e391ad8fc5b273269a54740790cbb1ee3)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Mar 8 12:58:13 2006 -0800

    _cairo_surface_copy_pattern_for_destination: Don't do any transform if there is no offset

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index f366928..bc103da 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -2018,13 +2018,15 @@ _cairo_surface_copy_pattern_for_destinat
 
     _cairo_pattern_init_copy (pattern_out, pattern);
 
-    cairo_matrix_init_translate (&device_to_surface,
-                                 - destination->device_x_offset,
-                                 - destination->device_y_offset);
-    cairo_matrix_init_scale (&tmp,
-                             1.0 / destination->device_x_scale,
-                             1.0 / destination->device_y_scale);
-    cairo_matrix_multiply (&device_to_surface, &device_to_surface, &tmp);
+    if (_cairo_surface_has_device_offset_or_scale (destination)) {
+	cairo_matrix_init_translate (&device_to_surface,
+				     - destination->device_x_offset,
+				     - destination->device_y_offset);
+	cairo_matrix_init_scale (&tmp,
+				 1.0 / destination->device_x_scale,
+				 1.0 / destination->device_y_scale);
+	cairo_matrix_multiply (&device_to_surface, &device_to_surface, &tmp);
 
-    _cairo_pattern_transform (pattern_out, &device_to_surface);
+	_cairo_pattern_transform (pattern_out, &device_to_surface);
+    }
 }
diff-tree 6d212c9e391ad8fc5b273269a54740790cbb1ee3 (from 81e469523fbc83b9ddcd74a6be5d8137a6d71c38)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Mar 8 12:51:46 2006 -0800

    _cairo_surface_copy_pattern_for_destination: Remove leaking second call to pattern_init_copy

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 06c8727..f366928 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -2026,7 +2026,5 @@ _cairo_surface_copy_pattern_for_destinat
                              1.0 / destination->device_y_scale);
     cairo_matrix_multiply (&device_to_surface, &device_to_surface, &tmp);
 
-
-    _cairo_pattern_init_copy (pattern_out, pattern);
     _cairo_pattern_transform (pattern_out, &device_to_surface);
 }
diff-tree 81e469523fbc83b9ddcd74a6be5d8137a6d71c38 (from 4ed3e60a25a877f65b82cf7c426659a89d195728)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Mar 8 12:44:49 2006 -0800

    Abstract away repeated test as _cairo_surface_has_device_offset_or_scale

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 446a405..06c8727 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -642,6 +642,15 @@ cairo_surface_get_device_offset (cairo_s
     *y_offset = surface->device_y_offset;
 }
 
+static cairo_bool_t
+_cairo_surface_has_device_offset_or_scale (cairo_surface_t *surface)
+{
+    return (surface->device_x_offset != 0.0 ||
+	    surface->device_y_offset != 0.0 ||
+	    surface->device_x_scale != 1.0 ||
+	    surface->device_y_scale != 1.0);
+}
+
 /**
  * _cairo_surface_acquire_source_image:
  * @surface: a #cairo_surface_t
@@ -1143,10 +1152,7 @@ _cairo_surface_stroke (cairo_surface_t		
 
     _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
 
-    if (surface->device_x_offset != 0.0 ||
-        surface->device_y_offset != 0.0 ||
-        surface->device_x_scale != 1.0 ||
-        surface->device_y_scale != 1.0)
+    if (_cairo_surface_has_device_offset_or_scale (surface))
     {
         _cairo_path_fixed_init_copy (&real_dev_path, path);
         _cairo_path_fixed_offset_and_scale (&real_dev_path,
@@ -1198,10 +1204,7 @@ _cairo_surface_fill (cairo_surface_t	*su
 
     _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
 
-    if (surface->device_x_offset != 0.0 ||
-        surface->device_y_offset != 0.0 ||
-        surface->device_x_scale != 1.0 ||
-        surface->device_y_scale != 1.0)
+    if (_cairo_surface_has_device_offset_or_scale (surface))
     {
         _cairo_path_fixed_init_copy (&real_dev_path, path);
         _cairo_path_fixed_offset_and_scale (&real_dev_path,
@@ -1427,10 +1430,7 @@ _cairo_surface_set_clip_region (cairo_su
     
     assert (surface->backend->set_clip_region != NULL);
 
-    if (surface->device_x_offset != 0.0 ||
-	surface->device_y_offset != 0.0 ||
-	surface->device_x_scale != 1.0 ||
-	surface->device_y_scale != 1.0)
+    if (_cairo_surface_has_device_offset_or_scale (surface))
     {
 	dev_region = pixman_region_create ();
 	if (surface->device_x_scale == 1.0 &&
@@ -1491,10 +1491,7 @@ _cairo_surface_intersect_clip_path (cair
     
     assert (surface->backend->intersect_clip_path != NULL);
 
-    if (surface->device_x_offset != 0.0 ||
-	surface->device_y_offset != 0.0 ||
-	surface->device_x_scale != 1.0 ||
-	surface->device_y_scale != 1.0)
+    if (_cairo_surface_has_device_offset_or_scale (surface))
     {
 	_cairo_path_fixed_init_copy (&real_dev_path, path);
 	_cairo_path_fixed_offset_and_scale (&real_dev_path,
@@ -1673,10 +1670,7 @@ _cairo_surface_show_glyphs (cairo_surfac
                                                  surface,
                                                  &dev_source.base);
 
-    if (surface->device_x_offset != 0.0 ||
-        surface->device_y_offset != 0.0 ||
-        surface->device_x_scale != 1.0 ||
-        surface->device_y_scale != 1.0)
+    if (_cairo_surface_has_device_offset_or_scale (surface))
     {
         int i;
 
diff-tree 4ed3e60a25a877f65b82cf7c426659a89d195728 (from d3ff6f0e4b17972361c28f490eaf05222ac97e10)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Mar 8 11:56:27 2006 -0800

    _cairo_surface_copy_pattern_for_destination: Fix transformation sign/order.
    
    This allows the scale-source-surface-paint test to start passing again
    at least.

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 918017e..446a405 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -2020,21 +2020,19 @@ _cairo_surface_copy_pattern_for_destinat
                                              cairo_surface_t *destination,
                                              cairo_pattern_t *pattern_out)
 {
+    cairo_matrix_t device_to_surface, tmp;
+
     _cairo_pattern_init_copy (pattern_out, pattern);
 
-    if (destination->device_x_scale != 1.0 ||
-        destination->device_y_scale != 1.0)
-    {
-        cairo_matrix_scale (&pattern_out->matrix,
-                            destination->device_x_scale,
-                            destination->device_y_scale);
-    }
+    cairo_matrix_init_translate (&device_to_surface,
+                                 - destination->device_x_offset,
+                                 - destination->device_y_offset);
+    cairo_matrix_init_scale (&tmp,
+                             1.0 / destination->device_x_scale,
+                             1.0 / destination->device_y_scale);
+    cairo_matrix_multiply (&device_to_surface, &device_to_surface, &tmp);
+
 
-    if (destination->device_x_offset != 0.0 ||
-        destination->device_y_offset != 0.0)
-    {
-        cairo_matrix_translate (&pattern_out->matrix,
-                                destination->device_x_offset,
-                                destination->device_y_offset);
-    }
+    _cairo_pattern_init_copy (pattern_out, pattern);
+    _cairo_pattern_transform (pattern_out, &device_to_surface);
 }
diff-tree d3ff6f0e4b17972361c28f490eaf05222ac97e10 (from 46a1f40b7d1787b570a8381a914a372400ef39a9)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Mar 8 11:54:33 2006 -0800

    _cairo_surface_fallback_composite_trapezoids: Remove unused variable.

diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index ae49a75..17abcf7 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -1133,7 +1133,6 @@ _cairo_surface_fallback_composite_trapez
     fallback_state_t state;
     cairo_trapezoid_t *offset_traps = NULL;
     cairo_status_t status;
-    int i;
 
     status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
     if (status) {
diff-tree 46a1f40b7d1787b570a8381a914a372400ef39a9 (from 6197d5a7618900f25155af16b91f082ee05ddd03)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Thu Mar 2 15:05:32 2006 +0100

    Move device offsets handling into high-level operations only (stroke/fill/paint/etc)
    
    Remove all device offsets handling from internal cairo_surface methods,
    which will become truly internal shortly.  Have all device offsets
    handled by top-level entry points (stroke/fill/paint/show_glyphs/mask, and
    clipping).

diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 3a5bf86..3e40c7e 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -932,8 +932,7 @@ _cairo_scaled_font_show_glyphs (cairo_sc
 					   &glyph_pattern.base, 
 					   NULL,
 					   mask,
-					   - glyph_surface->base.device_x_offset,
-                                           - glyph_surface->base.device_y_offset,
+					   0, 0,
 					   0, 0, 
 					   x - dest_x, 
 					   y - dest_y, 
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index f5e2da7..918017e 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -97,16 +97,20 @@ const cairo_surface_t _cairo_surface_nil
  */
 
 /* Helper macros for transforming surface coords to backend coords */
-#define BACKEND_X(_surf, _sx)  ((_sx)*((_surf)->device_x_scale)+((_surf)->device_x_offset))
-#define BACKEND_Y(_surf, _sy)  ((_sy)*((_surf)->device_y_scale)+((_surf)->device_y_offset))
-#define BACKEND_X_SIZE(_surf, _sx)  ((_sx)*((_surf)->device_x_scale))
-#define BACKEND_Y_SIZE(_surf, _sy)  ((_sy)*((_surf)->device_y_scale))
+#define BACKEND_TO_SURFACE_X(_surf, _sx)  ((_sx)*((_surf)->device_x_scale)+((_surf)->device_x_offset))
+#define BACKEND_TO_SURFACE_Y(_surf, _sy)  ((_sy)*((_surf)->device_y_scale)+((_surf)->device_y_offset))
+#define BACKEND_TO_SURFACE_WIDTH(_surf, _sw)  ((_sw)*((_surf)->device_x_scale))
+#define BACKEND_TO_SURFACE_HEIGHT(_surf, _sh)  ((_sh)*((_surf)->device_y_scale))
 
 /* Helper macros for transforming backend coords to surface coords */
-#define SURFACE_X(_surf, _bx)  (((_bx)-((_surf)->device_x_offset))/((_surf)->device_x_scale))
-#define SURFACE_Y(_surf, _by)  (((_by)-((_surf)->device_y_offset))/((_surf)->device_y_scale))
-#define SURFACE_X_SIZE(_surf, _bx)  ((_bx)/((_surf)->device_x_scale))
-#define SURFACE_Y_SIZE(_surf, _by)  ((_by)/((_surf)->device_y_scale))
+#define SURFACE_TO_BACKEND_X(_surf, _bx)  (((_bx)-((_surf)->device_x_offset))/((_surf)->device_x_scale))
+#define SURFACE_TO_BACKEND_Y(_surf, _by)  (((_by)-((_surf)->device_y_offset))/((_surf)->device_y_scale))
+#define SURFACE_TO_BACKEND_WIDTH(_surf, _bw)  ((_bw)/((_surf)->device_x_scale))
+#define SURFACE_TO_BACKEND_HEIGHT(_surf, _bh)  ((_bh)/((_surf)->device_y_scale))
+
+static void _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
+                                                         cairo_surface_t *destination,
+                                                         cairo_pattern_t *pattern_out);
 
 /**
  * _cairo_surface_set_error:
@@ -573,8 +577,8 @@ cairo_surface_mark_dirty_rectangle (cair
 	cairo_status_t status;
 	
 	status = surface->backend->mark_dirty_rectangle (surface,
-                                                         BACKEND_X(surface, x),
-                                                         BACKEND_Y(surface, y),
+                                                         SURFACE_TO_BACKEND_X(surface, x),
+                                                         SURFACE_TO_BACKEND_Y(surface, y),
 							 width, height);
 	
 	if (status)
@@ -729,8 +733,8 @@ _cairo_surface_acquire_dest_image (cairo
 
     if (interest_rect) {
 	dev_interest_rect = *interest_rect;
-        dev_interest_rect.x = BACKEND_X(surface, dev_interest_rect.x);
-        dev_interest_rect.y = BACKEND_Y(surface, dev_interest_rect.y);
+        //dev_interest_rect.x = SURFACE_TO_BACKEND_X(surface, dev_interest_rect.x);
+        //dev_interest_rect.y = SURFACE_TO_BACKEND_Y(surface, dev_interest_rect.y);
     }
 
     status = surface->backend->acquire_dest_image (surface,
@@ -738,8 +742,8 @@ _cairo_surface_acquire_dest_image (cairo
 						   image_out, image_rect, image_extra);
 
     /* move image_rect back into surface coordinates from backend device coordinates */
-    image_rect->x = SURFACE_X(surface, image_rect->x);
-    image_rect->y = SURFACE_Y(surface, image_rect->y);
+    //image_rect->x = BACKEND_TO_SURFACE_X(surface, image_rect->x);
+    //image_rect->y = BACKEND_TO_SURFACE_Y(surface, image_rect->y);
 
     return status;
 }
@@ -768,13 +772,13 @@ _cairo_surface_release_dest_image (cairo
     assert (!surface->finished);
 
     /* move image_rect into backend device coords (opposite of acquire_dest_image) */
-    image_rect->x = BACKEND_X(surface, image_rect->x);
-    image_rect->y = BACKEND_Y(surface, image_rect->y);
+    //image_rect->x = SURFACE_TO_BACKEND_X(surface, image_rect->x);
+    //image_rect->y = SURFACE_TO_BACKEND_Y(surface, image_rect->y);
 
     if (interest_rect) {
 	dev_interest_rect = *interest_rect;
-        dev_interest_rect.x = BACKEND_X(surface, dev_interest_rect.x);
-        dev_interest_rect.y = BACKEND_Y(surface, dev_interest_rect.y);
+        //dev_interest_rect.x = SURFACE_TO_BACKEND_X(surface, dev_interest_rect.x);
+        //dev_interest_rect.y = SURFACE_TO_BACKEND_Y(surface, dev_interest_rect.y);
     }
 
     if (surface->backend->release_dest_image)
@@ -907,29 +911,11 @@ _cairo_surface_composite (cairo_operator
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
     if (dst->backend->composite) {
-        int backend_src_x = src_x;
-        int backend_src_y = src_y;
-        int backend_mask_x = mask_x;
-        int backend_mask_y = mask_y;
-
-        if (src->type == CAIRO_PATTERN_TYPE_SURFACE) {
-            cairo_surface_t *src_surface = ((cairo_surface_pattern_t*)src)->surface;
-            backend_src_x = BACKEND_X(src_surface, src_x);
-            backend_src_y = BACKEND_Y(src_surface, src_y);
-        }
-
-        if (mask && mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
-            cairo_surface_t *mask_surface = ((cairo_surface_pattern_t*)mask)->surface;
-            backend_mask_x = BACKEND_X(mask_surface, mask_x);
-            backend_mask_y = BACKEND_Y(mask_surface, mask_y);
-        }
-
 	status = dst->backend->composite (op,
 					  src, mask, dst,
-                                          backend_src_x, backend_src_y,
-                                          backend_mask_x, backend_mask_y,
-                                          BACKEND_X(dst, dst_x),
-                                          BACKEND_Y(dst, dst_y),
+                                          src_x, src_y,
+                                          mask_x, mask_y,
+                                          dst_x, dst_y,
 					  width, height);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
@@ -1058,8 +1044,6 @@ _cairo_surface_fill_rectangles (cairo_su
 				int			num_rects)
 {
     cairo_int_status_t status;
-    cairo_rectangle_t *dev_rects = NULL;
-    int i;
 
     assert (! surface->is_snapshot);
 
@@ -1073,26 +1057,8 @@ _cairo_surface_fill_rectangles (cairo_su
 	return CAIRO_STATUS_SUCCESS;
 
     if (surface->backend->fill_rectangles) {
-	if (surface->device_x_offset != 0.0 ||
-	    surface->device_y_offset != 0.0 ||
-	    surface->device_x_scale != 1.0 ||
-	    surface->device_y_scale != 1.0)
-	{
-	    dev_rects = malloc(sizeof(cairo_rectangle_t) * num_rects);
-	    for (i = 0; i < num_rects; i++) {
-		dev_rects[i].x = BACKEND_X(surface, rects[i].x);
-		dev_rects[i].y = BACKEND_Y(surface, rects[i].y);
-
-		dev_rects[i].width = BACKEND_X_SIZE(surface, rects[i].width);
-		dev_rects[i].height = BACKEND_Y_SIZE(surface, rects[i].height);
-	    }
-	}
-
-	status = surface->backend->fill_rectangles (surface,
-						    op,
-						    color,
-						    dev_rects ? dev_rects : rects, num_rects);
-	free (dev_rects);
+	status = surface->backend->fill_rectangles (surface, op, color,
+						    rects, num_rects);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
     }
@@ -1107,16 +1073,24 @@ _cairo_surface_paint (cairo_surface_t	*s
 		      cairo_pattern_t	*source)
 {
     cairo_status_t status;
+    cairo_pattern_union_t dev_source;
 
     assert (! surface->is_snapshot);
 
+    _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
+
     if (surface->backend->paint) {
-	status = surface->backend->paint (surface, op, source);
+	status = surface->backend->paint (surface, op, &dev_source.base);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+            goto FINISH;
     }
 
-    return _cairo_surface_fallback_paint (surface, op, source);
+    status = _cairo_surface_fallback_paint (surface, op, &dev_source.base);
+
+FINISH:
+    _cairo_pattern_fini (&dev_source.base);
+
+    return status;
 }
 
 cairo_status_t
@@ -1126,16 +1100,27 @@ _cairo_surface_mask (cairo_surface_t	*su
 		     cairo_pattern_t	*mask)
 {
     cairo_status_t status;
+    cairo_pattern_union_t dev_source;
+    cairo_pattern_union_t dev_mask;
 
     assert (! surface->is_snapshot);
 
+    _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
+    _cairo_surface_copy_pattern_for_destination (mask, surface, &dev_mask.base);
+
     if (surface->backend->mask) {
-	status = surface->backend->mask (surface, op, source, mask);
+	status = surface->backend->mask (surface, op, &dev_source.base, &dev_mask.base);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+            goto FINISH;
     }
 
-    return _cairo_surface_fallback_mask (surface, op, source, mask);
+    status = _cairo_surface_fallback_mask (surface, op, &dev_source.base, &dev_mask.base);
+
+FINISH:
+    _cairo_pattern_fini (&dev_source.base);
+    _cairo_pattern_fini (&dev_mask.base);
+
+    return status;
 }
 
 cairo_status_t
@@ -1149,43 +1134,50 @@ _cairo_surface_stroke (cairo_surface_t		
 		       double			 tolerance,
 		       cairo_antialias_t	 antialias)
 {
+    cairo_status_t status;
+    cairo_pattern_union_t dev_source;
+    cairo_path_fixed_t *dev_path = path;
+    cairo_path_fixed_t real_dev_path;
+
     assert (! surface->is_snapshot);
 
-    if (surface->backend->stroke) {
-	cairo_status_t status;
-	cairo_path_fixed_t *dev_path = path;
-	cairo_path_fixed_t real_dev_path;
+    _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
 
-	if (surface->device_x_offset != 0.0 ||
-	    surface->device_y_offset != 0.0 ||
-	    surface->device_x_scale != 1.0 ||
-	    surface->device_y_scale != 1.0)
-        {
-	    _cairo_path_fixed_init_copy (&real_dev_path, path);
-	    _cairo_path_fixed_offset_and_scale (&real_dev_path,
-						_cairo_fixed_from_double (surface->device_x_offset),
-						_cairo_fixed_from_double (surface->device_y_offset),
-						_cairo_fixed_from_double (surface->device_x_scale),
-						_cairo_fixed_from_double (surface->device_y_scale));
-	    dev_path = &real_dev_path;
-	}
+    if (surface->device_x_offset != 0.0 ||
+        surface->device_y_offset != 0.0 ||
+        surface->device_x_scale != 1.0 ||
+        surface->device_y_scale != 1.0)
+    {
+        _cairo_path_fixed_init_copy (&real_dev_path, path);
+        _cairo_path_fixed_offset_and_scale (&real_dev_path,
+                                            _cairo_fixed_from_double (surface->device_x_offset),
+                                            _cairo_fixed_from_double (surface->device_y_offset),
+                                            _cairo_fixed_from_double (surface->device_x_scale),
+                                            _cairo_fixed_from_double (surface->device_y_scale));
+        dev_path = &real_dev_path;
+    }
 
-	status = surface->backend->stroke (surface, op, source,
+    if (surface->backend->stroke) {
+	status = surface->backend->stroke (surface, op, &dev_source.base,
 					   dev_path, stroke_style,
 					   ctm, ctm_inverse,
 					   tolerance, antialias);
 
-	if (dev_path == &real_dev_path)
-	    _cairo_path_fixed_fini (&real_dev_path);
-
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+            goto FINISH;
     }
 
-    return _cairo_surface_fallback_stroke (surface, op, source,
-					   path, stroke_style,
-					   ctm, ctm_inverse,
-					   tolerance, antialias);
+    status = _cairo_surface_fallback_stroke (surface, op, &dev_source.base,
+                                             dev_path, stroke_style,
+                                             ctm, ctm_inverse,
+                                             tolerance, antialias);
+
+FINISH:
+    if (dev_path == &real_dev_path)
+        _cairo_path_fixed_fini (&real_dev_path);
+    _cairo_pattern_fini (&dev_source.base);
+
+    return status;
 }
 
 cairo_status_t
@@ -1198,40 +1190,47 @@ _cairo_surface_fill (cairo_surface_t	*su
 		     cairo_antialias_t	 antialias)
 {
     cairo_status_t status;
+    cairo_pattern_union_t dev_source;
     cairo_path_fixed_t *dev_path = path;
     cairo_path_fixed_t real_dev_path;
 
     assert (! surface->is_snapshot);
 
-    if (surface->backend->fill) {
-        if (surface->device_x_offset != 0.0 ||
-            surface->device_y_offset != 0.0 ||
-            surface->device_x_scale != 1.0 ||
-            surface->device_y_scale != 1.0)
-        {
-            _cairo_path_fixed_init_copy (&real_dev_path, path);
-            _cairo_path_fixed_offset_and_scale (&real_dev_path,
-                                                _cairo_fixed_from_double (surface->device_x_offset),
-                                                _cairo_fixed_from_double (surface->device_y_offset),
-                                                _cairo_fixed_from_double (surface->device_x_scale),
-                                                _cairo_fixed_from_double (surface->device_y_scale));
-            dev_path = &real_dev_path;
-        }
+    _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
+
+    if (surface->device_x_offset != 0.0 ||
+        surface->device_y_offset != 0.0 ||
+        surface->device_x_scale != 1.0 ||
+        surface->device_y_scale != 1.0)
+    {
+        _cairo_path_fixed_init_copy (&real_dev_path, path);
+        _cairo_path_fixed_offset_and_scale (&real_dev_path,
+                                            _cairo_fixed_from_double (surface->device_x_offset),
+                                            _cairo_fixed_from_double (surface->device_y_offset),
+                                            _cairo_fixed_from_double (surface->device_x_scale),
+                                            _cairo_fixed_from_double (surface->device_y_scale));
+        dev_path = &real_dev_path;
+    }
 
-	status = surface->backend->fill (surface, op, source,
+    if (surface->backend->fill) {
+	status = surface->backend->fill (surface, op, &dev_source.base,
 					 dev_path, fill_rule,
 					 tolerance, antialias);
 
-        if (dev_path == &real_dev_path)
-            _cairo_path_fixed_fini (&real_dev_path);
-
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+            goto FINISH;
     }
 
-    return _cairo_surface_fallback_fill (surface, op, source,
-					 path, fill_rule,
-					 tolerance, antialias);
+    status = _cairo_surface_fallback_fill (surface, op, &dev_source.base,
+                                           dev_path, fill_rule,
+                                           tolerance, antialias);
+
+FINISH:
+    if (dev_path == &real_dev_path)
+        _cairo_path_fixed_fini (&real_dev_path);
+    _cairo_pattern_fini (&dev_source.base);
+
+    return status;
 }
   
 cairo_status_t
@@ -1249,7 +1248,6 @@ _cairo_surface_composite_trapezoids (cai
 				     int			num_traps)
 {
     cairo_int_status_t status;
-    cairo_trapezoid_t *dev_traps = NULL;
 
     assert (! dst->is_snapshot);
 
@@ -1265,36 +1263,13 @@ _cairo_surface_composite_trapezoids (cai
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
     if (dst->backend->composite_trapezoids) {
-	if (dst->device_x_offset != 0.0 ||
-	    dst->device_y_offset != 0.0 ||
-	    dst->device_x_scale != 1.0 ||
-	    dst->device_y_scale != 1.0)
-	{
-	    dev_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps);
-	    if (!dev_traps)
-		return CAIRO_STATUS_NO_MEMORY;
-
-	    _cairo_trapezoid_array_translate_and_scale
-		(dev_traps, traps, num_traps,
-		 dst->device_x_offset,
-		 dst->device_y_offset,
-		 dst->device_x_scale,
-		 dst->device_y_scale);
-	}
-
-
 	status = dst->backend->composite_trapezoids (op,
 						     pattern, dst,
 						     antialias,
 						     src_x, src_y,
-						     BACKEND_X(dst, dst_x),
-						     BACKEND_Y(dst, dst_y),
-						     // XXX what the heck do I do with width/height?
-						     // they're not the same for src and dst!
+                                                     dst_x, dst_y,
 						     width, height,
-						     dev_traps ? dev_traps : traps, num_traps);
-	free (dev_traps);
-
+						     traps, num_traps);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
     }
@@ -1470,10 +1445,10 @@ _cairo_surface_set_clip_region (cairo_su
 		pixman_box16_t tmpb;
 		pixman_region16_t *tmpr;
 
-		tmpb.x1 = BACKEND_X(surface, rects[i].x1);
-		tmpb.y1 = BACKEND_Y(surface, rects[i].y1);
-		tmpb.x2 = BACKEND_X(surface, rects[i].x2);
-		tmpb.y2 = BACKEND_Y(surface, rects[i].y2);
+		tmpb.x1 = SURFACE_TO_BACKEND_X(surface, rects[i].x1);
+		tmpb.y1 = SURFACE_TO_BACKEND_Y(surface, rects[i].y1);
+		tmpb.x2 = SURFACE_TO_BACKEND_X(surface, rects[i].x2);
+		tmpb.y2 = SURFACE_TO_BACKEND_Y(surface, rects[i].y2);
 
 		tmpr = pixman_region_create_simple (&tmpb);
 
@@ -1672,8 +1647,10 @@ _cairo_surface_get_extents (cairo_surfac
 
     status = surface->backend->get_extents (surface, rectangle);
 
-    rectangle->x = SURFACE_X(surface, rectangle->x);
-    rectangle->y = SURFACE_Y(surface, rectangle->y);
+    rectangle->x = BACKEND_TO_SURFACE_X(surface, rectangle->x);
+    rectangle->y = BACKEND_TO_SURFACE_Y(surface, rectangle->y);
+    rectangle->width = BACKEND_TO_SURFACE_WIDTH(surface, rectangle->width) - surface->device_x_offset;
+    rectangle->height = BACKEND_TO_SURFACE_HEIGHT(surface, rectangle->height) - surface->device_y_offset;
 
     return status;
 }
@@ -1687,41 +1664,51 @@ _cairo_surface_show_glyphs (cairo_surfac
 			    cairo_scaled_font_t	*scaled_font)
 {
     cairo_status_t status;
-    cairo_glyph_t *dev_glyphs = NULL;
+    cairo_glyph_t *dev_glyphs = (cairo_glyph_t*) glyphs;
+    cairo_pattern_union_t dev_source;
 
     assert (! surface->is_snapshot);
 
-    if (surface->backend->show_glyphs) {
-	if (surface->device_x_offset != 0.0 ||
-	    surface->device_y_offset != 0.0 ||
-	    surface->device_x_scale != 1.0 ||
-	    surface->device_y_scale != 1.0)
-	{
-            int i;
+    _cairo_surface_copy_pattern_for_destination (source,
+                                                 surface,
+                                                 &dev_source.base);
 
-            dev_glyphs = malloc (sizeof(cairo_glyph_t) * num_glyphs);
-            if (!dev_glyphs)
-                return CAIRO_STATUS_NO_MEMORY;
-
-            for (i = 0; i < num_glyphs; i++) {
-                dev_glyphs[i].index = glyphs[i].index;
-		// err, we really should scale the size of the glyphs, no?
-                dev_glyphs[i].x = BACKEND_X(surface, glyphs[i].x);
-                dev_glyphs[i].y = BACKEND_Y(surface, glyphs[i].y);
-            }
+    if (surface->device_x_offset != 0.0 ||
+        surface->device_y_offset != 0.0 ||
+        surface->device_x_scale != 1.0 ||
+        surface->device_y_scale != 1.0)
+    {
+        int i;
+
+        dev_glyphs = malloc (sizeof(cairo_glyph_t) * num_glyphs);
+        if (!dev_glyphs)
+            return CAIRO_STATUS_NO_MEMORY;
+
+        for (i = 0; i < num_glyphs; i++) {
+            dev_glyphs[i].index = glyphs[i].index;
+            // err, we really should scale the size of the glyphs, no?
+            dev_glyphs[i].x = SURFACE_TO_BACKEND_X(surface, glyphs[i].x);
+            dev_glyphs[i].y = SURFACE_TO_BACKEND_Y(surface, glyphs[i].y);
         }
+    }
 
-	status = surface->backend->show_glyphs (surface, op, source,
-						dev_glyphs ? dev_glyphs : glyphs,
-						num_glyphs, scaled_font);
-	free (dev_glyphs);
+    if (surface->backend->show_glyphs) {
+	status = surface->backend->show_glyphs (surface, op, &dev_source.base,
+						dev_glyphs, num_glyphs,
+                                                scaled_font);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
+            goto FINISH;
     }
 
-    return _cairo_surface_fallback_show_glyphs (surface, op, source,
-						glyphs, num_glyphs,
-						scaled_font);
+    status = _cairo_surface_fallback_show_glyphs (surface, op, &dev_source.base,
+                                                  dev_glyphs, num_glyphs,
+                                                  scaled_font);
+
+FINISH:
+    if (dev_glyphs != glyphs)
+        free (dev_glyphs);
+
+    return status;
 }
 
 /* XXX: Previously, we had a function named _cairo_surface_show_glyphs
@@ -1744,7 +1731,6 @@ _cairo_surface_old_show_glyphs (cairo_sc
 				int			 num_glyphs)
 {
     cairo_status_t status;
-    cairo_glyph_t *dev_glyphs = NULL;
 
     assert (! dst->is_snapshot);
 
@@ -1755,33 +1741,12 @@ _cairo_surface_old_show_glyphs (cairo_sc
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
     if (dst->backend->old_show_glyphs) {
-	if (dst->device_x_offset != 0.0 ||
-	    dst->device_y_offset != 0.0 ||
-	    dst->device_x_scale != 1.0 ||
-	    dst->device_y_scale != 1.0)
-	{
-	    int i;
-
-	    dev_glyphs = malloc(sizeof(cairo_glyph_t) * num_glyphs);
-	    for (i = 0; i < num_glyphs; i++) {
-		dev_glyphs[i] = glyphs[i];
-		// err, we really should scale the size of the glyphs, no?
-		dev_glyphs[i].x = BACKEND_X(dst, dev_glyphs[i].x);
-		dev_glyphs[i].y = BACKEND_Y(dst, dev_glyphs[i].y);
-	    }
-
-	    glyphs = dev_glyphs;
-	}
-
 	status = dst->backend->old_show_glyphs (scaled_font,
 						op, pattern, dst,
 						source_x, source_y,
-						BACKEND_X(dst, dest_x),
-						BACKEND_Y(dst, dest_y),
+                                                dest_x, dest_y,
 						width, height,
 						glyphs, num_glyphs);
-
-	free (dev_glyphs);
     } else
 	status = CAIRO_INT_STATUS_UNSUPPORTED;
 
@@ -1898,8 +1863,8 @@ _cairo_surface_composite_fixup_unbounded
      * We need to undo this before running through this function,
      * otherwise those offsets get applied twice.
      */
-    dst_x = SURFACE_X(dst, dst_x);
-    dst_y = SURFACE_Y(dst, dst_y);
+    dst_x = BACKEND_TO_SURFACE_X(dst, dst_x);
+    dst_y = BACKEND_TO_SURFACE_Y(dst, dst_y);
 
     /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
      * non-repeating sources and masks. Other sources and masks can be ignored.
@@ -1977,8 +1942,8 @@ _cairo_surface_composite_shape_fixup_unb
     assert (! dst->is_snapshot);
 
     /* See comment at start of _cairo_surface_composite_fixup_unbounded */
-    dst_x = SURFACE_X(dst, dst_x);
-    dst_y = SURFACE_Y(dst, dst_y);
+    dst_x = BACKEND_TO_SURFACE_X(dst, dst_x);
+    dst_y = BACKEND_TO_SURFACE_Y(dst, dst_y);
   
     /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
      * non-repeating sources and masks. Other sources and masks can be ignored.
@@ -2040,3 +2005,36 @@ _cairo_surface_is_opaque (const cairo_su
 
     return FALSE;
 }
+
+/**
+ * _cairo_surface_copy_pattern_for_destination
+ * @pattern: the pattern to copy
+ * @destination: the destination surface for which the pattern is being copied
+ * @pattern_out: the location to hold the copy
+ *
+ * Copies the given pattern, taking into account device scale and offsets
+ * of the destination surface.
+ */
+void
+_cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
+                                             cairo_surface_t *destination,
+                                             cairo_pattern_t *pattern_out)
+{
+    _cairo_pattern_init_copy (pattern_out, pattern);
+
+    if (destination->device_x_scale != 1.0 ||
+        destination->device_y_scale != 1.0)
+    {
+        cairo_matrix_scale (&pattern_out->matrix,
+                            destination->device_x_scale,
+                            destination->device_y_scale);
+    }
+
+    if (destination->device_x_offset != 0.0 ||
+        destination->device_y_offset != 0.0)
+    {
+        cairo_matrix_translate (&pattern_out->matrix,
+                                destination->device_x_offset,
+                                destination->device_y_offset);
+    }
+}
diff-tree 6197d5a7618900f25155af16b91f082ee05ddd03 (from 51cf7900e4987d18173ded806988d412752717f5)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Mar 1 11:54:21 2006 +0100

    Fix bug in test suite causing PS and PDF to fail with rgb24 and device offsets.
    
    Patch from cworth at cworth.org.
    
    The trick with this one is that the test suite is using device offsets
    in a rather fabricated way, and the final copy from an offset surface
    to a non-offset surface is between two surfaces of the same size, so
    must be 1:1. To get this we turn the device offset off before the
    copy.
    
    In a more conventional use of device offsets the surfaces would be of
    different sizes, and the offset would be desired during the copy.

diff --git a/test/cairo-test.c b/test/cairo-test.c
index fff8526..d0052de 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -1181,6 +1181,15 @@ ps_surface_write_to_png (cairo_surface_t
     ps_target_closure_t *ptc = cairo_surface_get_user_data (surface, &ps_closure_key);
     char    command[4096];
 
+    /* Both surface and ptc->target were originally created at the
+     * same dimensions. We want a 1:1 copy here, so we first clear any
+     * device offset on surface.
+     *
+     * In a more realistic use case of device offsets, the target of
+     * this copying would be of a different size than the source, and
+     * the offset would be desirable during the copy operation. */
+    cairo_surface_set_device_offset (surface, 0, 0);
+
     if (ptc->target) {
 	cairo_t *cr;
 	cr = cairo_create (ptc->target);
@@ -1273,6 +1282,15 @@ pdf_surface_write_to_png (cairo_surface_
     pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface, &pdf_closure_key);
     char    command[4096];
 
+    /* Both surface and ptc->target were originally created at the
+     * same dimensions. We want a 1:1 copy here, so we first clear any
+     * device offset on surface.
+     *
+     * In a more realistic use case of device offsets, the target of
+     * this copying would be of a different size than the source, and
+     * the offset would be desirable during the copy operation. */
+    cairo_surface_set_device_offset (surface, 0, 0);
+
     if (ptc->target) {
 	cairo_t *cr;
 	cr = cairo_create (ptc->target);
diff-tree 51cf7900e4987d18173ded806988d412752717f5 (from 4894f5a234959a0e50269c1adcc6b4faf08ba053)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Wed Mar 1 11:23:15 2006 +0100

    Take device offsets into account when compositing scaled glyph images
    
    Scaled glyph image surfaces have device offsets set on them to indicate
    the location of the glyph origin; however, those offsets weren't being
    taken into account for the call to composite, so the glyphs were
    being doubly-offset by this amount.

diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 91e6257..3a5bf86 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -920,11 +920,11 @@ _cairo_scaled_font_show_glyphs (cairo_sc
 	
 	/* round glyph locations to the nearest pixel */
 	x = (int) floor (glyphs[i].x + 
-			 glyph_surface->base.device_x_offset +
-			 0.5);
+                         glyph_surface->base.device_x_offset +
+                         0.5);
 	y = (int) floor (glyphs[i].y +
-			 glyph_surface->base.device_y_offset +
-			 0.5);
+                         glyph_surface->base.device_y_offset +
+                         0.5);
 	
 	_cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base);
 
@@ -932,7 +932,8 @@ _cairo_scaled_font_show_glyphs (cairo_sc
 					   &glyph_pattern.base, 
 					   NULL,
 					   mask,
-					   0, 0,
+					   - glyph_surface->base.device_x_offset,
+                                           - glyph_surface->base.device_y_offset,
 					   0, 0, 
 					   x - dest_x, 
 					   y - dest_y, 
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 3245af6..567ef01 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -2151,8 +2151,8 @@ _cairo_xlib_surface_add_glyph (Display *
      *  sitting around for x and y. 
      */
 
-    glyph_info.x = -(int) glyph_surface->base.device_x_offset;
-    glyph_info.y = -(int) glyph_surface->base.device_y_offset;
+    glyph_info.x = - (int) floor(glyph_surface->base.device_x_offset + 0.5);
+    glyph_info.y = - (int) floor(glyph_surface->base.device_y_offset + 0.5);
     glyph_info.width = glyph_surface->width;
     glyph_info.height = glyph_surface->height;
     glyph_info.xOff = 0;
diff-tree 4894f5a234959a0e50269c1adcc6b4faf08ba053 (from 40b39dddf9cd919fb2f456a8e296a60cc8296fbf)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Wed Feb 15 13:46:52 2006 -0800

    Implement device offset/scale at cairo-surface layer
    
    This patch implements device offset/scale at the cairo-surface layer,
    instead of them just being multiplied into the CTM at operation time.
    This allows identical drawing operations/clips/paths/etc. to operate
    identically on a surface with or without a device offset (and still
    have things end up in the same place relative to the dev offset).

diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 10212cc..2b2984d 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -501,37 +501,10 @@ _cairo_gstate_get_miter_limit (cairo_gst
     return gstate->stroke_style.miter_limit;
 }
 
-static void
-_cairo_gstate_apply_device_transform (cairo_gstate_t    *gstate,
-				      cairo_matrix_t	*matrix)
-{
-    if (gstate->target->device_x_scale != 1.0 ||
-	gstate->target->device_y_scale != 1.0)
-    {
-	cairo_matrix_scale (matrix,
-			    gstate->target->device_x_scale,
-			    gstate->target->device_y_scale);
-    }
-}
-
-static void
-_cairo_gstate_apply_device_inverse_transform (cairo_gstate_t    *gstate,
-					      cairo_matrix_t	*matrix)
-{
-    if (gstate->target->device_x_scale != 1.0 ||
-	gstate->target->device_y_scale != 1.0)
-    {
-	cairo_matrix_scale (matrix,
-			    1/gstate->target->device_x_scale,
-			    1/gstate->target->device_y_scale);
-    }
-}
-
 void
 _cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
 {
     *matrix = gstate->ctm;
-    _cairo_gstate_apply_device_inverse_transform (gstate, matrix);
 }
 
 cairo_status_t
@@ -617,9 +590,6 @@ _cairo_gstate_set_matrix (cairo_gstate_t
     if (status)
 	return status;
 
-    _cairo_gstate_apply_device_transform (gstate, &gstate->ctm);
-    _cairo_gstate_apply_device_inverse_transform (gstate, &gstate->ctm_inverse);
-
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -631,9 +601,6 @@ _cairo_gstate_identity_matrix (cairo_gst
     cairo_matrix_init_identity (&gstate->ctm);
     cairo_matrix_init_identity (&gstate->ctm_inverse);
 
-    _cairo_gstate_apply_device_transform (gstate, &gstate->ctm);
-    _cairo_gstate_apply_device_inverse_transform (gstate, &gstate->ctm_inverse);
-
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -675,15 +642,11 @@ void
 _cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
 {
     cairo_matrix_transform_point (&gstate->ctm, x, y);
-    *x += gstate->target->device_x_offset;
-    *y += gstate->target->device_y_offset;
 }
 
 void
 _cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
 {
-    *x -= gstate->target->device_x_offset;
-    *y -= gstate->target->device_y_offset;
     cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
 }
 
@@ -704,16 +667,8 @@ _cairo_gstate_copy_transformed_pattern (
 					cairo_pattern_t *original,
 					cairo_matrix_t  *ctm_inverse)
 {
-    cairo_matrix_t tmp_matrix = *ctm_inverse;
-  
     _cairo_pattern_init_copy (pattern, original);
-
-    if (gstate->target)
-	cairo_matrix_translate (&tmp_matrix,
-				- gstate->target->device_x_offset,
-				- gstate->target->device_y_offset);
-
-    _cairo_pattern_transform (pattern, &tmp_matrix);
+    _cairo_pattern_transform (pattern, ctm_inverse);
 }
 
 static void
diff --git a/src/cairo-path.c b/src/cairo-path.c
index 7358bee..41d87a8 100644
--- a/src/cairo-path.c
+++ b/src/cairo-path.c
@@ -568,3 +568,40 @@ _cairo_path_fixed_interpret (cairo_path_
 
     return CAIRO_STATUS_SUCCESS;
 }
+
+void
+_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
+				     cairo_fixed_t offx,
+				     cairo_fixed_t offy,
+				     cairo_fixed_t scalex,
+				     cairo_fixed_t scaley)
+{
+    cairo_path_arg_buf_t *arg_buf = path->arg_buf_head;
+    int i;
+    cairo_int64_t i64temp;
+    cairo_fixed_t fixedtemp;
+
+    while (arg_buf) {
+	 for (i = 0; i < arg_buf->num_points; i++) {
+	     /* CAIRO_FIXED_ONE? */
+	     if (scalex == 0x00010000) {
+		 arg_buf->points[i].x += offx;
+	     } else {
+		 fixedtemp = arg_buf->points[i].x + offx;
+		 i64temp = _cairo_int32x32_64_mul (fixedtemp, scalex);
+		 arg_buf->points[i].x = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
+	     }
+
+	     if (scaley == 0x00010000) {
+		 arg_buf->points[i].y += offy;
+	     } else {
+		 fixedtemp = arg_buf->points[i].y + offy;
+		 i64temp = _cairo_int32x32_64_mul (fixedtemp, scaley);
+		 arg_buf->points[i].y = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
+	     }
+	 }
+
+	 arg_buf = arg_buf->next;
+    }
+}
+
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index a5c723f..ae49a75 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -895,7 +895,8 @@ _cairo_surface_old_show_glyphs_draw_func
 					     op, 
 					     src, dst,
 					     extents->x,         extents->y,
-					     extents->x - dst_x, extents->y - dst_y,
+					     extents->x - dst_x,
+					     extents->y - dst_y,
 					     extents->width,     extents->height,
 					     glyph_info->glyphs,
 					     glyph_info->num_glyphs);
@@ -989,6 +990,11 @@ _cairo_surface_fallback_snapshot (cairo_
     _cairo_surface_release_source_image (surface,
 					 image, &image_extra);
 
+    snapshot->device_x_offset = surface->device_x_offset;
+    snapshot->device_y_offset = surface->device_y_offset;
+    snapshot->device_x_scale = surface->device_x_scale;
+    snapshot->device_y_scale = surface->device_y_scale;
+
     snapshot->is_snapshot = TRUE;
 
     return snapshot;
@@ -1018,12 +1024,17 @@ _cairo_surface_fallback_composite (cairo
 	return status;
     }
 
-    status = state.image->base.backend->composite (op, src, mask,
-						   &state.image->base,
-						   src_x, src_y, mask_x, mask_y,
-						   dst_x - state.image_rect.x,
-						   dst_y - state.image_rect.y,
-						   width, height);
+    /* We know this will never fail with the image backend; but
+     * instead of calling into it directly, we call
+     * _cairo_surface_composite so that we get the correct device
+     * offset handling.
+     */
+    status = _cairo_surface_composite (op, src, mask,
+				       &state.image->base,
+				       src_x, src_y, mask_x, mask_y,
+				       dst_x - state.image_rect.x,
+				       dst_y - state.image_rect.y,
+				       width, height);
     _fallback_fini (&state);
 
     return status;
@@ -1093,9 +1104,9 @@ _cairo_surface_fallback_fill_rectangles 
 	rects = offset_rects;
     }
 
-    status = state.image->base.backend->fill_rectangles (&state.image->base,
-							 op, color,
-							 rects, num_rects);
+    status = _cairo_surface_fill_rectangles (&state.image->base,
+					     op, color,
+					     rects, num_rects);
 
     free (offset_rects);
 
@@ -1134,39 +1145,25 @@ _cairo_surface_fallback_composite_trapez
     /* If the destination image isn't at 0,0, we need to offset the trapezoids */
     
     if (state.image_rect.x != 0 || state.image_rect.y != 0) {
-
-	cairo_fixed_t xoff = _cairo_fixed_from_int (state.image_rect.x);
-	cairo_fixed_t yoff = _cairo_fixed_from_int (state.image_rect.y);
-	
 	offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps);
 	if (!offset_traps) {
 	    status = CAIRO_STATUS_NO_MEMORY;
 	    goto DONE;
 	}
 
-	for (i = 0; i < num_traps; i++) {
-	    offset_traps[i].top = traps[i].top - yoff;
-	    offset_traps[i].bottom = traps[i].bottom - yoff;
-	    offset_traps[i].left.p1.x = traps[i].left.p1.x - xoff;
-	    offset_traps[i].left.p1.y = traps[i].left.p1.y - yoff;
-	    offset_traps[i].left.p2.x = traps[i].left.p2.x - xoff;
-	    offset_traps[i].left.p2.y = traps[i].left.p2.y - yoff;
-	    offset_traps[i].right.p1.x = traps[i].right.p1.x - xoff;
-	    offset_traps[i].right.p1.y = traps[i].right.p1.y - yoff;
-	    offset_traps[i].right.p2.x = traps[i].right.p2.x - xoff;
-	    offset_traps[i].right.p2.y = traps[i].right.p2.y - yoff;
-	}
-
+	_cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps,
+                                                    - state.image_rect.x, - state.image_rect.y,
+                                                    1.0, 1.0);
 	traps = offset_traps;
     }
 
-    state.image->base.backend->composite_trapezoids (op, pattern,
-						     &state.image->base,
-						     antialias,
-						     src_x, src_y,
-						     dst_x - state.image_rect.x,
-						     dst_y - state.image_rect.y,
-						     width, height, traps, num_traps);
+    _cairo_surface_composite_trapezoids (op, pattern,
+					 &state.image->base,
+					 antialias,
+					 src_x, src_y,
+					 dst_x - state.image_rect.x,
+					 dst_y - state.image_rect.y,
+					 width, height, traps, num_traps);
     if (offset_traps)
 	free (offset_traps);
 
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index f905dfd..f5e2da7 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -92,6 +92,22 @@ const cairo_surface_t _cairo_surface_nil
     0					/* current_clip_serial */
 };
 
+/* N.B.: set_device_offset already transforms the device offsets by the scale
+ * before storing in device_[xy]_scale
+ */
+
+/* Helper macros for transforming surface coords to backend coords */
+#define BACKEND_X(_surf, _sx)  ((_sx)*((_surf)->device_x_scale)+((_surf)->device_x_offset))
+#define BACKEND_Y(_surf, _sy)  ((_sy)*((_surf)->device_y_scale)+((_surf)->device_y_offset))
+#define BACKEND_X_SIZE(_surf, _sx)  ((_sx)*((_surf)->device_x_scale))
+#define BACKEND_Y_SIZE(_surf, _sy)  ((_sy)*((_surf)->device_y_scale))
+
+/* Helper macros for transforming backend coords to surface coords */
+#define SURFACE_X(_surf, _bx)  (((_bx)-((_surf)->device_x_offset))/((_surf)->device_x_scale))
+#define SURFACE_Y(_surf, _by)  (((_by)-((_surf)->device_y_offset))/((_surf)->device_y_scale))
+#define SURFACE_X_SIZE(_surf, _bx)  ((_bx)/((_surf)->device_x_scale))
+#define SURFACE_Y_SIZE(_surf, _by)  ((_by)/((_surf)->device_y_scale))
+
 /**
  * _cairo_surface_set_error:
  * @surface: a surface
@@ -556,7 +572,10 @@ cairo_surface_mark_dirty_rectangle (cair
     if (surface->backend->mark_dirty_rectangle) {
 	cairo_status_t status;
 	
-	status = surface->backend->mark_dirty_rectangle (surface, x, y, width, height);
+	status = surface->backend->mark_dirty_rectangle (surface,
+                                                         BACKEND_X(surface, x),
+                                                         BACKEND_Y(surface, y),
+							 width, height);
 	
 	if (status)
 	    _cairo_surface_set_error (surface, status);
@@ -601,6 +620,25 @@ cairo_surface_set_device_offset (cairo_s
 }
 
 /**
+ * cairo_surface_get_device_offset:
+ * @surface: a #cairo_surface_t
+ * @x_offset: the offset in the X direction, in device units
+ * @y_offset: the offset in the Y direction, in device units
+ *
+ * Returns a previous device offset set by
+ * cairo_surface_set_device_offset().
+ *
+ **/
+void
+cairo_surface_get_device_offset (cairo_surface_t *surface,
+				 double          *x_offset,
+				 double          *y_offset)
+{
+    *x_offset = surface->device_x_offset;
+    *y_offset = surface->device_y_offset;
+}
+
+/**
  * _cairo_surface_acquire_source_image:
  * @surface: a #cairo_surface_t
  * @image_out: location to store a pointer to an image surface that
@@ -651,6 +689,7 @@ _cairo_surface_release_source_image (cai
  * @surface: a #cairo_surface_t
  * @interest_rect: area of @surface for which fallback drawing is being done.
  *    A value of %NULL indicates that the entire surface is desired.
+ *    XXXX I'd like to get rid of being able to pass NULL here (nothing seems to)
  * @image_out: location to store a pointer to an image surface that includes at least
  *    the intersection of @interest_rect with the visible area of @surface.
  *    This surface could be @surface itself, a surface held internal to @surface,
@@ -683,10 +722,26 @@ _cairo_surface_acquire_dest_image (cairo
 				   cairo_rectangle_t       *image_rect,
 				   void                   **image_extra)
 {
+    cairo_rectangle_t dev_interest_rect;
+    cairo_status_t status;
+
     assert (!surface->finished);
 
-    return surface->backend->acquire_dest_image (surface, interest_rect,
-						 image_out, image_rect, image_extra);
+    if (interest_rect) {
+	dev_interest_rect = *interest_rect;
+        dev_interest_rect.x = BACKEND_X(surface, dev_interest_rect.x);
+        dev_interest_rect.y = BACKEND_Y(surface, dev_interest_rect.y);
+    }
+
+    status = surface->backend->acquire_dest_image (surface,
+						   interest_rect ? &dev_interest_rect : NULL,
+						   image_out, image_rect, image_extra);
+
+    /* move image_rect back into surface coordinates from backend device coordinates */
+    image_rect->x = SURFACE_X(surface, image_rect->x);
+    image_rect->y = SURFACE_Y(surface, image_rect->y);
+
+    return status;
 }
 
 /**
@@ -708,10 +763,22 @@ _cairo_surface_release_dest_image (cairo
 				   cairo_rectangle_t      *image_rect,
 				   void                   *image_extra)
 {
+    cairo_rectangle_t dev_interest_rect;
+
     assert (!surface->finished);
 
+    /* move image_rect into backend device coords (opposite of acquire_dest_image) */
+    image_rect->x = BACKEND_X(surface, image_rect->x);
+    image_rect->y = BACKEND_Y(surface, image_rect->y);
+
+    if (interest_rect) {
+	dev_interest_rect = *interest_rect;
+        dev_interest_rect.x = BACKEND_X(surface, dev_interest_rect.x);
+        dev_interest_rect.y = BACKEND_Y(surface, dev_interest_rect.y);
+    }
+
     if (surface->backend->release_dest_image)
-	surface->backend->release_dest_image (surface, interest_rect,
+	surface->backend->release_dest_image (surface, &dev_interest_rect,
 					      image, image_rect, image_extra);
 }
 
@@ -747,6 +814,13 @@ _cairo_surface_clone_similar (cairo_surf
 	return CAIRO_INT_STATUS_UNSUPPORTED;
       
     status = surface->backend->clone_similar (surface, src, clone_out);
+    if (status == CAIRO_STATUS_SUCCESS) {
+        (*clone_out)->device_x_offset = src->device_x_offset;
+        (*clone_out)->device_y_offset = src->device_y_offset;
+        (*clone_out)->device_x_scale = src->device_x_scale;
+        (*clone_out)->device_y_scale = src->device_y_scale;
+    }
+
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return status;
 
@@ -755,6 +829,12 @@ _cairo_surface_clone_similar (cairo_surf
 	return status;
 
     status = surface->backend->clone_similar (surface, &image->base, clone_out);
+    if (status == CAIRO_STATUS_SUCCESS) {
+        (*clone_out)->device_x_offset = src->device_x_offset;
+        (*clone_out)->device_y_offset = src->device_y_offset;
+        (*clone_out)->device_x_scale = src->device_x_scale;
+        (*clone_out)->device_y_scale = src->device_y_scale;
+    }
 
     /* If the above failed point, we could implement a full fallback
      * using acquire_dest_image, but that's going to be very
@@ -827,11 +907,29 @@ _cairo_surface_composite (cairo_operator
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
     if (dst->backend->composite) {
+        int backend_src_x = src_x;
+        int backend_src_y = src_y;
+        int backend_mask_x = mask_x;
+        int backend_mask_y = mask_y;
+
+        if (src->type == CAIRO_PATTERN_TYPE_SURFACE) {
+            cairo_surface_t *src_surface = ((cairo_surface_pattern_t*)src)->surface;
+            backend_src_x = BACKEND_X(src_surface, src_x);
+            backend_src_y = BACKEND_Y(src_surface, src_y);
+        }
+
+        if (mask && mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
+            cairo_surface_t *mask_surface = ((cairo_surface_pattern_t*)mask)->surface;
+            backend_mask_x = BACKEND_X(mask_surface, mask_x);
+            backend_mask_y = BACKEND_Y(mask_surface, mask_y);
+        }
+
 	status = dst->backend->composite (op,
 					  src, mask, dst,
-					  src_x, src_y,
-					  mask_x, mask_y,
-					  dst_x, dst_y,
+                                          backend_src_x, backend_src_y,
+                                          backend_mask_x, backend_mask_y,
+                                          BACKEND_X(dst, dst_x),
+                                          BACKEND_Y(dst, dst_y),
 					  width, height);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
@@ -960,6 +1058,8 @@ _cairo_surface_fill_rectangles (cairo_su
 				int			num_rects)
 {
     cairo_int_status_t status;
+    cairo_rectangle_t *dev_rects = NULL;
+    int i;
 
     assert (! surface->is_snapshot);
 
@@ -973,8 +1073,26 @@ _cairo_surface_fill_rectangles (cairo_su
 	return CAIRO_STATUS_SUCCESS;
 
     if (surface->backend->fill_rectangles) {
-	status = surface->backend->fill_rectangles (surface, op, color,
-						    rects, num_rects);
+	if (surface->device_x_offset != 0.0 ||
+	    surface->device_y_offset != 0.0 ||
+	    surface->device_x_scale != 1.0 ||
+	    surface->device_y_scale != 1.0)
+	{
+	    dev_rects = malloc(sizeof(cairo_rectangle_t) * num_rects);
+	    for (i = 0; i < num_rects; i++) {
+		dev_rects[i].x = BACKEND_X(surface, rects[i].x);
+		dev_rects[i].y = BACKEND_Y(surface, rects[i].y);
+
+		dev_rects[i].width = BACKEND_X_SIZE(surface, rects[i].width);
+		dev_rects[i].height = BACKEND_Y_SIZE(surface, rects[i].height);
+	    }
+	}
+
+	status = surface->backend->fill_rectangles (surface,
+						    op,
+						    color,
+						    dev_rects ? dev_rects : rects, num_rects);
+	free (dev_rects);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
     }
@@ -1035,10 +1153,31 @@ _cairo_surface_stroke (cairo_surface_t		
 
     if (surface->backend->stroke) {
 	cairo_status_t status;
+	cairo_path_fixed_t *dev_path = path;
+	cairo_path_fixed_t real_dev_path;
+
+	if (surface->device_x_offset != 0.0 ||
+	    surface->device_y_offset != 0.0 ||
+	    surface->device_x_scale != 1.0 ||
+	    surface->device_y_scale != 1.0)
+        {
+	    _cairo_path_fixed_init_copy (&real_dev_path, path);
+	    _cairo_path_fixed_offset_and_scale (&real_dev_path,
+						_cairo_fixed_from_double (surface->device_x_offset),
+						_cairo_fixed_from_double (surface->device_y_offset),
+						_cairo_fixed_from_double (surface->device_x_scale),
+						_cairo_fixed_from_double (surface->device_y_scale));
+	    dev_path = &real_dev_path;
+	}
+
 	status = surface->backend->stroke (surface, op, source,
-					   path, stroke_style,
+					   dev_path, stroke_style,
 					   ctm, ctm_inverse,
 					   tolerance, antialias);
+
+	if (dev_path == &real_dev_path)
+	    _cairo_path_fixed_fini (&real_dev_path);
+
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
     }
@@ -1059,13 +1198,33 @@ _cairo_surface_fill (cairo_surface_t	*su
 		     cairo_antialias_t	 antialias)
 {
     cairo_status_t status;
+    cairo_path_fixed_t *dev_path = path;
+    cairo_path_fixed_t real_dev_path;
 
     assert (! surface->is_snapshot);
 
     if (surface->backend->fill) {
+        if (surface->device_x_offset != 0.0 ||
+            surface->device_y_offset != 0.0 ||
+            surface->device_x_scale != 1.0 ||
+            surface->device_y_scale != 1.0)
+        {
+            _cairo_path_fixed_init_copy (&real_dev_path, path);
+            _cairo_path_fixed_offset_and_scale (&real_dev_path,
+                                                _cairo_fixed_from_double (surface->device_x_offset),
+                                                _cairo_fixed_from_double (surface->device_y_offset),
+                                                _cairo_fixed_from_double (surface->device_x_scale),
+                                                _cairo_fixed_from_double (surface->device_y_scale));
+            dev_path = &real_dev_path;
+        }
+
 	status = surface->backend->fill (surface, op, source,
-					 path, fill_rule,
+					 dev_path, fill_rule,
 					 tolerance, antialias);
+
+        if (dev_path == &real_dev_path)
+            _cairo_path_fixed_fini (&real_dev_path);
+
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
     }
@@ -1090,6 +1249,7 @@ _cairo_surface_composite_trapezoids (cai
 				     int			num_traps)
 {
     cairo_int_status_t status;
+    cairo_trapezoid_t *dev_traps = NULL;
 
     assert (! dst->is_snapshot);
 
@@ -1105,13 +1265,36 @@ _cairo_surface_composite_trapezoids (cai
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
     if (dst->backend->composite_trapezoids) {
+	if (dst->device_x_offset != 0.0 ||
+	    dst->device_y_offset != 0.0 ||
+	    dst->device_x_scale != 1.0 ||
+	    dst->device_y_scale != 1.0)
+	{
+	    dev_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps);
+	    if (!dev_traps)
+		return CAIRO_STATUS_NO_MEMORY;
+
+	    _cairo_trapezoid_array_translate_and_scale
+		(dev_traps, traps, num_traps,
+		 dst->device_x_offset,
+		 dst->device_y_offset,
+		 dst->device_x_scale,
+		 dst->device_y_scale);
+	}
+
+
 	status = dst->backend->composite_trapezoids (op,
 						     pattern, dst,
 						     antialias,
 						     src_x, src_y,
-						     dst_x, dst_y,
+						     BACKEND_X(dst, dst_x),
+						     BACKEND_Y(dst, dst_y),
+						     // XXX what the heck do I do with width/height?
+						     // they're not the same for src and dst!
 						     width, height,
-						     traps, num_traps);
+						     dev_traps ? dev_traps : traps, num_traps);
+	free (dev_traps);
+
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
     }
@@ -1258,6 +1441,9 @@ _cairo_surface_set_clip_region (cairo_su
 				pixman_region16_t   *region,
 				unsigned int	    serial)
 {
+    pixman_region16_t *dev_region = NULL;
+    cairo_status_t status;
+
     if (surface->status)
 	return surface->status;
 
@@ -1265,10 +1451,50 @@ _cairo_surface_set_clip_region (cairo_su
 	return CAIRO_STATUS_SURFACE_FINISHED;
     
     assert (surface->backend->set_clip_region != NULL);
-    
+
+    if (surface->device_x_offset != 0.0 ||
+	surface->device_y_offset != 0.0 ||
+	surface->device_x_scale != 1.0 ||
+	surface->device_y_scale != 1.0)
+    {
+	dev_region = pixman_region_create ();
+	if (surface->device_x_scale == 1.0 &&
+	    surface->device_y_scale == 1.0)
+	{
+	    pixman_region_copy (dev_region, region);
+	    pixman_region_translate (dev_region, surface->device_x_offset, surface->device_y_offset);
+	} else {
+	    int i, nr = pixman_region_num_rects (region);
+	    pixman_box16_t *rects = pixman_region_rects (region);
+	    for (i = 0; i < nr; i++) {
+		pixman_box16_t tmpb;
+		pixman_region16_t *tmpr;
+
+		tmpb.x1 = BACKEND_X(surface, rects[i].x1);
+		tmpb.y1 = BACKEND_Y(surface, rects[i].y1);
+		tmpb.x2 = BACKEND_X(surface, rects[i].x2);
+		tmpb.y2 = BACKEND_Y(surface, rects[i].y2);
+
+		tmpr = pixman_region_create_simple (&tmpb);
+
+		pixman_region_append (dev_region, tmpr);
+		pixman_region_destroy (tmpr);
+	    }
+
+	    pixman_region_validate (dev_region, &i);
+	}
+
+	region = dev_region;
+    }
+
     surface->current_clip_serial = serial;
 
-    return surface->backend->set_clip_region (surface, region);
+    status = surface->backend->set_clip_region (surface, region);
+
+    if (dev_region)
+	pixman_region_destroy (dev_region);
+
+    return status;
 }
 
 cairo_int_status_t
@@ -1278,6 +1504,10 @@ _cairo_surface_intersect_clip_path (cair
 				    double		tolerance,
 				    cairo_antialias_t	antialias)
 {
+    cairo_path_fixed_t *dev_path = path;
+    cairo_path_fixed_t real_dev_path;
+    cairo_status_t status;
+
     if (surface->status)
 	return surface->status;
 
@@ -1286,11 +1516,30 @@ _cairo_surface_intersect_clip_path (cair
     
     assert (surface->backend->intersect_clip_path != NULL);
 
-    return surface->backend->intersect_clip_path (surface,
-						  path,
-						  fill_rule,
-						  tolerance,
-						  antialias);
+    if (surface->device_x_offset != 0.0 ||
+	surface->device_y_offset != 0.0 ||
+	surface->device_x_scale != 1.0 ||
+	surface->device_y_scale != 1.0)
+    {
+	_cairo_path_fixed_init_copy (&real_dev_path, path);
+	_cairo_path_fixed_offset_and_scale (&real_dev_path,
+					    _cairo_fixed_from_double (surface->device_x_offset),
+					    _cairo_fixed_from_double (surface->device_y_offset),
+					    _cairo_fixed_from_double (surface->device_x_scale),
+					    _cairo_fixed_from_double (surface->device_y_scale));
+	dev_path = &real_dev_path;
+    }
+
+    status = surface->backend->intersect_clip_path (surface,
+						    dev_path,
+						    fill_rule,
+						    tolerance,
+						    antialias);
+
+    if (dev_path == &real_dev_path)
+	_cairo_path_fixed_fini (&real_dev_path);
+
+    return status;
 }
 
 static cairo_status_t
@@ -1306,11 +1555,11 @@ _cairo_surface_set_clip_path_recursive (
     if (status)
 	return status;
 
-    return surface->backend->intersect_clip_path (surface,
-						  &clip_path->path,
-						  clip_path->fill_rule,
-						  clip_path->tolerance,
-						  clip_path->antialias);
+    return _cairo_surface_intersect_clip_path (surface,
+					       &clip_path->path,
+					       clip_path->fill_rule,
+					       clip_path->tolerance,
+					       clip_path->antialias);
 }
 
 /**
@@ -1413,13 +1662,20 @@ cairo_status_t
 _cairo_surface_get_extents (cairo_surface_t   *surface,
 			    cairo_rectangle_t *rectangle)
 {
+    cairo_status_t status;
+
     if (surface->status)
 	return surface->status;
 
     if (surface->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
-    return surface->backend->get_extents (surface, rectangle);
+    status = surface->backend->get_extents (surface, rectangle);
+
+    rectangle->x = SURFACE_X(surface, rectangle->x);
+    rectangle->y = SURFACE_Y(surface, rectangle->y);
+
+    return status;
 }
 
 cairo_status_t
@@ -1431,13 +1687,34 @@ _cairo_surface_show_glyphs (cairo_surfac
 			    cairo_scaled_font_t	*scaled_font)
 {
     cairo_status_t status;
+    cairo_glyph_t *dev_glyphs = NULL;
 
     assert (! surface->is_snapshot);
 
     if (surface->backend->show_glyphs) {
+	if (surface->device_x_offset != 0.0 ||
+	    surface->device_y_offset != 0.0 ||
+	    surface->device_x_scale != 1.0 ||
+	    surface->device_y_scale != 1.0)
+	{
+            int i;
+
+            dev_glyphs = malloc (sizeof(cairo_glyph_t) * num_glyphs);
+            if (!dev_glyphs)
+                return CAIRO_STATUS_NO_MEMORY;
+
+            for (i = 0; i < num_glyphs; i++) {
+                dev_glyphs[i].index = glyphs[i].index;
+		// err, we really should scale the size of the glyphs, no?
+                dev_glyphs[i].x = BACKEND_X(surface, glyphs[i].x);
+                dev_glyphs[i].y = BACKEND_Y(surface, glyphs[i].y);
+            }
+        }
+
 	status = surface->backend->show_glyphs (surface, op, source,
-						glyphs, num_glyphs,
-						scaled_font);
+						dev_glyphs ? dev_glyphs : glyphs,
+						num_glyphs, scaled_font);
+	free (dev_glyphs);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
     }
@@ -1467,6 +1744,7 @@ _cairo_surface_old_show_glyphs (cairo_sc
 				int			 num_glyphs)
 {
     cairo_status_t status;
+    cairo_glyph_t *dev_glyphs = NULL;
 
     assert (! dst->is_snapshot);
 
@@ -1476,14 +1754,35 @@ _cairo_surface_old_show_glyphs (cairo_sc
     if (dst->finished)
 	return CAIRO_STATUS_SURFACE_FINISHED;
 
-    if (dst->backend->old_show_glyphs)
+    if (dst->backend->old_show_glyphs) {
+	if (dst->device_x_offset != 0.0 ||
+	    dst->device_y_offset != 0.0 ||
+	    dst->device_x_scale != 1.0 ||
+	    dst->device_y_scale != 1.0)
+	{
+	    int i;
+
+	    dev_glyphs = malloc(sizeof(cairo_glyph_t) * num_glyphs);
+	    for (i = 0; i < num_glyphs; i++) {
+		dev_glyphs[i] = glyphs[i];
+		// err, we really should scale the size of the glyphs, no?
+		dev_glyphs[i].x = BACKEND_X(dst, dev_glyphs[i].x);
+		dev_glyphs[i].y = BACKEND_Y(dst, dev_glyphs[i].y);
+	    }
+
+	    glyphs = dev_glyphs;
+	}
+
 	status = dst->backend->old_show_glyphs (scaled_font,
 						op, pattern, dst,
 						source_x, source_y,
-						dest_x, dest_y,
+						BACKEND_X(dst, dest_x),
+						BACKEND_Y(dst, dest_y),
 						width, height,
 						glyphs, num_glyphs);
-    else
+
+	free (dev_glyphs);
+    } else
 	status = CAIRO_INT_STATUS_UNSUPPORTED;
 
     return status;
@@ -1593,7 +1892,15 @@ _cairo_surface_composite_fixup_unbounded
     cairo_rectangle_t *mask_rectangle = NULL;
 
     assert (! dst->is_snapshot);
-  
+
+    /* This is a little odd; this function is called from the xlib/image surfaces,
+     * where the coordinates have already been transformed by the device_xy_offset.
+     * We need to undo this before running through this function,
+     * otherwise those offsets get applied twice.
+     */
+    dst_x = SURFACE_X(dst, dst_x);
+    dst_y = SURFACE_Y(dst, dst_y);
+
     /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
      * non-repeating sources and masks. Other sources and masks can be ignored.
      */
@@ -1668,6 +1975,10 @@ _cairo_surface_composite_shape_fixup_unb
     cairo_rectangle_t *mask_rectangle = NULL;
 
     assert (! dst->is_snapshot);
+
+    /* See comment at start of _cairo_surface_composite_fixup_unbounded */
+    dst_x = SURFACE_X(dst, dst_x);
+    dst_y = SURFACE_Y(dst, dst_y);
   
     /* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
      * non-repeating sources and masks. Other sources and masks can be ignored.
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index 6afb499..6733ca5 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -258,6 +258,54 @@ _cairo_traps_translate (cairo_traps_t *t
     }
 }
 
+void
+_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
+                                            cairo_trapezoid_t *src_traps,
+                                            int num_traps,
+                                            double tx, double ty,
+                                            double sx, double sy)
+{
+    int i;
+    cairo_fixed_t xoff = _cairo_fixed_from_double (tx);
+    cairo_fixed_t yoff = _cairo_fixed_from_double (ty);
+
+    if (sx == 1.0 && sy == 1.0) {
+        for (i = 0; i < num_traps; i++) {
+            offset_traps[i].top = src_traps[i].top + yoff;
+            offset_traps[i].bottom = src_traps[i].bottom + yoff;
+            offset_traps[i].left.p1.x = src_traps[i].left.p1.x + xoff;
+            offset_traps[i].left.p1.y = src_traps[i].left.p1.y + yoff;
+            offset_traps[i].left.p2.x = src_traps[i].left.p2.x + xoff;
+            offset_traps[i].left.p2.y = src_traps[i].left.p2.y + yoff;
+            offset_traps[i].right.p1.x = src_traps[i].right.p1.x + xoff;
+            offset_traps[i].right.p1.y = src_traps[i].right.p1.y + yoff;
+            offset_traps[i].right.p2.x = src_traps[i].right.p2.x + xoff;
+            offset_traps[i].right.p2.y = src_traps[i].right.p2.y + yoff;
+        }
+    } else {
+        cairo_fixed_t xsc = _cairo_fixed_from_double (sx);
+        cairo_fixed_t ysc = _cairo_fixed_from_double (sy);
+
+        for (i = 0; i < num_traps; i++) {
+#define FIXED_MUL(_a, _b) \
+            (_cairo_int64_to_int32(_cairo_int64_rsl(_cairo_int32x32_64_mul((_a), (_b)), 16)))
+
+            offset_traps[i].top = FIXED_MUL(src_traps[i].top + yoff, ysc);
+            offset_traps[i].bottom = FIXED_MUL(src_traps[i].bottom + yoff, ysc);
+            offset_traps[i].left.p1.x = FIXED_MUL(src_traps[i].left.p1.x + xoff, xsc);
+            offset_traps[i].left.p1.y = FIXED_MUL(src_traps[i].left.p1.y + yoff, ysc);
+            offset_traps[i].left.p2.x = FIXED_MUL(src_traps[i].left.p2.x + xoff, xsc);
+            offset_traps[i].left.p2.y = FIXED_MUL(src_traps[i].left.p2.y + yoff, ysc);
+            offset_traps[i].right.p1.x = FIXED_MUL(src_traps[i].right.p1.x + xoff, xsc);
+            offset_traps[i].right.p1.y = FIXED_MUL(src_traps[i].right.p1.y + yoff, ysc);
+            offset_traps[i].right.p2.x = FIXED_MUL(src_traps[i].right.p2.x + xoff, xsc);
+            offset_traps[i].right.p2.y = FIXED_MUL(src_traps[i].right.p2.y + yoff, ysc);
+
+#undef FIXED_MUL
+        }
+    }
+}
+
 cairo_status_t
 _cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3])
 {
@@ -859,4 +907,3 @@ _cairo_traps_extract_region (cairo_traps
 
     return CAIRO_STATUS_SUCCESS;
 }
-
diff --git a/src/cairo.h b/src/cairo.h
index ea4e20b..c1f191c 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1304,6 +1304,11 @@ cairo_surface_set_device_offset (cairo_s
 				 double           x_offset,
 				 double           y_offset);
 
+cairo_public void
+cairo_surface_get_device_offset (cairo_surface_t *surface,
+				 double          *x_offset,
+				 double          *y_offset);
+
 /* Image-surface functions */
 
 /**
diff --git a/src/cairoint.h b/src/cairoint.h
index cfa8b7d..529fae0 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1488,6 +1488,13 @@ _cairo_path_fixed_bounds (cairo_path_fix
 			  double *x1, double *y1,
 			  double *x2, double *y2);
 
+cairo_private void
+_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
+                                    cairo_fixed_t offx,
+                                    cairo_fixed_t offy,
+                                    cairo_fixed_t scalex,
+                                    cairo_fixed_t scaley);
+
 /* cairo_path_fill.c */
 cairo_private cairo_status_t
 _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
@@ -2038,6 +2045,13 @@ cairo_private cairo_status_t
 _cairo_traps_extract_region (cairo_traps_t      *tr,
 			     pixman_region16_t **region);
 
+cairo_private void
+_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
+					    cairo_trapezoid_t *src_traps,
+					    int num_traps,
+					    double tx, double ty,
+					    double sx, double sy);
+
 /* cairo_slope.c */
 cairo_private void
 _cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b);
diff --git a/test/buffer-diff.c b/test/buffer-diff.c
index c62c44e..89af811 100644
--- a/test/buffer-diff.c
+++ b/test/buffer-diff.c
@@ -287,9 +287,9 @@ image_diff_flattened (const char *filena
 
     b_flat_surface = cairo_image_surface_create_for_data (b_flat,
 							  CAIRO_FORMAT_ARGB32,
-							  width_a, height_a,
-							  stride_a);
-    /*cairo_surface_set_device_offset (b_flat_surface, -bx, -by);*/
+							  width_b, height_b,
+							  stride_b);
+    cairo_surface_set_device_offset (b_flat_surface, -bx, -by);
 
     cr = cairo_create (b_flat_surface);
 
@@ -306,7 +306,7 @@ image_diff_flattened (const char *filena
                                   b_flat,
                                   buf_diff,
 				  width_a, height_a,
-				  stride_a, stride_a, stride_a);
+                                  stride_a, stride_b, stride_a);
 
     if (pixels_changed) {
 	FILE *png_file = fopen (filename_diff, "wb");
diff --git a/test/cairo-test.c b/test/cairo-test.c
index 6a3d52a..fff8526 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -1427,6 +1427,11 @@ cairo_test_for_target (cairo_test_t *tes
     else
 	offset_str = strdup("");
     
+    if (dev_offset)
+	xasprintf (&offset_str, "-%d", dev_offset);
+    else
+	offset_str = strdup("");
+
     xasprintf (&png_name, "%s-%s-%s%s%s", test->name,
 	       target->name, format, offset_str, CAIRO_TEST_PNG_SUFFIX);
 
diff-tree 40b39dddf9cd919fb2f456a8e296a60cc8296fbf (from b3e2252b94297b7fbdbd3a3776781ea6df7c8bc6)
Author: Carl Worth <cworth at cworth.org>
Date:   Fri Mar 10 16:37:50 2006 -0800

    Shrink the size of a couple of tests (and update reference images).
    
    Shrink linear-gradient and text-pattern test outuput.
    
    The real motivation for this is to hide an annoying difference in the
    gradient output that occurs when under the influence of a device
    offsets. My opinion is that the gradient output should not change due
    to just an integer offset, but we currently don't have a precise
    gradient specification, so this minor deviation really isn't relevant.
    
    A better fix for this might have been to make the test suite more
    forgiving of tiny differences, (perhaps on a per-test basis), but
    another advantage of shrinking these tests is that they now run a lot
    faster.
    
    It is true that these tests now also exercise fewer different output
    values, but that's not the designed purpose of the tests so I don't
    feel bad about losing that characteristic.

diff --git a/test/linear-gradient-ref.png b/test/linear-gradient-ref.png
index 64ceddf..8568c13 100644
Binary files a/test/linear-gradient-ref.png and b/test/linear-gradient-ref.png differ
diff --git a/test/linear-gradient.c b/test/linear-gradient.c
index 38ba559..686a56c 100644
--- a/test/linear-gradient.c
+++ b/test/linear-gradient.c
@@ -47,9 +47,9 @@ static const double rotate_angles[] = { 
 static const int n_stops[] = { 2, 3 };
 #define N_N_STOPS 2
 
-#define UNIT_SIZE 75
-#define UNIT_SIZE 75
-#define PAD 5
+#define UNIT_SIZE 6
+#define UNIT_SIZE 6
+#define PAD 1
 
 #define WIDTH  N_GRADIENT_ANGLES * UNIT_SIZE + (N_GRADIENT_ANGLES + 1) * PAD
 #define HEIGHT N_N_STOPS * N_ROTATE_ANGLES * UNIT_SIZE + (N_N_STOPS * N_ROTATE_ANGLES + 1) * PAD
diff --git a/test/text-pattern-ref.png b/test/text-pattern-ref.png
index 8f8fc79..8de428e 100644
Binary files a/test/text-pattern-ref.png and b/test/text-pattern-ref.png differ
diff --git a/test/text-pattern-rgb24-ref.png b/test/text-pattern-rgb24-ref.png
index e5a7f70..cf4b937 100644
Binary files a/test/text-pattern-rgb24-ref.png and b/test/text-pattern-rgb24-ref.png differ
diff --git a/test/text-pattern.c b/test/text-pattern.c
index bf7a5e2..ba4e869 100644
--- a/test/text-pattern.c
+++ b/test/text-pattern.c
@@ -25,8 +25,8 @@
 
 #include "cairo-test.h"
 
-#define IMAGE_WIDTH 100
-#define IMAGE_HEIGHT 100
+#define IMAGE_WIDTH 64
+#define IMAGE_HEIGHT 64
 
 cairo_test_t test = {
     "text-pattern",
diff-tree b3e2252b94297b7fbdbd3a3776781ea6df7c8bc6 (from 7beb3e27a552c724bbdb147bc27b775af0d61063)
Author: Vladimir Vukicevic <vladimir at pobox.com>
Date:   Wed Feb 15 13:46:52 2006 -0800

    Augment test framework to test everything under device offsets as well.
    
    [With this change, two tests with gradients exhibit subtle differences
    under device offsets. I don't think we actually care about them
    though. -cworth]

diff --git a/test/.gitignore b/test/.gitignore
index 3f3c582..d4472f2 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -91,38 +91,10 @@ unantialiased-shapes
 unbounded-operator
 user-data
 xlib-surface
-*-image-out.png
-*-image-argb32-out.png
-*-image-rgb24-out.png
-*-pdf-argb32-out.png
-*-pdf-argb32-out.pdf
-*-pdf-rgb24-out.png
-*-pdf-rgb24-out.pdf
-*-ps-argb32-out.png
-*-ps-argb32-out.ps
-*-ps-rgb24-out.png
-*-ps-rgb24-out.ps
-*-svg-argb32-out.png
-*-svg-argb32-out.svg
-*-svg-rgb24-out.png
-*-svg-rgb24-out.svg
-*-test-fallback-argb32-out.png
-*-test-fallback-rgb24-out.png
-*-test-meta-argb32-out.png
-*-test-meta-rgb24-out.png
-*-test-paginated-argb32-out.png
-*-test-paginated-rgb24-out.png
-*-xcb-out.png
-*-xcb-argb32-out.png
-*-xcb-rgb24-out.png
-*-xlib-out.png
-*-xlib-argb32-out.png
-*-xlib-rgb24-out.png
-*-beos-rgb24-out.png
-*-beos_bitmap-rgb24-out.png
-*-beos_bitmap-argb32-out.png
-*-glitz-glx-rgb24-out.png
-*-glitz-glx-argb32-out.png
+*-out.pdf
+*-out.png
+*-out.ps
+*-out.svg
 *-diff.png
 *.gcno
 *.la
diff --git a/test/buffer-diff.c b/test/buffer-diff.c
index dd1b7c6..c62c44e 100644
--- a/test/buffer-diff.c
+++ b/test/buffer-diff.c
@@ -62,7 +62,9 @@ buffer_diff_core (unsigned char *_buf_a,
 		  unsigned char *_buf_diff,
 		  int		width,
 		  int		height,
-		  int		stride,
+		  int		stride_a,
+		  int		stride_b,
+		  int		stride_diff,
 		  pixman_bits_t mask)
 {
     int x, y;
@@ -72,12 +74,14 @@ buffer_diff_core (unsigned char *_buf_a,
     pixman_bits_t *buf_b = (pixman_bits_t*)_buf_b;
     pixman_bits_t *buf_diff = (pixman_bits_t*)_buf_diff;
 
-    stride /= sizeof(pixman_bits_t);
+    stride_a /= sizeof(pixman_bits_t);
+    stride_b /= sizeof(pixman_bits_t);
+    stride_diff /= sizeof(pixman_bits_t);
     for (y = 0; y < height; y++)
     {
-	row_a = buf_a + y * stride;
-	row_b = buf_b + y * stride;
-	row = buf_diff + y * stride;
+	row_a = buf_a + y * stride_a;
+	row_b = buf_b + y * stride_b;
+	row = buf_diff + y * stride_diff;
 	for (x = 0; x < width; x++)
 	{
 	    /* check if the pixels are the same */
@@ -112,9 +116,12 @@ buffer_diff (unsigned char *buf_a,
 	     unsigned char *buf_diff,
 	     int	   width,
 	     int	   height,
-	     int	   stride)
+	     int	   stride_a,
+	     int	   stride_b,
+	     int	   stride_diff)
 {
-    return buffer_diff_core(buf_a, buf_b, buf_diff, width, height, stride, 0xffffffff);
+    return buffer_diff_core(buf_a, buf_b, buf_diff,
+			    width, height, stride_a, stride_b, stride_diff, 0xffffffff);
 }
 
 int
@@ -123,9 +130,12 @@ buffer_diff_noalpha (unsigned char *buf_
 		     unsigned char *buf_diff,
 		     int	   width,
 		     int	   height,
-		     int	   stride)
+		     int	   stride_a,
+		     int	   stride_b,
+		     int	   stride_diff)
 {
-    return buffer_diff_core(buf_a, buf_b, buf_diff, width, height, stride, 0x00ffffff);
+    return buffer_diff_core(buf_a, buf_b, buf_diff,
+			    width, height, stride_a, stride_b, stride_diff, 0x00ffffff);
 }
 
 /* Image comparison code courtesy of Richard Worth <richard at theworths.org>
@@ -136,11 +146,16 @@ buffer_diff_noalpha (unsigned char *buf_
 int
 image_diff (const char *filename_a,
 	    const char *filename_b,
-	    const char *filename_diff)
+	    const char *filename_diff,
+	    int		ax,
+	    int		ay,
+	    int		bx,
+	    int		by)
 {
     int pixels_changed;
     unsigned int width_a, height_a, stride_a;
     unsigned int width_b, height_b, stride_b;
+    unsigned int stride_diff;
     unsigned char *buf_a, *buf_b, *buf_diff;
     read_png_status_t status;
 
@@ -154,9 +169,13 @@ image_diff (const char *filename_a,
 	return -1;
     }
 
+    width_a -= ax;
+    height_a -= ay;
+    width_b -= bx;
+    height_b -= by;
+
     if (width_a  != width_b  ||
-	height_a != height_b ||
-	stride_a != stride_b)
+	height_a != height_b)
     {
 	cairo_test_log ("Error: Image size mismatch: (%dx%d@%d) vs. (%dx%d@%d)\n"
 			"       for %s vs. %s\n",
@@ -168,17 +187,27 @@ image_diff (const char *filename_a,
 	return -1;
     }
 
-    buf_diff = xcalloc (stride_a * height_a, 1);
+    stride_diff = 4 * width_a;
+    buf_diff = xcalloc (stride_diff * height_a, 1);
 
-    pixels_changed = buffer_diff (buf_a, buf_b, buf_diff,
-				  width_a, height_a, stride_a);
+    pixels_changed = buffer_diff (buf_a + (ay * stride_a) + ax * 4,
+                                  buf_b + (by * stride_b) + by * 4,
+                                  buf_diff,
+                                  width_a, height_a,
+				  stride_a, stride_b, stride_diff);
 
     if (pixels_changed) {
-	FILE *png_file = fopen (filename_diff, "wb");
-	write_png_argb32 (buf_diff, png_file, width_a, height_a, stride_a);
-	fclose (png_file);
+	FILE *png_file;
+	if (filename_diff)
+	    png_file = fopen (filename_diff, "wb");
+	else
+	    png_file = stdout;
+	write_png_argb32 (buf_diff, png_file, width_a, height_a, stride_diff);
+	if (png_file != stdout)
+	    fclose (png_file);
     } else {
-	xunlink (filename_diff);
+	if (filename_diff)
+	    xunlink (filename_diff);
     }
 
     free (buf_a);
@@ -204,7 +233,11 @@ image_diff (const char *filename_a,
 int
 image_diff_flattened (const char *filename_a,
 		      const char *filename_b,
-		      const char *filename_diff)
+		      const char *filename_diff,
+		      int	  ax,
+		      int	  ay,
+		      int	  bx,
+		      int	  by)
 {
     int pixels_changed;
     unsigned int width_a, height_a, stride_a;
@@ -225,9 +258,13 @@ image_diff_flattened (const char *filena
 	return -1;
     }
 
+    width_a -= ax;
+    height_a -= ay;
+    width_b -= bx;
+    height_b -= by;
+
     if (width_a  != width_b  ||
-	height_a != height_b ||
-	stride_a != stride_b)
+	height_a != height_b)
     {
 	cairo_test_log ("Error: Image size mismatch: (%dx%d@%d) vs. (%dx%d@%d)\n"
 			"       for %s vs. %s\n",
@@ -241,17 +278,19 @@ image_diff_flattened (const char *filena
 
     buf_b_surface =  cairo_image_surface_create_for_data (buf_b,
 							  CAIRO_FORMAT_ARGB32,
-							  width_b, height_b,
+							  width_b + bx, height_b + bx,
 							  stride_b);
 
     buf_diff = xcalloc (stride_a * height_a, 1);
 
-    b_flat = xcalloc (stride_b * height_b, 1);
+    b_flat = xcalloc (stride_a * height_a, 1);
 
     b_flat_surface = cairo_image_surface_create_for_data (b_flat,
 							  CAIRO_FORMAT_ARGB32,
-							  width_b, height_b,
-							  stride_b);
+							  width_a, height_a,
+							  stride_a);
+    /*cairo_surface_set_device_offset (b_flat_surface, -bx, -by);*/
+
     cr = cairo_create (b_flat_surface);
 
     cairo_set_source_rgb (cr, 1, 1, 1);
@@ -263,8 +302,11 @@ image_diff_flattened (const char *filena
     cairo_surface_destroy (b_flat_surface);
     cairo_surface_destroy (buf_b_surface);
 
-    pixels_changed = buffer_diff (buf_a, b_flat, buf_diff,
-				  width_a, height_a, stride_a);
+    pixels_changed = buffer_diff (buf_a + (ay * stride_a) + ax * 4,
+                                  b_flat,
+                                  buf_diff,
+				  width_a, height_a,
+				  stride_a, stride_a, stride_a);
 
     if (pixels_changed) {
 	FILE *png_file = fopen (filename_diff, "wb");
diff --git a/test/buffer-diff.h b/test/buffer-diff.h
index b9c48ed..fd9662e 100644
--- a/test/buffer-diff.h
+++ b/test/buffer-diff.h
@@ -36,7 +36,9 @@ buffer_diff (unsigned char *buf_a,
 	     unsigned char *buf_diff,
 	     int	    width,
 	     int	    height,
-	     int	    stride);
+	     int	    stride_a,
+	     int	    stride_b,
+	     int	    stride_diff);
 
 /* Returns number of pixels changed ignoring the alpha channel.
  * Also fills in a "diff" buffer intended to visually show where the
@@ -48,7 +50,10 @@ buffer_diff_noalpha (unsigned char *buf_
 		     unsigned char *buf_diff,
 		     int	    width,
 		     int	    height,
-		     int	    stride);
+		     int	    stride_a,
+		     int	    stride_b,
+		     int	    stride_diff);
+
 
 /* Returns number of pixels changed, (or -1 on error).
  * Also saves a "diff" image intended to visually show where the
@@ -57,13 +62,21 @@ buffer_diff_noalpha (unsigned char *buf_
 int
 image_diff (const char *filename_a,
 	    const char *filename_b,
-	    const char *filename_diff);
+	    const char *filename_diff,
+	    int		ax,
+	    int		ay,
+	    int		bx,
+	    int		by);
 
 /* Like image_diff, but blending the contents of b over white first. */
 int
 image_diff_flattened (const char *filename_a,
 		      const char *filename_b,
-		      const char *filename_diff);
+		      const char *filename_diff,
+                      int         ax,
+                      int         ay,
+                      int         bx,
+                      int         by);
 
 
 #endif
diff --git a/test/cairo-test.c b/test/cairo-test.c
index 6615b87..6a3d52a 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -78,6 +78,8 @@ static const char *fail_face = "", *norm
 #define CAIRO_TEST_REF_SUFFIX "-ref.png"
 #define CAIRO_TEST_DIFF_SUFFIX "-diff.png"
 
+#define NUM_DEVICE_OFFSETS 2
+
 /* A fake format we use for the flattened ARGB output of the PS and
  * PDF surfaces. */
 #define CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED -1
@@ -1403,12 +1405,13 @@ cleanup_svg (void *closure)
 static cairo_test_status_t
 cairo_test_for_target (cairo_test_t *test,
 		       cairo_test_draw_function_t draw,
-		       cairo_test_target_t	 *target)
+		       cairo_test_target_t	 *target,
+		       int			  dev_offset)
 {
     cairo_test_status_t status;
     cairo_surface_t *surface;
     cairo_t *cr;
-    char *png_name, *ref_name, *diff_name;
+    char *png_name, *ref_name, *diff_name, *offset_str;
     char *srcdir;
     char *format;
     cairo_test_status_t ret;
@@ -1418,10 +1421,16 @@ cairo_test_for_target (cairo_test_t *tes
     if (!srcdir)
 	srcdir = ".";
     format = _cairo_test_content_name (target->content);
+
+    if (dev_offset)
+	xasprintf (&offset_str, "-%d", dev_offset);
+    else
+	offset_str = strdup("");
     
+    xasprintf (&png_name, "%s-%s-%s%s%s", test->name,
+	       target->name, format, offset_str, CAIRO_TEST_PNG_SUFFIX);
+
     /* First look for a target/format-specific reference image. */
-    xasprintf (&png_name, "%s-%s-%s%s", test->name,
-	       target->name, format, CAIRO_TEST_PNG_SUFFIX);
     xasprintf (&ref_name, "%s/%s-%s-%s%s", srcdir, test->name,
 	       target->name, format, CAIRO_TEST_REF_SUFFIX);
     if (access (ref_name, F_OK) != 0) {
@@ -1439,11 +1448,22 @@ cairo_test_for_target (cairo_test_t *tes
 		       CAIRO_TEST_REF_SUFFIX);
 	}
     }
-    xasprintf (&diff_name, "%s-%s-%s%s", test->name,
-	       target->name, format, CAIRO_TEST_DIFF_SUFFIX);
+    xasprintf (&diff_name, "%s-%s-%s%s%s", test->name,
+	       target->name, format, offset_str, CAIRO_TEST_DIFF_SUFFIX);
 
     /* Run the actual drawing code. */
+    if (test->width && test->height) {
+	test->width += dev_offset;
+	test->height += dev_offset;
+    }
+
     surface = (target->create_target_surface) (test, target->content, &target->closure);
+
+    if (test->width && test->height) {
+	test->width -= dev_offset;
+	test->height -= dev_offset;;
+    }
+
     if (surface == NULL) {
 	cairo_test_log ("Error: Failed to set %s target\n", target->name);
 	ret = CAIRO_TEST_UNTESTED;
@@ -1457,6 +1477,8 @@ cairo_test_for_target (cairo_test_t *tes
 	goto UNWIND_SURFACE;
     }
 
+    cairo_surface_set_device_offset (surface, dev_offset, dev_offset);
+
     cr = cairo_create (surface);
 
     /* Clear to transparent (or black) depending on whether the target
@@ -1490,9 +1512,9 @@ cairo_test_for_target (cairo_test_t *tes
 	xunlink (png_name);
 	(target->write_to_png) (surface, png_name);
 	if (target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
-	    pixels_changed = image_diff_flattened (png_name, ref_name, diff_name);
+	    pixels_changed = image_diff_flattened (png_name, ref_name, diff_name, dev_offset, dev_offset, 0, 0);
 	else
-	    pixels_changed = image_diff (png_name, ref_name, diff_name);
+	    pixels_changed = image_diff (png_name, ref_name, diff_name, dev_offset, dev_offset, 0, 0);
 	if (pixels_changed) {
 	    if (pixels_changed > 0)
 		cairo_test_log ("Error: %d pixels differ from reference image %s\n",
@@ -1518,6 +1540,7 @@ UNWIND_STRINGS:
     free (png_name);
     free (ref_name);
     free (diff_name);
+    free (offset_str);
 
     return ret;
 }
@@ -1526,7 +1549,7 @@ static cairo_test_status_t
 cairo_test_expecting (cairo_test_t *test, cairo_test_draw_function_t draw,
 		      cairo_test_status_t expectation)
 {
-    int i, num_targets;
+    int i, j, num_targets;
     const char *tname;
     cairo_test_status_t status, ret;
     cairo_test_target_t **targets_to_test;
@@ -1698,39 +1721,45 @@ cairo_test_expecting (cairo_test_t *test
      */
     ret = CAIRO_TEST_UNTESTED;
     for (i = 0; i < num_targets; i++) {
-    	cairo_test_target_t *target = targets_to_test[i];
-	cairo_test_log ("Testing %s with %s target\n", test->name, target->name);
-	printf ("%s-%s-%s:\t", test->name, target->name,
-		_cairo_test_content_name (target->content));
-
-	status = cairo_test_for_target (test, draw, target);
-
-	cairo_test_log ("TEST: %s TARGET: %s FORMAT: %s RESULT: ",
-			test->name, target->name,
-			_cairo_test_content_name (target->content));
-
-	switch (status) {
-	case CAIRO_TEST_SUCCESS:
-	    printf ("PASS\n");
-	    cairo_test_log ("PASS\n");
-	    if (ret == CAIRO_TEST_UNTESTED)
-		ret = CAIRO_TEST_SUCCESS;
-	    break;
-	case CAIRO_TEST_UNTESTED:
-	    printf ("UNTESTED\n");
-	    cairo_test_log ("UNTESTED\n");
-	    break;
-	default:
-	case CAIRO_TEST_FAILURE:
-	    if (expectation == CAIRO_TEST_FAILURE) {
-		printf ("XFAIL\n");
-		cairo_test_log ("XFAIL\n");
-	    } else {
-		printf ("%sFAIL%s\n", fail_face, normal_face);
-		cairo_test_log ("FAIL\n");
+	for (j = 0; j < NUM_DEVICE_OFFSETS; j++) {
+	    cairo_test_target_t *target = targets_to_test[i];
+	    int dev_offset = j * 25;
+
+	    cairo_test_log ("Testing %s with %s target (dev offset %d)\n", test->name, target->name, dev_offset);
+	    printf ("%s-%s-%s [%d]:\t", test->name, target->name,
+		    _cairo_test_content_name (target->content),
+		    dev_offset);
+
+	    status = cairo_test_for_target (test, draw, target, dev_offset);
+
+	    cairo_test_log ("TEST: %s TARGET: %s FORMAT: %s OFFSET: %d RESULT: ",
+			    test->name, target->name,
+			    _cairo_test_content_name (target->content),
+			    dev_offset);
+
+	    switch (status) {
+	    case CAIRO_TEST_SUCCESS:
+		printf ("PASS\n");
+		cairo_test_log ("PASS\n");
+		if (ret == CAIRO_TEST_UNTESTED)
+		    ret = CAIRO_TEST_SUCCESS;
+		break;
+	    case CAIRO_TEST_UNTESTED:
+		printf ("UNTESTED\n");
+		cairo_test_log ("UNTESTED\n");
+		break;
+	    default:
+	    case CAIRO_TEST_FAILURE:
+		if (expectation == CAIRO_TEST_FAILURE) {
+		    printf ("XFAIL\n");
+		    cairo_test_log ("XFAIL\n");
+		} else {
+		    printf ("%sFAIL%s\n", fail_face, normal_face);
+		    cairo_test_log ("FAIL\n");
+		}
+		ret = status;
+		break;
 	    }
-	    ret = status;
-	    break;
 	}
     }
     if (ret == CAIRO_TEST_UNTESTED)
diff --git a/test/imagediff.c b/test/imagediff.c
index de66b68..41d065c 100644
--- a/test/imagediff.c
+++ b/test/imagediff.c
@@ -34,54 +34,31 @@
 int 
 main (int argc, char *argv[])
 {
-    read_png_status_t status;
-    unsigned char *buffer_a;
-    unsigned int width_a, height_a, stride_a;
-    unsigned char *buffer_b;
-    unsigned int width_b, height_b, stride_b;
-
-    unsigned char *buffer;
-    unsigned int width, height, stride;
-    int buffer_size, total_pixels_changed;
+    int total_pixels_changed;
 
-    if (argc < 2) {
-	fprintf (stderr, "Usage: %s image1.png image2.png\n", argv[0]);
+    unsigned int ax, ay, bx, by;
+
+    if (argc != 3 && argc != 7) {
+	fprintf (stderr, "Usage: %s image1.png image2.png [ax ay bx by]\n", argv[0]);
 	fprintf (stderr, "Computes an output image designed to present a \"visual diff\" such that even\n");
 	fprintf (stderr, "small errors in single pixels are readily apparent in the output.\n");
 	fprintf (stderr, "The output image is written on stdout.\n");
 	exit (1);
     }
 
-    status = read_png_argb32 (argv[1], &buffer_a, &width_a, &height_a, &stride_a);
-    if (status)
-	return 1;
-
-    status = read_png_argb32 (argv[2], &buffer_b, &width_b, &height_b, &stride_b);
-    if (status)
-	return 1;
-
-    if ((width_a == width_b) && (height_a == height_b) && (stride_a == stride_b))
-    {
-	width = width_a;
-	height = height_a;
-	stride = stride_a;
+    if (argc == 7) {
+	ax = strtoul (argv[3], NULL, 0);
+	ay = strtoul (argv[4], NULL, 0);
+	bx = strtoul (argv[5], NULL, 0);
+	by = strtoul (argv[6], NULL, 0);
     } else {
-	fprintf (stderr, "Error. Both images must be the same size\n");
-	return 1;
+	ax = ay = bx = by = 0;
     }
 
-    buffer_size = stride * height;
-    buffer = xmalloc (buffer_size);
-    
-    total_pixels_changed = buffer_diff (buffer_a, buffer_b, buffer,
-					width_a, height_a, stride_a);
-
+    total_pixels_changed = image_diff (argv[1], argv[2], NULL, ax, ay, bx, by);
 
     if (total_pixels_changed)
 	fprintf (stderr, "Total pixels changed: %d\n", total_pixels_changed);
-    write_png_argb32 (buffer, stdout, width, height, stride);
-
-    free (buffer);
 
     return (total_pixels_changed != 0);
 }
diff --git a/test/make-html.pl b/test/make-html.pl
index f4bbb8c..8b34e12 100755
--- a/test/make-html.pl
+++ b/test/make-html.pl
@@ -29,8 +29,6 @@
 ## html to stdout that can be used to view all the test results at once.
 ##
 
-# some config options:
-
 # show reference images
 my $config_show_ref = 0;
 
@@ -49,20 +47,22 @@ my $teststats = {};
 foreach (<*.log>) {
   (open LOG, "$_") || next;
   while (<LOG>) {
-    next unless /^TEST: (.*) TARGET: (.*) FORMAT: (.*) RESULT: (.*)$/;
+    next unless /^TEST: (.*) TARGET: (.*) FORMAT: (.*) OFFSET: (.*) RESULT: (.*)$/;
     $tests->{$1} = {} unless $tests->{$1};
     $tests->{$1}->{$2} = {} unless $tests->{$1}->{$2};
-    $tests->{$1}->{$2}->{$3} = $4;
+    $tests->{$1}->{$2}->{$3} = {} unless $tests->{$1}->{$2}->{$3};
+    $tests->{$1}->{$2}->{$3}->{$4} = $5;
 
     $teststats->{$2} = {"PASS" => 0, "FAIL" => 0, "XFAIL" => 0, "UNTESTED" => 0}
       unless $teststats->{$2};
-    ($teststats->{$2}->{$4})++;
+    ($teststats->{$2}->{$5})++;
   }
   close LOG;
 }
 
 my $targeth = {};
 my $formath = {};
+my $offseth = {};
 
 foreach my $testname (sort(keys %$tests)) {
   my $v0 = $tests->{$testname};
@@ -71,13 +71,19 @@ foreach my $testname (sort(keys %$tests)
 
     $targeth->{$targetname} = 1;
     foreach my $formatname (sort(keys %$v1)) {
+      my $v2 = $v1->{$formatname};
+
       $formath->{$formatname} = 1;
+      foreach my $offsetval (sort(keys %$v2)) {
+        $offseth->{$offsetval} = 1;
+      }
     }
   }
 }
 
 my @targets = sort(keys %$targeth);
 my @formats = sort(keys %$formath);
+my @offsets = sort(keys %$offseth);
 
 sub printl {
   print @_, "\n";
@@ -133,72 +139,78 @@ sub testref {
 }
 
 sub testfiles {
-  my ($test, $target, $format, $rest) = @_;
+  my ($test, $target, $format, $offset, $rest) = @_;
   my $fmtstr = "";
+  my $offstr = "";
   if ($format eq "rgb24") {
     $fmtstr = "-rgb24";
   } elsif ($format eq "argb32") {
     $fmtstr = "-argb32";
   }
+  if ($offset ne "0") {
+    $offstr = "-" . $offset;
+  }
 
-  return ("out" => "$test-$target$fmtstr-out.png",
-	  "diff" => "$test-$target$fmtstr-diff.png");
+  return ("out" => "$test-$target$fmtstr$offstr-out.png",
+	  "diff" => "$test-$target$fmtstr$offstr-diff.png");
 }
 
 foreach my $test (sort(keys %$tests)) {
-  foreach my $format (@formats) {
-    my $testline = "";
+  foreach my $offset (@offsets) {
+    foreach my $format (@formats) {
+      my $testline = "";
+
+      my $num_failed = 0;
+
+      foreach my $target (@targets) {
+        my $tgtdata = $tests->{$test}->{$target};
+        if ($tgtdata) {
+          my $testres = $tgtdata->{$format}->{$offset};
+          if ($testres) {
+            my %testfiles = testfiles($test, $target, $format, $offset);
+            $testline .= "<td class=\"$testres\">";
+            $stats{$target}{$testres}++;
+            if ($testres eq "PASS") {
+              if ($config_show_all) {
+                $testline .= "<a href=\"" . $testfiles{"out"} . "\"><img src=\"" . $testfiles{"out"} . "\"></a>";
+              }
+            } elsif ($testres eq "FAIL") {
+              $num_failed++;
+
+              if ($config_show_fail || $config_show_all) {
+                $testline .= "<a href=\"" . $testfiles{"out"} . "\"><img src=\"" . $testfiles{"out"} . "\"></a>";
+                $testline .= "<hr size=\"1\">";
+                $testline .= "<a href=\"" . $testfiles{"diff"} . "\"><img src=\"" . $testfiles{"diff"} . "\"></a>";
+              }
+            } elsif ($testres eq "XFAIL") {
+              #nothing
+              if ($config_show_all) {
+                $testline .= "<a href=\"" . $testfiles{"out"} . "\"><img src=\"" . $testfiles{"out"} . "\"></a>";
+                $testline .= "<hr size=\"1\">";
+                $testline .= "<a href=\"" . $testfiles{"diff"} . "\"><img src=\"" . $testfiles{"diff"} . "\"></a>";
+              }
+            }
+
+            $testline .= "</td>";
+          } else {
+            $testline .= '<td></td>';
+          }
+        } else {
+          $testline .= '<td></td>';
+        }
+      }
 
-    my $num_failed = 0;
+      my $testref = testref($test, $format);
+      print '<tr><td>', "<a href=\"$testref\">", $test, ' (', $format, '/', $offset, ')</a></td>';
 
-    foreach my $target (@targets) {
-      my $tgtdata = $tests->{$test}->{$target};
-      if ($tgtdata) {
-	my $testres = $tgtdata->{$format};
-	if ($testres) {
-	  my %testfiles = testfiles($test, $target, $format);
-	  $testline .= "<td class=\"$testres\">";
-	  $stats{$target}{$testres}++;
-	  if ($testres eq "PASS") {
-	    if ($config_show_all) {
-	      $testline .= "<a href=\"" . $testfiles{"out"} . "\"><img src=\"" . $testfiles{"out"} . "\"></a>";
-	    }
-	  } elsif ($testres eq "FAIL") {
-	    $num_failed++;
-
-	    if ($config_show_fail || $config_show_all) {
-	      $testline .= "<a href=\"" . $testfiles{"out"} . "\"><img src=\"" . $testfiles{"out"} . "\"></a>";
-	      $testline .= "<hr size=\"1\">";
-	      $testline .= "<a href=\"" . $testfiles{"diff"} . "\"><img src=\"" . $testfiles{"diff"} . "\"></a>";
-	    }
-	  } elsif ($testres eq "XFAIL") {
-	    #nothing
-	    if ($config_show_all) {
-	      $testline .= "<a href=\"" . $testfiles{"out"} . "\"><img src=\"" . $testfiles{"out"} . "\"></a>";
-	      $testline .= "<hr size=\"1\">";
-	      $testline .= "<a href=\"" . $testfiles{"diff"} . "\"><img src=\"" . $testfiles{"diff"} . "\"></a>";
-	    }
-	  }
-
-	  $testline .= "</td>";
-	} else {
-	  $testline .= '<td></td>';
-	}
-      } else {
-	$testline .= '<td></td>';
+      if ($config_show_ref) {
+        print "<td><a href=\"$testref\"><img src=\"$testref\"></img></a></td>";
       }
-    }
 
-    my $testref = testref($test, $format);
-    print '<tr><td>', "<a href=\"$testref\">", $test, ' (', $format, ')</a></td>';
+      print $testline;
 
-    if ($config_show_ref) {
-      print "<td><a href=\"$testref\"><img src=\"$testref\"></img></a></td>";
+      print "</tr>\n";
     }
-
-    print $testline;
-
-    print "</tr>\n";
   }
 }
 
diff --git a/test/xlib-surface.c b/test/xlib-surface.c
index 0df5514..1aea873 100644
--- a/test/xlib-surface.c
+++ b/test/xlib-surface.c
@@ -160,6 +160,8 @@ do_test (Display        *dpy,
 				       diff_data + offset,
 				       SIZE - OFFSCREEN_OFFSET,
 				       SIZE - OFFSCREEN_OFFSET,
+				       4 * SIZE,
+				       4 * SIZE,
 				       4 * SIZE);
     } else {
 	result = !buffer_diff_noalpha (reference_data,
@@ -167,6 +169,8 @@ do_test (Display        *dpy,
 				       diff_data,
 				       SIZE,
 				       SIZE,
+				       4 * SIZE,
+				       4 * SIZE,
 				       4 * SIZE);
     }
 


More information about the cairo-commit mailing list