mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-04 03:38:06 +02:00
[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:
parent
ab1d106cba
commit
1d3453eee5
5 changed files with 45 additions and 8 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) \
|
||||
|
|
|
|||
BIN
test/huge-pattern-pdf-ref.png
Normal file
BIN
test/huge-pattern-pdf-ref.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
BIN
test/huge-pattern-pdf-rgb24-ref.png
Normal file
BIN
test/huge-pattern-pdf-rgb24-ref.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
BIN
test/huge-pattern-ps3-ref.png
Normal file
BIN
test/huge-pattern-ps3-ref.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Loading…
Add table
Reference in a new issue