do clipping prior to XGetImage, just in case the image would extend beyond the screen...
authorBrian Paul <brian.paul@tungstengraphics.com>
Tue, 9 Nov 2004 01:20:57 +0000 (01:20 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Tue, 9 Nov 2004 01:20:57 +0000 (01:20 +0000)
src/mesa/drivers/x11/xm_span.c

index 71a4c8008257f51c4dca7385557b2cc73aabdf8c..6e4bcb18a05401729e7b97a7a8c4cf9547d2eca0 100644 (file)
@@ -3456,6 +3456,47 @@ static void write_pixels_index_ximage( INDEX_PIXELS_ARGS )
 /*****                      Pixel reading                         *****/
 /**********************************************************************/
 
+#ifndef XFree86Server
+/**
+ * Do clip testing prior to calling XGetImage.  If any of the region lies
+ * outside the screen's bounds, XGetImage will return NULL.
+ * We use XTranslateCoordinates() to check if that's the case and
+ * adjust the x, y and length parameters accordingly.
+ * \return  -1 if span is totally clipped away,
+ *          else return number of pixels to skip in the destination array.
+ */
+static int
+clip_for_xgetimage(XMesaContext xmesa, GLuint *n, GLint *x, GLint *y)
+{
+   XMesaBuffer source = xmesa->xm_buffer;
+   Window rootWin = RootWindow(xmesa->display, 0);
+   Window child;
+   int screenWidth = WidthOfScreen(DefaultScreenOfDisplay(xmesa->display));
+   int dx, dy;
+   XTranslateCoordinates(xmesa->display, source->buffer, rootWin,
+                         *x, *y, &dx, &dy, &child);
+   if (dx >= screenWidth) {
+      /* totally clipped on right */
+      return -1;
+   }
+   if (dx < 0) {
+      /* clipped on left */
+      int clip = -dx;
+      if (clip >= *n)
+         return -1;  /* totally clipped on left */
+      *x += clip;
+      *n -= clip;
+      dx = 0;
+      return clip;
+   }
+   if (dx + *n > screenWidth) {
+      /* clipped on right */
+      int clip = dx + *n - screenWidth;
+      *n -= clip;
+   }
+   return 0;
+}
+#endif
 
 
 /*
@@ -3474,6 +3515,11 @@ static void read_index_span( const GLcontext *ctx,
 #ifndef XFree86Server
       XMesaImage *span = NULL;
       int error;
+      int k = clip_for_xgetimage(xmesa, &n, &x, &y);
+      if (k < 0)
+         return;
+      index += k;
+
       catch_xgetimage_errors( xmesa->display );
       span = XGetImage( xmesa->display, source->buffer,
                        x, y, n, 1, AllPlanes, ZPixmap );
@@ -3530,9 +3576,15 @@ static void read_color_span( const GLcontext *ctx,
                                  x, FLIP(source, y), n, 1, ZPixmap,
                                  ~0L, (pointer)span->data);
 #else
+      int k;
+      y = FLIP(source, y);
+      k = clip_for_xgetimage(xmesa, &n, &x, &y);
+      if (k < 0)
+         return;
+      rgba += k;
       catch_xgetimage_errors( xmesa->display );
       span = XGetImage( xmesa->display, source->buffer,
-                       x, FLIP(source, y), n, 1, AllPlanes, ZPixmap );
+                       x, y, n, 1, AllPlanes, ZPixmap );
       error = check_xgetimage_errors();
 #endif
       if (span && !error) {