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