[cairo] [patch] gl: fix gradient color texture generation

Henry (Yu) Song - SISA hsong at sisa.samsung.com
Wed Jul 25 15:41:34 PDT 2012


commit 143dcad36f057ed2bb4fc2970781a4efc9386602
Author: Henry Song <henry.song at samsung.com>
Date:   Wed Jul 25 15:34:52 2012 -0700

    gl: (1) increase minimal gradient texture width from  to 256.
    (2) set gradient color strip center to be a little offset from pixel
    center
    
    (1) gradient texture width of 8 is too small that results in lost of
    color precision when gradient end/start points are far apart.
    
    (2) due to a "bug" in pixman, we should not set p1.x and p2.x to be
    exact of pixel center - this results in a out-of-bound when pixman
    loops of over stops.
    
    fix test cases: huge-radial, huge-linear.
    bring test case: linear-gradient-large closer to reference image

diff --git a/src/cairo-gl-gradient.c b/src/cairo-gl-gradient.c
index ffb5468..c060ca1 100644
--- a/src/cairo-gl-gradient.c
+++ b/src/cairo-gl-gradient.c
@@ -52,7 +52,12 @@ _cairo_gl_gradient_sample_width (unsigned int                 n_stops,
     unsigned int n;
     int width;
 
-    width = 8;
+    /*  minimal 8 sample width is too small for situation where 
+     * gradient start/end points are far apart.  In GL backend, the 
+     * gl shader picks gradient color by interpolation.  If the texture
+     * width is too small, it results in lose of color precision
+     */
+    width = 256;
     for (n = 1; n < n_stops; n++) {
 	double dx = stops[n].offset - stops[n-1].offset;
 	double delta, max;
@@ -80,6 +85,7 @@ _cairo_gl_gradient_sample_width (unsigned int                 n_stops,
 	    width = ramp;
     }
 
+    /* increment by 8 is OK */
     width = (width + 7) & -8;
     return MIN (width, 1024);
 }
@@ -124,9 +130,17 @@ _cairo_gl_gradient_render (const cairo_gl_context_t    *ctx,
 	pixman_stops[i].color.alpha = stops[i].color.alpha_short;
     }
 
-    p1.x = _cairo_fixed_16_16_from_double (0.5);
+    /* due to a "bug" in pixman, we should not use exact center of pixel
+     * as the p1.x and p2.x.  This is beause pixman generates gradient
+     * color by interpolate two adjacent stops.  And the step of 
+     * interpolation is computed from p2.x - p1.x.  If we have set
+     * at the center of pixel, it results pixman picking stop colors from
+     * out-of-bound stops array.  see _gradient_walker_reset () in
+     * pixman-gradient-walker.c
+     */
+    p1.x = _cairo_fixed_16_16_from_double (0.6);
     p1.y = 0;
-    p2.x = _cairo_fixed_16_16_from_double (width - 0.5);
+    p2.x = _cairo_fixed_16_16_from_double (width - 0.6);
     p2.y = 0;
 
     gradient = pixman_image_create_linear_gradient (&p1, &p2,


More information about the cairo mailing list