[cairo-commit] 9 commits - src/cairo-gl-composite.c src/cairo-image-surface.c src/cairoint.h src/cairo-matrix.c src/cairo-pattern.c src/cairo-qt-surface.cpp src/cairo-script-surface.c src/cairo-skia-surface.cpp src/cairo-svg-surface.c src/cairo-types-private.h src/cairo-vg-surface.c src/cairo-win32-printing-surface.c src/cairo-xcb-surface-render.c src/cairo-xlib-surface.c src/cairo-xml-surface.c src/drm test/huge-linear.c test/huge-linear.image16.ref.png test/huge-radial.c test/Makefile.am test/Makefile.sources test/radial-gradient.c test/radial-gradient.image16.ref.png test/radial-gradient-mask.argb32.ref.png test/radial-gradient-mask.c test/radial-gradient-mask.image16.ref.png test/radial-gradient-mask.pdf.argb32.xfail.png test/radial-gradient-mask.pdf.rgb24.xfail.png test/radial-gradient-mask.quartz.argb32.ref.png test/radial-gradient-mask.quartz.rgb24.ref.png test/radial-gradient-mask.ref.png test/radial-gradient-mask.rgb24.ref.png test/radial-gradient-mask-source.argb32.ref.pn g test/radial-gradient-mask-source.c test/radial-gradient-mask-source.image16.ref.png test/radial-gradient-mask-source.pdf.argb32.xfail.png test/radial-gradient-mask-source.pdf.rgb24.xfail.png test/radial-gradient-mask-source.quartz.argb32.ref.png test/radial-gradient-mask-source.quartz.rgb24.ref.png test/radial-gradient-mask-source.rgb24.ref.png test/radial-gradient-mask-source.xlib.argb32.ref.png test/radial-gradient-mask-source.xlib.rgb24.ref.png test/radial-gradient-one-stop.argb32.ref.png test/radial-gradient-one-stop.c test/radial-gradient-one-stop.ps3.argb32.ref.png test/radial-gradient-one-stop.ps3.rgb24.ref.png test/radial-gradient-one-stop.ref.png test/radial-gradient-one-stop.rgb24.ref.png test/radial-gradient.pdf.xfail.png test/radial-gradient.quartz.ref.png test/radial-gradient.ref.png test/radial-gradient-source.argb32.ref.png test/radial-gradient-source.c test/radial-gradient-source.image16.ref.png test/radial-gradient-source.pdf.argb32.xfail.png test/radial-g radient-source.pdf.rgb24.xfail.png test/radial-gradient-source.quartz.argb32.ref.png test/radial-gradient-source.quartz.rgb24.ref.png test/radial-gradient-source.rgb24.ref.png test/radial-gradient.svg.xfail.png

Andrea Canciani ranma42 at kemper.freedesktop.org
Sun Jan 2 10:07:47 PST 2011


 dev/null                                             |binary
 src/cairo-gl-composite.c                             |   20 -
 src/cairo-image-surface.c                            |  228 +++---------
 src/cairo-matrix.c                                   |  315 +++++++++++++----
 src/cairo-pattern.c                                  |  337 ++++++++++---------
 src/cairo-qt-surface.cpp                             |   38 --
 src/cairo-script-surface.c                           |   18 -
 src/cairo-skia-surface.cpp                           |    8 
 src/cairo-svg-surface.c                              |   40 --
 src/cairo-types-private.h                            |   10 
 src/cairo-vg-surface.c                               |   18 -
 src/cairo-win32-printing-surface.c                   |    8 
 src/cairo-xcb-surface-render.c                       |  150 +-------
 src/cairo-xlib-surface.c                             |   99 ++---
 src/cairo-xml-surface.c                              |   14 
 src/cairoint.h                                       |   34 +
 src/drm/cairo-drm-i915-shader.c                      |   28 -
 src/drm/cairo-drm-i965-shader.c                      |   28 -
 test/Makefile.am                                     |   25 -
 test/Makefile.sources                                |    4 
 test/huge-linear.c                                   |    2 
 test/huge-linear.image16.ref.png                     |binary
 test/huge-radial.c                                   |    2 
 test/radial-gradient-mask-source.argb32.ref.png      |binary
 test/radial-gradient-mask-source.c                   |  111 ------
 test/radial-gradient-mask-source.image16.ref.png     |binary
 test/radial-gradient-mask-source.rgb24.ref.png       |binary
 test/radial-gradient-mask-source.xlib.argb32.ref.png |binary
 test/radial-gradient-mask-source.xlib.rgb24.ref.png  |binary
 test/radial-gradient-mask.c                          |  110 ------
 test/radial-gradient-mask.image16.ref.png            |binary
 test/radial-gradient-mask.ref.png                    |binary
 test/radial-gradient-one-stop.c                      |  107 ------
 test/radial-gradient-one-stop.ref.png                |binary
 test/radial-gradient-source.argb32.ref.png           |binary
 test/radial-gradient-source.c                        |  115 ------
 test/radial-gradient-source.image16.ref.png          |binary
 test/radial-gradient-source.rgb24.ref.png            |binary
 test/radial-gradient.c                               |  248 +++++++++++--
 test/radial-gradient.image16.ref.png                 |binary
 test/radial-gradient.ref.png                         |binary
 41 files changed, 891 insertions(+), 1226 deletions(-)

New commits:
commit 200e147322a7a17dec91ad5f678a07fdfaf38de2
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Fri Dec 17 11:04:53 2010 +0100

    pattern: Use double precision for gradient extreme objects
    
    Using double precision for gradient extreme objects ensures that they
    are preserved as specified when constructing the gradient pattern.
    
    Fixes huge-linear, huge-radial.
    
    Fixes part of https://bugs.freedesktop.org/show_bug.cgi?id=32215

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 5057fa6..dbd5306 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -170,14 +170,14 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
         if (unlikely (status))
             return status;
 
-	dx = _cairo_fixed_to_double (linear->p2.x - linear->p1.x);
-	dy = _cairo_fixed_to_double (linear->p2.y - linear->p1.y);
+	dx = linear->pd2.x - linear->pd1.x;
+	dy = linear->pd2.y - linear->pd1.y;
 	sf = 1.0 / (dx * dx + dy * dy);
 	dx *= sf;
 	dy *= sf;
 
-	x0 = _cairo_fixed_to_double (linear->p1.x);
-	y0 = _cairo_fixed_to_double (linear->p1.y);
+	x0 = linear->pd1.x;
+	y0 = linear->pd1.y;
 	offset = dx * x0 + dy * y0;
 
 	if (_cairo_matrix_is_identity (&linear->base.base.matrix)) {
@@ -203,12 +203,12 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
 	cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient;
         double x0, y0, r0, x1, y1, r1;
 
-	x0 = _cairo_fixed_to_double (radial->c1.x);
-	x1 = _cairo_fixed_to_double (radial->c2.x);
-	y0 = _cairo_fixed_to_double (radial->c1.y);
-	y1 = _cairo_fixed_to_double (radial->c2.y);
-	r0 = _cairo_fixed_to_double (radial->r1);
-	r1 = _cairo_fixed_to_double (radial->r2);
+	x0 = radial->cd1.center.x;
+	x1 = radial->cd2.center.x;
+	y0 = radial->cd1.center.y;
+	y1 = radial->cd2.center.y;
+	r0 = radial->cd1.radius;
+	r1 = radial->cd2.radius;
 
         status = _cairo_gl_create_gradient_texture (dst,
                                                     gradient,
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 13bf99d..08e0708 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -504,10 +504,10 @@ _cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
 {
     _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_LINEAR);
 
-    pattern->p1.x = _cairo_fixed_from_double (x0);
-    pattern->p1.y = _cairo_fixed_from_double (y0);
-    pattern->p2.x = _cairo_fixed_from_double (x1);
-    pattern->p2.y = _cairo_fixed_from_double (y1);
+    pattern->pd1.x = x0;
+    pattern->pd1.y = y0;
+    pattern->pd2.x = x1;
+    pattern->pd2.y = y1;
 }
 
 static void
@@ -517,12 +517,12 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
 {
     _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_RADIAL);
 
-    pattern->c1.x = _cairo_fixed_from_double (cx0);
-    pattern->c1.y = _cairo_fixed_from_double (cy0);
-    pattern->r1   = _cairo_fixed_from_double (fabs (radius0));
-    pattern->c2.x = _cairo_fixed_from_double (cx1);
-    pattern->c2.y = _cairo_fixed_from_double (cy1);
-    pattern->r2   = _cairo_fixed_from_double (fabs (radius1));
+    pattern->cd1.center.x = cx0;
+    pattern->cd1.center.y = cy0;
+    pattern->cd1.radius   = fabs (radius0);
+    pattern->cd2.center.x = cx1;
+    pattern->cd2.center.y = cy1;
+    pattern->cd2.radius   = fabs (radius1);
 }
 
 cairo_pattern_t *
@@ -2075,10 +2075,8 @@ _cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern,
      * pattern. We actually only need 3/4 corners, so we skip the
      * fourth.
      */
-    point0.x = _cairo_fixed_to_double (pattern->p1.x);
-    point0.y = _cairo_fixed_to_double (pattern->p1.y);
-    point1.x = _cairo_fixed_to_double (pattern->p2.x);
-    point1.y = _cairo_fixed_to_double (pattern->p2.y);
+    point0 = pattern->pd1;
+    point1 = pattern->pd2;
 
     _cairo_matrix_get_affine (&pattern->base.base.matrix,
 			      &a, &b, &c, &d, &tx, &ty);
@@ -2531,7 +2529,8 @@ _cairo_pattern_reset_solid_surface_cache (void)
 static cairo_bool_t
 _linear_pattern_is_degenerate (const cairo_linear_pattern_t *linear)
 {
-    return linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y;
+    return fabs (linear->pd1.x - linear->pd2.x) < DBL_EPSILON &&
+	   fabs (linear->pd1.y - linear->pd2.y) < DBL_EPSILON;
 }
 
 static cairo_bool_t
@@ -2541,18 +2540,22 @@ _radial_pattern_is_degenerate (const cairo_radial_pattern_t *radial)
      * represented as a solid or clear pattern.  This corresponds to
      * one of the two cases:
      *
-     * 1) The radii are both zero.
+     * 1) The radii are both very small:
+     *      |dr| < DBL_EPSILON && min (r0, r1) < DBL_EPSILON
      *
-     * 2) The two circles have same radius and are at the same point.
-     *    (Cylinder gradient that doesn't move with the parameter.)
+     * 2) The two circles have about the same radius and are very
+     *    close to each other (approximately a cylinder gradient that
+     *    doesn't move with the parameter):
+     *      |dr| < DBL_EPSILON && max (|dx|, |dy|) < 2 * DBL_EPSILON
      *
-     * These checks are made in fixed point, so they're implicitly
-     * using an epsilon that is larger than the epsilons we're using
-     * in the floating point tests.
+     * These checks are consistent with the assumptions used in
+     * _cairo_radial_pattern_box_to_parameter ().
      */
-    return radial->r1 == radial->r2 &&
-	(radial->r1 == 0 /* && radial->r2 == 0 */ ||
-	 (radial->c1.x == radial->c2.x && radial->c1.y == radial->c2.y));
+
+    return fabs (radial->cd1.radius - radial->cd2.radius) < DBL_EPSILON &&
+	(MIN (radial->cd1.radius, radial->cd2.radius) < DBL_EPSILON ||
+	 MAX (fabs (radial->cd1.center.x - radial->cd2.center.x),
+	      fabs (radial->cd1.center.y - radial->cd2.center.y)) < 2 * DBL_EPSILON);
 }
 
 static void
@@ -2581,10 +2584,10 @@ _cairo_linear_pattern_box_to_parameter (const cairo_linear_pattern_t *linear,
      * tdy is the difference between top and bottom corners
      */
 
-    p1x = _cairo_fixed_to_double (linear->p1.x);
-    p1y = _cairo_fixed_to_double (linear->p1.y);
-    pdx = _cairo_fixed_to_double (linear->p2.x) - p1x;
-    pdy = _cairo_fixed_to_double (linear->p2.y) - p1y;
+    p1x = linear->pd1.x;
+    p1y = linear->pd1.y;
+    pdx = linear->pd2.x - p1x;
+    pdy = linear->pd2.y - p1y;
     invsqnorm = 1.0 / (pdx * pdx + pdy * pdy);
     pdx *= invsqnorm;
     pdy *= invsqnorm;
@@ -2648,12 +2651,12 @@ _cairo_radial_pattern_box_to_parameter (const cairo_radial_pattern_t *radial,
 
     x_focus = y_focus = 0; /* silence gcc */
 
-    cx = _cairo_fixed_to_double (radial->c1.x);
-    cy = _cairo_fixed_to_double (radial->c1.y);
-    cr = _cairo_fixed_to_double (radial->r1);
-    dx = _cairo_fixed_to_double (radial->c2.x) - cx;
-    dy = _cairo_fixed_to_double (radial->c2.y) - cy;
-    dr = _cairo_fixed_to_double (radial->r2)   - cr;
+    cx = radial->cd1.center.x;
+    cy = radial->cd1.center.y;
+    cr = radial->cd1.radius;
+    dx = radial->cd2.center.x - cx;
+    dy = radial->cd2.center.y - cy;
+    dr = radial->cd2.radius   - cr;
 
     /* translate by -(cx, cy) to simplify computations */
     x0 -= cx;
@@ -3018,18 +3021,18 @@ _cairo_gradient_pattern_interpolate (const cairo_gradient_pattern_t *gradient,
     assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
 	    gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
 
-#define lerp(a,b) _cairo_fixed_to_double(a)*(1-t) + _cairo_fixed_to_double(b)*t
+#define lerp(a,b) (a)*(1-t) + (b)*t
 
     if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
 	cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
-	out_circle->center.x = lerp(linear->p1.x, linear->p2.x);
-	out_circle->center.y = lerp(linear->p1.y, linear->p2.y);
+	out_circle->center.x = lerp (linear->pd1.x, linear->pd2.x);
+	out_circle->center.y = lerp (linear->pd1.y, linear->pd2.y);
 	out_circle->radius = 0;
     } else {
 	cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient;
-	out_circle->center.x = lerp(radial->c1.x, radial->c2.x);
-	out_circle->center.y = lerp(radial->c1.y, radial->c2.y);
-	out_circle->radius   = lerp(radial->r1, radial->r2);
+	out_circle->center.x = lerp (radial->cd1.center.x, radial->cd2.center.x);
+	out_circle->center.y = lerp (radial->cd1.center.y, radial->cd2.center.y);
+	out_circle->radius   = lerp (radial->cd1.radius  , radial->cd2.radius);
     }
 
 #undef lerp
@@ -3061,44 +3064,32 @@ _cairo_gradient_pattern_fit_to_range (const cairo_gradient_pattern_t *gradient,
     if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
 	cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
 
-	out_circle[0].center.x = _cairo_fixed_to_double (linear->p1.x);
-	out_circle[0].center.y = _cairo_fixed_to_double (linear->p1.y);
+	out_circle[0].center = linear->pd1;
 	out_circle[0].radius = 0;
-	out_circle[1].center.x = _cairo_fixed_to_double (linear->p2.x);
-	out_circle[1].center.y = _cairo_fixed_to_double (linear->p2.y);
+	out_circle[1].center = linear->pd2;
 	out_circle[1].radius = 0;
 
-	dim = fabs (_cairo_fixed_to_double (linear->p1.x));
-	dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p1.y)));
-	dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p2.x)));
-	dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p2.y)));
-	dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p1.x) -
-			      _cairo_fixed_to_double (linear->p2.x)));
-	dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p1.y) -
-			      _cairo_fixed_to_double (linear->p2.y)));
+	dim = fabs (linear->pd1.x);
+	dim = MAX (dim, fabs (linear->pd1.y));
+	dim = MAX (dim, fabs (linear->pd2.x));
+	dim = MAX (dim, fabs (linear->pd2.y));
+	dim = MAX (dim, fabs (linear->pd1.x - linear->pd2.x));
+	dim = MAX (dim, fabs (linear->pd1.y - linear->pd2.y));
     } else {
 	cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient;
 
-	out_circle[0].center.x = _cairo_fixed_to_double (radial->c1.x);
-	out_circle[0].center.y = _cairo_fixed_to_double (radial->c1.y);
-	out_circle[0].radius = _cairo_fixed_to_double (radial->r1);
-
-	out_circle[1].center.x = _cairo_fixed_to_double (radial->c2.x);
-	out_circle[1].center.y = _cairo_fixed_to_double (radial->c2.y);
-	out_circle[1].radius = _cairo_fixed_to_double (radial->r2);
-
-	dim = fabs (_cairo_fixed_to_double (radial->c1.x));
-	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c1.y)));
-	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->r1)));
-	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c2.x)));
-	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c2.y)));
-	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->r2)));
-	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c1.x) -
-			      _cairo_fixed_to_double (radial->c2.x)));
-	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c1.y) -
-			      _cairo_fixed_to_double (radial->c2.y)));
-	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->r1) -
-			      _cairo_fixed_to_double (radial->r2)));
+	out_circle[0] = radial->cd1;
+	out_circle[1] = radial->cd2;
+
+	dim = fabs (radial->cd1.center.x);
+	dim = MAX (dim, fabs (radial->cd1.center.y));
+	dim = MAX (dim, fabs (radial->cd1.radius));
+	dim = MAX (dim, fabs (radial->cd2.center.x));
+	dim = MAX (dim, fabs (radial->cd2.center.y));
+	dim = MAX (dim, fabs (radial->cd2.radius));
+	dim = MAX (dim, fabs (radial->cd1.center.x - radial->cd2.center.x));
+	dim = MAX (dim, fabs (radial->cd1.center.y - radial->cd2.center.y));
+	dim = MAX (dim, fabs (radial->cd1.radius   - radial->cd2.radius));
     }
 
     if (unlikely (dim > max_value)) {
@@ -4243,13 +4234,13 @@ _cairo_pattern_get_extents (const cairo_pattern_t         *pattern,
 	    if (pattern->extend != CAIRO_EXTEND_NONE)
 		goto UNBOUNDED;
 
-	    cx1 = _cairo_fixed_to_double (radial->c1.x);
-	    cy1 = _cairo_fixed_to_double (radial->c1.y);
-	    r1 = _cairo_fixed_to_double (radial->r1);
+	    cx1 = radial->cd1.center.x;
+	    cy1 = radial->cd1.center.y;
+	    r1  = radial->cd1.radius;
 
-	    cx2 = _cairo_fixed_to_double (radial->c2.x);
-	    cy2 = _cairo_fixed_to_double (radial->c2.y);
-	    r2 = _cairo_fixed_to_double (radial->r2);
+	    cx2 = radial->cd2.center.x;
+	    cy2 = radial->cd2.center.y;
+	    r2  = radial->cd2.radius;
 
 	    x1 = MIN (cx1 - r1, cx2 - r2);
 	    y1 = MIN (cy1 - r1, cy2 - r2);
@@ -4278,14 +4269,14 @@ _cairo_pattern_get_extents (const cairo_pattern_t         *pattern,
 	    if (pattern->matrix.xy != 0. || pattern->matrix.yx != 0.)
 		goto UNBOUNDED;
 
-	    if (linear->p1.x == linear->p2.x) {
+	    if (linear->pd1.x == linear->pd2.x) {
 		x1 = -HUGE_VAL;
 		x2 = HUGE_VAL;
-		y1 = _cairo_fixed_to_double (MIN (linear->p1.y, linear->p2.y));
-		y2 = _cairo_fixed_to_double (MAX (linear->p1.y, linear->p2.y));
-	    } else if (linear->p1.y == linear->p2.y) {
-		x1 = _cairo_fixed_to_double (MIN (linear->p1.x, linear->p2.x));
-		x2 = _cairo_fixed_to_double (MAX (linear->p1.x, linear->p2.x));
+		y1 = MIN (linear->pd1.y, linear->pd2.y);
+		y2 = MAX (linear->pd1.y, linear->pd2.y);
+	    } else if (linear->pd1.y == linear->pd2.y) {
+		x1 = MIN (linear->pd1.x, linear->pd2.x);
+		x2 = MAX (linear->pd1.x, linear->pd2.x);
 		y1 = -HUGE_VAL;
 		y2 = HUGE_VAL;
 	    } else {
@@ -4402,8 +4393,8 @@ unsigned long
 _cairo_linear_pattern_hash (unsigned long hash,
 			    const cairo_linear_pattern_t *linear)
 {
-    hash = _cairo_hash_bytes (hash, &linear->p1, sizeof (linear->p1));
-    hash = _cairo_hash_bytes (hash, &linear->p2, sizeof (linear->p2));
+    hash = _cairo_hash_bytes (hash, &linear->pd1, sizeof (linear->pd1));
+    hash = _cairo_hash_bytes (hash, &linear->pd2, sizeof (linear->pd2));
 
     return _cairo_gradient_color_stops_hash (hash, &linear->base);
 }
@@ -4412,10 +4403,10 @@ unsigned long
 _cairo_radial_pattern_hash (unsigned long hash,
 			    const cairo_radial_pattern_t *radial)
 {
-    hash = _cairo_hash_bytes (hash, &radial->c1, sizeof (radial->c1));
-    hash = _cairo_hash_bytes (hash, &radial->r1, sizeof (radial->r1));
-    hash = _cairo_hash_bytes (hash, &radial->c2, sizeof (radial->c2));
-    hash = _cairo_hash_bytes (hash, &radial->r2, sizeof (radial->r2));
+    hash = _cairo_hash_bytes (hash, &radial->cd1.center, sizeof (radial->cd1.center));
+    hash = _cairo_hash_bytes (hash, &radial->cd1.radius, sizeof (radial->cd1.radius));
+    hash = _cairo_hash_bytes (hash, &radial->cd2.center, sizeof (radial->cd2.center));
+    hash = _cairo_hash_bytes (hash, &radial->cd2.radius, sizeof (radial->cd2.radius));
 
     return _cairo_gradient_color_stops_hash (hash, &radial->base);
 }
@@ -4548,16 +4539,16 @@ cairo_bool_t
 _cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
 			     const cairo_linear_pattern_t *b)
 {
-    if (a->p1.x != b->p1.x)
+    if (a->pd1.x != b->pd1.x)
 	return FALSE;
 
-    if (a->p1.y != b->p1.y)
+    if (a->pd1.y != b->pd1.y)
 	return FALSE;
 
-    if (a->p2.x != b->p2.x)
+    if (a->pd2.x != b->pd2.x)
 	return FALSE;
 
-    if (a->p2.y != b->p2.y)
+    if (a->pd2.y != b->pd2.y)
 	return FALSE;
 
     return _cairo_gradient_color_stops_equal (&a->base, &b->base);
@@ -4567,22 +4558,22 @@ cairo_bool_t
 _cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
 			     const cairo_radial_pattern_t *b)
 {
-    if (a->c1.x != b->c1.x)
+    if (a->cd1.center.x != b->cd1.center.x)
 	return FALSE;
 
-    if (a->c1.y != b->c1.y)
+    if (a->cd1.center.y != b->cd1.center.y)
 	return FALSE;
 
-    if (a->r1 != b->r1)
+    if (a->cd1.radius != b->cd1.radius)
 	return FALSE;
 
-    if (a->c2.x != b->c2.x)
+    if (a->cd2.center.x != b->cd2.center.x)
 	return FALSE;
 
-    if (a->c2.y != b->c2.y)
+    if (a->cd2.center.y != b->cd2.center.y)
 	return FALSE;
 
-    if (a->r2 != b->r2)
+    if (a->cd2.radius != b->cd2.radius)
 	return FALSE;
 
     return _cairo_gradient_color_stops_equal (&a->base, &b->base);
@@ -4859,13 +4850,13 @@ cairo_pattern_get_linear_points (cairo_pattern_t *pattern,
 	return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
 
     if (x0)
-	*x0 = _cairo_fixed_to_double (linear->p1.x);
+	*x0 = linear->pd1.x;
     if (y0)
-	*y0 = _cairo_fixed_to_double (linear->p1.y);
+	*y0 = linear->pd1.y;
     if (x1)
-	*x1 = _cairo_fixed_to_double (linear->p2.x);
+	*x1 = linear->pd2.x;
     if (y1)
-	*y1 = _cairo_fixed_to_double (linear->p2.y);
+	*y1 = linear->pd2.y;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -4903,17 +4894,17 @@ cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
 	return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
 
     if (x0)
-	*x0 = _cairo_fixed_to_double (radial->c1.x);
+	*x0 = radial->cd1.center.x;
     if (y0)
-	*y0 = _cairo_fixed_to_double (radial->c1.y);
+	*y0 = radial->cd1.center.y;
     if (r0)
-	*r0 = _cairo_fixed_to_double (radial->r1);
+	*r0 = radial->cd1.radius;
     if (x1)
-	*x1 = _cairo_fixed_to_double (radial->c2.x);
+	*x1 = radial->cd2.center.x;
     if (y1)
-	*y1 = _cairo_fixed_to_double (radial->c2.y);
+	*y1 = radial->cd2.center.y;
     if (r1)
-	*r1 = _cairo_fixed_to_double (radial->r2);
+	*r1 = radial->cd2.radius;
 
     return CAIRO_STATUS_SUCCESS;
 }
diff --git a/src/cairo-qt-surface.cpp b/src/cairo-qt-surface.cpp
index 7e528a3..25ee9e9 100644
--- a/src/cairo-qt-surface.cpp
+++ b/src/cairo-qt-surface.cpp
@@ -870,40 +870,34 @@ struct PatternToBrushConverter {
 
 	    if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
 		cairo_linear_pattern_t *lpat = (cairo_linear_pattern_t *) pattern;
-		grad = new QLinearGradient (_cairo_fixed_to_double (lpat->p1.x),
-					    _cairo_fixed_to_double (lpat->p1.y),
-					    _cairo_fixed_to_double (lpat->p2.x),
-					    _cairo_fixed_to_double (lpat->p2.y));
+		grad = new QLinearGradient (lpat->pd1.x, lpat->pd1.y,
+					    lpat->pd2.x, lpat->pd2.y);
 	    } else if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
 		cairo_radial_pattern_t *rpat = (cairo_radial_pattern_t *) pattern;
 
 		/* Based on the SVG surface code */
 
-		cairo_point_t *c0, *c1;
-		cairo_fixed_t radius0, radius1;
+		cairo_circle_double_t *c0, *c1;
+		double x0, y0, r0, x1, y1, r1;
 
-		if (rpat->r1 < rpat->r2) {
-		    c0 = &rpat->c1;
-		    c1 = &rpat->c2;
-		    radius0 = rpat->r1;
-		    radius1 = rpat->r2;
+		if (rpat->cd1.radius < rpat->cd2.radius) {
+		    c0 = &rpat->cd1;
+		    c1 = &rpat->cd2;
 		    reverse_stops = FALSE;
 		} else {
-		    c0 = &rpat->c2;
-		    c1 = &rpat->c1;
-		    radius0 = rpat->r2;
-		    radius1 = rpat->r1;
+		    c0 = &rpat->cd2;
+		    c1 = &rpat->cd1;
 		    reverse_stops = TRUE;
 		}
 
-		double x0 = _cairo_fixed_to_double (c0->x);
-		double y0 = _cairo_fixed_to_double (c0->y);
-		double r0 = _cairo_fixed_to_double (radius0);
-		double x1 = _cairo_fixed_to_double (c1->x);
-		double y1 = _cairo_fixed_to_double (c1->y);
-		double r1 = _cairo_fixed_to_double (radius1);
+		x0 = c0->center.x;
+		y0 = c0->center.y;
+		r0 = c0->radius;
+		x1 = c1->center.x;
+		y1 = c1->center.y;
+		r1 = c1->radius;
 
-		if (rpat->r1 == rpat->r2) {
+		if (r0 == r1) {
 		    grad = new QRadialGradient (x1, y1, r1, x1, y1);
 		} else {
 		    double fx = (r1 * x0 - r0 * x1) / (r1 - r0);
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 9e12e57..5200b3a 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -929,10 +929,8 @@ _emit_linear_pattern (cairo_script_surface_t *surface,
 
     _cairo_output_stream_printf (ctx->stream,
 				 "%f %f %f %f linear",
-				 _cairo_fixed_to_double (linear->p1.x),
-				 _cairo_fixed_to_double (linear->p1.y),
-				 _cairo_fixed_to_double (linear->p2.x),
-				 _cairo_fixed_to_double (linear->p2.y));
+				 linear->pd1.x, linear->pd1.y,
+				 linear->pd2.x, linear->pd2.y);
     return _emit_gradient_color_stops (&linear->base, ctx->stream);
 }
 
@@ -947,12 +945,12 @@ _emit_radial_pattern (cairo_script_surface_t *surface,
 
     _cairo_output_stream_printf (ctx->stream,
 				 "%f %f %f %f %f %f radial",
-				 _cairo_fixed_to_double (radial->c1.x),
-				 _cairo_fixed_to_double (radial->c1.y),
-				 _cairo_fixed_to_double (radial->r1),
-				 _cairo_fixed_to_double (radial->c2.x),
-				 _cairo_fixed_to_double (radial->c2.y),
-				 _cairo_fixed_to_double (radial->r2));
+				 radial->cd1.center.x,
+				 radial->cd1.center.y,
+				 radial->cd1.radius,
+				 radial->cd2.center.x,
+				 radial->cd2.center.y,
+				 radial->cd2.radius);
     return _emit_gradient_color_stops (&radial->base, ctx->stream);
 }
 
diff --git a/src/cairo-skia-surface.cpp b/src/cairo-skia-surface.cpp
index e29f022..537c1bc 100644
--- a/src/cairo-skia-surface.cpp
+++ b/src/cairo-skia-surface.cpp
@@ -356,10 +356,10 @@ pattern_to_sk_shader (cairo_skia_surface_t *dst, const cairo_pattern_t *pattern,
 	    cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
 	    SkPoint points[2];
 
-	    points[0].set (CAIRO_FIXED_TO_SK_SCALAR (linear->p1.x),
-			   CAIRO_FIXED_TO_SK_SCALAR (linear->p1.y));
-	    points[1].set (CAIRO_FIXED_TO_SK_SCALAR (linear->p2.x),
-			   CAIRO_FIXED_TO_SK_SCALAR (linear->p2.y));
+	    points[0].set (SkFloatToScalar (linear->pd1.x),
+			   SkFloatToScalar (linear->pd1.y));
+	    points[1].set (SkFloatToScalar (linear->pd2.x),
+			   SkFloatToScalar (linear->pd2.y));
 	    shader = SkGradientShader::CreateLinear (points, colors, pos, gradient->n_stops,
 						     extend_to_sk (pattern->extend));
 	} else {
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 89e13d0..bb5bccf 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1784,7 +1784,6 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t    *surface,
 					const cairo_matrix_t   *parent_matrix)
 {
     cairo_svg_document_t *document = surface->document;
-    double x0, y0, x1, y1;
     cairo_matrix_t p2u;
     cairo_status_t status;
 
@@ -1793,17 +1792,13 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t    *surface,
     /* cairo_pattern_set_matrix ensures the matrix is invertible */
     assert (status == CAIRO_STATUS_SUCCESS);
 
-    x0 = _cairo_fixed_to_double (pattern->p1.x);
-    y0 = _cairo_fixed_to_double (pattern->p1.y);
-    x1 = _cairo_fixed_to_double (pattern->p2.x);
-    y1 = _cairo_fixed_to_double (pattern->p2.y);
-
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "<linearGradient id=\"linear%d\" "
 				 "gradientUnits=\"userSpaceOnUse\" "
 				 "x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" ",
 				 document->linear_pattern_id,
-				 x0, y0, x1, y1);
+				 pattern->pd1.x, pattern->pd1.y,
+				 pattern->pd2.x, pattern->pd2.y);
 
     _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base),
     _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix);
@@ -1842,38 +1837,33 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t    *surface,
     double fx, fy;
     cairo_bool_t reverse_stops;
     cairo_status_t status;
-    cairo_point_t *c0, *c1;
-    cairo_fixed_t radius0, radius1;
+    cairo_circle_double_t *c0, *c1;
 
     extend = pattern->base.base.extend;
 
-    if (pattern->r1 < pattern->r2) {
-	c0 = &pattern->c1;
-	c1 = &pattern->c2;
-	radius0 = pattern->r1;
-	radius1 = pattern->r2;
+    if (pattern->cd1.radius < pattern->cd2.radius) {
+	c0 = &pattern->cd1;
+	c1 = &pattern->cd2;
 	reverse_stops = FALSE;
     } else {
-	c0 = &pattern->c2;
-	c1 = &pattern->c1;
-	radius0 = pattern->r2;
-	radius1 = pattern->r1;
+	c0 = &pattern->cd2;
+	c1 = &pattern->cd1;
 	reverse_stops = TRUE;
     }
 
-    x0 = _cairo_fixed_to_double (c0->x);
-    y0 = _cairo_fixed_to_double (c0->y);
-    r0 = _cairo_fixed_to_double (radius0);
-    x1 = _cairo_fixed_to_double (c1->x);
-    y1 = _cairo_fixed_to_double (c1->y);
-    r1 = _cairo_fixed_to_double (radius1);
+    x0 = c0->center.x;
+    y0 = c0->center.y;
+    r0 = c0->radius;
+    x1 = c1->center.x;
+    y1 = c1->center.y;
+    r1 = c1->radius;
 
     p2u = pattern->base.base.matrix;
     status = cairo_matrix_invert (&p2u);
     /* cairo_pattern_set_matrix ensures the matrix is invertible */
     assert (status == CAIRO_STATUS_SUCCESS);
 
-    if (pattern->r1 == pattern->r2) {
+    if (r0 == r1) {
 	unsigned int n_stops = pattern->base.n_stops;
 
 	_cairo_output_stream_printf (document->xml_node_defs,
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index a09b410..967781c 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -422,17 +422,15 @@ typedef struct _cairo_gradient_pattern {
 typedef struct _cairo_linear_pattern {
     cairo_gradient_pattern_t base;
 
-    cairo_point_t p1;
-    cairo_point_t p2;
+    cairo_point_double_t pd1;
+    cairo_point_double_t pd2;
 } cairo_linear_pattern_t;
 
 typedef struct _cairo_radial_pattern {
     cairo_gradient_pattern_t base;
 
-    cairo_point_t c1;
-    cairo_fixed_t r1;
-    cairo_point_t c2;
-    cairo_fixed_t r2;
+    cairo_circle_double_t cd1;
+    cairo_circle_double_t cd2;
 } cairo_radial_pattern_t;
 
 typedef union {
diff --git a/src/cairo-vg-surface.c b/src/cairo-vg-surface.c
index 39059f6..0034d73 100644
--- a/src/cairo-vg-surface.c
+++ b/src/cairo-vg-surface.c
@@ -772,10 +772,10 @@ _vg_setup_linear_source (cairo_vg_context_t *context,
 {
     VGfloat linear[4];
 
-    linear[0] = _cairo_fixed_to_double (lpat->p1.x);
-    linear[1] = _cairo_fixed_to_double (lpat->p1.y);
-    linear[2] = _cairo_fixed_to_double (lpat->p2.x);
-    linear[3] = _cairo_fixed_to_double (lpat->p2.y);
+    linear[0] = lpat->pd1.x;
+    linear[1] = lpat->pd1.y;
+    linear[2] = lpat->pd2.x;
+    linear[3] = lpat->pd2.y;
 
     vgSetParameteri (context->paint,
 		     VG_PAINT_COLOR_RAMP_SPREAD_MODE,
@@ -799,11 +799,11 @@ _vg_setup_radial_source (cairo_vg_context_t *context,
 {
     VGfloat radial[5];
 
-    radial[0] = _cairo_fixed_to_double (rpat->c1.x);
-    radial[1] = _cairo_fixed_to_double (rpat->c1.y);
-    radial[2] = _cairo_fixed_to_double (rpat->c2.x);
-    radial[3] = _cairo_fixed_to_double (rpat->c2.y);
-    radial[4] = _cairo_fixed_to_double (rpat->r2);
+    radial[0] = rpat->cd1.center.x;
+    radial[1] = rpat->cd1.center.y;
+    radial[2] = rpat->cd2.center.x;
+    radial[3] = rpat->cd2.center.y;
+    radial[4] = rpat->cd2.radius;
 
     vgSetParameteri (context->paint,
 		     VG_PAINT_COLOR_RAMP_SPREAD_MODE, VG_COLOR_RAMP_SPREAD_PAD);
diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index dabeece..af6f164 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -824,10 +824,10 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surfa
 
     cairo_matrix_multiply (&mat, &surface->ctm, &mat);
 
-    p1x = _cairo_fixed_to_double (pattern->p1.x);
-    p1y = _cairo_fixed_to_double (pattern->p1.y);
-    p2x = _cairo_fixed_to_double (pattern->p2.x);
-    p2y = _cairo_fixed_to_double (pattern->p2.y);
+    p1x = pattern->pd1.x;
+    p1y = pattern->pd1.y;
+    p2x = pattern->pd2.x;
+    p2y = pattern->pd2.y;
     cairo_matrix_translate (&mat, p1x, p1y);
 
     xd = p2x - p1x;
diff --git a/src/cairo-xml-surface.c b/src/cairo-xml-surface.c
index 0f25852..83d4f91 100644
--- a/src/cairo-xml-surface.c
+++ b/src/cairo-xml-surface.c
@@ -554,10 +554,8 @@ _cairo_xml_emit_linear (cairo_xml_t *xml,
 {
     _cairo_xml_printf (xml,
 		       "<linear x1='%f' y1='%f' x2='%f' y2='%f'>",
-		       _cairo_fixed_to_double (linear->p1.x),
-		       _cairo_fixed_to_double (linear->p1.y),
-		       _cairo_fixed_to_double (linear->p2.x),
-		       _cairo_fixed_to_double (linear->p2.y));
+		       linear->pd1.x, linear->pd1.y,
+		       linear->pd2.x, linear->pd2.y);
     _cairo_xml_indent (xml, 2);
     _cairo_xml_emit_gradient (xml, &linear->base);
     _cairo_xml_indent (xml, -2);
@@ -571,12 +569,8 @@ _cairo_xml_emit_radial (cairo_xml_t *xml,
 {
     _cairo_xml_printf (xml,
 		       "<radial x1='%f' y1='%f' r1='%f' x2='%f' y2='%f' r2='%f'>",
-		       _cairo_fixed_to_double (radial->c1.x),
-		       _cairo_fixed_to_double (radial->c1.y),
-		       _cairo_fixed_to_double (radial->r1),
-		       _cairo_fixed_to_double (radial->c2.x),
-		       _cairo_fixed_to_double (radial->c2.y),
-		       _cairo_fixed_to_double (radial->r2));
+		       radial->cd1.center.x, radial->cd1.center.y, radial->cd1.radius,
+		       radial->cd2.center.x, radial->cd2.center.y, radial->cd2.radius);
     _cairo_xml_indent (xml, 2);
     _cairo_xml_emit_gradient (xml, &radial->base);
     _cairo_xml_indent (xml, -2);
diff --git a/src/drm/cairo-drm-i915-shader.c b/src/drm/cairo-drm-i915-shader.c
index 483f187..84e501f 100644
--- a/src/drm/cairo-drm-i915-shader.c
+++ b/src/drm/cairo-drm-i915-shader.c
@@ -332,16 +332,18 @@ i915_shader_radial_init (struct i915_shader_radial *r,
 {
     double dx, dy, dr, r1;
 
-    dx = _cairo_fixed_to_double (radial->c2.x - radial->c1.x);
-    dy = _cairo_fixed_to_double (radial->c2.y - radial->c1.y);
-    dr = _cairo_fixed_to_double (radial->r2 - radial->r1);
+    dx = radial->cd2.center.x - radial->cd1.center.x;
+    dy = radial->cd2.center.y - radial->cd1.center.y;
+    dr = radial->cd2.radius   - radial->cd1.radius;
 
-    r1 = _cairo_fixed_to_double (radial->r1);
+    r1 = radial->cd1.radius;
 
-    if (radial->c2.x == radial->c1.x && radial->c2.y == radial->c1.y) {
+    if (radial->cd2.center.x == radial->cd1.center.x &&
+	radial->cd2.center.y == radial->cd1.center.y)
+    {
 	/* XXX dr == 0, meaningless with anything other than PAD */
-	r->constants[0] = _cairo_fixed_to_double (radial->c1.x) / dr;
-	r->constants[1] = _cairo_fixed_to_double (radial->c1.y) / dr;
+	r->constants[0] = radial->cd1.center.x / dr;
+	r->constants[1] = radial->cd1.center.y / dr;
 	r->constants[2] = 1. / dr;
 	r->constants[3] = -r1 / dr;
 
@@ -352,8 +354,8 @@ i915_shader_radial_init (struct i915_shader_radial *r,
 
 	r->base.mode = RADIAL_ONE;
     } else {
-	r->constants[0] = -_cairo_fixed_to_double (radial->c1.x);
-	r->constants[1] = -_cairo_fixed_to_double (radial->c1.y);
+	r->constants[0] = -radial->cd1.center.x;
+	r->constants[1] = -radial->cd1.center.y;
 	r->constants[2] = r1;
 	r->constants[3] = -4 * (dx*dx + dy*dy - dr*dr);
 
@@ -1028,8 +1030,8 @@ i915_shader_linear_init (struct i915_shader_linear *l,
     double x0, y0, sf;
     double dx, dy, offset;
 
-    dx = _cairo_fixed_to_double (linear->p2.x - linear->p1.x);
-    dy = _cairo_fixed_to_double (linear->p2.y - linear->p1.y);
+    dx = linear->pd2.x - linear->pd1.x;
+    dy = linear->pd2.y - linear->pd1.y;
     sf = dx * dx + dy * dy;
     if (sf <= 1e-5)
 	return FALSE;
@@ -1037,8 +1039,8 @@ i915_shader_linear_init (struct i915_shader_linear *l,
     dx /= sf;
     dy /= sf;
 
-    x0 = _cairo_fixed_to_double (linear->p1.x);
-    y0 = _cairo_fixed_to_double (linear->p1.y);
+    x0 = linear->pd1.x;
+    y0 = linear->pd1.y;
     offset = dx*x0 + dy*y0;
 
     if (_cairo_matrix_is_identity (&linear->base.base.matrix)) {
diff --git a/src/drm/cairo-drm-i965-shader.c b/src/drm/cairo-drm-i965-shader.c
index 5a5c966..03d7d44 100644
--- a/src/drm/cairo-drm-i965-shader.c
+++ b/src/drm/cairo-drm-i965-shader.c
@@ -161,14 +161,14 @@ i965_shader_acquire_linear (i965_shader_t *shader,
     src->base.filter = i965_filter (CAIRO_FILTER_BILINEAR);
     src->base.extend = i965_extend (linear->base.base.extend);
 
-    dx = _cairo_fixed_to_double (linear->p2.x - linear->p1.x);
-    dy = _cairo_fixed_to_double (linear->p2.y - linear->p1.y);
+    dx = linear->pd2.x - linear->pd1.x;
+    dy = linear->pd2.y - linear->pd1.y;
     sf = 1. / (dx * dx + dy * dy);
     dx *= sf;
     dy *= sf;
 
-    x0 = _cairo_fixed_to_double (linear->p1.x);
-    y0 = _cairo_fixed_to_double (linear->p1.y);
+    x0 = linear->pd1.x;
+    y0 = linear->pd1.y;
     offset = dx*x0 + dy*y0;
 
     if (_cairo_matrix_is_identity (&linear->base.base.matrix)) {
@@ -215,24 +215,26 @@ i965_shader_acquire_radial (i965_shader_t *shader,
     src->base.filter = i965_filter (CAIRO_FILTER_BILINEAR);
     src->base.extend = i965_extend (radial->base.base.extend);
 
-    dx = _cairo_fixed_to_double (radial->c2.x - radial->c1.x);
-    dy = _cairo_fixed_to_double (radial->c2.y - radial->c1.y);
-    dr = _cairo_fixed_to_double (radial->r2 - radial->r1);
+    dx = radial->cd2.center.x - radial->cd1.center.x;
+    dy = radial->cd2.center.y - radial->cd1.center.y;
+    dr = radial->cd2.radius   - radial->cd1.radius;
 
-    r1 = _cairo_fixed_to_double (radial->r1);
+    r1 = radial->cd1.radius;
 
-    if (FALSE && radial->c2.x == radial->c1.x && radial->c2.y == radial->c1.y) {
+    if (FALSE && (radial->cd2.center.x == radial->cd1.center.x &&
+		  radial->cd2.center.y == radial->cd1.center.y))
+    {
 	/* XXX dr == 0, meaningless with anything other than PAD */
-	src->base.constants[0] = _cairo_fixed_to_double (radial->c1.x) / dr;
-	src->base.constants[1] = _cairo_fixed_to_double (radial->c1.y) / dr;
+	src->base.constants[0] = radial->cd1.center.x / dr;
+	src->base.constants[1] = radial->cd1.center.y / dr;
 	src->base.constants[2] = 1. / dr;
 	src->base.constants[3] = -r1 / dr;
 
 	src->base.constants_size = 4;
 	src->base.mode = RADIAL_ONE;
     } else {
-	src->base.constants[0] = -_cairo_fixed_to_double (radial->c1.x);
-	src->base.constants[1] = -_cairo_fixed_to_double (radial->c1.y);
+	src->base.constants[0] = -radial->cd1.center.x;
+	src->base.constants[1] = -radial->cd1.center.y;
 	src->base.constants[2] = r1;
 	src->base.constants[3] = -4 * (dx*dx + dy*dy - dr*dr);
 
commit 6472864b2c424c0dfe4ff4e76eff8dfb896e60e8
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Thu Dec 16 23:07:30 2010 +0100

    test: Huge means more than MAX_INT
    
    Cairo makes it possible to create gradients whose extreme objects are
    defined with double precision coordinates, but it internally
    represents them with 24.8 fixed point precision.
    
    This shows that coordinates that don't fit the valid range are
    mishandled and don't even trigger an error status.

diff --git a/test/huge-linear.c b/test/huge-linear.c
index 3d49c2e..f84b4ea 100644
--- a/test/huge-linear.c
+++ b/test/huge-linear.c
@@ -27,7 +27,7 @@
 #include "cairo-test.h"
 
 /* set this to 0.1 to make this test work */
-#define FACTOR 10
+#define FACTOR 1.e6
 
 /* XXX poppler-cairo doesn't handle gradients very well... */
 
diff --git a/test/huge-radial.c b/test/huge-radial.c
index a7b50f3..21524b7 100644
--- a/test/huge-radial.c
+++ b/test/huge-radial.c
@@ -29,7 +29,7 @@
 #include "cairo-test.h"
 
 /* set this to 0.1 to make this test work */
-#define FACTOR 10
+#define FACTOR 1.e6
 
 /* XXX poppler-cairo doesn't handle gradients very well... */
 
commit 38dce5d14473e1106c8ea7a67b9be0f400d442a2
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Fri Dec 17 11:03:03 2010 +0100

    pattern: Factor out pattern rescaling
    
    The same code was duplicated (incorrectly and with some minor
    differences) in pattern, image, xlib and xcb.
    
    _cairo_gradient_pattern_max_val() abstracts that code in a function
    that can be used whenever a gradients extremes need to be rescaled to
    fit within a given range.
    
    Fixes huge-linear, huge-radial.
    
    Fixes part of https://bugs.freedesktop.org/show_bug.cgi?id=32215

diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 010aa32..7820f57 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -1075,7 +1075,9 @@ _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
     pixman_gradient_stop_t pixman_stops_static[2];
     pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
     pixman_transform_t      pixman_transform;
-    cairo_matrix_t matrix = pattern->base.matrix;
+    cairo_matrix_t matrix;
+    cairo_circle_double_t extremes[2];
+    pixman_point_fixed_t p1, p2;
     unsigned int i;
     cairo_status_t status;
 
@@ -1094,66 +1096,24 @@ _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
 	pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
     }
 
-    if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
-	cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
-	pixman_point_fixed_t p1, p2;
-	cairo_fixed_t xdim, ydim;
-
-	xdim = fabs (linear->p2.x - linear->p1.x);
-	ydim = fabs (linear->p2.y - linear->p1.y);
-
-	/*
-	 * Transform the matrix to avoid overflow when converting between
-	 * cairo_fixed_t and pixman_fixed_t (without incurring performance
-	 * loss when the transformation is unnecessary).
-	 *
-	 * XXX: Consider converting out-of-range co-ordinates and transforms.
-	 * Having a function to compute the required transformation to
-	 * "normalize" a given bounding box would be generally useful -
-	 * cf linear patterns, gradient patterns, surface patterns...
-	 */
-	if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
-	    _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
-	{
-	    double sf;
-
-	    if (xdim > ydim)
-		sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
-	    else
-		sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
-
-	    p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
-	    p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
-	    p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
-	    p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
+    _cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
 
-	    cairo_matrix_scale (&matrix, sf, sf);
-	}
-	else
-	{
-	    p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
-	    p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
-	    p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
-	    p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
-	}
+    p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
+    p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
+    p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
+    p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
 
+    if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
 	pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
 							    pixman_stops,
 							    pattern->n_stops);
     } else {
-	cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
-	pixman_point_fixed_t c1, c2;
 	pixman_fixed_t r1, r2;
 
-	c1.x = _cairo_fixed_to_16_16 (radial->c1.x);
-	c1.y = _cairo_fixed_to_16_16 (radial->c1.y);
-	r1   = _cairo_fixed_to_16_16 (radial->r1);
-
-	c2.x = _cairo_fixed_to_16_16 (radial->c2.x);
-	c2.y = _cairo_fixed_to_16_16 (radial->c2.y);
-	r2   = _cairo_fixed_to_16_16 (radial->r2);
+	r1   = _cairo_fixed_16_16_from_double (extremes[0].radius);
+	r2   = _cairo_fixed_16_16_from_double (extremes[1].radius);
 
-	pixman_image = pixman_image_create_radial_gradient (&c1, &c2, r1, r2,
+	pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
 							    pixman_stops,
 							    pattern->n_stops);
     }
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index c69e70b..13bf99d 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -35,6 +35,8 @@
 
 #include <float.h>
 
+#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
+
 /**
  * SECTION:cairo-pattern
  * @Title: cairo_pattern_t
@@ -2124,6 +2126,8 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
     cairo_image_surface_t *image;
     pixman_image_t	  *pixman_image;
     pixman_transform_t	  pixman_transform;
+    cairo_circle_double_t extremes[2];
+    pixman_point_fixed_t  p1, p2;
     cairo_status_t	  status;
     cairo_bool_t	  repeat = FALSE;
     int                   ix, iy;
@@ -2151,71 +2155,24 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
 	pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
     }
 
-    if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR)
-    {
-	cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
-	pixman_point_fixed_t p1, p2;
-	cairo_fixed_t xdim, ydim;
+    _cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
 
-	xdim = linear->p2.x - linear->p1.x;
-	ydim = linear->p2.y - linear->p1.y;
-
-	/*
-	 * Transform the matrix to avoid overflow when converting between
-	 * cairo_fixed_t and pixman_fixed_t (without incurring performance
-	 * loss when the transformation is unnecessary).
-	 *
-	 * XXX: Consider converting out-of-range co-ordinates and transforms.
-	 * Having a function to compute the required transformation to
-	 * "normalize" a given bounding box would be generally useful -
-	 * cf linear patterns, gradient patterns, surface patterns...
-	 */
-#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
-	if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
-	    _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
-	{
-	    double sf;
-
-	    if (xdim > ydim)
-		sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
-	    else
-		sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
-
-	    p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
-	    p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
-	    p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
-	    p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
-
-	    cairo_matrix_scale (&matrix, sf, sf);
-	}
-	else
-	{
-	    p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
-	    p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
-	    p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
-	    p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
-	}
+    p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
+    p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
+    p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
+    p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
 
+    if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
 	pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
 							    pixman_stops,
 							    pattern->n_stops);
-    }
-    else
-    {
-	cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
-	pixman_point_fixed_t c1, c2;
+    } else {
 	pixman_fixed_t r1, r2;
 
-	c1.x = _cairo_fixed_to_16_16 (radial->c1.x);
-	c1.y = _cairo_fixed_to_16_16 (radial->c1.y);
-	r1   = _cairo_fixed_to_16_16 (radial->r1);
-
-	c2.x = _cairo_fixed_to_16_16 (radial->c2.x);
-	c2.y = _cairo_fixed_to_16_16 (radial->c2.y);
-	r2   = _cairo_fixed_to_16_16 (radial->r2);
+	r1   = _cairo_fixed_16_16_from_double (extremes[0].radius);
+	r2   = _cairo_fixed_16_16_from_double (extremes[1].radius);
 
-	pixman_image = pixman_image_create_radial_gradient (&c1, &c2,
-							    r1, r2,
+	pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
 							    pixman_stops,
 							    pattern->n_stops);
     }
@@ -3078,6 +3035,91 @@ _cairo_gradient_pattern_interpolate (const cairo_gradient_pattern_t *gradient,
 #undef lerp
 }
 
+
+/**
+ * _cairo_gradient_pattern_fit_to_range
+ *
+ * Scale the extremes of a gradient to guarantee that the coordinates
+ * and their deltas are within the range (-max_value, max_value). The
+ * new extremes are stored in out_circle.
+ *
+ * The pattern matrix is scaled to guarantee that the aspect of the
+ * gradient is the same and the result is stored in out_matrix.
+ *
+ **/
+void
+_cairo_gradient_pattern_fit_to_range (const cairo_gradient_pattern_t *gradient,
+				      double			      max_value,
+				      cairo_matrix_t                 *out_matrix,
+				      cairo_circle_double_t	      out_circle[2])
+{
+    double dim;
+
+    assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
+	    gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
+
+    if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
+	cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
+
+	out_circle[0].center.x = _cairo_fixed_to_double (linear->p1.x);
+	out_circle[0].center.y = _cairo_fixed_to_double (linear->p1.y);
+	out_circle[0].radius = 0;
+	out_circle[1].center.x = _cairo_fixed_to_double (linear->p2.x);
+	out_circle[1].center.y = _cairo_fixed_to_double (linear->p2.y);
+	out_circle[1].radius = 0;
+
+	dim = fabs (_cairo_fixed_to_double (linear->p1.x));
+	dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p1.y)));
+	dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p2.x)));
+	dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p2.y)));
+	dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p1.x) -
+			      _cairo_fixed_to_double (linear->p2.x)));
+	dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p1.y) -
+			      _cairo_fixed_to_double (linear->p2.y)));
+    } else {
+	cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient;
+
+	out_circle[0].center.x = _cairo_fixed_to_double (radial->c1.x);
+	out_circle[0].center.y = _cairo_fixed_to_double (radial->c1.y);
+	out_circle[0].radius = _cairo_fixed_to_double (radial->r1);
+
+	out_circle[1].center.x = _cairo_fixed_to_double (radial->c2.x);
+	out_circle[1].center.y = _cairo_fixed_to_double (radial->c2.y);
+	out_circle[1].radius = _cairo_fixed_to_double (radial->r2);
+
+	dim = fabs (_cairo_fixed_to_double (radial->c1.x));
+	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c1.y)));
+	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->r1)));
+	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c2.x)));
+	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c2.y)));
+	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->r2)));
+	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c1.x) -
+			      _cairo_fixed_to_double (radial->c2.x)));
+	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c1.y) -
+			      _cairo_fixed_to_double (radial->c2.y)));
+	dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->r1) -
+			      _cairo_fixed_to_double (radial->r2)));
+    }
+
+    if (unlikely (dim > max_value)) {
+	cairo_matrix_t scale;
+
+	dim = max_value / dim;
+
+	out_circle[0].center.x *= dim;
+	out_circle[0].center.y *= dim;
+	out_circle[0].radius   *= dim;
+	out_circle[1].center.x *= dim;
+	out_circle[1].center.y *= dim;
+	out_circle[1].radius   *= dim;
+
+	cairo_matrix_init_scale (&scale, dim, dim);
+	cairo_matrix_multiply (out_matrix, &gradient->base.matrix, &scale);
+    } else {
+	*out_matrix = gradient->base.matrix;
+    }
+}
+
 static cairo_bool_t
 _gradient_is_clear (const cairo_gradient_pattern_t *gradient,
 		    const cairo_rectangle_int_t *extents)
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 068ab3d..fb23fbe 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -879,14 +879,16 @@ _cairo_xcb_linear_picture (cairo_xcb_surface_t *target,
 			   const cairo_rectangle_int_t *extents)
 {
     char buf[CAIRO_STACK_BUFFER_SIZE];
-    cairo_fixed_t xdim, ydim;
     xcb_render_fixed_t *stops;
     xcb_render_color_t *colors;
     xcb_render_pointfix_t p1, p2;
-    cairo_matrix_t matrix = pattern->base.base.matrix;
+    cairo_matrix_t matrix;
+    cairo_circle_double_t extremes[2];
     cairo_xcb_picture_t *picture;
     cairo_status_t status;
 
+    _cairo_gradient_pattern_fit_to_range (&pattern->base, PIXMAN_MAX_INT >> 1, &matrix, extremes);
+
     picture = (cairo_xcb_picture_t *)
 	_cairo_xcb_screen_lookup_linear_picture (target->screen, pattern);
     if (picture != NULL)
@@ -907,46 +909,13 @@ _cairo_xcb_linear_picture (cairo_xcb_surface_t *target,
     }
     picture->filter = CAIRO_FILTER_DEFAULT;
 
-    xdim = pattern->p2.x - pattern->p1.x;
-    ydim = pattern->p2.y - pattern->p1.y;
-
-    /*
-     * Transform the matrix to avoid overflow when converting between
-     * cairo_fixed_t and pixman_fixed_t (without incurring performance
-     * loss when the transformation is unnecessary).
-     *
-     * XXX: Consider converting out-of-range co-ordinates and transforms.
-     * Having a function to compute the required transformation to
-     * "normalize" a given bounding box would be generally useful -
-     * cf linear patterns, gradient patterns, surface patterns...
-     */
-#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
-    if (unlikely (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
-		  _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT))
-    {
-	double sf;
-
-	if (xdim > ydim)
-	    sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
-	else
-	    sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
-
-	p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p1.x) * sf);
-	p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p1.y) * sf);
-	p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p2.x) * sf);
-	p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p2.y) * sf);
+    colors = (xcb_render_color_t *) (stops + pattern->base.n_stops);
 
-	cairo_matrix_scale (&matrix, sf, sf);
-    }
-    else
-    {
-	p1.x = _cairo_fixed_to_16_16 (pattern->p1.x);
-	p1.y = _cairo_fixed_to_16_16 (pattern->p1.y);
-	p2.x = _cairo_fixed_to_16_16 (pattern->p2.x);
-	p2.y = _cairo_fixed_to_16_16 (pattern->p2.y);
-    }
+    p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
+    p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
+    p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
+    p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
 
-    colors = (xcb_render_color_t *) (stops + pattern->base.n_stops);
     _cairo_xcb_connection_render_create_linear_gradient (target->connection,
 							 picture->picture,
 							 p1, p2,
@@ -985,11 +954,15 @@ _cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
     char buf[CAIRO_STACK_BUFFER_SIZE];
     xcb_render_fixed_t *stops;
     xcb_render_color_t *colors;
-    xcb_render_pointfix_t c1, c2;
+    xcb_render_pointfix_t p1, p2;
     xcb_render_fixed_t r1, r2;
+    cairo_matrix_t matrix;
+    cairo_circle_double_t extremes[2];
     cairo_xcb_picture_t *picture;
     cairo_status_t status;
 
+    _cairo_gradient_pattern_fit_to_range (&pattern->base, PIXMAN_MAX_INT >> 1, &matrix, extremes);
+
     picture = (cairo_xcb_picture_t *)
 	_cairo_xcb_screen_lookup_radial_picture (target->screen, pattern);
     if (picture != NULL)
@@ -1010,17 +983,19 @@ _cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
     }
     picture->filter = CAIRO_FILTER_DEFAULT;
 
-    c1.x = _cairo_fixed_to_16_16 (pattern->c1.x);
-    c1.y = _cairo_fixed_to_16_16 (pattern->c1.y);
-    r1 = _cairo_fixed_to_16_16 (pattern->r1);
-    c2.x = _cairo_fixed_to_16_16 (pattern->c2.x);
-    c2.y = _cairo_fixed_to_16_16 (pattern->c2.y);
-    r2 = _cairo_fixed_to_16_16 (pattern->r2);
-
     colors = (xcb_render_color_t *) (stops + pattern->base.n_stops);
+
+    p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
+    p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
+    p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
+    p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
+
+    r1 = _cairo_fixed_16_16_from_double (extremes[0].radius);
+    r2 = _cairo_fixed_16_16_from_double (extremes[1].radius);
+
     _cairo_xcb_connection_render_create_radial_gradient (target->connection,
 							 picture->picture,
-							 c1, c2, r1, r2,
+							 p1, p2, r1, r2,
 							 pattern->base.n_stops,
 							 stops, colors);
 
@@ -1036,7 +1011,7 @@ _cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
     }
 
 setup_picture:
-    _cairo_xcb_picture_set_matrix (picture, &pattern->base.base.matrix,
+    _cairo_xcb_picture_set_matrix (picture, &matrix,
 				   pattern->base.base.filter,
 				   extents->x + extents->width/2.,
 				   extents->y + extents->height/2.);
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index f59b61b..693ece2 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -59,6 +59,7 @@
 #include <X11/Xutil.h> /* for XDestroyImage */
 
 #define XLIB_COORD_MAX 32767
+#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
 
 #define DEBUG 0
 
@@ -2094,6 +2095,7 @@ _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_display_t *display,
 	    cairo_matrix_t matrix = pattern->matrix;
 	    cairo_xlib_surface_t *surface;
 	    char buf[CAIRO_STACK_BUFFER_SIZE];
+	    cairo_circle_double_t extremes[2];
 	    XFixed *stops;
 	    XRenderColor *colors;
 	    XRenderPictFormat *format;
@@ -2143,70 +2145,32 @@ _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_display_t *display,
 	    XSync (display->display, False);
 #endif
 
+	    _cairo_gradient_pattern_fit_to_range (gradient, PIXMAN_MAX_INT >> 1, &matrix, extremes);
+
 	    if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
-		cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
 		XLinearGradient grad;
 
-		cairo_fixed_t xdim, ydim;
-
-		xdim = linear->p2.x - linear->p1.x;
-		ydim = linear->p2.y - linear->p1.y;
-
-		/*
-		 * Transform the matrix to avoid overflow when converting between
-		 * cairo_fixed_t and pixman_fixed_t (without incurring performance
-		 * loss when the transformation is unnecessary).
-		 *
-		 * XXX: Consider converting out-of-range co-ordinates and transforms.
-		 * Having a function to compute the required transformation to
-		 * "normalize" a given bounding box would be generally useful -
-		 * cf linear patterns, gradient patterns, surface patterns...
-		 */
-#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
-		if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
-		    _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
-		{
-		    double sf;
-
-		    if (xdim > ydim)
-			sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
-		    else
-			sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
-
-		    grad.p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
-		    grad.p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
-		    grad.p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
-		    grad.p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
-
-		    cairo_matrix_scale (&matrix, sf, sf);
-		}
-		else
-		{
-		    grad.p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
-		    grad.p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
-		    grad.p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
-		    grad.p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
-		}
+		grad.p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
+		grad.p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
+		grad.p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
+		grad.p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
 
 		picture = XRenderCreateLinearGradient (display->display, &grad,
 						       stops, colors,
 						       gradient->n_stops);
 	    } else {
-		cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
 		XRadialGradient grad;
 
-		grad.inner.x = _cairo_fixed_to_16_16 (radial->c1.x);
-		grad.inner.y = _cairo_fixed_to_16_16 (radial->c1.y);
-		grad.inner.radius = _cairo_fixed_to_16_16 (radial->r1);
-
-		grad.outer.x = _cairo_fixed_to_16_16 (radial->c2.x);
-		grad.outer.y = _cairo_fixed_to_16_16 (radial->c2.y);
-		grad.outer.radius = _cairo_fixed_to_16_16 (radial->r2);
+		grad.inner.x      = _cairo_fixed_16_16_from_double (extremes[0].center.x);
+		grad.inner.y      = _cairo_fixed_16_16_from_double (extremes[0].center.y);
+		grad.inner.radius = _cairo_fixed_16_16_from_double (extremes[0].radius);
+		grad.outer.x      = _cairo_fixed_16_16_from_double (extremes[1].center.x);
+		grad.outer.y      = _cairo_fixed_16_16_from_double (extremes[1].center.y);
+		grad.outer.radius = _cairo_fixed_16_16_from_double (extremes[1].radius);
 
 		picture = XRenderCreateRadialGradient (display->display, &grad,
 						       stops, colors,
 						       gradient->n_stops);
-
 	    }
 
 	    if (stops != (XFixed *) buf)
diff --git a/src/cairoint.h b/src/cairoint.h
index 6c34c5b..f8e13b2 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2241,6 +2241,12 @@ _cairo_gradient_pattern_interpolate (const cairo_gradient_pattern_t *gradient,
                                      double			     t,
                                      cairo_circle_double_t	    *out_circle);
 
+cairo_private void
+_cairo_gradient_pattern_fit_to_range (const cairo_gradient_pattern_t *gradient,
+				      double			      max_value,
+				      cairo_matrix_t                 *out_matrix,
+				      cairo_circle_double_t	      out_circle[2]);
+
 cairo_private cairo_bool_t
 _cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern);
 
commit 7b188f852ef502306c8bd0a72ee3857b5f29e724
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Thu Dec 16 22:39:09 2010 +0100

    test: Make huge-* test gradients not within pixed_fixed_t range
    
    Cairo represents gradients coordinate with 24.8 fixed point precision,
    but pixman uses 16.16 fixed point coordinates.
    
    This shows that cairo is currently unable to handle gradients with
    coordinates which are valid for cairo but not for pixman.

diff --git a/test/huge-linear.c b/test/huge-linear.c
index e57d299..3d49c2e 100644
--- a/test/huge-linear.c
+++ b/test/huge-linear.c
@@ -27,7 +27,7 @@
 #include "cairo-test.h"
 
 /* set this to 0.1 to make this test work */
-#define FACTOR 1
+#define FACTOR 10
 
 /* XXX poppler-cairo doesn't handle gradients very well... */
 
diff --git a/test/huge-linear.image16.ref.png b/test/huge-linear.image16.ref.png
index 30297b9..56dc58a 100644
Binary files a/test/huge-linear.image16.ref.png and b/test/huge-linear.image16.ref.png differ
diff --git a/test/huge-radial.c b/test/huge-radial.c
index 7356244..a7b50f3 100644
--- a/test/huge-radial.c
+++ b/test/huge-radial.c
@@ -29,7 +29,7 @@
 #include "cairo-test.h"
 
 /* set this to 0.1 to make this test work */
-#define FACTOR 1
+#define FACTOR 10
 
 /* XXX poppler-cairo doesn't handle gradients very well... */
 
commit 51594d9787905618de608a367c3a5fc0544c52e3
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Fri Dec 17 11:04:41 2010 +0100

    matrix: Cairo matrix to pixman transform/offset conversion
    
    Xlib, XCB and image use the same code to convert a cairo_matrix_t to a
    backend-specific transform.
    
    The code did not handle correctly some matrices, thus a new function
    that performs the conversion in a more generic way was added and used
    in the backends instead of fixing the repeated code.
    
    Fixes part of https://bugs.freedesktop.org/show_bug.cgi?id=32215

diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 07998cd..010aa32 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -856,25 +856,6 @@ _cairo_image_surface_unset_clip_region (cairo_image_surface_t *surface)
     pixman_image_set_clip_region32 (surface->pixman_image, NULL);
 }
 
-static double
-_pixman_nearest_sample (double d)
-{
-    return ceil (d - .5);
-}
-
-static cairo_bool_t
-_nearest_sample (cairo_filter_t filter, double *tx, double *ty)
-{
-    if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) {
-	*tx = _pixman_nearest_sample (*tx);
-	*ty = _pixman_nearest_sample (*ty);
-    } else {
-	if (*tx != floor (*tx) || *ty != floor (*ty))
-	    return FALSE;
-    }
-    return fabs (*tx) < PIXMAN_MAX_INT && fabs (*ty) < PIXMAN_MAX_INT;
-}
-
 #if HAS_ATOMIC_OPS
 static pixman_image_t *__pixman_transparent_image;
 static pixman_image_t *__pixman_black_image;
@@ -1093,9 +1074,10 @@ _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
     pixman_image_t	  *pixman_image;
     pixman_gradient_stop_t pixman_stops_static[2];
     pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
+    pixman_transform_t      pixman_transform;
     cairo_matrix_t matrix = pattern->base.matrix;
-    double tx, ty;
     unsigned int i;
+    cairo_status_t status;
 
     if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
 	pixman_stops = _cairo_malloc_ab (pattern->n_stops,
@@ -1182,49 +1164,19 @@ _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
     if (unlikely (pixman_image == NULL))
 	return NULL;
 
-    tx = pattern->base.matrix.x0;
-    ty = pattern->base.matrix.y0;
-    if (! _cairo_matrix_is_translation (&pattern->base.matrix) ||
-	! _nearest_sample (pattern->base.filter, &tx, &ty))
-    {
-	pixman_transform_t pixman_transform;
-
-	if (tx != 0. || ty != 0.) {
-	    cairo_matrix_t m, inv;
-	    cairo_status_t status;
-	    double x, y;
-
-	    /* pixman also limits the [xy]_offset to 16 bits so evenly
-	     * spread the bits between the two.
-	     */
-	    inv = pattern->base.matrix;
-	    status = cairo_matrix_invert (&inv);
-	    assert (status == CAIRO_STATUS_SUCCESS);
-
-	    x = floor (inv.x0 / 2);
-	    y = floor (inv.y0 / 2);
-	    tx = -x;
-	    ty = -y;
-	    cairo_matrix_init_translate (&inv, x, y);
-	    cairo_matrix_multiply (&m, &inv, &pattern->base.matrix);
-	    _cairo_matrix_to_pixman_matrix (&m, &pixman_transform,
-					    extents->x + extents->width/2.,
-					    extents->y + extents->height/2.);
-	} else {
-	    tx = ty = 0;
-	    _cairo_matrix_to_pixman_matrix (&pattern->base.matrix,
-					    &pixman_transform,
-					    extents->x + extents->width/2.,
-					    extents->y + extents->height/2.);
-	}
-
-	if (! pixman_image_set_transform (pixman_image, &pixman_transform)) {
+    *ix = *iy = 0;
+    status = _cairo_matrix_to_pixman_matrix_offset (&matrix, pattern->base.filter,
+						    extents->x + extents->width/2.,
+						    extents->y + extents->height/2.,
+						    &pixman_transform, ix, iy);
+    if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
+	if (unlikely (status != CAIRO_STATUS_SUCCESS) ||
+	    ! pixman_image_set_transform (pixman_image, &pixman_transform))
+	{
 	    pixman_image_unref (pixman_image);
 	    return NULL;
 	}
     }
-    *ix = tx;
-    *iy = ty;
 
     {
 	pixman_repeat_t pixman_repeat;
@@ -1373,16 +1325,15 @@ _pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
 			   cairo_matrix_t *dst_device_transform,
 			   int *ix, int *iy)
 {
+    pixman_transform_t pixman_transform;
     pixman_image_t *pixman_image;
+    cairo_matrix_t m;
     cairo_rectangle_int_t sample;
     cairo_extend_t extend;
     cairo_filter_t filter;
-    double tx, ty;
+    cairo_status_t status;
     cairo_bool_t undo_src_transform = FALSE;
 
-    tx = pattern->base.matrix.x0;
-    ty = pattern->base.matrix.y0;
-
     extend = pattern->base.extend;
     filter = sampled_area (pattern, extents, &sample);
 
@@ -1424,12 +1375,11 @@ _pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
 	    }
 
 	    /* avoid allocating a 'pattern' image if we can reuse the original */
+	    *ix = *iy = 0;
 	    if (extend == CAIRO_EXTEND_NONE &&
-		_cairo_matrix_is_translation (&pattern->base.matrix) &&
-		_nearest_sample (filter, &tx, &ty))
+		_cairo_matrix_is_pixman_translation (&pattern->base.matrix,
+						     filter, ix, iy))
 	    {
-		*ix = tx;
-		*iy = ty;
 		return pixman_image_ref (source->pixman_image);
 	    }
 
@@ -1466,12 +1416,12 @@ _pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
 		}
 	    }
 
+	    *ix = sub->extents.x;
+	    *iy = sub->extents.y;
 	    if (is_contained &&
-		_cairo_matrix_is_translation (&pattern->base.matrix) &&
-		_nearest_sample (filter, &tx, &ty))
+		_cairo_matrix_is_pixman_translation (&pattern->base.matrix,
+						     filter, ix, iy))
 	    {
-		*ix = tx + sub->extents.x;
-		*iy = ty + sub->extents.y;
 		return pixman_image_ref (source->pixman_image);
 	    }
 
@@ -1488,6 +1438,8 @@ _pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
 	}
     }
 
+    *ix = *iy = 0;
+
     if (pixman_image == NULL) {
 	struct acquire_source_cleanup *cleanup;
 	cairo_image_surface_t *image;
@@ -1543,61 +1495,33 @@ _pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
 	undo_src_transform = TRUE;
     }
 
-    if (! _cairo_matrix_is_translation (&pattern->base.matrix) ||
-	! _nearest_sample (filter, &tx, &ty))
-    {
-	pixman_transform_t pixman_transform;
-	cairo_matrix_t m;
-
-	m = pattern->base.matrix;
-	if (undo_src_transform) {
-	    cairo_matrix_t sm;
-
-	    cairo_matrix_init_scale (&sm,
-				     dst_device_transform->xx,
-				     dst_device_transform->yy);
-	    cairo_matrix_multiply (&m, &m, &sm);
-	}
-
-	if (m.x0 != 0. || m.y0 != 0.) {
-	    cairo_matrix_t inv;
-	    cairo_status_t status;
-	    double x, y;
-
-	    /* pixman also limits the [xy]_offset to 16 bits so evenly
-	     * spread the bits between the two.
-	     */
-	    inv = m;
-	    status = cairo_matrix_invert (&inv);
-	    assert (status == CAIRO_STATUS_SUCCESS);
-
-	    x = floor (inv.x0 / 2);
-	    y = floor (inv.y0 / 2);
-	    tx = -x;
-	    ty = -y;
-	    cairo_matrix_init_translate (&inv, x, y);
-	    cairo_matrix_multiply (&m, &inv, &m);
-	} else {
-	    tx = ty = 0;
-	}
+    m = pattern->base.matrix;
+    if (undo_src_transform) {
+	cairo_matrix_t sm;
 
-	_cairo_matrix_to_pixman_matrix (&m, &pixman_transform,
-					extents->x + extents->width/2.,
-					extents->y + extents->height/2.);
-	if (! pixman_image_set_transform (pixman_image, &pixman_transform)) {
-	    pixman_image_unref (pixman_image);
-	    return NULL;
-	}
+	cairo_matrix_init_scale (&sm,
+				 dst_device_transform->xx,
+				 dst_device_transform->yy);
+	cairo_matrix_multiply (&m, &m, &sm);
     }
-    *ix = tx;
-    *iy = ty;
 
-    if (_cairo_matrix_has_unity_scale (&pattern->base.matrix) &&
-	tx == pattern->base.matrix.x0 &&
-	ty == pattern->base.matrix.y0)
+    status = _cairo_matrix_to_pixman_matrix_offset (&m, filter,
+						    extents->x + extents->width/2.,
+						    extents->y + extents->height/2.,
+						    &pixman_transform, ix, iy);
+    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
     {
+	/* If the transform is an identity, we don't need to set it
+	 * and we can use any filtering, so choose the fastest one. */
 	pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
     }
+    else if (unlikely (status != CAIRO_STATUS_SUCCESS ||
+		       ! pixman_image_set_transform (pixman_image,
+						     &pixman_transform)))
+    {
+	pixman_image_unref (pixman_image);
+	return NULL;
+    }
     else
     {
 	pixman_filter_t pixman_filter;
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index 2536ebf..124fbe5 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -36,6 +36,9 @@
 
 #include "cairoint.h"
 #include "cairo-error-private.h"
+#include <float.h>
+
+#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
 
 #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
 #define ISFINITE(x) isfinite (x)
@@ -906,87 +909,265 @@ _cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
      */
 }
 
-void
+static const pixman_transform_t pixman_identity_transform = {{
+        {1 << 16,        0,       0},
+        {       0, 1 << 16,       0},
+        {       0,       0, 1 << 16}
+    }};
+
+static cairo_status_t
 _cairo_matrix_to_pixman_matrix (const cairo_matrix_t	*matrix,
 				pixman_transform_t	*pixman_transform,
 				double xc,
 				double yc)
 {
-    static const pixman_transform_t pixman_identity_transform = {{
-        {1 << 16,        0,       0},
-        {       0, 1 << 16,       0},
-        {       0,       0, 1 << 16}
-    }};
+    cairo_matrix_t inv;
+    unsigned max_iterations;
+
+    pixman_transform->matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx);
+    pixman_transform->matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy);
+    pixman_transform->matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0);
+
+    pixman_transform->matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx);
+    pixman_transform->matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy);
+    pixman_transform->matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0);
+
+    pixman_transform->matrix[2][0] = 0;
+    pixman_transform->matrix[2][1] = 0;
+    pixman_transform->matrix[2][2] = 1 << 16;
+
+    /* The conversion above breaks cairo's translation invariance:
+     * a translation of (a, b) in device space translates to
+     * a translation of (xx * a + xy * b, yx * a + yy * b)
+     * for cairo, while pixman uses rounded versions of xx ... yy.
+     * This error increases as a and b get larger.
+     *
+     * To compensate for this, we fix the point (xc, yc) in pattern
+     * space and adjust pixman's transform to agree with cairo's at
+     * that point.
+     */
 
-    if (_cairo_matrix_is_identity (matrix)) {
-        *pixman_transform = pixman_identity_transform;
-    } else {
-        cairo_matrix_t inv;
-	unsigned max_iterations;
-
-        pixman_transform->matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx);
-        pixman_transform->matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy);
-        pixman_transform->matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0);
-
-        pixman_transform->matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx);
-        pixman_transform->matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy);
-        pixman_transform->matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0);
-
-        pixman_transform->matrix[2][0] = 0;
-        pixman_transform->matrix[2][1] = 0;
-        pixman_transform->matrix[2][2] = 1 << 16;
-
-        /* The conversion above breaks cairo's translation invariance:
-         * a translation of (a, b) in device space translates to
-         * a translation of (xx * a + xy * b, yx * a + yy * b)
-         * for cairo, while pixman uses rounded versions of xx ... yy.
-         * This error increases as a and b get larger.
-         *
-         * To compensate for this, we fix the point (xc, yc) in pattern
-         * space and adjust pixman's transform to agree with cairo's at
-         * that point.
+    if (_cairo_matrix_has_unity_scale (matrix))
+	return CAIRO_STATUS_SUCCESS;
+
+    if (unlikely (fabs (matrix->xx) > PIXMAN_MAX_INT ||
+		  fabs (matrix->xy) > PIXMAN_MAX_INT ||
+		  fabs (matrix->x0) > PIXMAN_MAX_INT ||
+		  fabs (matrix->yx) > PIXMAN_MAX_INT ||
+		  fabs (matrix->yy) > PIXMAN_MAX_INT ||
+		  fabs (matrix->y0) > PIXMAN_MAX_INT))
+    {
+	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
+    }
+
+    /* Note: If we can't invert the transformation, skip the adjustment. */
+    inv = *matrix;
+    if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS)
+	return CAIRO_STATUS_SUCCESS;
+
+    /* find the pattern space coordinate that maps to (xc, yc) */
+    max_iterations = 5;
+    do {
+	double x,y;
+	pixman_vector_t vector;
+	cairo_fixed_16_16_t dx, dy;
+
+	vector.vector[0] = _cairo_fixed_16_16_from_double (xc);
+	vector.vector[1] = _cairo_fixed_16_16_from_double (yc);
+	vector.vector[2] = 1 << 16;
+
+	/* If we can't transform the reference point, skip the adjustment. */
+	if (! pixman_transform_point_3d (pixman_transform, &vector))
+	    return CAIRO_STATUS_SUCCESS;
+
+	x = pixman_fixed_to_double (vector.vector[0]);
+	y = pixman_fixed_to_double (vector.vector[1]);
+	cairo_matrix_transform_point (&inv, &x, &y);
+
+	/* Ideally, the vector should now be (xc, yc).
+	 * We can now compensate for the resulting error.
 	 */
+	x -= xc;
+	y -= yc;
+	cairo_matrix_transform_distance (matrix, &x, &y);
+	dx = _cairo_fixed_16_16_from_double (x);
+	dy = _cairo_fixed_16_16_from_double (y);
+	pixman_transform->matrix[0][2] -= dx;
+	pixman_transform->matrix[1][2] -= dy;
 
-	if (_cairo_matrix_has_unity_scale (matrix))
-	    return;
+	if (dx == 0 && dy == 0)
+	    return CAIRO_STATUS_SUCCESS;
+    } while (--max_iterations);
 
-        /* Note: If we can't invert the transformation, skip the adjustment. */
-        inv = *matrix;
-        if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS)
-            return;
+    /* We didn't find an exact match between cairo and pixman, but
+     * the matrix should be mostly correct */
+    return CAIRO_STATUS_SUCCESS;
+}
 
-        /* find the pattern space coordinate that maps to (xc, yc) */
-	xc += .5; yc += .5; /* offset for the pixel centre */
-	max_iterations = 5;
-	do {
-	    double x,y;
-	    pixman_vector_t vector;
-	    cairo_fixed_16_16_t dx, dy;
+static inline double
+_pixman_nearest_sample (double d)
+{
+    return ceil (d - .5);
+}
 
-	    vector.vector[0] = _cairo_fixed_16_16_from_double (xc);
-	    vector.vector[1] = _cairo_fixed_16_16_from_double (yc);
-	    vector.vector[2] = 1 << 16;
+/**
+ * _cairo_matrix_is_pixman_translation:
+ * @matrix: a matrix
+ * @filter: the filter to be used on the pattern transformed by @matrix
+ * @x_offset: the translation in the X direction
+ * @y_offset: the translation in the Y direction
+ *
+ * Checks if @matrix translated by (x_offset, y_offset) can be
+ * represented using just an offset (within the range pixman can
+ * accept) and an identity matrix.
+ *
+ * Passing a non-zero value in x_offset/y_offset has the same effect
+ * as applying cairo_matrix_translate (matrix, x_offset, y_offset) and
+ * setting x_offset and y_offset to 0.
+ *
+ * Upon return x_offset and y_offset contain the translation vector if
+ * the return value is %TRUE. If the return value is %FALSE, they will
+ * not be modified.
+ *
+ * Return value: %TRUE if @matrix can be represented as a pixman
+ * translation, %FALSE otherwise.
+ **/
+cairo_bool_t
+_cairo_matrix_is_pixman_translation (const cairo_matrix_t     *matrix,
+				     cairo_filter_t            filter,
+				     int                      *x_offset,
+				     int                      *y_offset)
+{
+    double tx, ty;
+
+    if (!_cairo_matrix_is_translation (matrix))
+	return FALSE;
+
+    tx = matrix->x0 + *x_offset;
+    ty = matrix->y0 + *y_offset;
+
+    if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) {
+	tx = _pixman_nearest_sample (tx);
+	ty = _pixman_nearest_sample (ty);
+    } else if (tx != floor (tx) || ty != floor (ty)) {
+	return FALSE;
+    }
+
+    if (fabs (tx) > PIXMAN_MAX_INT || fabs (ty) > PIXMAN_MAX_INT)
+	return FALSE;
+
+    *x_offset = _cairo_lround (tx);
+    *y_offset = _cairo_lround (ty);
+    return TRUE;
+}
 
-	    if (! pixman_transform_point_3d (pixman_transform, &vector))
-		return;
+/**
+ * _cairo_matrix_to_pixman_matrix_offset:
+ * @matrix: a matrix
+ * @filter: the filter to be used on the pattern transformed by @matrix
+ * @xc: the X coordinate of the point to fix in pattern space
+ * @yc: the Y coordinate of the point to fix in pattern space
+ * @out_transform: the transformation which best approximates @matrix
+ * @x_offset: the translation in the X direction
+ * @y_offset: the translation in the Y direction
+ *
+ * This function tries to represent @matrix translated by (x_offset,
+ * y_offset) as a %pixman_transform_t and an translation.
+ *
+ * Passing a non-zero value in x_offset/y_offset has the same effect
+ * as applying cairo_matrix_translate (matrix, x_offset, y_offset) and
+ * setting x_offset and y_offset to 0.
+ *
+ * If it is possible to represent the matrix with an identity
+ * %pixman_transform_t and a translation within the valid range for
+ * pixman, this function will set @out_transform to be the identity,
+ * @x_offset and @y_offset to be the translation vector and will
+ * return %CAIRO_INT_STATUS_NOTHING_TO_DO. Otherwise it will try to
+ * evenly divide the translational component of @matrix between
+ * @out_transform and (@x_offset, @y_offset).
+ *
+ * Upon return x_offset and y_offset contain the translation vector.
+ *
+ * Return value: %CAIRO_INT_STATUS_NOTHING_TO_DO if the out_transform
+ * is the identity, %CAIRO_STATUS_INVALID_MATRIX if it was not
+ * possible to represent @matrix as a pixman_transform_t without
+ * overflows, %CAIRO_STATUS_SUCCESS otherwise.
+ **/
+cairo_status_t
+_cairo_matrix_to_pixman_matrix_offset (const cairo_matrix_t	*matrix,
+				       cairo_filter_t            filter,
+				       double                    xc,
+				       double                    yc,
+				       pixman_transform_t	*out_transform,
+				       int                      *x_offset,
+				       int                      *y_offset)
+{
+    cairo_bool_t is_pixman_translation;
 
-	    x = pixman_fixed_to_double (vector.vector[0]);
-	    y = pixman_fixed_to_double (vector.vector[1]);
-	    cairo_matrix_transform_point (&inv, &x, &y);
+    is_pixman_translation = _cairo_matrix_is_pixman_translation (matrix,
+								 filter,
+								 x_offset,
+								 y_offset);
 
-	    /* Ideally, the vector should now be (xc, yc).
-	     * We can now compensate for the resulting error.
+    if (is_pixman_translation) {
+	*out_transform = pixman_identity_transform;
+	return CAIRO_INT_STATUS_NOTHING_TO_DO;
+    } else {
+	cairo_matrix_t m;
+
+	m = *matrix;
+	cairo_matrix_translate (&m, *x_offset, *y_offset);
+	if (m.x0 != 0.0 || m.y0 != 0.0) {
+	    double tx, ty, norm;
+	    int i, j;
+
+	    /* pixman also limits the [xy]_offset to 16 bits so evenly
+	     * spread the bits between the two.
+	     *
+	     * To do this, find the solutions of:
+	     *   |x| = |x*m.xx + y*m.xy + m.x0|
+	     *   |y| = |x*m.yx + y*m.yy + m.y0|
+	     *
+	     * and select the one whose maximum norm is smallest.
 	     */
-	    x -= xc;
-	    y -= yc;
-	    cairo_matrix_transform_distance (matrix, &x, &y);
-	    dx = _cairo_fixed_16_16_from_double (x);
-	    dy = _cairo_fixed_16_16_from_double (y);
-	    pixman_transform->matrix[0][2] -= dx;
-	    pixman_transform->matrix[1][2] -= dy;
-
-	    if (dx == 0 && dy == 0)
-		break;
-	} while (--max_iterations);
+	    tx = m.x0;
+	    ty = m.y0;
+	    norm = fmax (fabs (tx), fabs (ty));
+
+	    for (i = -1; i < 2; i+=2) {
+		for (j = -1; j < 2; j+=2) {
+		    double x, y, den, new_norm;
+
+		    den = (m.xx + i) * (m.yy + j) - m.xy * m.yx;
+		    if (fabs (den) < DBL_EPSILON)
+			continue;
+
+		    x = m.y0 * m.xy - m.x0 * (m.yy + j);
+		    y = m.x0 * m.yx - m.y0 * (m.xx + i);
+
+		    den = 1 / den;
+		    x *= den;
+		    y *= den;
+
+		    new_norm = fmax (fabs (x), fabs (y));
+		    if (norm > new_norm) {
+			norm = new_norm;
+			tx = x;
+			ty = y;
+		    }
+		}
+	    }
+
+	    tx = floor (tx);
+	    ty = floor (ty);
+	    *x_offset = -tx;
+	    *y_offset = -ty;
+	    cairo_matrix_translate (&m, tx, ty);
+	} else {
+	    *x_offset = 0;
+	    *y_offset = 0;
+	}
+
+	return _cairo_matrix_to_pixman_matrix (&m, out_transform, xc, yc);
     }
 }
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 34a5cf4..c69e70b 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -2126,7 +2126,7 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
     pixman_transform_t	  pixman_transform;
     cairo_status_t	  status;
     cairo_bool_t	  repeat = FALSE;
-
+    int                   ix, iy;
     pixman_gradient_stop_t pixman_stops_static[2];
     pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
     unsigned int i;
@@ -2286,12 +2286,21 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
 	return image->base.status;
     }
 
-    _cairo_matrix_to_pixman_matrix (&matrix, &pixman_transform,
-				    width/2., height/2.);
-    if (!pixman_image_set_transform (pixman_image, &pixman_transform)) {
-	cairo_surface_destroy (&image->base);
-	pixman_image_unref (pixman_image);
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    ix = x;
+    iy = y;
+    status = _cairo_matrix_to_pixman_matrix_offset (&matrix,
+						    pattern->base.filter,
+						    width/2., height/2.,
+						    &pixman_transform,
+						    &ix, &iy);
+    if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
+	if (unlikely (status != CAIRO_STATUS_SUCCESS) ||
+	    ! pixman_image_set_transform (pixman_image, &pixman_transform))
+	{
+	    cairo_surface_destroy (&image->base);
+	    pixman_image_unref (pixman_image);
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	}
     }
 
     switch (pattern->base.extend) {
@@ -2313,7 +2322,7 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
                               pixman_image,
                               NULL,
                               image->pixman_image,
-                              x, y,
+			      ix, iy,
                               0, 0,
                               0, 0,
                               width, height);
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index e3d1ac4..068ab3d 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -428,33 +428,6 @@ _pattern_is_supported (uint32_t flags,
     return pattern->type != CAIRO_PATTERN_TYPE_MESH;
 }
 
-static double
-_pixman_nearest_sample (double d)
-{
-    return ceil (d - .5);
-}
-
-static cairo_bool_t
-_nearest_sample (const cairo_matrix_t *m,
-		 cairo_filter_t filter,
-		 double *tx, double *ty)
-{
-    *tx = m->x0;
-    *ty = m->y0;
-    if ((filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
-       && _cairo_matrix_has_unity_scale (m))
-    {
-	*tx = _pixman_nearest_sample (*tx);
-	*ty = _pixman_nearest_sample (*ty);
-    }
-    else
-    {
-	if (*tx != floor (*tx) || *ty != floor (*ty))
-	    return FALSE;
-    }
-    return fabs (*tx) < PIXMAN_MAX_INT && fabs (*ty) < PIXMAN_MAX_INT;
-}
-
 static void
 _cairo_xcb_picture_set_matrix (cairo_xcb_picture_t *picture,
 			       const cairo_matrix_t *matrix,
@@ -462,46 +435,19 @@ _cairo_xcb_picture_set_matrix (cairo_xcb_picture_t *picture,
 			       double xc, double yc)
 {
     xcb_render_transform_t transform;
-    cairo_matrix_t m;
-    double tx, ty;
-
-    m = *matrix;
-    if (_nearest_sample (&m, filter, &tx, &ty))
-	m.x0 = m.y0 = 0;
-    else
-	tx = ty = 0;
-
-    if (! _cairo_matrix_is_identity (&m)) {
-	cairo_matrix_t inv;
-	cairo_status_t status;
-
-	inv = m;
-	status = cairo_matrix_invert (&inv);
-	assert (status == CAIRO_STATUS_SUCCESS);
-
-	if (m.x0 != 0. || m.y0 != 0.) {
-	    double x, y;
-
-	    /* pixman also limits the [xy]_offset to 16 bits so evenly
-	     * spread the bits between the two.
-	     */
-	    x = floor (inv.x0 / 2);
-	    y = floor (inv.y0 / 2);
-	    tx = -x;
-	    ty = -y;
-	    cairo_matrix_init_translate (&inv, x, y);
-	    cairo_matrix_multiply (&m, &inv, &m);
-	} else {
-	    if (tx != 0. || ty != 0.)
-		cairo_matrix_transform_point (&inv, &tx, &ty);
-	}
-    }
+    pixman_transform_t *pixman_transform;
+    cairo_status_t ignored;
 
     /* Casting between pixman_transform_t and xcb_render_transform_t is safe
      * because they happen to be the exact same type.
      */
-    _cairo_matrix_to_pixman_matrix (&m,
-				    (pixman_transform_t *) &transform, xc, yc);
+    pixman_transform = (pixman_transform_t *) &transform;
+
+    picture->x = picture->x0;
+    picture->y = picture->y0;
+    ignored = _cairo_matrix_to_pixman_matrix_offset (matrix, filter, xc, yc,
+						     pixman_transform,
+						     &picture->x, &picture->y);
 
     if (memcmp (&picture->transform, &transform, sizeof (xcb_render_transform_t))) {
 	_cairo_xcb_connection_render_set_picture_transform (_picture_to_connection (picture),
@@ -510,9 +456,6 @@ _cairo_xcb_picture_set_matrix (cairo_xcb_picture_t *picture,
 
 	picture->transform = transform;
     }
-
-    picture->x = picture->x0 + tx;
-    picture->y = picture->y0 + ty;
 }
 
 static void
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 76cf5d1..f59b61b 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1623,17 +1623,28 @@ static cairo_status_t
 _cairo_xlib_surface_set_matrix (cairo_xlib_display_t *display,
                                 cairo_xlib_surface_t *surface,
 				const cairo_matrix_t *matrix,
+				cairo_filter_t        filter,
 				double                xc,
-				double                yc)
+				double                yc,
+				int                  *x_offset,
+				int                  *y_offset)
 {
     XTransform xtransform;
+    pixman_transform_t *pixman_transform;
+    cairo_status_t status;
 
     /* Casting between pixman_transform_t and XTransform is safe because
      * they happen to be the exact same type.
      */
-    _cairo_matrix_to_pixman_matrix (matrix,
-				    (pixman_transform_t *) &xtransform,
-				    xc, yc);
+    pixman_transform = (pixman_transform_t *) &xtransform;
+
+    status = _cairo_matrix_to_pixman_matrix_offset (matrix, filter, xc, yc,
+						    pixman_transform,
+						    x_offset, y_offset);
+    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+	status = CAIRO_STATUS_SUCCESS;
+    if (unlikely (status != CAIRO_STATUS_SUCCESS))
+	return status;
 
     if (memcmp (&xtransform, &surface->xtransform, sizeof (XTransform)) == 0)
 	return CAIRO_STATUS_SUCCESS;
@@ -1757,11 +1768,11 @@ _cairo_xlib_surface_set_component_alpha (cairo_xlib_surface_t *surface,
 }
 
 static cairo_int_status_t
-_cairo_xlib_surface_set_attributes (cairo_xlib_display_t             *display,
-                                    cairo_xlib_surface_t	     *surface,
-				    const cairo_surface_attributes_t *attributes,
-				    double			      xc,
-				    double			      yc)
+_cairo_xlib_surface_set_attributes (cairo_xlib_display_t       *display,
+                                    cairo_xlib_surface_t       *surface,
+				    cairo_surface_attributes_t *attributes,
+				    double			xc,
+				    double			yc)
 {
     cairo_int_status_t status;
     XRenderPictureAttributes pa;
@@ -1770,7 +1781,11 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_display_t             *display,
     _cairo_xlib_surface_ensure_src_picture (display, surface);
 
     status = _cairo_xlib_surface_set_matrix (display, surface,
-                                             &attributes->matrix, xc, yc);
+					     &attributes->matrix,
+					     attributes->filter,
+					     xc, yc,
+					     &attributes->x_offset,
+					     &attributes->y_offset);
     if (unlikely (status))
 	return status;
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 780ee05..6c34c5b 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2070,11 +2070,20 @@ cairo_private double
 _cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix,
 					     double radius) cairo_pure;
 
-cairo_private void
-_cairo_matrix_to_pixman_matrix (const cairo_matrix_t	*matrix,
-				pixman_transform_t	*pixman_transform,
-				double                   xc,
-				double                   yc);
+cairo_private cairo_bool_t
+_cairo_matrix_is_pixman_translation (const cairo_matrix_t     *matrix,
+				     cairo_filter_t            filter,
+				     int                      *out_x_offset,
+				     int                      *out_y_offset);
+
+cairo_private cairo_status_t
+_cairo_matrix_to_pixman_matrix_offset (const cairo_matrix_t	*matrix,
+				       cairo_filter_t            filter,
+				       double                    xc,
+				       double                    yc,
+				       pixman_transform_t	*out_transform,
+				       int                      *out_x_offset,
+				       int                      *out_y_offset);
 
 /* cairo-traps.c */
 cairo_private void
commit ada6057b8ccab133909b127850c41abb3216a842
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Fri Dec 31 13:01:50 2010 +0100

    test: New radial-gradient tests
    
    The old radial gradient tests were actually drawing the same gradients
    with different operators (OVER/SOURCE) and operations (paint/mask).
    
    It is possible to refactor them to share the gradient construction
    code. This makes it easy to change the gradient shape in all of them
    to test more interesting combinations.
    
    Instead of testing 16 generic positions we are now testing just 7
    cases, which correspond to every possible combination of the relative
    size and position of the two circles defining the gradient. In
    particular we are now testing a constant radius gradient and gradients
    with tangent circles.

diff --git a/test/Makefile.am b/test/Makefile.am
index 9935116..b33e4f9 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1045,37 +1045,20 @@ REFERENCE_IMAGES = \
 	quartz-surface-source.ps2.ref.png \
 	quartz-surface-source.ps3.ref.png \
 	radial-gradient.image16.ref.png \
-	radial-gradient.pdf.xfail.png \
-	radial-gradient.quartz.ref.png \
 	radial-gradient.ref.png \
-	radial-gradient.svg.xfail.png \
 	radial-gradient-extend.ps3.ref.png \
 	radial-gradient-extend.ref.png \
 	radial-gradient-source.image16.ref.png \
 	radial-gradient-source.argb32.ref.png \
 	radial-gradient-source.rgb24.ref.png \
-	radial-gradient-source.pdf.argb32.xfail.png \
-	radial-gradient-source.pdf.rgb24.xfail.png \
-	radial-gradient-source.quartz.argb32.ref.png \
-	radial-gradient-source.quartz.rgb24.ref.png \
-	radial-gradient-mask.argb32.ref.png \
-	radial-gradient-mask.rgb24.ref.png \
+	radial-gradient-mask.ref.png \
 	radial-gradient-mask.image16.ref.png \
-	radial-gradient-mask.pdf.argb32.xfail.png \
-	radial-gradient-mask.pdf.rgb24.xfail.png \
-	radial-gradient-mask.quartz.argb32.ref.png \
-	radial-gradient-mask.quartz.rgb24.ref.png \
 	radial-gradient-mask-source.argb32.ref.png \
 	radial-gradient-mask-source.rgb24.ref.png \
 	radial-gradient-mask-source.image16.ref.png \
-	radial-gradient-mask-source.pdf.argb32.xfail.png \
-	radial-gradient-mask-source.pdf.rgb24.xfail.png \
-	radial-gradient-mask-source.quartz.argb32.ref.png \
-	radial-gradient-mask-source.quartz.rgb24.ref.png \
-	radial-gradient-one-stop.argb32.ref.png \
-	radial-gradient-one-stop.rgb24.ref.png \
-	radial-gradient-one-stop.ps3.argb32.ref.png \
-	radial-gradient-one-stop.ps3.rgb24.ref.png \
+	radial-gradient-mask-source.xlib.argb32.ref.png \
+	radial-gradient-mask-source.xlib.rgb24.ref.png \
+	radial-gradient-one-stop.ref.png \
 	random-intersections-eo.image16.ref.png \
 	random-intersections-eo.ps.ref.png \
 	random-intersections-eo.quartz.ref.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index 27b8a27..9e5e4d2 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -206,10 +206,6 @@ test_sources = \
 	push-group-path-offset.c			\
 	radial-gradient.c				\
 	radial-gradient-extend.c			\
-	radial-gradient-mask.c				\
-	radial-gradient-mask-source.c			\
-	radial-gradient-one-stop.c			\
-	radial-gradient-source.c			\
 	random-intersections-eo.c			\
 	random-intersections-nonzero.c			\
 	random-intersections-curves-eo.c		\
diff --git a/test/radial-gradient-mask-source.argb32.ref.png b/test/radial-gradient-mask-source.argb32.ref.png
index c161346..2bf65b3 100644
Binary files a/test/radial-gradient-mask-source.argb32.ref.png and b/test/radial-gradient-mask-source.argb32.ref.png differ
diff --git a/test/radial-gradient-mask-source.c b/test/radial-gradient-mask-source.c
deleted file mode 100644
index 27b5270..0000000
--- a/test/radial-gradient-mask-source.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright © 2005, 2007 Red Hat, Inc.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * Author: Carl D. Worth <cworth at cworth.org>
- */
-
-#include "cairo-test.h"
-
-#define NUM_GRADIENTS 4
-#define NUM_EXTEND 4
-#define SIZE 60
-#define WIDTH (SIZE * NUM_GRADIENTS * NUM_GRADIENTS)
-#define HEIGHT (SIZE * NUM_EXTEND)
-
-static void
-draw_gradient (cairo_t		*cr,
-	       int		x,
-	       int		y,
-	       int		size,
-	       double		r1_offset,
-	       double		r1_radius,
-	       double		r2_offset,
-	       double		r2_radius,
-	       cairo_extend_t	extend)
-{
-    cairo_pattern_t *pattern;
-
-    cairo_save (cr);
-
-    pattern = cairo_pattern_create_radial (x + size/2.0 + r1_offset,
-					   y + size/2.0 + r1_offset,
-					   r1_radius,
-					   x + size/2.0 + r2_offset,
-					   y + size/2.0 + r2_offset,
-					   r2_radius);
-    cairo_pattern_add_color_stop_rgba (pattern, 0.0,
-				       1.0, 0.0, 0.0, 1.0);
-    cairo_pattern_add_color_stop_rgba (pattern, sqrt (1.0 / 2.0),
-				       0.0, 1.0, 0.0, 0.0);
-    cairo_pattern_add_color_stop_rgba (pattern, 1.0,
-				       0.0, 0.0, 1.0, 0.5);
-    cairo_pattern_set_extend (pattern, extend);
-
-    cairo_rectangle (cr, x, y, size, size);
-    cairo_clip (cr);
-
-    cairo_set_source_rgb (cr, 1, 0, 1);
-    cairo_mask (cr, pattern);
-
-    cairo_pattern_destroy (pattern);
-
-    cairo_restore (cr);
-}
-
-static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
-{
-    int i, j, k;
-    cairo_extend_t extend[NUM_EXTEND] = {
-	CAIRO_EXTEND_NONE,
-	CAIRO_EXTEND_REPEAT,
-	CAIRO_EXTEND_REFLECT,
-	CAIRO_EXTEND_PAD
-    };
-
-    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-    for (j = 0; j < NUM_EXTEND; j++) {
-	for (i = 0; i < NUM_GRADIENTS; i++) {
-	    double r1_offset = i % 2 ? SIZE / 12.0 : 0.0;
-	    double r1_radius = i >= NUM_GRADIENTS / 2 ? SIZE / 6.0 : 0.0;
-	    for (k = 0; k < NUM_GRADIENTS; k++) {
-		double r2_offset = k % 2 ? SIZE / 12.0 : 0.0;
-		double r2_radius = k >= NUM_GRADIENTS / 2 ? SIZE / 3.0 : SIZE / 12.;
-		draw_gradient (cr,
-			       i * SIZE * NUM_GRADIENTS + k * SIZE, j * SIZE, SIZE,
-			       r1_offset, r1_radius,
-			       r2_offset, r2_radius,
-			       extend[j]);
-	    }
-	}
-    }
-
-    return CAIRO_TEST_SUCCESS;
-}
-
-CAIRO_TEST (radial_gradient_mask_source,
-	    "Simple test of radial gradients using a MASK with a SOURCE operator",
-	    "gradient,mask,source", /* keywords */
-	    NULL, /* requirements */
-	    WIDTH, HEIGHT,
-	    NULL, draw)
diff --git a/test/radial-gradient-mask-source.image16.ref.png b/test/radial-gradient-mask-source.image16.ref.png
index 0a14563..edb93a9 100644
Binary files a/test/radial-gradient-mask-source.image16.ref.png and b/test/radial-gradient-mask-source.image16.ref.png differ
diff --git a/test/radial-gradient-mask-source.pdf.argb32.xfail.png b/test/radial-gradient-mask-source.pdf.argb32.xfail.png
deleted file mode 100644
index 0cb4330..0000000
Binary files a/test/radial-gradient-mask-source.pdf.argb32.xfail.png and /dev/null differ
diff --git a/test/radial-gradient-mask-source.pdf.rgb24.xfail.png b/test/radial-gradient-mask-source.pdf.rgb24.xfail.png
deleted file mode 100644
index 8c096b6..0000000
Binary files a/test/radial-gradient-mask-source.pdf.rgb24.xfail.png and /dev/null differ
diff --git a/test/radial-gradient-mask-source.quartz.argb32.ref.png b/test/radial-gradient-mask-source.quartz.argb32.ref.png
deleted file mode 100644
index 9cb1caa..0000000
Binary files a/test/radial-gradient-mask-source.quartz.argb32.ref.png and /dev/null differ
diff --git a/test/radial-gradient-mask-source.quartz.rgb24.ref.png b/test/radial-gradient-mask-source.quartz.rgb24.ref.png
deleted file mode 100644
index 303033b..0000000
Binary files a/test/radial-gradient-mask-source.quartz.rgb24.ref.png and /dev/null differ
diff --git a/test/radial-gradient-mask-source.rgb24.ref.png b/test/radial-gradient-mask-source.rgb24.ref.png
index 884ebb4..5533519 100644
Binary files a/test/radial-gradient-mask-source.rgb24.ref.png and b/test/radial-gradient-mask-source.rgb24.ref.png differ
diff --git a/test/radial-gradient-mask-source.xlib.argb32.ref.png b/test/radial-gradient-mask-source.xlib.argb32.ref.png
new file mode 100644
index 0000000..1c901c9
Binary files /dev/null and b/test/radial-gradient-mask-source.xlib.argb32.ref.png differ
diff --git a/test/radial-gradient-mask-source.xlib.rgb24.ref.png b/test/radial-gradient-mask-source.xlib.rgb24.ref.png
new file mode 100644
index 0000000..e50fe8f
Binary files /dev/null and b/test/radial-gradient-mask-source.xlib.rgb24.ref.png differ
diff --git a/test/radial-gradient-mask.argb32.ref.png b/test/radial-gradient-mask.argb32.ref.png
deleted file mode 100644
index c161346..0000000
Binary files a/test/radial-gradient-mask.argb32.ref.png and /dev/null differ
diff --git a/test/radial-gradient-mask.c b/test/radial-gradient-mask.c
deleted file mode 100644
index ba03a12..0000000
--- a/test/radial-gradient-mask.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright © 2005, 2007 Red Hat, Inc.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * Author: Carl D. Worth <cworth at cworth.org>
- */
-
-#include "cairo-test.h"
-
-#define NUM_GRADIENTS 4
-#define NUM_EXTEND 4
-#define SIZE 60
-#define WIDTH (SIZE * NUM_GRADIENTS * NUM_GRADIENTS)
-#define HEIGHT (SIZE * NUM_EXTEND)
-
-static void
-draw_gradient (cairo_t		*cr,
-	       int		x,
-	       int		y,
-	       int		size,
-	       double		r1_offset,
-	       double		r1_radius,
-	       double		r2_offset,
-	       double		r2_radius,
-	       cairo_extend_t	extend)
-{
-    cairo_pattern_t *pattern;
-
-    cairo_save (cr);
-
-    pattern = cairo_pattern_create_radial (x + size/2.0 + r1_offset,
-					   y + size/2.0 + r1_offset,
-					   r1_radius,
-					   x + size/2.0 + r2_offset,
-					   y + size/2.0 + r2_offset,
-					   r2_radius);
-    cairo_pattern_add_color_stop_rgba (pattern, 0.0,
-				       1.0, 0.0, 0.0, 1.0);
-    cairo_pattern_add_color_stop_rgba (pattern, sqrt (1.0 / 2.0),
-				       0.0, 1.0, 0.0, 0.0);
-    cairo_pattern_add_color_stop_rgba (pattern, 1.0,
-				       0.0, 0.0, 1.0, 0.5);
-    cairo_pattern_set_extend (pattern, extend);
-
-    cairo_rectangle (cr, x, y, size, size);
-    cairo_clip (cr);
-
-    cairo_set_source_rgb (cr, 1, 0, 1);
-    cairo_mask (cr, pattern);
-
-    cairo_pattern_destroy (pattern);
-
-    cairo_restore (cr);
-}
-
-static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
-{
-    int i, j, k;
-    cairo_extend_t extend[NUM_EXTEND] = {
-	CAIRO_EXTEND_NONE,
-	CAIRO_EXTEND_REPEAT,
-	CAIRO_EXTEND_REFLECT,
-	CAIRO_EXTEND_PAD
-    };
-
-    for (j = 0; j < NUM_EXTEND; j++) {
-	for (i = 0; i < NUM_GRADIENTS; i++) {
-	    double r1_offset = i % 2 ? SIZE / 12.0 : 0.0;
-	    double r1_radius = i >= NUM_GRADIENTS / 2 ? SIZE / 6.0 : 0.0;
-	    for (k = 0; k < NUM_GRADIENTS; k++) {
-		double r2_offset = k % 2 ? SIZE / 12.0 : 0.0;
-		double r2_radius = k >= NUM_GRADIENTS / 2 ? SIZE / 3.0 : SIZE / 12.;
-		draw_gradient (cr,
-			       i * SIZE * NUM_GRADIENTS + k * SIZE, j * SIZE, SIZE,
-			       r1_offset, r1_radius,
-			       r2_offset, r2_radius,
-			       extend[j]);
-	    }
-	}
-    }
-
-    return CAIRO_TEST_SUCCESS;
-}
-
-CAIRO_TEST (radial_gradient_mask,
-	    "Simple test of radial gradients using a MASK",
-	    "gradient,mask", /* keywords */
-	    NULL, /* requirements */
-	    WIDTH, HEIGHT,
-	    NULL, draw)
diff --git a/test/radial-gradient-mask.image16.ref.png b/test/radial-gradient-mask.image16.ref.png
index 0a14563..78712ca 100644
Binary files a/test/radial-gradient-mask.image16.ref.png and b/test/radial-gradient-mask.image16.ref.png differ
diff --git a/test/radial-gradient-mask.pdf.argb32.xfail.png b/test/radial-gradient-mask.pdf.argb32.xfail.png
deleted file mode 100644
index 0cb4330..0000000
Binary files a/test/radial-gradient-mask.pdf.argb32.xfail.png and /dev/null differ
diff --git a/test/radial-gradient-mask.pdf.rgb24.xfail.png b/test/radial-gradient-mask.pdf.rgb24.xfail.png
deleted file mode 100644
index 8c096b6..0000000
Binary files a/test/radial-gradient-mask.pdf.rgb24.xfail.png and /dev/null differ
diff --git a/test/radial-gradient-mask.quartz.argb32.ref.png b/test/radial-gradient-mask.quartz.argb32.ref.png
deleted file mode 100644
index 9cb1caa..0000000
Binary files a/test/radial-gradient-mask.quartz.argb32.ref.png and /dev/null differ
diff --git a/test/radial-gradient-mask.quartz.rgb24.ref.png b/test/radial-gradient-mask.quartz.rgb24.ref.png
deleted file mode 100644
index 303033b..0000000
Binary files a/test/radial-gradient-mask.quartz.rgb24.ref.png and /dev/null differ
diff --git a/test/radial-gradient-mask.ref.png b/test/radial-gradient-mask.ref.png
new file mode 100644
index 0000000..4db39aa
Binary files /dev/null and b/test/radial-gradient-mask.ref.png differ
diff --git a/test/radial-gradient-mask.rgb24.ref.png b/test/radial-gradient-mask.rgb24.ref.png
deleted file mode 100644
index 884ebb4..0000000
Binary files a/test/radial-gradient-mask.rgb24.ref.png and /dev/null differ
diff --git a/test/radial-gradient-one-stop.argb32.ref.png b/test/radial-gradient-one-stop.argb32.ref.png
deleted file mode 100644
index 0aa4510..0000000
Binary files a/test/radial-gradient-one-stop.argb32.ref.png and /dev/null differ
diff --git a/test/radial-gradient-one-stop.c b/test/radial-gradient-one-stop.c
deleted file mode 100644
index 552de23..0000000
--- a/test/radial-gradient-one-stop.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright © 2005, 2007 Red Hat, Inc.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * Author: Carl D. Worth <cworth at cworth.org>
- */
-
-#include "cairo-test.h"
-
-#define NUM_GRADIENTS 4
-#define NUM_EXTEND 4
-#define SIZE 60
-#define WIDTH (SIZE * NUM_GRADIENTS * NUM_GRADIENTS)
-#define HEIGHT (SIZE * NUM_EXTEND)
-
-static void
-draw_gradient (cairo_t		*cr,
-	       int		x,
-	       int		y,
-	       int		size,
-	       double		r1_offset,
-	       double		r1_radius,
-	       double		r2_offset,
-	       double		r2_radius,
-	       cairo_extend_t	extend)
-{
-    cairo_pattern_t *pattern;
-
-    cairo_save (cr);
-
-    pattern = cairo_pattern_create_radial (x + size/2.0 + r1_offset,
-					   y + size/2.0 + r1_offset,
-					   r1_radius,
-					   x + size/2.0 + r2_offset,
-					   y + size/2.0 + r2_offset,
-					   r2_radius);
-    cairo_pattern_add_color_stop_rgb (pattern, 0.25, 1, 0, 0);
-    cairo_pattern_set_extend (pattern, extend);
-
-    cairo_rectangle (cr, x, y, size, size);
-    cairo_clip (cr);
-
-    cairo_set_source (cr, pattern);
-    cairo_paint (cr);
-
-    cairo_pattern_destroy (pattern);
-
-    cairo_restore (cr);
-}
-
-static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
-{
-    int i, j, k;
-    cairo_extend_t extend[NUM_EXTEND] = {
-	CAIRO_EXTEND_NONE,
-	CAIRO_EXTEND_REPEAT,
-	CAIRO_EXTEND_REFLECT,
-	CAIRO_EXTEND_PAD
-    };
-
-    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-
-    for (j = 0; j < NUM_EXTEND; j++) {
-	for (i = 0; i < NUM_GRADIENTS; i++) {
-	    double r1_offset = i % 2 ? SIZE / 12.0 : 0.0;
-	    double r1_radius = i >= NUM_GRADIENTS / 2 ? SIZE / 6.0 : 0.0;
-	    for (k = 0; k < NUM_GRADIENTS; k++) {
-		double r2_offset = k % 2 ? SIZE / 12.0 : 0.0;
-		double r2_radius = k >= NUM_GRADIENTS / 2 ? SIZE / 3.0 : SIZE / 12.;
-		draw_gradient (cr,
-			       i * SIZE * NUM_GRADIENTS + k * SIZE, j * SIZE, SIZE,
-			       r1_offset, r1_radius,
-			       r2_offset, r2_radius,
-			       extend[j]);
-	    }
-	}
-    }
-
-    return CAIRO_TEST_SUCCESS;
-}
-
-CAIRO_TEST (radial_gradient_one_stop,
-	    "Tests radial gradients with a single stop",
-	    "gradient,radial", /* keywords */
-	    NULL, /* requirements */
-	    WIDTH, HEIGHT,
-	    NULL, draw)
diff --git a/test/radial-gradient-one-stop.ps3.argb32.ref.png b/test/radial-gradient-one-stop.ps3.argb32.ref.png
deleted file mode 100644
index 0d21508..0000000
Binary files a/test/radial-gradient-one-stop.ps3.argb32.ref.png and /dev/null differ
diff --git a/test/radial-gradient-one-stop.ps3.rgb24.ref.png b/test/radial-gradient-one-stop.ps3.rgb24.ref.png
deleted file mode 100644
index 0d965cc..0000000
Binary files a/test/radial-gradient-one-stop.ps3.rgb24.ref.png and /dev/null differ
diff --git a/test/radial-gradient-one-stop.ref.png b/test/radial-gradient-one-stop.ref.png
new file mode 100644
index 0000000..fb35be6
Binary files /dev/null and b/test/radial-gradient-one-stop.ref.png differ
diff --git a/test/radial-gradient-one-stop.rgb24.ref.png b/test/radial-gradient-one-stop.rgb24.ref.png
deleted file mode 100644
index 74c848b..0000000
Binary files a/test/radial-gradient-one-stop.rgb24.ref.png and /dev/null differ
diff --git a/test/radial-gradient-source.argb32.ref.png b/test/radial-gradient-source.argb32.ref.png
index d915579..4ab4796 100644
Binary files a/test/radial-gradient-source.argb32.ref.png and b/test/radial-gradient-source.argb32.ref.png differ
diff --git a/test/radial-gradient-source.c b/test/radial-gradient-source.c
deleted file mode 100644
index b546157..0000000
--- a/test/radial-gradient-source.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright © 2005, 2007 Red Hat, Inc.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * Author: Carl D. Worth <cworth at cworth.org>
- */
-
-/* 20091017: A simple variant on radial-gradient, using the SOURCE operator
- * instead as a potential bug was found in pixman under those conditions.
- */
-
-#include "cairo-test.h"
-
-#define NUM_GRADIENTS 4
-#define NUM_EXTEND 4
-#define SIZE 60
-#define WIDTH (SIZE * NUM_GRADIENTS * NUM_GRADIENTS)
-#define HEIGHT (SIZE * NUM_EXTEND)
-
-static void
-draw_gradient (cairo_t		*cr,
-	       int		x,
-	       int		y,
-	       int		size,
-	       double		r1_offset,
-	       double		r1_radius,
-	       double		r2_offset,
-	       double		r2_radius,
-	       cairo_extend_t	extend)
-{
-    cairo_pattern_t *pattern;
-
-    cairo_save (cr);
-
-    pattern = cairo_pattern_create_radial (x + size/2.0 + r1_offset,
-					   y + size/2.0 + r1_offset,
-					   r1_radius,
-					   x + size/2.0 + r2_offset,
-					   y + size/2.0 + r2_offset,
-					   r2_radius);
-    cairo_pattern_add_color_stop_rgba (pattern, 0.0,
-				       1.0, 0.0, 0.0, 1.0);
-    cairo_pattern_add_color_stop_rgba (pattern, sqrt (1.0 / 2.0),
-				       0.0, 1.0, 0.0, 0.0);
-    cairo_pattern_add_color_stop_rgba (pattern, 1.0,
-				       0.0, 0.0, 1.0, 0.5);
-    cairo_pattern_set_extend (pattern, extend);
-
-    cairo_rectangle (cr, x, y, size, size);
-    cairo_clip (cr);
-
-    cairo_set_source (cr, pattern);
-    cairo_paint (cr);
-
-    cairo_pattern_destroy (pattern);
-
-    cairo_restore (cr);
-}
-
-static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
-{
-    int i, j, k;
-    cairo_extend_t extend[NUM_EXTEND] = {
-	CAIRO_EXTEND_NONE,
-	CAIRO_EXTEND_REPEAT,
-	CAIRO_EXTEND_REFLECT,
-	CAIRO_EXTEND_PAD
-    };
-
-    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-    for (j = 0; j < NUM_EXTEND; j++) {
-	for (i = 0; i < NUM_GRADIENTS; i++) {
-	    double r1_offset = i % 2 ? SIZE / 12.0 : 0.0;
-	    double r1_radius = i >= NUM_GRADIENTS / 2 ? SIZE / 6.0 : 0.0;
-	    for (k = 0; k < NUM_GRADIENTS; k++) {
-		double r2_offset = k % 2 ? SIZE / 12.0 : 0.0;
-		double r2_radius = k >= NUM_GRADIENTS / 2 ? SIZE / 3.0 : SIZE / 12.;
-		draw_gradient (cr,
-			       i * SIZE * NUM_GRADIENTS + k * SIZE, j * SIZE, SIZE,
-			       r1_offset, r1_radius,
-			       r2_offset, r2_radius,
-			       extend[j]);
-	    }
-	}
-    }
-
-    return CAIRO_TEST_SUCCESS;
-}
-
-CAIRO_TEST (radial_gradient_source,
-	    "Simple test of radial gradients using the SOURCE operator",
-	    "gradient,source", /* keywords */
-	    NULL, /* requirements */
-	    WIDTH, HEIGHT,
-	    NULL, draw)
diff --git a/test/radial-gradient-source.image16.ref.png b/test/radial-gradient-source.image16.ref.png
index 8c815df..f992b6f 100644
Binary files a/test/radial-gradient-source.image16.ref.png and b/test/radial-gradient-source.image16.ref.png differ
diff --git a/test/radial-gradient-source.pdf.argb32.xfail.png b/test/radial-gradient-source.pdf.argb32.xfail.png
deleted file mode 100644
index e450448..0000000
Binary files a/test/radial-gradient-source.pdf.argb32.xfail.png and /dev/null differ
diff --git a/test/radial-gradient-source.pdf.rgb24.xfail.png b/test/radial-gradient-source.pdf.rgb24.xfail.png
deleted file mode 100644
index fc0174d..0000000
Binary files a/test/radial-gradient-source.pdf.rgb24.xfail.png and /dev/null differ
diff --git a/test/radial-gradient-source.quartz.argb32.ref.png b/test/radial-gradient-source.quartz.argb32.ref.png
deleted file mode 100644
index 77caab8..0000000
Binary files a/test/radial-gradient-source.quartz.argb32.ref.png and /dev/null differ
diff --git a/test/radial-gradient-source.quartz.rgb24.ref.png b/test/radial-gradient-source.quartz.rgb24.ref.png
deleted file mode 100644
index 2870f5e..0000000
Binary files a/test/radial-gradient-source.quartz.rgb24.ref.png and /dev/null differ
diff --git a/test/radial-gradient-source.rgb24.ref.png b/test/radial-gradient-source.rgb24.ref.png
index 09c2edc..afaa241 100644
Binary files a/test/radial-gradient-source.rgb24.ref.png and b/test/radial-gradient-source.rgb24.ref.png differ
diff --git a/test/radial-gradient.c b/test/radial-gradient.c
index a6d145c..3ad4bb9 100644
--- a/test/radial-gradient.c
+++ b/test/radial-gradient.c
@@ -26,56 +26,113 @@
 
 #include "cairo-test.h"
 
-#define NUM_GRADIENTS 4
+#define NUM_GRADIENTS 7
 #define NUM_EXTEND 4
-#define SIZE 60
-#define WIDTH (SIZE * NUM_GRADIENTS * NUM_GRADIENTS)
+#define SIZE 120
+#define WIDTH (SIZE * NUM_GRADIENTS)
 #define HEIGHT (SIZE * NUM_EXTEND)
 
-static void
-draw_gradient (cairo_t		*cr,
-	       int		x,
-	       int		y,
-	       int		size,
-	       double		r1_offset,
-	       double		r1_radius,
-	       double		r2_offset,
-	       double		r2_radius,
-	       cairo_extend_t	extend)
+typedef void (*composite_t)(cairo_t *cr, cairo_pattern_t *pattern);
+typedef void (*add_stops_t)(cairo_pattern_t *pattern);
+
+/*
+ * We want to test all the possible relative positions of the start
+ * and end circle:
+ *
+ *  - The start circle can be smaller/equal/bigger than the end
+ *    circle. A radial gradient can be classified in one of these
+ *    three cases depending on the sign of dr.
+ *
+ *  - The smaller circle can be completely inside/internally
+ *    tangent/outside (at least in part) of the bigger circle. This
+ *    classification is the same as the one which can be computed by
+ *    examining the sign of a = (dx^2 + dy^2 - dr^2).
+ *
+ *  - If the two circles have the same size, neither can be inside or
+ *    internally tangent
+ *
+ * This test draws radial gradients whose circles always have the same
+ * centers (0, 0) and (1, 0), but with different radiuses. From left
+ * to right:
+ *
+ * - Small start circle completely inside the end circle
+ *     0.25 -> 1.75; dr =  1.5 > 0; a = 1 - 1.50^2 < 0
+ *
+ * - Small start circle internally tangent to the end circle
+ *     0.50 -> 1.50; dr =  1.0 > 0; a = 1 - 1.00^2 = 0
+ *
+ * - Small start circle outside of the end circle
+ *     0.50 -> 1.00; dr =  0.5 > 0; a = 1 - 0.50^2 > 0
+ *
+ * - Start circle with the same size as the end circle
+ *     1.00 -> 1.00; dr =  0.0 = 0; a = 1 - 0.00^2 > 0
+ *
+ * - Small end circle outside of the start circle
+ *     1.00 -> 0.50; dr = -0.5 > 0; a = 1 - 0.50^2 > 0
+ *
+ * - Small end circle internally tangent to the start circle
+ *     1.50 -> 0.50; dr = -1.0 > 0; a = 1 - 1.00^2 = 0
+ *
+ * - Small end circle completely inside the start circle
+ *     1.75 -> 0.25; dr = -1.5 > 0; a = 1 - 1.50^2 < 0
+ *
+ */
+
+const static double radiuses[NUM_GRADIENTS] = {
+    0.25,
+    0.50,
+    0.50,
+    1.00,
+    1.00,
+    1.50,
+    1.75
+};
+
+static cairo_pattern_t *
+create_pattern (int index)
 {
-    cairo_pattern_t *pattern;
-
-    cairo_save (cr);
-
-    pattern = cairo_pattern_create_radial (x + size/2.0 + r1_offset,
-					   y + size/2.0 + r1_offset,
-					   r1_radius,
-					   x + size/2.0 + r2_offset,
-					   y + size/2.0 + r2_offset,
-					   r2_radius);
-    cairo_pattern_add_color_stop_rgba (pattern, 0.0,
-				       1.0, 0.0, 0.0, 1.0);
-    cairo_pattern_add_color_stop_rgba (pattern, sqrt (1.0 / 2.0),
-				       0.0, 1.0, 0.0, 0.0);
-    cairo_pattern_add_color_stop_rgba (pattern, 1.0,
-				       0.0, 0.0, 1.0, 0.5);
-    cairo_pattern_set_extend (pattern, extend);
-
-    cairo_rectangle (cr, x, y, size, size);
-    cairo_clip (cr);
+    double x0, x1, radius0, radius1, left, right, center;
 
-    cairo_set_source (cr, pattern);
-    cairo_paint (cr);
+    x0 = 0;
+    x1 = 1;
+    radius0 = radiuses[index];
+    radius1 = radiuses[NUM_GRADIENTS - index - 1];
+
+    /* center the gradient */
+    left = fmin (x0 - radius0, x1 - radius1);
+    right = fmax (x0 + radius0, x1 + radius1);
+    center = (left + right) * 0.5;
+    x0 -= center;
+    x1 -= center;
 
-    cairo_pattern_destroy (pattern);
+    /* scale to make it fit within a 1x1 rect centered in (0,0) */
+    x0 *= 0.25;
+    x1 *= 0.25;
+    radius0 *= 0.25;
+    radius1 *= 0.25;
 
-    cairo_restore (cr);
+    return cairo_pattern_create_radial (x0, 0, radius0, x1, 0, radius1);
 }
 
+static void
+pattern_add_stops (cairo_pattern_t *pattern)
+{
+    cairo_pattern_add_color_stop_rgba (pattern, 0.0,        1, 0, 0, 0.75);
+    cairo_pattern_add_color_stop_rgba (pattern, sqrt (0.5), 0, 1, 0, 0);
+    cairo_pattern_add_color_stop_rgba (pattern, 1.0,        0, 0, 1, 1);
+}
+
+static void
+pattern_add_single_stop (cairo_pattern_t *pattern)
+{
+    cairo_pattern_add_color_stop_rgba (pattern, 0.25, 1, 0, 0, 1);
+}
+
+
 static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
+draw (cairo_t *cr, add_stops_t add_stops, composite_t composite)
 {
-    int i, j, k;
+    int i, j;
     cairo_extend_t extend[NUM_EXTEND] = {
 	CAIRO_EXTEND_NONE,
 	CAIRO_EXTEND_REPEAT,
@@ -83,30 +140,117 @@ draw (cairo_t *cr, int width, int height)
 	CAIRO_EXTEND_PAD
     };
 
-    cairo_test_paint_checkered (cr);
+    cairo_scale (cr, SIZE, SIZE);
+    cairo_translate (cr, 0.5, 0.5);
 
     for (j = 0; j < NUM_EXTEND; j++) {
+	cairo_save (cr);
 	for (i = 0; i < NUM_GRADIENTS; i++) {
-	    double r1_offset = i % 2 ? SIZE / 12.0 : 0.0;
-	    double r1_radius = i >= NUM_GRADIENTS / 2 ? SIZE / 6.0 : 0.0;
-	    for (k = 0; k < NUM_GRADIENTS; k++) {
-		double r2_offset = k % 2 ? SIZE / 12.0 : 0.0;
-		double r2_radius = k >= NUM_GRADIENTS / 2 ? SIZE / 3.0 : SIZE / 12.;
-		draw_gradient (cr,
-			       i * SIZE * NUM_GRADIENTS + k * SIZE, j * SIZE, SIZE,
-			       r1_offset, r1_radius,
-			       r2_offset, r2_radius,
-			       extend[j]);
-	    }
+	    cairo_pattern_t *pattern;
+
+	    pattern = create_pattern (i);
+	    add_stops (pattern);
+	    cairo_pattern_set_extend (pattern, extend[j]);
+
+	    cairo_save (cr);
+	    cairo_rectangle (cr, -0.5, -0.5, 1, 1);
+	    cairo_clip (cr);
+	    composite (cr, pattern);
+	    cairo_restore (cr);
+	    cairo_pattern_destroy (pattern);
+
+	    cairo_translate (cr, 1, 0);
 	}
+	cairo_restore (cr);
+	cairo_translate (cr, 0, 1);
     }
 
     return CAIRO_TEST_SUCCESS;
 }
 
+
+static void
+composite_simple (cairo_t *cr, cairo_pattern_t *pattern)
+{
+    cairo_set_source (cr, pattern);
+    cairo_paint (cr);
+}
+
+static void
+composite_mask (cairo_t *cr, cairo_pattern_t *pattern)
+{
+    cairo_set_source_rgb (cr, 1, 0, 1);
+    cairo_mask (cr, pattern);
+}
+
+
+static cairo_test_status_t
+draw_simple (cairo_t *cr, int width, int height)
+{
+    cairo_test_paint_checkered (cr);
+    return draw (cr, pattern_add_stops, composite_simple);
+}
+
+static cairo_test_status_t
+draw_mask (cairo_t *cr, int width, int height)
+{
+    cairo_test_paint_checkered (cr);
+    return draw (cr, pattern_add_stops, composite_mask);
+}
+
+static cairo_test_status_t
+draw_source (cairo_t *cr, int width, int height)
+{
+    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+    return draw (cr, pattern_add_stops, composite_simple);
+}
+
+
+static cairo_test_status_t
+draw_mask_source (cairo_t *cr, int width, int height)
+{
+    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+    return draw (cr, pattern_add_stops, composite_mask);
+}
+
+static cairo_test_status_t
+draw_one_stop (cairo_t *cr, int width, int height)
+{
+    cairo_test_paint_checkered (cr);
+    return draw (cr, pattern_add_single_stop, composite_simple);
+}
+
 CAIRO_TEST (radial_gradient,
 	    "Simple test of radial gradients",
 	    "gradient", /* keywords */
 	    NULL, /* requirements */
 	    WIDTH, HEIGHT,
-	    NULL, draw)
+	    NULL, draw_simple)
+
+CAIRO_TEST (radial_gradient_mask,
+	    "Simple test of radial gradients using a MASK",
+	    "gradient,mask", /* keywords */
+	    NULL, /* requirements */
+	    WIDTH, HEIGHT,
+	    NULL, draw_mask)
+
+CAIRO_TEST (radial_gradient_source,
+	    "Simple test of radial gradients using the SOURCE operator",
+	    "gradient,source", /* keywords */
+	    NULL, /* requirements */
+	    WIDTH, HEIGHT,
+	    NULL, draw_source)
+
+CAIRO_TEST (radial_gradient_mask_source,
+	    "Simple test of radial gradients using a MASK with a SOURCE operator",
+	    "gradient,mask,source", /* keywords */
+	    NULL, /* requirements */
+	    WIDTH, HEIGHT,
+	    NULL, draw_mask_source)
+
+CAIRO_TEST (radial_gradient_one_stop,
+	    "Tests radial gradients with a single stop",
+	    "gradient,radial", /* keywords */
+	    NULL, /* requirements */
+	    WIDTH, HEIGHT,
+	    NULL, draw_one_stop)
diff --git a/test/radial-gradient.image16.ref.png b/test/radial-gradient.image16.ref.png
index 737f518..91202d3 100644
Binary files a/test/radial-gradient.image16.ref.png and b/test/radial-gradient.image16.ref.png differ
diff --git a/test/radial-gradient.pdf.xfail.png b/test/radial-gradient.pdf.xfail.png
deleted file mode 100644
index f7e68fb..0000000
Binary files a/test/radial-gradient.pdf.xfail.png and /dev/null differ
diff --git a/test/radial-gradient.quartz.ref.png b/test/radial-gradient.quartz.ref.png
deleted file mode 100644
index 21b6b46..0000000
Binary files a/test/radial-gradient.quartz.ref.png and /dev/null differ
diff --git a/test/radial-gradient.ref.png b/test/radial-gradient.ref.png
index 91eda56..a2cbbc8 100644
Binary files a/test/radial-gradient.ref.png and b/test/radial-gradient.ref.png differ
diff --git a/test/radial-gradient.svg.xfail.png b/test/radial-gradient.svg.xfail.png
deleted file mode 100644
index ab54a3d..0000000
Binary files a/test/radial-gradient.svg.xfail.png and /dev/null differ
commit b4aa01f72f98d71bded5f6fa3eaf3d12ad30eb2c
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Thu Dec 16 22:46:50 2010 +0100

    pattern: Make functions not used elsewhere static
    
    _cairo_pattern_init_linear() and _cairo_pattern_init_radial() are only
    called from within cairo-pattern.c

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index e514e3a..34a5cf4 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -496,7 +496,7 @@ _cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern,
     pattern->stops      = NULL;
 }
 
-void
+static void
 _cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
 			    double x0, double y0, double x1, double y1)
 {
@@ -508,7 +508,7 @@ _cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
     pattern->p2.y = _cairo_fixed_from_double (y1);
 }
 
-void
+static void
 _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
 			    double cx0, double cy0, double radius0,
 			    double cx1, double cy1, double radius1)
diff --git a/src/cairoint.h b/src/cairoint.h
index 1a762a1..780ee05 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2195,15 +2195,6 @@ _cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
 				 cairo_surface_t *surface);
 
 cairo_private void
-_cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
-			    double x0, double y0, double x1, double y1);
-
-cairo_private void
-_cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
-			    double cx0, double cy0, double radius0,
-			    double cx1, double cy1, double radius1);
-
-cairo_private void
 _cairo_pattern_fini (cairo_pattern_t *pattern);
 
 cairo_private cairo_pattern_t *
commit b0aef7202d40f3f45b8914e8bd0edfcc6e5112ad
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Fri Dec 17 10:44:41 2010 +0100

    pattern: Use cairo_color_stop_t when hashing gradient stops
    
    Since 18b48a6ebc044c07f08bafd0abcb68c595c5746c the color of each
    gradient stop is stored in a cairo_color_stop_t, but
    _cairo_gradient_color_stops_hash() was not updated accordingly.

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 94d37dc..e514e3a 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -4341,7 +4341,7 @@ _cairo_gradient_color_stops_hash (unsigned long hash,
 				  sizeof (double));
 	hash = _cairo_hash_bytes (hash,
 				  &gradient->stops[n].color,
-				  sizeof (cairo_color_t));
+				  sizeof (cairo_color_stop_t));
     }
 
     return hash;
commit 0501777598cf8fc4e8668e9121eac6b389591f22
Author: Andrea Canciani <ranma42 at gmail.com>
Date:   Fri Dec 17 11:02:02 2010 +0100

    pattern: Remove unused 'opaque' variable
    
    opaque is never read, thus it can be removed.

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index ef29ad3..94d37dc 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -2126,7 +2126,6 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
     pixman_transform_t	  pixman_transform;
     cairo_status_t	  status;
     cairo_bool_t	  repeat = FALSE;
-    cairo_bool_t          opaque = TRUE;
 
     pixman_gradient_stop_t pixman_stops_static[2];
     pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
@@ -2150,8 +2149,6 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
 	pixman_stops[i].color.green = pattern->stops[i].color.green_short;
 	pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
 	pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
-	if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (pixman_stops[i].color.alpha))
-	    opaque = FALSE;
     }
 
     if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR)


More information about the cairo-commit mailing list