pixman: Branch 'master'

Chris Wilson ickle at kemper.freedesktop.org
Thu Jul 23 11:12:04 PDT 2009


 pixman/pixman-radial-gradient.c |   49 +++++++++++++++++++---------------------
 1 file changed, 24 insertions(+), 25 deletions(-)

New commits:
commit 20d2df03059d6a5941464d80e81e8116ebf4dbfe
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Jul 23 19:08:40 2009 +0100

    Fix inversion of radial gradients when r2 > r1
    
    Fixes: Bug 22908 -- Invalid output of radial gradient
    http://bugs.freedesktop.org/show_bug.cgi?id=22908
    
    We also include a modified patch by André Tupinambá <andrelrt at gmail.com>,
    to pull constant expressions out of the inner radial gradient walker.

diff --git a/pixman/pixman-radial-gradient.c b/pixman/pixman-radial-gradient.c
index a3b5916..04c170e 100644
--- a/pixman/pixman-radial-gradient.c
+++ b/pixman/pixman-radial-gradient.c
@@ -155,6 +155,9 @@ radial_gradient_get_scanline_32 (pixman_image_t *image,
      * for t:
      *
      * t = (-2·B ± ⎷(B² - 4·A·C)) / 2·A
+     *
+     * When computing t over a scanline, we notice that some expressions are
+     * constant so we can compute them just once.
      */
 
     gradient_t *gradient = (gradient_t *)image;
@@ -198,41 +201,37 @@ radial_gradient_get_scanline_32 (pixman_image_t *image,
 
     if (affine)
     {
+	double r1   = radial->c1.radius / 65536.;
+	double r1sq = r1 * r1;
+	double pdx  = rx - radial->c1.x / 65536.;
+	double pdy  = ry - radial->c1.y / 65536.;
+	double A = radial->A;
+	double invA = -65536. / (2. * A);
+	double A4 = -4. * A;
+	double B  = -2. * (pdx*radial->cdx + pdy*radial->cdy + r1*radial->dr);
+	double cB = -2. *  (cx*radial->cdx +  cy*radial->cdy);
+	pixman_bool_t invert = A * radial->dr < 0;
+
 	while (buffer < end)
 	{
 	    if (!mask || *mask++ & mask_bits)
 	    {
-		double pdx, pdy;
-		double B, C;
-		double det;
-		double c1x = radial->c1.x / 65536.0;
-		double c1y = radial->c1.y / 65536.0;
-		double r1  = radial->c1.radius / 65536.0;
 		pixman_fixed_48_16_t t;
-
-		pdx = rx - c1x;
-		pdy = ry - c1y;
-
-		B = -2 * (pdx * radial->cdx +
-			  pdy * radial->cdy +
-			  r1 * radial->dr);
-		C = pdx * pdx + pdy * pdy - r1 * r1;
-
-		det = (B * B) - (4 * radial->A * C);
-		if (det < 0.0)
-		    det = 0.0;
-
-		if (radial->A < 0)
-		    t = (pixman_fixed_48_16_t) ((-B - sqrt (det)) / (2.0 * radial->A) * 65536);
+		double det = B * B + A4 * (pdx * pdx + pdy * pdy - r1sq);
+		if (det <= 0.)
+		    t = (pixman_fixed_48_16_t) (B * invA);
+		else if (invert)
+		    t = (pixman_fixed_48_16_t) ((B + sqrt (det)) * invA);
 		else
-		    t = (pixman_fixed_48_16_t) ((-B + sqrt (det)) / (2.0 * radial->A) * 65536);
+		    t = (pixman_fixed_48_16_t) ((B - sqrt (det)) * invA);
 
 		*buffer = _pixman_gradient_walker_pixel (&walker, t);
 	    }
 	    ++buffer;
 
-	    rx += cx;
-	    ry += cy;
+	    pdx += cx;
+	    pdy += cy;
+	    B += cB;
 	}
     }
     else
@@ -273,7 +272,7 @@ radial_gradient_get_scanline_32 (pixman_image_t *image,
 		if (det < 0.0)
 		    det = 0.0;
 
-		if (radial->A < 0)
+		if (radial->A * radial->dr < 0)
 		    t = (pixman_fixed_48_16_t) ((-B - sqrt (det)) / (2.0 * radial->A) * 65536);
 		else
 		    t = (pixman_fixed_48_16_t) ((-B + sqrt (det)) / (2.0 * radial->A) * 65536);


More information about the xorg-commit mailing list