Move workaround logic to pixman-bits-image.c.
authorSøren Sandmann Pedersen <sandmann@redhat.com>
Sat, 11 Jul 2009 07:25:25 +0000 (03:25 -0400)
committerSøren Sandmann Pedersen <sandmann@redhat.com>
Sun, 12 Jul 2009 07:06:13 +0000 (03:06 -0400)
Instead of computing whether a workaround is needed on every call to
_pixman_run_fast_path(), just cache this information in the image.

Also, when workarounds are needed, clip against the source geometry to
prevent out of bound reads.

pixman/pixman-bits-image.c
pixman/pixman-image.c
pixman/pixman-private.h
pixman/pixman-utils.c

index 8036705..977b172 100644 (file)
@@ -727,6 +727,61 @@ bits_image_fetch_untransformed_64 (pixman_image_t * image, int x, int y,
     }
 }
 
+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;
+}
+
+static pixman_bool_t
+source_image_needs_out_of_bounds_workaround (bits_image_t *image)
+{
+    if (image->common.clip_sources                     &&
+       image->common.repeat == PIXMAN_REPEAT_NONE      &&
+       out_of_bounds_workaround)
+    {
+       const pixman_box32_t *boxes;
+       int n;
+
+       if (!image->common.client_clip)
+       {
+           /* 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->width &&
+                   boxes[0].y2 == image->height)
+               {
+                   /* pixmap */
+                   return FALSE;
+               }
+           }
+       }
+
+       return TRUE;
+    }
+       
+    return FALSE;
+}
+
 static void
 bits_image_property_changed (pixman_image_t *image)
 {
@@ -766,6 +821,9 @@ bits_image_property_changed (pixman_image_t *image)
 
     bits->store_scanline_64 = bits_image_store_scanline_64;
     bits->store_scanline_32 = bits_image_store_scanline_32;
+
+    bits->common.need_workaround =
+       source_image_needs_out_of_bounds_workaround (bits);
 }
 
 static uint32_t *
index f95bf3f..d7020f2 100644 (file)
@@ -115,6 +115,7 @@ _pixman_image_allocate (void)
        common->client_clip = FALSE;
        common->destroy_func = NULL;
        common->destroy_data = NULL;
+       common->need_workaround = FALSE;
     }
 
     return image;
@@ -381,6 +382,8 @@ pixman_image_set_source_clipping (pixman_image_t  *image,
                                  pixman_bool_t    clip_sources)
 {
     image->common.clip_sources = clip_sources;
+
+    image_property_changed (image);
 }
 
 /* Unlike all the other property setters, this function does not
index b0056c4..081d35c 100644 (file)
@@ -71,6 +71,7 @@ struct image_common
     pixman_bool_t              clip_sources;       /* Whether the clip applies when
                                                     * the image is used as a source
                                                     */
+    pixman_bool_t              need_workaround;
     pixman_transform_t        *transform;
     pixman_repeat_t            repeat;
     pixman_filter_t            filter;
index c7b97ef..fddfb85 100644 (file)
 
 #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
  */
@@ -105,13 +85,20 @@ clip_source_image (pixman_region32_t *     region,
                  int           dx,
                  int           dy)
 {
-    /* Source clips are ignored, unless they are explicitly turned on
-     * and the clip in question was set by an X client. (Because if
-     * the clip was not set by a client, then it is a hierarchy
-     * clip and those should always be ignored for sources).
+    /* The workaround lets certain fast paths run even when they
+     * would normally be rejected because of out-of-bounds access.
+     * We need to clip against the source geometry in that case
      */
-    if (!picture->common.clip_sources || !picture->common.client_clip)
-       return TRUE;
+    if (!picture->common.need_workaround)
+    {
+       /* Source clips are ignored, unless they are explicitly turned on
+        * and the clip in question was set by an X client. (Because if
+        * the clip was not set by a client, then it is a hierarchy
+        * clip and those should always be ignored for sources).
+        */
+       if (!picture->common.clip_sources || !picture->common.client_clip)
+           return TRUE;
+    }
 
     return clip_general_image (region,
                             &picture->common.clip_region,
@@ -157,7 +144,7 @@ pixman_compute_composite_region32 (pixman_region32_t *      region,
      *      pixman_disable_out_of_bounds_workaround();
      *
      */
-    if (!(dst_image->common.clip_sources && out_of_bounds_workaround))
+    if (!(dst_image->common.need_workaround))
     {
        region->extents.x2 = MIN (region->extents.x2, dst_image->bits.width);
        region->extents.y2 = MIN (region->extents.y2, dst_image->bits.height);
@@ -610,41 +597,6 @@ 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 (!out_of_bounds_workaround)
-       return FALSE;
-    
-    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,
@@ -740,7 +692,7 @@ _pixman_run_fast_path (const pixman_fast_path_t *paths,
 
            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))
+               src->common.need_workaround)
            {
                walk_region_internal (imp, op,
                                      src, mask, dest,