[cairo-commit] 3 commits - src/cairo-quartz-surface.c test/gradient-zero-stops.c test/gradient-zero-stops-ref.png test/gradient-zero-stops-rgb24-ref.png test/Makefile.am

Brian Ewins brianewins at kemper.freedesktop.org
Thu Dec 6 13:31:36 PST 2007


 src/cairo-quartz-surface.c             |  218 ++++++++++++++++++---------------
 test/Makefile.am                       |    3 
 test/gradient-zero-stops-ref.png       |binary
 test/gradient-zero-stops-rgb24-ref.png |binary
 test/gradient-zero-stops.c             |   66 +++++++++
 5 files changed, 188 insertions(+), 99 deletions(-)

New commits:
commit 19680f545a1620d944322775c1b85b0e5f93fa0f
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Thu Dec 6 21:31:15 2007 +0000

    [quartz] fix gradient-zero-stops crash (moz#407104)
    
    Fixes failure in gradient-zero-stops test, reported
    by Boris Zbarsky (thanks!) as Mozill a bug#407104.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 740be7a..107e717 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -648,6 +648,12 @@ _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface,
     if (mat.xx != 1.0 || mat.yy != 1.0 || mat.xy != 0.0 || mat.yx != 0.0)
 	return DO_UNSUPPORTED;
 
+    if (!lpat->base.n_stops) {
+	CGContextSetRGBStrokeColor (surface->cgContext, 0., 0., 0., 0.);
+	CGContextSetRGBFillColor (surface->cgContext, 0., 0., 0., 0.);
+	return DO_SOLID;
+    }
+
     x0 = mat.x0;
     y0 = mat.y0;
     rgb = CGColorSpaceCreateDeviceRGB();
@@ -694,6 +700,12 @@ _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
     if (mat.xx != 1.0 || mat.yy != 1.0 || mat.xy != 0.0 || mat.yx != 0.0)
 	return DO_UNSUPPORTED;
 
+    if (!rpat->base.n_stops) {
+	CGContextSetRGBStrokeColor (surface->cgContext, 0., 0., 0., 0.);
+	CGContextSetRGBFillColor (surface->cgContext, 0., 0., 0., 0.);
+	return DO_SOLID;
+    }
+
     x0 = mat.x0;
     y0 = mat.y0;
     rgb = CGColorSpaceCreateDeviceRGB();
commit e6c34bb6912d2801ee6c0d56ec0e98739c786e9f
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Thu Dec 6 21:31:14 2007 +0000

    [quartz] refactor gradient handling
    
    Avoid checking the gradient type twice. This refactor
    also makes it easier to check when the gradient has no stops,
    and will make it easier to separate out the different
    implementations of EXTEND_REPEAT, REFLECT for linear and
    radial gradients.

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index b51a85a..740be7a 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1,7 +1,7 @@
 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
 /* cairo - a vector graphics library with display and print output
  *
- * Copyright © 2006, 2007 Mozilla Corporation
+ * Copyright � 2006, 2007 Mozilla Corporation
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -378,94 +378,6 @@ CreateGradientFunction (cairo_gradient_pattern_t *gpat)
 			     &callbacks);
 }
 
-static cairo_int_status_t
-_cairo_quartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat,
-						CGShadingRef *shading)
-{
-    cairo_matrix_t mat;
-    double x0, y0;
-
-    if (abspat->type != CAIRO_PATTERN_TYPE_LINEAR &&
-	abspat->type != CAIRO_PATTERN_TYPE_RADIAL)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    /* bandaid for mozilla bug 379321, also visible in the
-     * linear-gradient-reflect test.
-     */
-    if (abspat->extend == CAIRO_EXTEND_REFLECT ||
-	abspat->extend == CAIRO_EXTEND_REPEAT)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    /* We can only do this if we have an identity pattern matrix;
-     * otherwise fall back through to the generic pattern case.
-     * XXXperf we could optimize this by creating a pattern with the shading;
-     * but we'd need to know the extents to do that.
-     * ... but we don't care; we can use the surface extents for it
-     * XXXtodo - implement gradients with non-identity pattern matrices
-     */
-    cairo_pattern_get_matrix (abspat, &mat);
-    if (mat.xx != 1.0 || mat.yy != 1.0 || mat.xy != 0.0 || mat.yx != 0.0)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    x0 = mat.x0;
-    y0 = mat.y0;
-
-    if (abspat->type == CAIRO_PATTERN_TYPE_LINEAR) {
-	cairo_linear_pattern_t *lpat = (cairo_linear_pattern_t*) abspat;
-	CGPoint start, end;
-	CGFunctionRef gradFunc;
-	CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
-	bool extend = abspat->extend == CAIRO_EXTEND_PAD;
-
-	start = CGPointMake (_cairo_fixed_to_double (lpat->p1.x) - x0,
-			     _cairo_fixed_to_double (lpat->p1.y) - y0);
-	end = CGPointMake (_cairo_fixed_to_double (lpat->p2.x) - x0,
-			   _cairo_fixed_to_double (lpat->p2.y) - y0);
-
-	cairo_pattern_reference (abspat);
-	gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) lpat);
-	*shading = CGShadingCreateAxial (rgb,
-					start, end,
-					gradFunc,
-					extend, extend);
-	CGColorSpaceRelease(rgb);
-	CGFunctionRelease(gradFunc);
-
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    if (abspat->type == CAIRO_PATTERN_TYPE_RADIAL) {
-	cairo_radial_pattern_t *rpat = (cairo_radial_pattern_t*) abspat;
-	CGPoint start, end;
-	CGFunctionRef gradFunc;
-	CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
-	bool extend = abspat->extend == CAIRO_EXTEND_PAD;
-
-	start = CGPointMake (_cairo_fixed_to_double (rpat->c1.x) - x0,
-			     _cairo_fixed_to_double (rpat->c1.y) - y0);
-	end = CGPointMake (_cairo_fixed_to_double (rpat->c2.x) - x0,
-			   _cairo_fixed_to_double (rpat->c2.y) - y0);
-
-	cairo_pattern_reference (abspat);
-	gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) rpat);
-	*shading = CGShadingCreateRadial (rgb,
-					 start,
-					 _cairo_fixed_to_double (rpat->r1),
-					 end,
-					 _cairo_fixed_to_double (rpat->r2),
-					 gradFunc,
-					 extend, extend);
-	CGColorSpaceRelease(rgb);
-	CGFunctionRelease(gradFunc);
-
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    /* Shouldn't be reached */
-    ASSERT_NOT_REACHED;
-    return CAIRO_STATUS_SUCCESS;
-}
-
 /* generic cairo surface -> cairo_quartz_surface_t function */
 static cairo_int_status_t
 _cairo_quartz_surface_to_quartz (cairo_surface_t *target,
@@ -707,6 +619,106 @@ typedef enum {
 } cairo_quartz_action_t;
 
 static cairo_quartz_action_t
+_cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface,
+				   cairo_linear_pattern_t *lpat)
+{
+    cairo_pattern_t *abspat = (cairo_pattern_t *) lpat;
+    cairo_matrix_t mat;
+    double x0, y0;
+    CGPoint start, end;
+    CGFunctionRef gradFunc;
+    CGColorSpaceRef rgb;
+    bool extend = abspat->extend == CAIRO_EXTEND_PAD;
+
+    /* bandaid for mozilla bug 379321, also visible in the
+     * linear-gradient-reflect test.
+     */
+    if (abspat->extend == CAIRO_EXTEND_REFLECT ||
+	abspat->extend == CAIRO_EXTEND_REPEAT)
+	return DO_UNSUPPORTED;
+
+    /* We can only do this if we have an identity pattern matrix;
+     * otherwise fall back through to the generic pattern case.
+     * XXXperf we could optimize this by creating a pattern with the shading;
+     * but we'd need to know the extents to do that.
+     * ... but we don't care; we can use the surface extents for it
+     * XXXtodo - implement gradients with non-identity pattern matrices
+     */
+    cairo_pattern_get_matrix (abspat, &mat);
+    if (mat.xx != 1.0 || mat.yy != 1.0 || mat.xy != 0.0 || mat.yx != 0.0)
+	return DO_UNSUPPORTED;
+
+    x0 = mat.x0;
+    y0 = mat.y0;
+    rgb = CGColorSpaceCreateDeviceRGB();
+
+    start = CGPointMake (_cairo_fixed_to_double (lpat->p1.x) - x0,
+			 _cairo_fixed_to_double (lpat->p1.y) - y0);
+    end = CGPointMake (_cairo_fixed_to_double (lpat->p2.x) - x0,
+		       _cairo_fixed_to_double (lpat->p2.y) - y0);
+
+    cairo_pattern_reference (abspat);
+    gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) lpat);
+    surface->sourceShading = CGShadingCreateAxial (rgb,
+						   start, end,
+						   gradFunc,
+						   extend, extend);
+    CGColorSpaceRelease(rgb);
+    CGFunctionRelease(gradFunc);
+
+    return DO_SHADING;
+}
+
+static cairo_quartz_action_t
+_cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
+				   cairo_radial_pattern_t *rpat)
+{
+    cairo_pattern_t *abspat = (cairo_pattern_t *)rpat;
+    cairo_matrix_t mat;
+    double x0, y0;
+    CGPoint start, end;
+    CGFunctionRef gradFunc;
+    CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
+    bool extend = abspat->extend == CAIRO_EXTEND_PAD;
+
+    /* bandaid for mozilla bug 379321, also visible in the
+     * linear-gradient-reflect test.
+     */
+    if (abspat->extend == CAIRO_EXTEND_REFLECT ||
+	abspat->extend == CAIRO_EXTEND_REPEAT)
+	return DO_UNSUPPORTED;
+
+    /* XXXtodo - implement gradients with non-identity pattern matrices
+     */
+    cairo_pattern_get_matrix (abspat, &mat);
+    if (mat.xx != 1.0 || mat.yy != 1.0 || mat.xy != 0.0 || mat.yx != 0.0)
+	return DO_UNSUPPORTED;
+
+    x0 = mat.x0;
+    y0 = mat.y0;
+    rgb = CGColorSpaceCreateDeviceRGB();
+
+    start = CGPointMake (_cairo_fixed_to_double (rpat->c1.x) - x0,
+			 _cairo_fixed_to_double (rpat->c1.y) - y0);
+    end = CGPointMake (_cairo_fixed_to_double (rpat->c2.x) - x0,
+		       _cairo_fixed_to_double (rpat->c2.y) - y0);
+
+    cairo_pattern_reference (abspat);
+    gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) rpat);
+    surface->sourceShading = CGShadingCreateRadial (rgb,
+						    start,
+						    _cairo_fixed_to_double (rpat->r1),
+						    end,
+						    _cairo_fixed_to_double (rpat->r2),
+						    gradFunc,
+						    extend, extend);
+    CGColorSpaceRelease(rgb);
+    CGFunctionRelease(gradFunc);
+
+    return DO_SHADING;
+}
+
+static cairo_quartz_action_t
 _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
 			    cairo_pattern_t *source)
 {
@@ -727,19 +739,15 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
 				  solid->color.alpha);
 
 	return DO_SOLID;
-    } else if (source->type == CAIRO_PATTERN_TYPE_LINEAR ||
-	       source->type == CAIRO_PATTERN_TYPE_RADIAL)
+    } else if (source->type == CAIRO_PATTERN_TYPE_LINEAR)
     {
-	CGShadingRef shading = NULL;
-	cairo_int_status_t status;
-
-	status = _cairo_quartz_cairo_gradient_pattern_to_quartz (source, &shading);
-	if (status)
-	    return DO_UNSUPPORTED;
+	cairo_linear_pattern_t *lpat = (cairo_linear_pattern_t *)source;
+	return _cairo_quartz_setup_linear_source (surface, lpat);
 
-	surface->sourceShading = shading;
+    } else if (source->type == CAIRO_PATTERN_TYPE_RADIAL) {
+	cairo_radial_pattern_t *rpat = (cairo_radial_pattern_t *)source;
+	return _cairo_quartz_setup_radial_source (surface, rpat);
 
-	return DO_SHADING;
     } else if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
 	       (source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImage && source->extend == CAIRO_EXTEND_REPEAT)))
     {
commit b81c8473bd0b8b829dc7eba9a105890f0c2f1158
Author: Brian Ewins <Brian.Ewins at gmail.com>
Date:   Thu Dec 6 21:31:10 2007 +0000

    [test] add test for gradient with no stops
    
    Boris Zbarsky reported a bug where having zero stops in a
    gradient pattern would crash in the quartz surface. This
    test checks for that case. Mozilla bug#407104.
    
    This also crashes testing pdf; and the ps, svg surfaces
    look suspicious (they reference stops[0]) but I havent
    been able to test them yet.

diff --git a/test/Makefile.am b/test/Makefile.am
index ec2d028..e4459af 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -50,6 +50,7 @@ get-clip                        \
 get-group-target		\
 get-path-extents                \
 gradient-alpha			\
+gradient-zero-stops \
 infinite-join			\
 in-fill-empty-trapezoid		\
 invalid-matrix			\
@@ -311,6 +312,8 @@ REFERENCE_IMAGES = \
 	glyph-cache-pressure-ref.png	\
 	gradient-alpha-ref.png	\
 	gradient-alpha-rgb24-ref.png	\
+	gradient-zero-stops-ref.png	\
+	gradient-zero-stops-rgb24-ref.png	\
 	infinite-join-ref.png	\
 	leaky-dash-ps-argb32-ref.png	\
 	leaky-dash-ref.png	\
diff --git a/test/gradient-zero-stops-ref.png b/test/gradient-zero-stops-ref.png
new file mode 100644
index 0000000..3f18670
Binary files /dev/null and b/test/gradient-zero-stops-ref.png differ
diff --git a/test/gradient-zero-stops-rgb24-ref.png b/test/gradient-zero-stops-rgb24-ref.png
new file mode 100644
index 0000000..eb24e4b
Binary files /dev/null and b/test/gradient-zero-stops-rgb24-ref.png differ
diff --git a/test/gradient-zero-stops.c b/test/gradient-zero-stops.c
new file mode 100644
index 0000000..0cf145d
--- /dev/null
+++ b/test/gradient-zero-stops.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2007 Brian Ewins
+ *
+ * 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: Brian Ewins <Brian.Ewins at gmail.com>
+ */
+
+#include "cairo-test.h"
+
+/* This test case is designed to exercise the following bug:
+ *
+ *      Crash when trying to paint gradient with no stops
+ *      https://bugzilla.mozilla.org/show_bug.cgi?id=407104
+ */
+
+static cairo_test_draw_function_t draw;
+
+cairo_test_t test = {
+    "gradient-zero-stops",
+    "Verifies that gradients with no stops dont cause problems.",
+    2, 2,
+    draw
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_pattern_t *pat;
+    
+    pat = cairo_pattern_create_linear (0., 0., 1., 1.);
+    cairo_set_source (cr, pat);
+    cairo_paint (cr);
+    cairo_pattern_destroy (pat);
+
+    pat = cairo_pattern_create_radial (0., 0., 0., 1., 1., 1.);
+    cairo_set_source (cr, pat);
+    cairo_paint (cr);
+    cairo_pattern_destroy (pat);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+    return cairo_test (&test);
+}


More information about the cairo-commit mailing list