pattern: Factor out pattern rescaling

The same code was duplicated (incorrectly and with some minor
differences) in pattern, image, xlib and xcb.

_cairo_gradient_pattern_max_val() abstracts that code in a function
that can be used whenever a gradients extremes need to be rescaled to
fit within a given range.

Fixes huge-linear, huge-radial.

Fixes part of https://bugs.freedesktop.org/show_bug.cgi?id=32215
This commit is contained in:
Andrea Canciani 2010-12-17 11:03:03 +01:00
parent 7b188f852e
commit 38dce5d144
5 changed files with 158 additions and 211 deletions

View file

@ -1075,7 +1075,9 @@ _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
pixman_gradient_stop_t pixman_stops_static[2];
pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
pixman_transform_t pixman_transform;
cairo_matrix_t matrix = pattern->base.matrix;
cairo_matrix_t matrix;
cairo_circle_double_t extremes[2];
pixman_point_fixed_t p1, p2;
unsigned int i;
cairo_status_t status;
@ -1094,66 +1096,24 @@ _pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
}
_cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
pixman_point_fixed_t p1, p2;
cairo_fixed_t xdim, ydim;
xdim = fabs (linear->p2.x - linear->p1.x);
ydim = fabs (linear->p2.y - linear->p1.y);
/*
* Transform the matrix to avoid overflow when converting between
* cairo_fixed_t and pixman_fixed_t (without incurring performance
* loss when the transformation is unnecessary).
*
* XXX: Consider converting out-of-range co-ordinates and transforms.
* Having a function to compute the required transformation to
* "normalize" a given bounding box would be generally useful -
* cf linear patterns, gradient patterns, surface patterns...
*/
if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
_cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
{
double sf;
if (xdim > ydim)
sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
else
sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
cairo_matrix_scale (&matrix, sf, sf);
}
else
{
p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
}
pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
pixman_stops,
pattern->n_stops);
} else {
cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
pixman_point_fixed_t c1, c2;
pixman_fixed_t r1, r2;
c1.x = _cairo_fixed_to_16_16 (radial->c1.x);
c1.y = _cairo_fixed_to_16_16 (radial->c1.y);
r1 = _cairo_fixed_to_16_16 (radial->r1);
r1 = _cairo_fixed_16_16_from_double (extremes[0].radius);
r2 = _cairo_fixed_16_16_from_double (extremes[1].radius);
c2.x = _cairo_fixed_to_16_16 (radial->c2.x);
c2.y = _cairo_fixed_to_16_16 (radial->c2.y);
r2 = _cairo_fixed_to_16_16 (radial->r2);
pixman_image = pixman_image_create_radial_gradient (&c1, &c2, r1, r2,
pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
pixman_stops,
pattern->n_stops);
}

View file

@ -35,6 +35,8 @@
#include <float.h>
#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
/**
* SECTION:cairo-pattern
* @Title: cairo_pattern_t
@ -2124,6 +2126,8 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
cairo_image_surface_t *image;
pixman_image_t *pixman_image;
pixman_transform_t pixman_transform;
cairo_circle_double_t extremes[2];
pixman_point_fixed_t p1, p2;
cairo_status_t status;
cairo_bool_t repeat = FALSE;
int ix, iy;
@ -2151,71 +2155,24 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
}
if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR)
{
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
pixman_point_fixed_t p1, p2;
cairo_fixed_t xdim, ydim;
_cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes);
xdim = linear->p2.x - linear->p1.x;
ydim = linear->p2.y - linear->p1.y;
/*
* Transform the matrix to avoid overflow when converting between
* cairo_fixed_t and pixman_fixed_t (without incurring performance
* loss when the transformation is unnecessary).
*
* XXX: Consider converting out-of-range co-ordinates and transforms.
* Having a function to compute the required transformation to
* "normalize" a given bounding box would be generally useful -
* cf linear patterns, gradient patterns, surface patterns...
*/
#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
_cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
{
double sf;
if (xdim > ydim)
sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
else
sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
cairo_matrix_scale (&matrix, sf, sf);
}
else
{
p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
}
p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
pixman_stops,
pattern->n_stops);
}
else
{
cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
pixman_point_fixed_t c1, c2;
} else {
pixman_fixed_t r1, r2;
c1.x = _cairo_fixed_to_16_16 (radial->c1.x);
c1.y = _cairo_fixed_to_16_16 (radial->c1.y);
r1 = _cairo_fixed_to_16_16 (radial->r1);
r1 = _cairo_fixed_16_16_from_double (extremes[0].radius);
r2 = _cairo_fixed_16_16_from_double (extremes[1].radius);
c2.x = _cairo_fixed_to_16_16 (radial->c2.x);
c2.y = _cairo_fixed_to_16_16 (radial->c2.y);
r2 = _cairo_fixed_to_16_16 (radial->r2);
pixman_image = pixman_image_create_radial_gradient (&c1, &c2,
r1, r2,
pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2,
pixman_stops,
pattern->n_stops);
}
@ -3078,6 +3035,91 @@ _cairo_gradient_pattern_interpolate (const cairo_gradient_pattern_t *gradient,
#undef lerp
}
/**
* _cairo_gradient_pattern_fit_to_range
*
* Scale the extremes of a gradient to guarantee that the coordinates
* and their deltas are within the range (-max_value, max_value). The
* new extremes are stored in out_circle.
*
* The pattern matrix is scaled to guarantee that the aspect of the
* gradient is the same and the result is stored in out_matrix.
*
**/
void
_cairo_gradient_pattern_fit_to_range (const cairo_gradient_pattern_t *gradient,
double max_value,
cairo_matrix_t *out_matrix,
cairo_circle_double_t out_circle[2])
{
double dim;
assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
out_circle[0].center.x = _cairo_fixed_to_double (linear->p1.x);
out_circle[0].center.y = _cairo_fixed_to_double (linear->p1.y);
out_circle[0].radius = 0;
out_circle[1].center.x = _cairo_fixed_to_double (linear->p2.x);
out_circle[1].center.y = _cairo_fixed_to_double (linear->p2.y);
out_circle[1].radius = 0;
dim = fabs (_cairo_fixed_to_double (linear->p1.x));
dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p1.y)));
dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p2.x)));
dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p2.y)));
dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p1.x) -
_cairo_fixed_to_double (linear->p2.x)));
dim = MAX (dim, fabs (_cairo_fixed_to_double (linear->p1.y) -
_cairo_fixed_to_double (linear->p2.y)));
} else {
cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient;
out_circle[0].center.x = _cairo_fixed_to_double (radial->c1.x);
out_circle[0].center.y = _cairo_fixed_to_double (radial->c1.y);
out_circle[0].radius = _cairo_fixed_to_double (radial->r1);
out_circle[1].center.x = _cairo_fixed_to_double (radial->c2.x);
out_circle[1].center.y = _cairo_fixed_to_double (radial->c2.y);
out_circle[1].radius = _cairo_fixed_to_double (radial->r2);
dim = fabs (_cairo_fixed_to_double (radial->c1.x));
dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c1.y)));
dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->r1)));
dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c2.x)));
dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c2.y)));
dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->r2)));
dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c1.x) -
_cairo_fixed_to_double (radial->c2.x)));
dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->c1.y) -
_cairo_fixed_to_double (radial->c2.y)));
dim = MAX (dim, fabs (_cairo_fixed_to_double (radial->r1) -
_cairo_fixed_to_double (radial->r2)));
}
if (unlikely (dim > max_value)) {
cairo_matrix_t scale;
dim = max_value / dim;
out_circle[0].center.x *= dim;
out_circle[0].center.y *= dim;
out_circle[0].radius *= dim;
out_circle[1].center.x *= dim;
out_circle[1].center.y *= dim;
out_circle[1].radius *= dim;
cairo_matrix_init_scale (&scale, dim, dim);
cairo_matrix_multiply (out_matrix, &gradient->base.matrix, &scale);
} else {
*out_matrix = gradient->base.matrix;
}
}
static cairo_bool_t
_gradient_is_clear (const cairo_gradient_pattern_t *gradient,
const cairo_rectangle_int_t *extents)

View file

@ -879,14 +879,16 @@ _cairo_xcb_linear_picture (cairo_xcb_surface_t *target,
const cairo_rectangle_int_t *extents)
{
char buf[CAIRO_STACK_BUFFER_SIZE];
cairo_fixed_t xdim, ydim;
xcb_render_fixed_t *stops;
xcb_render_color_t *colors;
xcb_render_pointfix_t p1, p2;
cairo_matrix_t matrix = pattern->base.base.matrix;
cairo_matrix_t matrix;
cairo_circle_double_t extremes[2];
cairo_xcb_picture_t *picture;
cairo_status_t status;
_cairo_gradient_pattern_fit_to_range (&pattern->base, PIXMAN_MAX_INT >> 1, &matrix, extremes);
picture = (cairo_xcb_picture_t *)
_cairo_xcb_screen_lookup_linear_picture (target->screen, pattern);
if (picture != NULL)
@ -907,46 +909,13 @@ _cairo_xcb_linear_picture (cairo_xcb_surface_t *target,
}
picture->filter = CAIRO_FILTER_DEFAULT;
xdim = pattern->p2.x - pattern->p1.x;
ydim = pattern->p2.y - pattern->p1.y;
/*
* Transform the matrix to avoid overflow when converting between
* cairo_fixed_t and pixman_fixed_t (without incurring performance
* loss when the transformation is unnecessary).
*
* XXX: Consider converting out-of-range co-ordinates and transforms.
* Having a function to compute the required transformation to
* "normalize" a given bounding box would be generally useful -
* cf linear patterns, gradient patterns, surface patterns...
*/
#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
if (unlikely (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
_cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT))
{
double sf;
if (xdim > ydim)
sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
else
sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p1.x) * sf);
p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p1.y) * sf);
p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p2.x) * sf);
p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p2.y) * sf);
cairo_matrix_scale (&matrix, sf, sf);
}
else
{
p1.x = _cairo_fixed_to_16_16 (pattern->p1.x);
p1.y = _cairo_fixed_to_16_16 (pattern->p1.y);
p2.x = _cairo_fixed_to_16_16 (pattern->p2.x);
p2.y = _cairo_fixed_to_16_16 (pattern->p2.y);
}
colors = (xcb_render_color_t *) (stops + pattern->base.n_stops);
p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
_cairo_xcb_connection_render_create_linear_gradient (target->connection,
picture->picture,
p1, p2,
@ -985,11 +954,15 @@ _cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
char buf[CAIRO_STACK_BUFFER_SIZE];
xcb_render_fixed_t *stops;
xcb_render_color_t *colors;
xcb_render_pointfix_t c1, c2;
xcb_render_pointfix_t p1, p2;
xcb_render_fixed_t r1, r2;
cairo_matrix_t matrix;
cairo_circle_double_t extremes[2];
cairo_xcb_picture_t *picture;
cairo_status_t status;
_cairo_gradient_pattern_fit_to_range (&pattern->base, PIXMAN_MAX_INT >> 1, &matrix, extremes);
picture = (cairo_xcb_picture_t *)
_cairo_xcb_screen_lookup_radial_picture (target->screen, pattern);
if (picture != NULL)
@ -1010,17 +983,19 @@ _cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
}
picture->filter = CAIRO_FILTER_DEFAULT;
c1.x = _cairo_fixed_to_16_16 (pattern->c1.x);
c1.y = _cairo_fixed_to_16_16 (pattern->c1.y);
r1 = _cairo_fixed_to_16_16 (pattern->r1);
c2.x = _cairo_fixed_to_16_16 (pattern->c2.x);
c2.y = _cairo_fixed_to_16_16 (pattern->c2.y);
r2 = _cairo_fixed_to_16_16 (pattern->r2);
colors = (xcb_render_color_t *) (stops + pattern->base.n_stops);
p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
r1 = _cairo_fixed_16_16_from_double (extremes[0].radius);
r2 = _cairo_fixed_16_16_from_double (extremes[1].radius);
_cairo_xcb_connection_render_create_radial_gradient (target->connection,
picture->picture,
c1, c2, r1, r2,
p1, p2, r1, r2,
pattern->base.n_stops,
stops, colors);
@ -1036,7 +1011,7 @@ _cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
}
setup_picture:
_cairo_xcb_picture_set_matrix (picture, &pattern->base.base.matrix,
_cairo_xcb_picture_set_matrix (picture, &matrix,
pattern->base.base.filter,
extents->x + extents->width/2.,
extents->y + extents->height/2.);

View file

@ -59,6 +59,7 @@
#include <X11/Xutil.h> /* for XDestroyImage */
#define XLIB_COORD_MAX 32767
#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
#define DEBUG 0
@ -2094,6 +2095,7 @@ _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_display_t *display,
cairo_matrix_t matrix = pattern->matrix;
cairo_xlib_surface_t *surface;
char buf[CAIRO_STACK_BUFFER_SIZE];
cairo_circle_double_t extremes[2];
XFixed *stops;
XRenderColor *colors;
XRenderPictFormat *format;
@ -2143,70 +2145,32 @@ _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_display_t *display,
XSync (display->display, False);
#endif
_cairo_gradient_pattern_fit_to_range (gradient, PIXMAN_MAX_INT >> 1, &matrix, extremes);
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
XLinearGradient grad;
cairo_fixed_t xdim, ydim;
xdim = linear->p2.x - linear->p1.x;
ydim = linear->p2.y - linear->p1.y;
/*
* Transform the matrix to avoid overflow when converting between
* cairo_fixed_t and pixman_fixed_t (without incurring performance
* loss when the transformation is unnecessary).
*
* XXX: Consider converting out-of-range co-ordinates and transforms.
* Having a function to compute the required transformation to
* "normalize" a given bounding box would be generally useful -
* cf linear patterns, gradient patterns, surface patterns...
*/
#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
_cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
{
double sf;
if (xdim > ydim)
sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
else
sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
grad.p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
grad.p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
grad.p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
grad.p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
cairo_matrix_scale (&matrix, sf, sf);
}
else
{
grad.p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
grad.p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
grad.p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
grad.p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
}
grad.p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
grad.p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
grad.p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
grad.p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
picture = XRenderCreateLinearGradient (display->display, &grad,
stops, colors,
gradient->n_stops);
} else {
cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
XRadialGradient grad;
grad.inner.x = _cairo_fixed_to_16_16 (radial->c1.x);
grad.inner.y = _cairo_fixed_to_16_16 (radial->c1.y);
grad.inner.radius = _cairo_fixed_to_16_16 (radial->r1);
grad.outer.x = _cairo_fixed_to_16_16 (radial->c2.x);
grad.outer.y = _cairo_fixed_to_16_16 (radial->c2.y);
grad.outer.radius = _cairo_fixed_to_16_16 (radial->r2);
grad.inner.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
grad.inner.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
grad.inner.radius = _cairo_fixed_16_16_from_double (extremes[0].radius);
grad.outer.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
grad.outer.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
grad.outer.radius = _cairo_fixed_16_16_from_double (extremes[1].radius);
picture = XRenderCreateRadialGradient (display->display, &grad,
stops, colors,
gradient->n_stops);
}
if (stops != (XFixed *) buf)

View file

@ -2241,6 +2241,12 @@ _cairo_gradient_pattern_interpolate (const cairo_gradient_pattern_t *gradient,
double t,
cairo_circle_double_t *out_circle);
cairo_private void
_cairo_gradient_pattern_fit_to_range (const cairo_gradient_pattern_t *gradient,
double max_value,
cairo_matrix_t *out_matrix,
cairo_circle_double_t out_circle[2]);
cairo_private cairo_bool_t
_cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern);