зеркало из https://github.com/mozilla/pjs.git
Backed out changeset 6db996debbd1
This commit is contained in:
Родитель
0f39b94346
Коммит
dffbaa3961
|
@ -715,90 +715,72 @@ CreateGradientFunction (const cairo_gradient_pattern_t *gpat)
|
|||
&gradient_callbacks);
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateLinearParametersToIncludePoint(double *min_t, double *max_t, CGPoint *start,
|
||||
double dx, double dy,
|
||||
double x, double y)
|
||||
{
|
||||
/* Compute a parameter t such that a line perpendicular to the (dx,dy)
|
||||
vector, passing through (start->x + dx*t, start->y + dy*t), also
|
||||
passes through (x,y).
|
||||
|
||||
Let px = x - start->x, py = y - start->y.
|
||||
t is given by
|
||||
(px - dx*t)*dx + (py - dy*t)*dy = 0
|
||||
|
||||
Solving for t we get
|
||||
numerator = dx*px + dy*py
|
||||
denominator = dx^2 + dy^2
|
||||
t = numerator/denominator
|
||||
|
||||
In CreateRepeatingLinearGradientFunction we know the length of (dx,dy)
|
||||
is not zero. (This is checked in _cairo_quartz_setup_linear_source.)
|
||||
*/
|
||||
double px = x - start->x;
|
||||
double py = y - start->y;
|
||||
double numerator = dx*px + dy*py;
|
||||
double denominator = dx*dx + dy*dy;
|
||||
double t = numerator/denominator;
|
||||
|
||||
if (*min_t > t) {
|
||||
*min_t = t;
|
||||
}
|
||||
if (*max_t < t) {
|
||||
*max_t = t;
|
||||
}
|
||||
}
|
||||
|
||||
static CGFunctionRef
|
||||
CreateRepeatingLinearGradientFunction (cairo_quartz_surface_t *surface,
|
||||
const cairo_gradient_pattern_t *gpat,
|
||||
CGPoint *start, CGPoint *end,
|
||||
cairo_rectangle_int_t *extents)
|
||||
CGAffineTransform matrix)
|
||||
{
|
||||
cairo_pattern_t *pat;
|
||||
float input_value_range[2];
|
||||
double t_min = 0.;
|
||||
double t_max = 0.;
|
||||
double dx = end->x - start->x;
|
||||
double dy = end->y - start->y;
|
||||
double bounds_x1, bounds_x2, bounds_y1, bounds_y2;
|
||||
|
||||
if (!extents) {
|
||||
extents = &surface->extents;
|
||||
CGPoint mstart, mend;
|
||||
|
||||
double dx, dy;
|
||||
int x_rep_start = 0, x_rep_end = 0;
|
||||
int y_rep_start = 0, y_rep_end = 0;
|
||||
|
||||
int rep_start, rep_end;
|
||||
|
||||
// figure out how many times we'd need to repeat the gradient pattern
|
||||
// to cover the whole (transformed) surface area
|
||||
mstart = CGPointApplyAffineTransform (*start, matrix);
|
||||
mend = CGPointApplyAffineTransform (*end, matrix);
|
||||
|
||||
dx = fabs (mend.x - mstart.x);
|
||||
dy = fabs (mend.y - mstart.y);
|
||||
|
||||
if (dx > 1e-6) {
|
||||
x_rep_start = (int) ceil(MIN(mstart.x, mend.x) / dx);
|
||||
x_rep_end = (int) ceil((surface->extents.width - MAX(mstart.x, mend.x)) / dx);
|
||||
|
||||
if (mend.x < mstart.x) {
|
||||
int swap = x_rep_end;
|
||||
x_rep_end = x_rep_start;
|
||||
x_rep_start = swap;
|
||||
}
|
||||
}
|
||||
bounds_x1 = extents->x;
|
||||
bounds_y1 = extents->y;
|
||||
bounds_x2 = extents->x + extents->width;
|
||||
bounds_y2 = extents->y + extents->height;
|
||||
_cairo_matrix_transform_bounding_box (&gpat->base.matrix,
|
||||
&bounds_x1, &bounds_y1,
|
||||
&bounds_x2, &bounds_y2,
|
||||
NULL);
|
||||
|
||||
UpdateLinearParametersToIncludePoint(&t_min, &t_max, start, dx, dy,
|
||||
bounds_x1, bounds_y1);
|
||||
UpdateLinearParametersToIncludePoint(&t_min, &t_max, start, dx, dy,
|
||||
bounds_x2, bounds_y1);
|
||||
UpdateLinearParametersToIncludePoint(&t_min, &t_max, start, dx, dy,
|
||||
bounds_x2, bounds_y2);
|
||||
UpdateLinearParametersToIncludePoint(&t_min, &t_max, start, dx, dy,
|
||||
bounds_x1, bounds_y2);
|
||||
if (dy > 1e-6) {
|
||||
y_rep_start = (int) ceil(MIN(mstart.y, mend.y) / dy);
|
||||
y_rep_end = (int) ceil((surface->extents.width - MAX(mstart.y, mend.y)) / dy);
|
||||
|
||||
/* Move t_min and t_max to the nearest usable integer to try to avoid
|
||||
subtle variations due to numerical instability, especially accidentally
|
||||
cutting off a pixel. Extending the gradient repetitions is always safe. */
|
||||
t_min = floor (t_min);
|
||||
t_max = ceil (t_max);
|
||||
end->x = start->x + dx*t_max;
|
||||
end->y = start->y + dy*t_max;
|
||||
start->x = start->x + dx*t_min;
|
||||
start->y = start->y + dy*t_min;
|
||||
if (mend.y < mstart.y) {
|
||||
int swap = y_rep_end;
|
||||
y_rep_end = y_rep_start;
|
||||
y_rep_start = swap;
|
||||
}
|
||||
}
|
||||
|
||||
rep_start = MAX(x_rep_start, y_rep_start);
|
||||
rep_end = MAX(x_rep_end, y_rep_end);
|
||||
|
||||
// extend the line between start and end by rep_start times from the start
|
||||
// and rep_end times from the end
|
||||
|
||||
dx = end->x - start->x;
|
||||
dy = end->y - start->y;
|
||||
|
||||
start->x = start->x - dx * rep_start;
|
||||
start->y = start->y - dy * rep_start;
|
||||
|
||||
end->x = end->x + dx * rep_end;
|
||||
end->y = end->y + dy * rep_end;
|
||||
|
||||
// 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.
|
||||
input_value_range[0] = t_min;
|
||||
input_value_range[1] = t_max;
|
||||
input_value_range[0] = 0.0 - 1.0 * rep_start;
|
||||
input_value_range[1] = 1.0 + 1.0 * rep_end;
|
||||
|
||||
if (_cairo_pattern_create_copy (&pat, &gpat->base))
|
||||
/* quartz doesn't deal very well with malloc failing, so there's
|
||||
|
@ -863,9 +845,10 @@ static CGFunctionRef
|
|||
CreateRepeatingRadialGradientFunction (cairo_quartz_surface_t *surface,
|
||||
const cairo_gradient_pattern_t *gpat,
|
||||
CGPoint *start, double *start_radius,
|
||||
CGPoint *end, double *end_radius,
|
||||
cairo_rectangle_int_t *extents)
|
||||
CGPoint *end, double *end_radius)
|
||||
{
|
||||
CGRect clip = CGContextGetClipBoundingBox (surface->cgContext);
|
||||
CGAffineTransform transform;
|
||||
cairo_pattern_t *pat;
|
||||
float input_value_range[2];
|
||||
CGPoint *inner;
|
||||
|
@ -877,19 +860,10 @@ CreateRepeatingRadialGradientFunction (cairo_quartz_surface_t *surface,
|
|||
double t_min, t_max, t_temp;
|
||||
/* outer minus inner */
|
||||
double dr, dx, dy;
|
||||
double bounds_x1, bounds_x2, bounds_y1, bounds_y2;
|
||||
|
||||
if (!extents) {
|
||||
extents = &surface->extents;
|
||||
}
|
||||
bounds_x1 = extents->x;
|
||||
bounds_y1 = extents->y;
|
||||
bounds_x2 = extents->x + extents->width;
|
||||
bounds_y2 = extents->y + extents->height;
|
||||
_cairo_matrix_transform_bounding_box (&gpat->base.matrix,
|
||||
&bounds_x1, &bounds_y1,
|
||||
&bounds_x2, &bounds_y2,
|
||||
NULL);
|
||||
_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 */
|
||||
|
@ -909,7 +883,6 @@ CreateRepeatingRadialGradientFunction (cairo_quartz_surface_t *surface,
|
|||
dx = outer->x - inner->x;
|
||||
dy = outer->y - inner->y;
|
||||
|
||||
/* We can't round or fudge t_min here, it has to be as accurate as possible. */
|
||||
t_min = -(*inner_radius/dr);
|
||||
inner->x += t_min*dx;
|
||||
inner->y += t_min*dy;
|
||||
|
@ -917,19 +890,19 @@ CreateRepeatingRadialGradientFunction (cairo_quartz_surface_t *surface,
|
|||
|
||||
t_temp = 0.;
|
||||
UpdateRadialParameterToIncludePoint(&t_temp, inner, dr, dx, dy,
|
||||
bounds_x1, bounds_y1);
|
||||
clip.origin.x, clip.origin.y);
|
||||
UpdateRadialParameterToIncludePoint(&t_temp, inner, dr, dx, dy,
|
||||
bounds_x2, bounds_y1);
|
||||
clip.origin.x + clip.size.width, clip.origin.y);
|
||||
UpdateRadialParameterToIncludePoint(&t_temp, inner, dr, dx, dy,
|
||||
bounds_x2, bounds_y2);
|
||||
clip.origin.x + clip.size.width, clip.origin.y + clip.size.height);
|
||||
UpdateRadialParameterToIncludePoint(&t_temp, inner, dr, dx, dy,
|
||||
bounds_x1, bounds_y2);
|
||||
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.
|
||||
Since the circles are alway expanding and contain the earlier circles,
|
||||
it's safe to extend t_max/t_temp as much as we want, so round t_temp up
|
||||
to the nearest integer. This may help us give stable results. */
|
||||
t_temp = ceil (t_temp);
|
||||
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;
|
||||
|
@ -1250,23 +1223,9 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface,
|
|||
return DO_IMAGE;
|
||||
}
|
||||
|
||||
/*
|
||||
Quartz does not support repeating radients. We handle repeating gradients
|
||||
by manually extending the gradient and repeating color stops. We need to
|
||||
minimize the number of repetitions since Quartz seems to sample our color
|
||||
function across the entire range, even if part of that range is not needed
|
||||
for the visible area of the gradient, and it samples with some fixed resolution,
|
||||
so if the gradient range is too large it samples with very low resolution and
|
||||
the gradient is very coarse. CreateRepeatingLinearGradientFunction and
|
||||
CreateRepeatingRadialGradientFunction compute the number of repetitions needed
|
||||
based on the extents of the object (the clip region cannot be used here since
|
||||
we don't want the rasterization of the entire gradient to depend on the
|
||||
clip region).
|
||||
*/
|
||||
static cairo_quartz_action_t
|
||||
_cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface,
|
||||
const cairo_linear_pattern_t *lpat,
|
||||
cairo_rectangle_int_t *extents)
|
||||
const cairo_linear_pattern_t *lpat)
|
||||
{
|
||||
const cairo_pattern_t *abspat = &lpat->base.base;
|
||||
cairo_matrix_t mat;
|
||||
|
@ -1281,16 +1240,6 @@ _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface,
|
|||
return DO_SOLID;
|
||||
}
|
||||
|
||||
if (lpat->p1.x == lpat->p2.x &&
|
||||
lpat->p1.y == lpat->p2.y) {
|
||||
/* Quartz handles cases where the vector has no length very
|
||||
* differently from pixman.
|
||||
* Whatever the correct behaviour is, let's at least have only pixman's
|
||||
* implementation to worry about.
|
||||
*/
|
||||
return _cairo_quartz_setup_fallback_source (surface, abspat);
|
||||
}
|
||||
|
||||
mat = abspat->matrix;
|
||||
cairo_matrix_invert (&mat);
|
||||
_cairo_quartz_cairo_matrix_to_quartz (&mat, &surface->sourceTransform);
|
||||
|
@ -1310,7 +1259,7 @@ _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface,
|
|||
gradFunc = CreateRepeatingLinearGradientFunction (surface,
|
||||
&lpat->base,
|
||||
&start, &end,
|
||||
extents);
|
||||
surface->sourceTransform);
|
||||
}
|
||||
|
||||
surface->sourceShading = CGShadingCreateAxial (rgb,
|
||||
|
@ -1326,8 +1275,7 @@ _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface,
|
|||
|
||||
static cairo_quartz_action_t
|
||||
_cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
|
||||
const cairo_radial_pattern_t *rpat,
|
||||
cairo_rectangle_int_t *extents)
|
||||
const cairo_radial_pattern_t *rpat)
|
||||
{
|
||||
const cairo_pattern_t *abspat = &rpat->base.base;
|
||||
cairo_matrix_t mat;
|
||||
|
@ -1379,8 +1327,7 @@ _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
|
|||
gradFunc = CreateRepeatingRadialGradientFunction (surface,
|
||||
&rpat->base,
|
||||
&start, &r1,
|
||||
&end, &r2,
|
||||
extents);
|
||||
&end, &r2);
|
||||
}
|
||||
|
||||
surface->sourceShading = CGShadingCreateRadial (rgb,
|
||||
|
@ -1399,8 +1346,7 @@ _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
|
|||
|
||||
static cairo_quartz_action_t
|
||||
_cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
|
||||
const cairo_pattern_t *source,
|
||||
cairo_rectangle_int_t *extents)
|
||||
const cairo_pattern_t *source)
|
||||
{
|
||||
assert (!(surface->sourceImage || surface->sourceShading || surface->sourcePattern));
|
||||
|
||||
|
@ -1426,12 +1372,14 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
|
|||
|
||||
if (source->type == CAIRO_PATTERN_TYPE_LINEAR) {
|
||||
const cairo_linear_pattern_t *lpat = (const cairo_linear_pattern_t *)source;
|
||||
return _cairo_quartz_setup_linear_source (surface, lpat, extents);
|
||||
return _cairo_quartz_setup_linear_source (surface, lpat);
|
||||
|
||||
}
|
||||
|
||||
if (source->type == CAIRO_PATTERN_TYPE_RADIAL) {
|
||||
const cairo_radial_pattern_t *rpat = (const cairo_radial_pattern_t *)source;
|
||||
return _cairo_quartz_setup_radial_source (surface, rpat, extents);
|
||||
return _cairo_quartz_setup_radial_source (surface, rpat);
|
||||
|
||||
}
|
||||
|
||||
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
|
||||
|
@ -1909,7 +1857,7 @@ _cairo_quartz_surface_paint (void *abstract_surface,
|
|||
|
||||
CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op));
|
||||
|
||||
action = _cairo_quartz_setup_source (surface, source, NULL);
|
||||
action = _cairo_quartz_setup_source (surface, source);
|
||||
|
||||
if (action == DO_SOLID || action == DO_PATTERN) {
|
||||
CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x,
|
||||
|
@ -1943,25 +1891,6 @@ _cairo_quartz_surface_paint (void *abstract_surface,
|
|||
return rv;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_cairo_quartz_source_needs_extents (const cairo_pattern_t *source)
|
||||
{
|
||||
/* For repeating gradients we need to manually extend the gradient and
|
||||
repeat stops, since Quartz doesn't support repeating gradients natively.
|
||||
We need to minimze the number of repeated stops, and since rasterization
|
||||
depends on the number of repetitions we use (even if some of the
|
||||
repetitions go beyond the extents of the object or outside the clip
|
||||
region), it's important to use the same number of repetitions when
|
||||
rendering an object no matter what the clip region is. So the
|
||||
computation of the repetition count cannot depended on the clip region,
|
||||
and should only depend on the object extents, so we need to compute
|
||||
the object extents for repeating gradients. */
|
||||
return (source->type == CAIRO_PATTERN_TYPE_LINEAR ||
|
||||
source->type == CAIRO_PATTERN_TYPE_RADIAL) &&
|
||||
(source->extend == CAIRO_EXTEND_REPEAT ||
|
||||
source->extend == CAIRO_EXTEND_REFLECT);
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_quartz_surface_fill (void *abstract_surface,
|
||||
cairo_operator_t op,
|
||||
|
@ -2002,17 +1931,7 @@ _cairo_quartz_surface_fill (void *abstract_surface,
|
|||
CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
|
||||
CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op));
|
||||
|
||||
if (_cairo_quartz_source_needs_extents (source))
|
||||
{
|
||||
/* We don't need precise extents since these are only used to
|
||||
compute the number of gradient reptitions needed to cover the
|
||||
object. */
|
||||
cairo_rectangle_int_t path_extents;
|
||||
_cairo_path_fixed_approximate_fill_extents (path, &path_extents);
|
||||
action = _cairo_quartz_setup_source (surface, source, &path_extents);
|
||||
} else {
|
||||
action = _cairo_quartz_setup_source (surface, source, NULL);
|
||||
}
|
||||
action = _cairo_quartz_setup_source (surface, source);
|
||||
|
||||
CGContextBeginPath (surface->cgContext);
|
||||
|
||||
|
@ -2145,14 +2064,7 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
|
|||
|
||||
CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op));
|
||||
|
||||
if (_cairo_quartz_source_needs_extents (source))
|
||||
{
|
||||
cairo_rectangle_int_t path_extents;
|
||||
_cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &path_extents);
|
||||
action = _cairo_quartz_setup_source (surface, source, &path_extents);
|
||||
} else {
|
||||
action = _cairo_quartz_setup_source (surface, source, NULL);
|
||||
}
|
||||
action = _cairo_quartz_setup_source (surface, source);
|
||||
|
||||
CGContextBeginPath (surface->cgContext);
|
||||
|
||||
|
@ -2273,16 +2185,7 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
|
|||
|
||||
CGContextSaveGState (surface->cgContext);
|
||||
|
||||
if (_cairo_quartz_source_needs_extents (source))
|
||||
{
|
||||
cairo_rectangle_int_t glyph_extents;
|
||||
_cairo_scaled_font_glyph_device_extents (scaled_font, glyphs, num_glyphs,
|
||||
&glyph_extents);
|
||||
action = _cairo_quartz_setup_source (surface, source, &glyph_extents);
|
||||
} else {
|
||||
action = _cairo_quartz_setup_source (surface, source, NULL);
|
||||
}
|
||||
|
||||
action = _cairo_quartz_setup_source (surface, source);
|
||||
if (action == DO_SOLID || action == DO_PATTERN) {
|
||||
CGContextSetTextDrawingMode (surface->cgContext, kCGTextFill);
|
||||
} else if (action == DO_IMAGE || action == DO_TILED_IMAGE || action == DO_SHADING) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче