[cairo-commit] cairo/src cairo-xlib-surface.c,1.119,1.120

Owen Taylor commit at pdx.freedesktop.org
Wed Aug 31 15:09:37 PDT 2005


Committed by: otaylor

Update of /cvs/cairo/cairo/src
In directory gabe:/tmp/cvs-serv7110/src

Modified Files:
	cairo-xlib-surface.c 
Log Message:
2005-08-31  Owen Taylor  <otaylor at redhat.com>

        * src/cairo-xlib-surface.c (_get_image_surface)
        (_draw_image_surface): Handle displays which don't match
        the local endianness by byteswapping on GetImage/PutImage.
        (#4321, reported by Sjoerd Simons)


Index: cairo-xlib-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-xlib-surface.c,v
retrieving revision 1.119
retrieving revision 1.120
diff -u -d -r1.119 -r1.120
--- cairo-xlib-surface.c	31 Aug 2005 22:08:02 -0000	1.119
+++ cairo-xlib-surface.c	31 Aug 2005 22:09:35 -0000	1.120
@@ -60,6 +60,9 @@
 static cairo_bool_t
 _cairo_surface_is_xlib (cairo_surface_t *surface);
 
+static cairo_bool_t
+_native_byte_order_lsb (void);
+
 /*
  * Instead of taking two round trips for each blending request,
  * assume that if a particular drawable fails GetImage that it will
@@ -314,6 +317,116 @@
     return False;
 }
 
+static void
+_swap_ximage_2bytes (XImage *ximage)
+{
+    int i, j;
+    char *line = ximage->data;
+
+    for (j = ximage->height; j; j--) {
+	uint16_t *p = (uint16_t *)line;
+	for (i = ximage->width; i; i--) {
+	    *p = (((*p & 0x00ff) << 8) |
+		  ((*p)          >> 8));
+	    p++;
+	}
+
+	line += ximage->bytes_per_line;
+    }
+}
+
+static void
+_swap_ximage_4bytes (XImage *ximage)
+{
+    int i, j;
+    char *line = ximage->data;
+
+    for (j = ximage->height; j; j--) {
+	uint32_t *p = (uint32_t *)line;
+	for (i = ximage->width; i; i--) {
+	    *p = (((*p & 0x000000ff) << 24) |
+		  ((*p & 0x0000ff00) << 8) |
+		  ((*p & 0x00ff0000) >> 8) |
+		  ((*p)              >> 24));
+	    p++;
+	}
+
+	line += ximage->bytes_per_line;
+    }
+}
+
+static void
+_swap_ximage_bits (XImage *ximage)
+{
+    int i, j;
+    char *line = ximage->data;
+    int unit = ximage->bitmap_unit;
+    int line_bytes = ((ximage->width + unit - 1) & ~(unit - 1)) / 8;
+
+    for (j = ximage->height; j; j--) {
+	char *p = line;
+	
+	for (i = line_bytes; i; i--) {
+	    char b = *p;
+	    b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
+	    b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
+	    b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
+	    *p = b;
+	    
+	    p++;
+	}
+
+	line += ximage->bytes_per_line;
+    }
+}
+
+static void
+_swap_ximage_to_native (XImage *ximage)
+{
+    int unit_bytes = 0;
+    int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
+
+    if (ximage->bits_per_pixel == 1 &&
+	ximage->bitmap_bit_order != native_byte_order) {
+	_swap_ximage_bits (ximage);
+	if (ximage->bitmap_bit_order == ximage->byte_order)
+	    return;
+    }
+    
+    if (ximage->byte_order == native_byte_order)
+	return;
+
+    switch (ximage->bits_per_pixel) {
+    case 1:
+	unit_bytes = ximage->bitmap_unit / 8;
+	break;
+    case 8:
+    case 16:
+    case 32:
+	unit_bytes = ximage->bits_per_pixel / 8;
+	break;
+    default:
+        /* This could be hit on some uncommon but possible cases,
+	 * such as bpp=4. These are cases that libpixman can't deal
+	 * with in any case.
+	 */
+	ASSERT_NOT_REACHED;
+    }
+
+    switch (unit_bytes) {
+    case 1:
+	return;
+    case 2:
+	_swap_ximage_2bytes (ximage);
+	break;
+    case 4:
+	_swap_ximage_4bytes (ximage);
+	break;
+    default:
+	ASSERT_NOT_REACHED;
+    }
+}
+
 static cairo_status_t
 _get_image_surface (cairo_xlib_surface_t   *surface,
 		    cairo_rectangle_t      *interest_rect,
@@ -417,6 +530,8 @@
     }
     if (!ximage)
 	return CAIRO_STATUS_NO_MEMORY;
+
+    _swap_ximage_to_native (ximage);
 					
     /*
      * Compute the pixel format masks from either a visual or a 
@@ -557,40 +672,35 @@
 		     int                    dst_x,
 		     int                    dst_y)
 {
-    XImage *ximage;
-    unsigned bitmap_pad;
-
-    /* XXX this is wrong */
-    if (image->depth > 16)
-	bitmap_pad = 32;
-    else if (image->depth > 8)
-	bitmap_pad = 16;
-    else
-	bitmap_pad = 8;
-
-    ximage = XCreateImage (surface->dpy,
-			   DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)),
-			   image->depth,
-			   ZPixmap,
-			   0,
-			   (char *) image->data,
-			   image->width,
-			   image->height,
-			   bitmap_pad,
-			   image->stride);
-    if (ximage == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
+    XImage ximage;
+    int bpp, alpha, red, green, blue;
+    int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
+    
+    pixman_format_get_masks (pixman_image_get_format (image->pixman_image),
+			     &bpp, &alpha, &red, &green, &blue);
+    
+    ximage.width = image->width;
+    ximage.height = image->height;
+    ximage.format = ZPixmap;
+    ximage.data = (char *)image->data;
+    ximage.byte_order = native_byte_order;
+    ximage.bitmap_unit = 32;	/* always for libpixman */
+    ximage.bitmap_bit_order = native_byte_order;
+    ximage.bitmap_pad = 32;	/* always for libpixman */
+    ximage.depth = image->depth;
+    ximage.bytes_per_line = image->stride;
+    ximage.bits_per_pixel = bpp;
+    ximage.red_mask = red;
+    ximage.green_mask = green;
+    ximage.blue_mask = blue;
 
+    XInitImage (&ximage);
+    
     _cairo_xlib_surface_ensure_gc (surface);
     XPutImage(surface->dpy, surface->drawable, surface->gc,
-	      ximage, 0, 0, dst_x, dst_y,
+	      &ximage, 0, 0, dst_x, dst_y,
 	      image->width, image->height);
 
-    /* Foolish XDestroyImage thinks it can free my data, but I won't
-       stand for it. */
-    ximage->data = NULL;
-    XDestroyImage (ximage);
-
     return CAIRO_STATUS_SUCCESS;
 
 }



More information about the cairo-commit mailing list