summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <sandmann@redhat.com>2009-07-09 01:35:11 -0400
committerSøren Sandmann Pedersen <sandmann@redhat.com>2009-07-10 02:57:09 -0400
commit0fce356762864572ae126733f657600fbb9116ce (patch)
treea442f33e6f2f5b9574496f9b091d69e2ec1e9212
parent61254a3c09497214a9c7ca89e275286533a3be2e (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.c69
-rw-r--r--pixman/pixman.h3
-rw-r--r--test/scaling-test.c2
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 (&region);
if (pixman_compute_composite_region32 (
- &region, src_image, mask_image, dst_image, src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height))
+ &region, 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 (&region);
- 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]);