mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-01-03 00:00:17 +01:00
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:
parent
7b188f852e
commit
38dce5d144
5 changed files with 158 additions and 211 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue