From 85227a9fa930bc79852be6b2206caeaf7beb2681 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 5 Mar 2007 23:40:54 +0100 Subject: [PATCH] update technical documentation in the radial gradient implementation and add support to the degenerate case where A == 0 --- pixman/src/fbcompose.c | 169 +++++++++++++++++------------------------------- 1 files changed, 59 insertions(+), 110 deletions(-) diff --git a/pixman/src/fbcompose.c b/pixman/src/fbcompose.c index 233b90c..2264303 100644 --- a/pixman/src/fbcompose.c +++ b/pixman/src/fbcompose.c @@ -3086,118 +3086,51 @@ static void fbFetchSourcePict(PicturePtr } else { /* - * In the radial gradient problem we are given two circles (c₁,r₁) and - * (c₂,r₂) that define the gradient itself. Then, for any point p, we + * In the radial gradient problem we are given two circles (C1,R1) and (C2,R2) + * that define the gradient itself. Then, for any point p, we * must compute the value(s) of t within [0.0, 1.0] representing the * circle(s) that would color the point. * - * There are potentially two values of t since the point p can be - * colored by both sides of the circle, (which happens whenever one - * circle is not entirely contained within the other). + * We can define an "intermediate" circle as: * - * If we solve for a value of t that is outside of [0.0, 1.0] then we - * use the extend mode (NONE, REPEAT, REFLECT, or PAD) to map to a - * value within [0.0, 1.0]. + * Ct = C1 + t*(C2-C1) + * Rt = R1 + t*(R2-R1) * - * Here is an illustration of the problem: + * its equation being: * - * p₂ - * p • - * • ╲ - * · ╲r₂ - * p₁ · ╲ - * • θ╲ - * ╲ ╌╌• - * ╲r₁ · c₂ - * θ╲ · - * ╌╌• - * c₁ + * (X-Ct.X)^2 + (Y-Ct.Y)^2 = Rt^2 * - * Given (c₁,r₁), (c₂,r₂) and p, we must find an angle θ such that two - * points p₁ and p₂ on the two circles are collinear with p. Then, the - * desired value of t is the ratio of the length of p₁p to the length - * of p₁p₂. + * let: + * dX = C2.x - C1.x + * dY = C2.y - C1.y + * dR = R2 - R1 + * rx = X - C1.x + * ry = Y - C1.y * - * So, we have six unknown values: (p₁x, p₁y), (p₂x, p₂y), θ and t. - * We can also write six equations that constrain the problem: + * the equation can be re-written as: * - * Point p₁ is a distance r₁ from c₁ at an angle of θ: + * (rx - t*dX)^2 + (ry - t*dY)^2 = (R1 + t*dR)^2 * - * 1. p₁x = c₁x + r₁·cos θ - * 2. p₁y = c₁y + r₁·sin θ + * after simplification, this becomes: * - * Point p₂ is a distance r₂ from c₂ at an angle of θ: + * A*t^2 - 2*B*t + C = 0 * - * 3. p₂x = c₂x + r2·cos θ - * 4. p₂y = c₂y + r2·sin θ + * for A = dX^2 + dY^2 - dR^2 + * B = rx*dX + ry*dY + R1*dR + * C = rx^2 + ry^2 - R1^2 * - * Point p lies at a fraction t along the line segment p₁p₂: + * Note that A is a constant. (A == 0 && B == 0) corresponds to the case + * where both circles are identical, and there is no solution. * - * 5. px = t·p₂x + (1-t)·p₁x - * 6. py = t·p₂y + (1-t)·p₁y + * A == 0 && B != 0 correspond to the case where the circles touch each + * other at a single point of contact, there is only a single solution + * t = C/(2*B) in this case * - * To solve, first subtitute 1-4 into 5 and 6: + * for A != 0, we can compute det = B^2 - A*C * - * px = t·(c₂x + r₂·cos θ) + (1-t)·(c₁x + r₁·cos θ) - * py = t·(c₂y + r₂·sin θ) + (1-t)·(c₁y + r₁·sin θ) - * - * Then solve each for cos θ and sin θ expressed as a function of t: - * - * cos θ = (-(c₂x - c₁x)·t + (px - c₁x)) / ((r₂-r₁)·t + r₁) - * sin θ = (-(c₂y - c₁y)·t + (py - c₁y)) / ((r₂-r₁)·t + r₁) - * - * To simplify this a bit, we define new variables for several of the - * common terms as shown below: - * - * p₂ - * p • - * • ╲ - * · ┆ ╲r₂ - * p₁ · ┆ ╲ - * • pdy┆ ╲ - * ╲ ┆ •c₂ - * ╲r₁ ┆ · ┆ - * ╲ ·┆ ┆cdy - * •╌╌╌╌┴╌╌╌╌╌╌╌┘ - * c₁ pdx cdx - * - * cdx = (c₂x - c₁x) - * cdy = (c₂y - c₁y) - * dr = r₂-r₁ - * pdx = px - c₁x - * pdy = py - c₁y - * - * Note that cdx, cdy, and dr do not depend on point p at all, so can - * be pre-computed for the entire gradient. The simplifed equations - * are now: - * - * cos θ = (-cdx·t + pdx) / (dr·t + r₁) - * sin θ = (-cdy·t + pdy) / (dr·t + r₁) - * - * Finally, to get a single function of t and eliminate the last - * unknown θ, we use the identity sin²θ + cos²θ = 1. First, square - * each equation, (we knew a quadratic was coming since it must be - * possible to obtain two solutions in some cases): - * - * cos²θ = (cdx²t² - 2·cdx·pdx·t + pdx²) / (dr²·t² + 2·r₁·dr·t + r₁²) - * sin²θ = (cdy²t² - 2·cdy·pdy·t + pdy²) / (dr²·t² + 2·r₁·dr·t + r₁²) - * - * Then add both together, set the result equal to 1, and express as a - * standard quadratic equation in t of the form At² + Bt + C = 0 - * - * (cdx² + cdy² - dr²)·t² - 2·(cdx·pdx + cdy·pdy + r₁·dr)·t + (pdx² + pdy² - r₁²) = 0 - * - * In other words: - * - * A = cdx² + cdy² - dr² - * B = -2·(pdx·cdx + pdy·cdy + r₁·dr) - * C = pdx² + pdy² - r₁² - * - * And again, notice that A does not depend on p, so can be - * precomputed. From here we just use the quadratic formula to solve - * for t: - * - * t = (-2·B ± ⎷(B² - 4·A·C)) / 2·A + * if det < 0, there is no solution, but we *force* det to 0 to get one + * if det > 0, we have two possible solutions, we choose one according + * to the sign of A */ /* radial or conical */ Bool projective = FALSE; @@ -3230,33 +3163,49 @@ static void fbFetchSourcePict(PicturePtr pixman_radial_gradient_image_t *radial; radial = &pGradient->radial; if (!projective) { + double c1x = xFixedToDouble (radial->c1.x); + double c1y = xFixedToDouble (radial->c1.y); + double r1 = xFixedToDouble (radial->c1.radius); + + rx -= c1x; + ry -= c1y; + + /* handle the degenerate case A == 0 here */ + if (radial->A == 0.) { + while (buffer < end) { + if (!mask || *mask++ & maskBits) + { + double B = rx*radial->cdx + ry*radial->cdy + r1*radial->dr; + double C = rx*rx + ry*ry - r1*r1; + xFixed_48_16 t; + + t = (xFixed_48_16) (C / (2*B)); + + *buffer = _gradient_walker_pixel (&walker, t); + } + rx += cx; + ry += cy; + ++buffer; + } + } while (buffer < end) { if (!mask || *mask++ & maskBits) { - double pdx, pdy; double B, C; double det; - double c1x = xFixedToDouble (radial->c1.x); - double c1y = xFixedToDouble (radial->c1.y); - double r1 = xFixedToDouble (radial->c1.radius); xFixed_48_16 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); + B = (rx * radial->cdx + ry * radial->cdy + r1 * radial->dr); + C = (rx * rx + ry * ry - r1 * r1); - det = (B * B) - (4 * radial->A * C); + det = (B * B) - (radial->A * C); if (det < 0.0) det = 0.0; if (radial->A < 0) - t = (xFixed_48_16) ((- B - sqrt(det)) / (2.0 * radial->A) * 65536); + t = (xFixed_48_16) ((B - sqrt(det)) / (radial->A) * 65536); else - t = (xFixed_48_16) ((- B + sqrt(det)) / (2.0 * radial->A) * 65536); + t = (xFixed_48_16) ((B + sqrt(det)) / (radial->A) * 65536); *buffer = _gradient_walker_pixel (&walker, t); } -- 1.4.1 From e01ac93070420757b76df6d2f8cf912a5baedba2 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 5 Mar 2007 23:53:36 +0100 Subject: [PATCH] implement forward differencing to speed up radial gradient computations --- pixman/src/fbcompose.c | 33 ++++++++++++++++++++++----------- 1 files changed, 22 insertions(+), 11 deletions(-) diff --git a/pixman/src/fbcompose.c b/pixman/src/fbcompose.c index 2264303..0dd0730 100644 --- a/pixman/src/fbcompose.c +++ b/pixman/src/fbcompose.c @@ -3131,6 +3131,14 @@ static void fbFetchSourcePict(PicturePtr * if det < 0, there is no solution, but we *force* det to 0 to get one * if det > 0, we have two possible solutions, we choose one according * to the sign of A + * + * we compute the successive values of B and C throught forward differencing + * on each pixel, we increment rx and ry by constant values: + * + * B(x+ix,y+iy) - B(x,y) = ix*dX + iy*dY which is constant + * C(x+ix,y+iy) - C(x,y) = ix^2 + 2*(rx*ix+ry*iY) which is linear in rx and ry, so + * it increases by 2*(ix^2 + iy^2) + * each step */ /* radial or conical */ Bool projective = FALSE; @@ -3166,38 +3174,40 @@ static void fbFetchSourcePict(PicturePtr double c1x = xFixedToDouble (radial->c1.x); double c1y = xFixedToDouble (radial->c1.y); double r1 = xFixedToDouble (radial->c1.radius); + double B, dB, C, dC, ddC; rx -= c1x; ry -= c1y; + B = rx*radial->cdx + ry*radial->cdy + r1*radial->dr; + dB = cx*radial->cdx + cy*radial->cdy; + C = rx*rx + ry*ry - r1*r1; + dC = cx*cx + cy*cy + 2*(rx*cx + ry*cy); + ddC = 2*(cx*cx + cy*cy); + /* handle the degenerate case A == 0 here */ - if (radial->A == 0.) { + if (radial->A == 0.0) { while (buffer < end) { if (!mask || *mask++ & maskBits) { - double B = rx*radial->cdx + ry*radial->cdy + r1*radial->dr; - double C = rx*rx + ry*ry - r1*r1; xFixed_48_16 t; t = (xFixed_48_16) (C / (2*B)); *buffer = _gradient_walker_pixel (&walker, t); } - rx += cx; - ry += cy; + B += dB; + C += dC; + dC += ddC; ++buffer; } } while (buffer < end) { if (!mask || *mask++ & maskBits) { - double B, C; double det; xFixed_48_16 t; - B = (rx * radial->cdx + ry * radial->cdy + r1 * radial->dr); - C = (rx * rx + ry * ry - r1 * r1); - det = (B * B) - (radial->A * C); if (det < 0.0) det = 0.0; @@ -3209,9 +3219,10 @@ static void fbFetchSourcePict(PicturePtr *buffer = _gradient_walker_pixel (&walker, t); } + B += dB; + C += dC; + dC += ddC; ++buffer; - rx += cx; - ry += cy; } } else { /* In cairo, we don't have projective transformed -- 1.4.1 From 6386e929b0709fbdb4acc98105d0d61c82403e61 Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 6 Mar 2007 00:28:37 +0100 Subject: [PATCH] remove multiplications from within the radial gradient computation loops --- pixman/src/fbcompose.c | 50 ++++++++++++++++++++++++++++++++++-------------- 1 files changed, 35 insertions(+), 15 deletions(-) diff --git a/pixman/src/fbcompose.c b/pixman/src/fbcompose.c index 0dd0730..fb93079 100644 --- a/pixman/src/fbcompose.c +++ b/pixman/src/fbcompose.c @@ -3139,6 +3139,19 @@ static void fbFetchSourcePict(PicturePtr * C(x+ix,y+iy) - C(x,y) = ix^2 + 2*(rx*ix+ry*iY) which is linear in rx and ry, so * it increases by 2*(ix^2 + iy^2) * each step + * + * we can also divide everything by A if it is not 0, we're left with: + * + * t^2 - 2*b*t + c = 0 with b = B/A and c = C/A + * + * solutions are given with: + * det = b^2 - c + * if (det < 0) + * det = 0; + * + * t1 = b - sqrt(det) + * t2 = b + sqrt(det) + * */ /* radial or conical */ Bool projective = FALSE; @@ -3174,17 +3187,17 @@ static void fbFetchSourcePict(PicturePtr double c1x = xFixedToDouble (radial->c1.x); double c1y = xFixedToDouble (radial->c1.y); double r1 = xFixedToDouble (radial->c1.radius); - double B, dB, C, dC, ddC; + double B, dB, C, dC, ddC, invA = 1./radial->A; rx -= c1x; ry -= c1y; - B = rx*radial->cdx + ry*radial->cdy + r1*radial->dr; - dB = cx*radial->cdx + cy*radial->cdy; - C = rx*rx + ry*ry - r1*r1; - dC = cx*cx + cy*cy + 2*(rx*cx + ry*cy); - ddC = 2*(cx*cx + cy*cy); - + B = (rx*radial->cdx + ry*radial->cdy + r1*radial->dr)*invA; + dB = (cx*radial->cdx + cy*radial->cdy)*invA; + C = (rx*rx + ry*ry - r1*r1)*invA; + dC = (cx*cx + cy*cy + 2*(rx*cx + ry*cy))*invA; + ddC = 2*(cx*cx + cy*cy)*invA; + /* handle the degenerate case A == 0 here */ if (radial->A == 0.0) { while (buffer < end) { @@ -3208,14 +3221,21 @@ static void fbFetchSourcePict(PicturePtr double det; xFixed_48_16 t; - det = (B * B) - (radial->A * C); - if (det < 0.0) - det = 0.0; - - if (radial->A < 0) - t = (xFixed_48_16) ((B - sqrt(det)) / (radial->A) * 65536); - else - t = (xFixed_48_16) ((B + sqrt(det)) / (radial->A) * 65536); + det = (B * B) - C; + if (det <= 0.0) + t = (xFixed_48_16)(B * 65536); + else { + /* the old code did the following: + * + * if (A < 0) t = B/A - sqrt(det)/A + * if (A > 0) t = B/A + sqrt(det)/A + * + * since we have divided both B and C by A here + * we can use a *single* solution here to get + * exactly the same values + */ + t = (xFixed_48_16) ((B + sqrt(det)) * 65536); + } *buffer = _gradient_walker_pixel (&walker, t); } -- 1.4.1 From 5dc4dd714397c05db986fc03abc2b25aa810a38e Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 6 Mar 2007 00:41:51 +0100 Subject: [PATCH] forward difference the determinant in radial gradient computation loop saves a multiply and a substraction on each iteration --- pixman/src/fbcompose.c | 63 +++++++++++++++++++++++++++--------------------- 1 files changed, 36 insertions(+), 27 deletions(-) diff --git a/pixman/src/fbcompose.c b/pixman/src/fbcompose.c index fb93079..6801f3c 100644 --- a/pixman/src/fbcompose.c +++ b/pixman/src/fbcompose.c @@ -3152,6 +3152,12 @@ static void fbFetchSourcePict(PicturePtr * t1 = b - sqrt(det) * t2 = b + sqrt(det) * + * finally, we can also forward-difference the determinant to remove + * one mult and one substraction from the loop: + * + * det = b^2 - c + * ddet = 2*b*db - dc + * dddet = 2*db*db - ddc */ /* radial or conical */ Bool projective = FALSE; @@ -3214,35 +3220,38 @@ static void fbFetchSourcePict(PicturePtr dC += ddC; ++buffer; } - } - while (buffer < end) { - if (!mask || *mask++ & maskBits) - { - double det; - xFixed_48_16 t; - - det = (B * B) - C; - if (det <= 0.0) - t = (xFixed_48_16)(B * 65536); - else { - /* the old code did the following: - * - * if (A < 0) t = B/A - sqrt(det)/A - * if (A > 0) t = B/A + sqrt(det)/A - * - * since we have divided both B and C by A here - * we can use a *single* solution here to get - * exactly the same values - */ - t = (xFixed_48_16) ((B + sqrt(det)) * 65536); - } + } else { + double D = B*B - C; + double dD = 2*B*dB + dB*dB - dC; + double ddD = 2*dB*dB - ddC; + + while (buffer < end) { + if (!mask || *mask++ & maskBits) + { + xFixed_48_16 t; + + if (D <= 0.0) + t = (xFixed_48_16)(B * 65536); + else { + /* the old code did the following: + * + * if (A < 0) t = B/A - sqrt(det)/A + * if (A > 0) t = B/A + sqrt(det)/A + * + * since we have divided both B and C by A here + * we can use a *single* solution here to get + * exactly the same values + */ + t = (xFixed_48_16) ((B + sqrt(D)) * 65536); + } - *buffer = _gradient_walker_pixel (&walker, t); + *buffer = _gradient_walker_pixel (&walker, t); + } + B += dB; + D += dD; + dD += ddD; + ++buffer; } - B += dB; - C += dC; - dC += ddC; - ++buffer; } } else { /* In cairo, we don't have projective transformed -- 1.4.1 From ff009d862c1c6f04780dbec40dcb99d1b4610beb Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 6 Mar 2007 13:07:51 +0100 Subject: [PATCH] update documentation and better handle degenerate cases --- pixman/src/fbcompose.c | 15 ++++++++++----- 1 files changed, 10 insertions(+), 5 deletions(-) diff --git a/pixman/src/fbcompose.c b/pixman/src/fbcompose.c index 6801f3c..26cdf45 100644 --- a/pixman/src/fbcompose.c +++ b/pixman/src/fbcompose.c @@ -3156,7 +3156,7 @@ static void fbFetchSourcePict(PicturePtr * one mult and one substraction from the loop: * * det = b^2 - c - * ddet = 2*b*db - dc + * ddet = 2*b*db + db*db - dc * dddet = 2*db*db - ddc */ /* radial or conical */ @@ -3204,16 +3204,21 @@ static void fbFetchSourcePict(PicturePtr dC = (cx*cx + cy*cy + 2*(rx*cx + ry*cy))*invA; ddC = 2*(cx*cx + cy*cy)*invA; +#define NEARLY_ZERO(x) (fabs(x) < 1e-51) + /* handle the degenerate case A == 0 here */ - if (radial->A == 0.0) { + if (NEARLY_ZERO(radial->A)) { while (buffer < end) { if (!mask || *mask++ & maskBits) { - xFixed_48_16 t; + xFixed_48_16 t; - t = (xFixed_48_16) (C / (2*B)); + if (NEARLY_ZERO(B)) + t = 0; + else + t = (xFixed_48_16) (C / (2*B)); - *buffer = _gradient_walker_pixel (&walker, t); + *buffer = _gradient_walker_pixel (&walker, t); } B += dB; C += dC; -- 1.4.1 From 5d1c1dc90b08a57884878ab11c53009e96d6d2d7 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 12 Mar 2007 13:28:28 +0100 Subject: [PATCH] getting rid of the need_reset field in pixman's gradient_walker_t --- pixman/src/fbcompose.c | 19 +++++++------------ 1 files changed, 7 insertions(+), 12 deletions(-) diff --git a/pixman/src/fbcompose.c b/pixman/src/fbcompose.c index 26cdf45..5b35dec 100644 --- a/pixman/src/fbcompose.c +++ b/pixman/src/fbcompose.c @@ -2746,7 +2746,6 @@ typedef struct int num_stops; unsigned int spread; - int need_reset; } GradientWalker; static void @@ -2757,15 +2756,13 @@ _gradient_walker_init (GradientWalker * walker->num_stops = pGradient->gradient.nstops; walker->stops = pGradient->gradient.stops; walker->left_x = 0; - walker->right_x = 0x10000; + walker->right_x = 0; /* will force reset */ walker->stepper = 0; walker->left_ag = 0; walker->left_rb = 0; walker->right_ag = 0; walker->right_rb = 0; walker->spread = spread; - - walker->need_reset = TRUE; } static void @@ -2913,14 +2910,12 @@ _gradient_walker_reset (GradientWalker int32_t width = right_x - left_x; walker->stepper = ((1 << 24) + width/2)/width; } - - walker->need_reset = FALSE; } #define GRADIENT_WALKER_NEED_RESET(w,x) \ - ( (w)->need_reset || (x) < (w)->left_x || (x) >= (w)->right_x) + ( (x) < (w)->left_x || (x) >= (w)->right_x) + -/* the following assumes that GRADIENT_WALKER_NEED_RESET(w,x) is FALSE */ static CARD32 _gradient_walker_pixel (GradientWalker *walker, xFixed_32_32 x) @@ -3197,7 +3192,7 @@ static void fbFetchSourcePict(PicturePtr rx -= c1x; ry -= c1y; - + B = (rx*radial->cdx + ry*radial->cdy + r1*radial->dr)*invA; dB = (cx*radial->cdx + cy*radial->cdy)*invA; C = (rx*rx + ry*ry - r1*r1)*invA; @@ -3212,12 +3207,12 @@ #define NEARLY_ZERO(x) (fabs(x) < 1e- if (!mask || *mask++ & maskBits) { xFixed_48_16 t; - + if (NEARLY_ZERO(B)) t = 0; else t = (xFixed_48_16) (C / (2*B)); - + *buffer = _gradient_walker_pixel (&walker, t); } B += dB; @@ -3229,7 +3224,7 @@ #define NEARLY_ZERO(x) (fabs(x) < 1e- double D = B*B - C; double dD = 2*B*dB + dB*dB - dC; double ddD = 2*dB*dB - ddC; - + while (buffer < end) { if (!mask || *mask++ & maskBits) { -- 1.4.1 From 1c435c1048e04cfa898c4e996ccb20c2c0d5ba18 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 12 Mar 2007 14:44:39 +0100 Subject: [PATCH] optimize gradient fill for the case where all color stops are opaque --- pixman/src/fbcompose.c | 203 +++++++++++++++++++++++++++++++++++++----------- 1 files changed, 156 insertions(+), 47 deletions(-) diff --git a/pixman/src/fbcompose.c b/pixman/src/fbcompose.c index 5b35dec..5fa3ab8 100644 --- a/pixman/src/fbcompose.c +++ b/pixman/src/fbcompose.c @@ -2745,6 +2745,7 @@ typedef struct pixman_gradient_stop_t *stops; int num_stops; unsigned int spread; + int all_opaque; } GradientWalker; @@ -2763,6 +2764,20 @@ _gradient_walker_init (GradientWalker * walker->right_ag = 0; walker->right_rb = 0; walker->spread = spread; + + { + int all_opaque = 1; + int nn; + + for (nn = 0; nn < walker->num_stops; nn++) { + if ((walker->stops[nn].color.alpha >> 8) != 0xFF) { + all_opaque = 0; + break; + } + } + + walker->all_opaque = all_opaque; + } } static void @@ -2948,6 +2963,31 @@ _gradient_walker_pixel (GradientWalker return (color | (t1 & 0xff00ff) | (t2 & 0xff00)); } + +static CARD32 +_gradient_walker_pixel_opaque (GradientWalker *walker, + xFixed_32_32 x) +{ + int dist, idist; + uint32_t t1, t2; + + if (GRADIENT_WALKER_NEED_RESET (walker, x)) + _gradient_walker_reset (walker, x); + + dist = ((int)(x - walker->left_x)*walker->stepper) >> 16; + idist = 256 - dist; + + /* combined INTERPOLATE and premultiply */ + t1 = walker->left_rb*idist + walker->right_rb*dist; + t1 = (t1 >> 8) & 0xff00ff; + + t2 = walker->left_ag*idist + walker->right_ag*dist; + t2 &= 0xff00ff00; + + return (t1 | t2); +} + + static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *buffer, CARD32 *mask, CARD32 maskBits) { SourcePictPtr pGradient = pict->pSourcePict; @@ -3011,21 +3051,44 @@ static void fbFetchSourcePict(PicturePtr } else { - if (!mask) { - while (buffer < end) - { - *buffer = _gradient_walker_pixel (&walker, t); - buffer += 1; - t += inc; + if (walker.all_opaque) + { + if (!mask) { + while (buffer < end) + { + *buffer = _gradient_walker_pixel_opaque (&walker, t); + buffer += 1; + t += inc; + } + } else { + while (buffer < end) { + if (*mask++ & maskBits) + { + *buffer = _gradient_walker_pixel_opaque (&walker, t); + } + buffer += 1; + t += inc; + } } - } else { - while (buffer < end) { - if (*mask++ & maskBits) + } + else + { + if (!mask) { + while (buffer < end) { *buffer = _gradient_walker_pixel (&walker, t); + buffer += 1; + t += inc; + } + } else { + while (buffer < end) { + if (*mask++ & maskBits) + { + *buffer = _gradient_walker_pixel (&walker, t); + } + buffer += 1; + t += inc; } - buffer += 1; - t += inc; } } } @@ -3203,54 +3266,100 @@ #define NEARLY_ZERO(x) (fabs(x) < 1e- /* handle the degenerate case A == 0 here */ if (NEARLY_ZERO(radial->A)) { - while (buffer < end) { - if (!mask || *mask++ & maskBits) - { - xFixed_48_16 t; + if (walker.all_opaque) + { + while (buffer < end) { + if (!mask || *mask++ & maskBits) + { + xFixed_48_16 t; - if (NEARLY_ZERO(B)) - t = 0; - else - t = (xFixed_48_16) (C / (2*B)); + if (NEARLY_ZERO(B)) + t = 0; + else + t = (xFixed_48_16) (C / (2*B)); - *buffer = _gradient_walker_pixel (&walker, t); + *buffer = _gradient_walker_pixel_opaque (&walker, t); + } + B += dB; + C += dC; + dC += ddC; + ++buffer; + } + } + else + { + while (buffer < end) { + if (!mask || *mask++ & maskBits) + { + xFixed_48_16 t; + + if (NEARLY_ZERO(B)) + t = 0; + else + t = (xFixed_48_16) (C / (2*B)); + + *buffer = _gradient_walker_pixel (&walker, t); + } + B += dB; + C += dC; + dC += ddC; + ++buffer; } - B += dB; - C += dC; - dC += ddC; - ++buffer; } } else { double D = B*B - C; double dD = 2*B*dB + dB*dB - dC; double ddD = 2*dB*dB - ddC; - while (buffer < end) { - if (!mask || *mask++ & maskBits) - { - xFixed_48_16 t; - - if (D <= 0.0) - t = (xFixed_48_16)(B * 65536); - else { - /* the old code did the following: - * - * if (A < 0) t = B/A - sqrt(det)/A - * if (A > 0) t = B/A + sqrt(det)/A - * - * since we have divided both B and C by A here - * we can use a *single* solution here to get - * exactly the same values - */ - t = (xFixed_48_16) ((B + sqrt(D)) * 65536); + if (walker.all_opaque) + { + while (buffer < end) { + if (!mask || *mask++ & maskBits) + { + xFixed_48_16 t; + + if (D <= 0.0) + t = (xFixed_48_16)(B * 65536); + else { + /* the old code did the following: + * + * if (A < 0) t = B/A - sqrt(det)/A + * if (A > 0) t = B/A + sqrt(det)/A + * + * since we have divided both B and C by A here + * we can use a *single* solution here to get + * exactly the same values + */ + t = (xFixed_48_16) ((B + sqrt(D)) * 65536); + } + + *buffer = _gradient_walker_pixel_opaque (&walker, t); } + B += dB; + D += dD; + dD += ddD; + ++buffer; + } + } + else + { + while (buffer < end) { + if (!mask || *mask++ & maskBits) + { + xFixed_48_16 t; - *buffer = _gradient_walker_pixel (&walker, t); + if (D <= 0.0) + t = (xFixed_48_16)(B * 65536); + else + t = (xFixed_48_16) ((B + sqrt(D)) * 65536); + + *buffer = _gradient_walker_pixel (&walker, t); + } + B += dB; + D += dD; + dD += ddD; + ++buffer; } - B += dB; - D += dD; - dD += ddD; - ++buffer; } } } else { -- 1.4.1