Gradient fixes
* Port fix for bug 7685 from pixman. Patch by Carl Worth * Add projective version of radial gradient code. * Make sure that all Pict*Gradient types have PictGradient as prefix, since code in various places relies on that.
This commit is contained in:
parent
38d14e8589
commit
84838268b3
203
fb/fbcompose.c
203
fb/fbcompose.c
|
@ -3148,13 +3148,128 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *
|
|||
}
|
||||
}
|
||||
} 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
|
||||
* 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).
|
||||
*
|
||||
* 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].
|
||||
*
|
||||
* Here is an illustration of the problem:
|
||||
*
|
||||
* p₂
|
||||
* p •
|
||||
* • ╲
|
||||
* · ╲r₂
|
||||
* p₁ · ╲
|
||||
* • θ╲
|
||||
* ╲ ╌╌•
|
||||
* ╲r₁ · c₂
|
||||
* θ╲ ·
|
||||
* ╌╌•
|
||||
* c₁
|
||||
*
|
||||
* 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₂.
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* Point p₁ is a distance r₁ from c₁ at an angle of θ:
|
||||
*
|
||||
* 1. p₁x = c₁x + r₁·cos θ
|
||||
* 2. p₁y = c₁y + r₁·sin θ
|
||||
*
|
||||
* Point p₂ is a distance r₂ from c₂ at an angle of θ:
|
||||
*
|
||||
* 3. p₂x = c₂x + r2·cos θ
|
||||
* 4. p₂y = c₂y + r2·sin θ
|
||||
*
|
||||
* Point p lies at a fraction t along the line segment p₁p₂:
|
||||
*
|
||||
* 5. px = t·p₂x + (1-t)·p₁x
|
||||
* 6. py = t·p₂y + (1-t)·p₁y
|
||||
*
|
||||
* To solve, first subtitute 1-4 into 5 and 6:
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
/* radial or conical */
|
||||
Bool affine = TRUE;
|
||||
double cx = 1.;
|
||||
double cy = 0.;
|
||||
double cz = 0.;
|
||||
double rx = x;
|
||||
double ry = y;
|
||||
double rx = x + 0.5;
|
||||
double ry = y + 0.5;
|
||||
double rz = 1.;
|
||||
|
||||
if (pict->transform) {
|
||||
|
@ -3176,25 +3291,38 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *
|
|||
}
|
||||
|
||||
if (pGradient->type == SourcePictTypeRadial) {
|
||||
PictRadialGradient *radial;
|
||||
radial = &pGradient->radial;
|
||||
if (affine) {
|
||||
rx -= pGradient->radial.fx;
|
||||
ry -= pGradient->radial.fy;
|
||||
|
||||
while (buffer < end) {
|
||||
double b, c, det, s;
|
||||
|
||||
if (!mask || *mask++ & maskBits)
|
||||
{
|
||||
xFixed_48_16 t;
|
||||
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;
|
||||
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);
|
||||
|
||||
det = (B * B) - (4 * 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);
|
||||
else
|
||||
t = (xFixed_48_16) ((- B + sqrt(det)) / (2.0 * radial->A) * 65536);
|
||||
|
||||
b = 2*(rx*pGradient->radial.dx + ry*pGradient->radial.dy);
|
||||
c = -(rx*rx + ry*ry);
|
||||
det = (b * b) - (4 * pGradient->radial.a * c);
|
||||
s = (-b + sqrt(det))/(2. * pGradient->radial.a);
|
||||
|
||||
t = (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536);
|
||||
|
||||
WRITE(buffer, _gradient_walker_pixel (&walker, t));
|
||||
WRITE(buffer, _gradient_walker_pixel (&walker, t));
|
||||
}
|
||||
++buffer;
|
||||
|
||||
|
@ -3202,35 +3330,50 @@ static void fbFetchSourcePict(PicturePtr pict, int x, int y, int width, CARD32 *
|
|||
ry += cy;
|
||||
}
|
||||
} else {
|
||||
/* projective */
|
||||
while (buffer < end) {
|
||||
double x, y;
|
||||
double b, c, det, s;
|
||||
|
||||
if (!mask || *mask++ & maskBits)
|
||||
{
|
||||
xFixed_48_16 t;
|
||||
|
||||
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;
|
||||
xFixed_48_16 t;
|
||||
double x, y;
|
||||
|
||||
if (rz != 0) {
|
||||
x = rx/rz;
|
||||
y = ry/rz;
|
||||
} else {
|
||||
x = y = 0.;
|
||||
}
|
||||
x -= pGradient->radial.fx;
|
||||
y -= pGradient->radial.fy;
|
||||
b = 2*(x*pGradient->radial.dx + y*pGradient->radial.dy);
|
||||
c = -(x*x + y*y);
|
||||
det = (b * b) - (4 * pGradient->radial.a * c);
|
||||
s = (-b + sqrt(det))/(2. * pGradient->radial.a);
|
||||
t = (xFixed_48_16)((s*pGradient->radial.m + pGradient->radial.b)*65536);
|
||||
|
||||
WRITE(buffer, _gradient_walker_pixel (&walker, t));
|
||||
pdx = x - c1x;
|
||||
pdy = y - 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 = (xFixed_48_16) ((- B - sqrt(det)) / (2.0 * radial->A) * 65536);
|
||||
else
|
||||
t = (xFixed_48_16) ((- B + sqrt(det)) / (2.0 * radial->A) * 65536);
|
||||
|
||||
WRITE(buffer, _gradient_walker_pixel (&walker, t));
|
||||
}
|
||||
++buffer;
|
||||
|
||||
rx += cx;
|
||||
ry += cy;
|
||||
rz += cz;
|
||||
rz += cz;
|
||||
}
|
||||
}
|
||||
} else /* SourcePictTypeConical */ {
|
||||
|
|
|
@ -1051,6 +1051,7 @@ CreateRadialGradientPicture (Picture pid, xPointFixed *inner, xPointFixed *outer
|
|||
radial = &pPicture->pSourcePict->radial;
|
||||
|
||||
radial->type = SourcePictTypeRadial;
|
||||
#if 0
|
||||
{
|
||||
double x = (double)innerRadius / (double)outerRadius;
|
||||
radial->dx = (outer->x - inner->x);
|
||||
|
@ -1066,7 +1067,20 @@ CreateRadialGradientPicture (Picture pid, xPointFixed *inner, xPointFixed *outer
|
|||
x = outerRadius/65536.;
|
||||
radial->a = x*x - radial->dx*radial->dx - radial->dy*radial->dy;
|
||||
}
|
||||
|
||||
#endif
|
||||
radial->c1.x = inner->x;
|
||||
radial->c1.y = inner->y;
|
||||
radial->c1.radius = innerRadius;
|
||||
radial->c2.x = outer->x;
|
||||
radial->c2.y = outer->y;
|
||||
radial->c2.radius = outerRadius;
|
||||
radial->cdx = (radial->c2.x - radial->c1.x) / 65536.;
|
||||
radial->cdy = (radial->c2.y - radial->c1.y) / 65536.;
|
||||
radial->dr = (radial->c2.radius - radial->c1.radius) / 65536.;
|
||||
radial->A = ( radial->cdx * radial->cdx
|
||||
+ radial->cdy * radial->cdy
|
||||
- radial->dr * radial->dr);
|
||||
|
||||
initGradient(pPicture->pSourcePict, nStops, stops, colors, error);
|
||||
if (*error) {
|
||||
xfree(pPicture);
|
||||
|
|
|
@ -105,17 +105,26 @@ typedef struct _PictLinearGradient {
|
|||
xPointFixed p2;
|
||||
} PictLinearGradient, *PictLinearGradientPtr;
|
||||
|
||||
typedef struct _PictCircle {
|
||||
xFixed x;
|
||||
xFixed y;
|
||||
xFixed radius;
|
||||
} PictCircle, *PictCirclePtr;
|
||||
|
||||
typedef struct _PictRadialGradient {
|
||||
unsigned int type;
|
||||
unsigned int class;
|
||||
int nstops;
|
||||
PictGradientStopPtr stops;
|
||||
double fx;
|
||||
double fy;
|
||||
double dx;
|
||||
double dy;
|
||||
double a;
|
||||
double m;
|
||||
double b;
|
||||
int stopRange;
|
||||
CARD32 *colorTable;
|
||||
int colorTableSize;
|
||||
PictCircle c1;
|
||||
PictCircle c2;
|
||||
double cdx;
|
||||
double cdy;
|
||||
double dr;
|
||||
double A;
|
||||
} PictRadialGradient, *PictRadialGradientPtr;
|
||||
|
||||
typedef struct _PictConicalGradient {
|
||||
|
|
Loading…
Reference in New Issue
Block a user