Backed out changeset 875c4ba4cbc8

This commit is contained in:
Robert O'Callahan 2009-08-25 15:46:20 -07:00
parent 0580caa913
commit ad0d3ca554

View File

@ -713,10 +713,10 @@ CreateGradientFunction (const cairo_gradient_pattern_t *gpat)
}
static CGFunctionRef
CreateRepeatingLinearGradientFunction (cairo_quartz_surface_t *surface,
const cairo_gradient_pattern_t *gpat,
CGPoint *start, CGPoint *end,
CGAffineTransform matrix)
CreateRepeatingGradientFunction (cairo_quartz_surface_t *surface,
const cairo_gradient_pattern_t *gpat,
CGPoint *start, CGPoint *end,
CGAffineTransform matrix)
{
cairo_pattern_t *pat;
float input_value_range[2];
@ -796,146 +796,6 @@ CreateRepeatingLinearGradientFunction (cairo_quartz_surface_t *surface,
&callbacks);
}
static void
UpdateRadialParameterToIncludePoint(double *max_t, CGPoint *center,
double dr, double dx, double dy,
double x, double y)
{
/* Compute a parameter t such that a circle centered at
(center->x + dx*t, center->y + dy*t) with radius dr*t contains the
point (x,y).
Let px = x - center->x, py = y - center->y.
Parameter values for which t is on the circle are given by
(px - dx*t)^2 + (py - dy*t)^2 = (t*dr)^2
Solving for t using the quadratic formula, and simplifying, we get
numerator = dx*px + dy*py +-
sqrt( dr^2*(px^2 + py^2) - (dx*py - dy*px)^2 )
denominator = dx^2 + dy^2 - dr^2
t = numerator/denominator
In CreateRepeatingRadialGradientFunction we know the outer circle
contains the inner circle. Therefore the distance between the circle
centers plus the radius of the inner circle is less than the radius of
the outer circle. (This is checked in _cairo_quartz_setup_radial_source.)
Therefore
dx^2 + dy^2 < dr^2
So the denominator is negative and the larger solution for t is given by
numerator = dx*px + dy*py -
sqrt( dr^2*(px^2 + py^2) - (dx*py - dy*px)^2 )
denominator = dx^2 + dy^2 - dr^2
t = numerator/denominator
dx^2 + dy^2 < dr^2 also ensures that the operand of sqrt is positive.
*/
double px = x - center->x;
double py = y - center->y;
double dx_py_minus_dy_px = dx*py - dy*px;
double numerator = dx*px + dy*py -
sqrt (dr*dr*(px*px + py*py) - dx_py_minus_dy_px*dx_py_minus_dy_px);
double denominator = dx*dx + dy*dy - dr*dr;
double t = numerator/denominator;
if (*max_t < t) {
*max_t = t;
}
}
/* This must only be called when one of the circles properly contains the other */
static CGFunctionRef
CreateRepeatingRadialGradientFunction (cairo_quartz_surface_t *surface,
const cairo_gradient_pattern_t *gpat,
CGPoint *start, double *start_radius,
CGPoint *end, double *end_radius)
{
CGRect clip = CGContextGetClipBoundingBox (surface->cgContext);
CGAffineTransform transform;
cairo_pattern_t *pat;
float input_value_range[2];
float output_value_ranges[8] = { 0.f, 1.f, 0.f, 1.f, 0.f, 1.f, 0.f, 1.f };
CGFunctionCallbacks callbacks = {
0, ComputeGradientValue, (CGFunctionReleaseInfoCallback) cairo_pattern_destroy
};
CGPoint *inner;
double *inner_radius;
CGPoint *outer;
double *outer_radius;
/* minimum and maximum t-parameter values that will make our gradient
cover the clipBox */
double t_min, t_max, t_temp;
/* outer minus inner */
double dr, dx, dy;
_cairo_quartz_cairo_matrix_to_quartz (&gpat->base.matrix, &transform);
/* clip is in cairo device coordinates; get it into cairo user space */
clip = CGRectApplyAffineTransform (clip, transform);
if (*start_radius < *end_radius) {
/* end circle contains start circle */
inner = start;
outer = end;
inner_radius = start_radius;
outer_radius = end_radius;
} else {
/* start circle contains end circle */
inner = end;
outer = start;
inner_radius = end_radius;
outer_radius = start_radius;
}
dr = *outer_radius - *inner_radius;
dx = outer->x - inner->x;
dy = outer->y - inner->y;
t_min = -(*inner_radius/dr);
inner->x += t_min*dx;
inner->y += t_min*dy;
*inner_radius = 0.;
t_temp = 0.;
UpdateRadialParameterToIncludePoint(&t_temp, inner, dr, dx, dy,
clip.origin.x, clip.origin.y);
UpdateRadialParameterToIncludePoint(&t_temp, inner, dr, dx, dy,
clip.origin.x + clip.size.width, clip.origin.y);
UpdateRadialParameterToIncludePoint(&t_temp, inner, dr, dx, dy,
clip.origin.x + clip.size.width, clip.origin.y + clip.size.height);
UpdateRadialParameterToIncludePoint(&t_temp, inner, dr, dx, dy,
clip.origin.x, clip.origin.y + clip.size.height);
/* UpdateRadialParameterToIncludePoint assumes t=0 means radius 0.
But for the parameter values we use with Quartz, t_min means radius 0.
Also, add a small fudge factor to avoid rounding issues. Since the
circles are alway expanding and containing the earlier circles, this is
OK. */
t_temp += 1e-6;
t_max = t_min + t_temp;
outer->x = inner->x + t_temp*dx;
outer->y = inner->y + t_temp*dy;
*outer_radius = t_temp*dr;
/* set the input range for the function -- the function knows how to
map values outside of 0.0 .. 1.0 to that range for REPEAT/REFLECT. */
if (*start_radius < *end_radius) {
input_value_range[0] = t_min;
input_value_range[1] = t_max;
} else {
input_value_range[0] = -t_max;
input_value_range[1] = -t_min;
}
if (_cairo_pattern_create_copy (&pat, &gpat->base))
/* quartz doesn't deal very well with malloc failing, so there's
* not much point in us trying either */
return NULL;
return CGFunctionCreate (pat,
1,
input_value_range,
4,
output_value_ranges,
&callbacks);
}
/* Obtain a CGImageRef from a #cairo_surface_t * */
static void
@ -1257,14 +1117,13 @@ _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface,
_cairo_fixed_to_double (lpat->p2.y));
if (abspat->extend == CAIRO_EXTEND_NONE ||
abspat->extend == CAIRO_EXTEND_PAD)
abspat->extend == CAIRO_EXTEND_PAD)
{
gradFunc = CreateGradientFunction (&lpat->base);
} else {
gradFunc = CreateRepeatingLinearGradientFunction (surface,
&lpat->base,
&start, &end,
surface->sourceTransform);
gradFunc = CreateRepeatingGradientFunction (surface,
&lpat->base,
&start, &end, surface->sourceTransform);
}
surface->sourceShading = CGShadingCreateAxial (rgb,
@ -1288,15 +1147,6 @@ _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
CGFunctionRef gradFunc;
CGColorSpaceRef rgb;
bool extend = abspat->extend == CAIRO_EXTEND_PAD;
double c1x = _cairo_fixed_to_double (rpat->c1.x);
double c1y = _cairo_fixed_to_double (rpat->c1.y);
double c2x = _cairo_fixed_to_double (rpat->c2.x);
double c2y = _cairo_fixed_to_double (rpat->c2.y);
double r1 = _cairo_fixed_to_double (rpat->r1);
double r2 = _cairo_fixed_to_double (rpat->r2);
double dx = c1x - c2x;
double dy = c1y - c2y;
double centerDistance = sqrt (dx*dx + dy*dy);
if (rpat->base.n_stops == 0) {
CGContextSetRGBStrokeColor (surface->cgContext, 0., 0., 0., 0.);
@ -1304,15 +1154,15 @@ _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
return DO_SOLID;
}
if (r2 <= centerDistance + r1 + 1e-6 && /* circle 2 doesn't contain circle 1 */
r1 <= centerDistance + r2 + 1e-6) { /* circle 1 doesn't contain circle 2 */
/* Quartz handles cases where neither circle contains the other very
* differently from pixman.
* Whatever the correct behaviour is, let's at least have only pixman's
* implementation to worry about.
* Note that this also catches the cases where r1 == r2.
if (abspat->extend == CAIRO_EXTEND_REPEAT ||
abspat->extend == CAIRO_EXTEND_REFLECT)
{
/* I started trying to map these to Quartz, but it's much harder
* then the linear case (I think it would involve doing multiple
* Radial shadings). So, instead, let's just render an image
* for pixman to draw the shading into, and use that.
*/
return _cairo_quartz_setup_fallback_source (surface, abspat);
return _cairo_quartz_setup_fallback_source (surface, &rpat->base.base);
}
mat = abspat->matrix;
@ -1321,25 +1171,18 @@ _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
rgb = CGColorSpaceCreateDeviceRGB();
start = CGPointMake (c1x, c1y);
end = CGPointMake (c2x, c2y);
start = CGPointMake (_cairo_fixed_to_double (rpat->c1.x),
_cairo_fixed_to_double (rpat->c1.y));
end = CGPointMake (_cairo_fixed_to_double (rpat->c2.x),
_cairo_fixed_to_double (rpat->c2.y));
if (abspat->extend == CAIRO_EXTEND_NONE ||
abspat->extend == CAIRO_EXTEND_PAD)
{
gradFunc = CreateGradientFunction (&rpat->base);
} else {
gradFunc = CreateRepeatingRadialGradientFunction (surface,
&rpat->base,
&start, &r1,
&end, &r2);
}
gradFunc = CreateGradientFunction (&rpat->base);
surface->sourceShading = CGShadingCreateRadial (rgb,
start,
r1,
_cairo_fixed_to_double (rpat->r1),
end,
r2,
_cairo_fixed_to_double (rpat->r2),
gradFunc,
extend, extend);