diff options
author | Søren Sandmann Pedersen <sandmann@redhat.com> | 2009-07-09 01:35:11 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <sandmann@redhat.com> | 2009-07-10 02:57:09 -0400 |
commit | 0fce356762864572ae126733f657600fbb9116ce (patch) | |
tree | a442f33e6f2f5b9574496f9b091d69e2ec1e9212 | |
parent | 61254a3c09497214a9c7ca89e275286533a3be2e (diff) |
Add workarounds for X servers doing out-of-bounds accesses.
Old X servers rely on out-of-bounds accesses when they are asked
to composite with a window as the source. They create a pixman image
pointing to some bogus position in memory, but then they set a clip
region to the position where the actual bits are.
Due to a bug in old versions of pixman, where it would not clip
against the image bounds when a clip region was set, this would
actually work.
The workaround added by this commit is to try and detect whether a
source drawable is actually a window without a client clip set. Such a
window will generally have a clip region that corresponds exactly to
the hierarchy clip in the server, whereas pixmaps will have a clip
region that is an exact match to the drawable.
When we detect such a window, we allow a fast path to run that would
normally be rejected due to the sources not completely subsuming the
composite region.
Fixed X servers should call the new function
pixman_disable_out_of_bounds_workaround() to disable the workaround.
This was reported in bug 22484.
-rw-r--r-- | pixman/pixman-utils.c | 69 | ||||
-rw-r--r-- | pixman/pixman.h | 3 | ||||
-rw-r--r-- | test/scaling-test.c | 2 |
3 files changed, 69 insertions, 5 deletions
diff --git a/pixman/pixman-utils.c b/pixman/pixman-utils.c index e4563d0..6deb0d2 100644 --- a/pixman/pixman-utils.c +++ b/pixman/pixman-utils.c @@ -30,6 +30,26 @@ #include "pixman-private.h" +static pixman_bool_t out_of_bounds_workaround = TRUE; + +/* Old X servers rely on out-of-bounds accesses when they are asked + * to composite with a window as the source. They create a pixman image + * pointing to some bogus position in memory, but then they set a clip + * region to the position where the actual bits are. + * + * Due to a bug in old versions of pixman, where it would not clip + * against the image bounds when a clip region was set, this would + * actually work. So by default we allow certain out-of-bound access + * to happen unless explicitly disabled. + * + * Fixed X servers should call this function to disable the workaround. + */ +PIXMAN_EXPORT void +pixman_disable_out_of_bounds_workaround (void) +{ + out_of_bounds_workaround = FALSE; +} + /* * Computing composite region */ @@ -131,9 +151,13 @@ pixman_compute_composite_region32 (pixman_region32_t * region, /* Some X servers rely on an old bug, where pixman would just believe the * set clip_region and not clip against the destination geometry. So, * since only X servers set "source clip", we don't clip against - * destination geometry when that is set. + * destination geometry when that is set and when the workaround has + * not been explicitly disabled by + * + * pixman_disable_out_of_bounds_workaround(); + * */ - if (!dst_image->common.clip_sources) + if (!(dst_image->common.clip_sources && out_of_bounds_workaround)) { region->extents.x2 = MIN (region->extents.x2, dst_image->bits.width); region->extents.y2 = MIN (region->extents.y2, dst_image->bits.height); @@ -477,7 +501,9 @@ _pixman_walk_composite_region (pixman_implementation_t *imp, pixman_region32_init (®ion); if (pixman_compute_composite_region32 ( - ®ion, src_image, mask_image, dst_image, src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height)) + ®ion, src_image, mask_image, dst_image, + src_x, src_y, mask_x, mask_y, dest_x, dest_y, + width, height)) { walk_region_internal (imp, op, src_image, mask_image, dst_image, @@ -584,6 +610,38 @@ image_covers (pixman_image_t *image, pixman_box32_t *extents, int x, int y) return TRUE; } +static pixman_bool_t +source_image_needs_out_of_bounds_workaround (pixman_image_t *image) +{ + if (image->common.clip_sources && + !image->common.client_clip && + image->common.have_clip_region) + { + const pixman_box32_t *boxes; + int n; + + /* There is no client clip, so the drawable in question + * is a window if the clip region is different from the + * full drawable + */ + boxes = pixman_region32_rectangles (&image->common.clip_region, &n); + if (n == 1) + { + if (boxes[0].x1 == 0 && boxes[0].y1 == 0 && + boxes[0].x2 == image->bits.width && + boxes[0].y2 == image->bits.height) + { + /* pixmap */ + return FALSE; + } + } + + return TRUE; + } + + return FALSE; +} + pixman_bool_t _pixman_run_fast_path (const pixman_fast_path_t *paths, pixman_implementation_t *imp, @@ -677,8 +735,9 @@ _pixman_run_fast_path (const pixman_fast_path_t *paths, { pixman_box32_t *extents = pixman_region32_extents (®ion); - if (image_covers (src, extents, dest_x - src_x, dest_y - src_y) && - (!mask || image_covers (mask, extents, dest_x - mask_x, dest_y - mask_y))) + if ((image_covers (src, extents, dest_x - src_x, dest_y - src_y) && + (!mask || image_covers (mask, extents, dest_x - mask_x, dest_y - mask_y))) || + source_image_needs_out_of_bounds_workaround (src)) { walk_region_internal (imp, op, src, mask, dest, diff --git a/pixman/pixman.h b/pixman/pixman.h index df69511..0a85e56 100644 --- a/pixman/pixman.h +++ b/pixman/pixman.h @@ -434,6 +434,9 @@ void pixman_region_set_static_pointers (pixman_box16_t pixman_region16_data_t *broken_data); + +void pixman_disable_out_of_bounds_workaround (void); + /* creation/destruction */ void pixman_region_init (pixman_region16_t *region); void pixman_region_init_rect (pixman_region16_t *region, diff --git a/test/scaling-test.c b/test/scaling-test.c index 1919d5f..c56fac7 100644 --- a/test/scaling-test.c +++ b/test/scaling-test.c @@ -310,6 +310,8 @@ int main(int argc, char *argv[]) int i, n = 0; uint32_t crc = 0; + pixman_disable_out_of_bounds_workaround(); + if (argc >= 2) n = atoi(argv[1]); |