[pattern] Rescale the linear pattern matrix to avoid overflow.

As proof-of-principle, compute a scale factor to avoid overflow when
converting a linear pattern to pixman_fixed_t. Fixes test/huge-pattern,
but the principle should be extended to handle more cases of overflow.
This commit is contained in:
Chris Wilson 2008-10-12 11:21:14 +01:00
parent ab1d106cba
commit 1d3453eee5
5 changed files with 45 additions and 8 deletions

View file

@ -1248,6 +1248,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
unsigned int i;
int clone_offset_x, clone_offset_y;
cairo_matrix_t matrix = pattern->base.matrix;
if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
pixman_stops = _cairo_malloc_ab (pattern->n_stops, sizeof(pixman_gradient_stop_t));
@ -1267,11 +1268,46 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
{
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
pixman_point_fixed_t p1, p2;
cairo_fixed_t xdim, ydim;
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);
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);
}
pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
pixman_stops,
@ -1315,7 +1351,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
}
attr->x_offset = attr->y_offset = 0;
attr->matrix = pattern->base.matrix;
attr->matrix = matrix;
attr->extend = pattern->base.extend;
attr->filter = CAIRO_FILTER_NEAREST;
attr->acquired = FALSE;
@ -1363,7 +1399,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
return image->base.status;
}
_cairo_matrix_to_pixman_matrix (&pattern->base.matrix, &pixman_transform);
_cairo_matrix_to_pixman_matrix (&matrix, &pixman_transform);
if (!pixman_image_set_transform (pixman_image, &pixman_transform)) {
cairo_surface_destroy (&image->base);
pixman_image_unref (pixman_image);

View file

@ -541,6 +541,9 @@ REFERENCE_IMAGES = \
gradient-zero-stops-rgb24-ref.png \
group-paint-ref.png \
huge-pattern-ref.png \
huge-pattern-ps3-ref.png \
huge-pattern-pdf-ref.png \
huge-pattern-pdf-rgb24-ref.png \
image-surface-source-ref.png \
infinite-join-ref.png \
infinite-join-ps2-ref.png \
@ -947,7 +950,6 @@ $(REFERENCE_IMAGES)
# room, with Carl as a moderator and not let them out
# until they have come up with an interface and
# semantics that actually work. :-)
# huge-pattern - range overflow of fixed-point
# long-lines - range overflow of fixed-point
# self-copy-overlap - vector surfaces take snapshot of patterns in contrast
# to the raster backends which don't. One solution
@ -971,7 +973,6 @@ degenerate-path$(EXEEXT) \
device-offset-scale$(EXEEXT) \
extend-pad$(EXEEXT) \
fallback-resolution$(EXEEXT) \
huge-pattern$(EXEEXT) \
long-lines$(EXEEXT) \
self-copy-overlap$(EXEEXT) \
self-intersecting$(EXEEXT) \

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB