[cairo] [PATCH] Ensure the quartz backend returns the first stop for negative positions on the gradient line of a nonrepeating linear gradient.

Jeff Muizelaar jeff at infidigm.net
Thu May 6 19:25:16 PDT 2010

commit 5016bd6beb4be2c1cb5b25ab322f64842f928055
Author: Robert O'Callahan <robert at ocallahan.org>
Date:   Thu Jan 14 15:31:56 2010 -0500

     Ensure the quartz backend returns the first stop for negative 
positions on the gradient line of a nonrepeating linear gradient.

     I discovered a small bug in cairo-quartz gradients. If you have 
multiple stops
     at position 0, then cairo-quartz pads with the *last* stop at 
position 0,
     instead of the first stop at position 0. This patch fixes that.

     From https://bugzilla.mozilla.org/show_bug.cgi?id=513395

diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 463fc6e..547bc55 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -800,12 +800,32 @@ static const cairo_quartz_float_t 
gradient_output_value_ranges[8] = {
  static const CGFunctionCallbacks gradient_callbacks = {
      0, ComputeGradientValue, (CGFunctionReleaseInfoCallback) 
+/* Quartz will clamp input values to the input range.
+   Our stops are all in the range 0.0 to 1.0. However, the color before the
+   beginning of the gradient line is obtained by Quartz computing a 
+   position on the gradient line, clamping it to the input range we 
+   for our color function, and then calling our color function (actually it
+   pre-samples the color function into an array, but that doesn't 
matter just
+   here). Therefore if we set the lower bound to 0.0, a negative position
+   on the gradient line will pass 0.0 to ComputeGradientValue, which will
+   select the last color stop with position 0, although it should select
+   the first color stop (this matters when there are multiple color 
stops with
+   position 0).
+   Therefore we pass a small negative number as the lower bound of the 
+   range, so this value gets passed into ComputeGradientValue, which will
+   return the color of the first stop. The number should be small because
+   as far as I can tell, Quartz pre-samples the entire input range of 
the color
+   function into an array of fixed size, so if the input range is larger
+   than needed, the resolution of the gradient will be unnecessarily low.
+static const cairo_quartz_float_t 
nonrepeating_gradient_input_value_range[2] = { -0.001f, 1.f };

  static CGFunctionRef
  CreateGradientFunction (const cairo_gradient_pattern_t *gpat)
      cairo_pattern_t *pat;
-    cairo_quartz_float_t input_value_range[2] = { 0.f, 1.f };

      if (_cairo_pattern_create_copy (&pat, &gpat->base))
      /* quartz doesn't deal very well with malloc failing, so there's
@@ -814,7 +834,7 @@ CreateGradientFunction (const 
cairo_gradient_pattern_t *gpat)

      return CGFunctionCreate (pat,
-                 input_value_range,
+                 nonrepeating_gradient_input_value_range,

More information about the cairo mailing list