summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2005-08-31 15:09:43 +0000
committerOwen Taylor <otaylor@redhat.com>2005-08-31 15:09:43 +0000
commitd521fa3a759457b1b5ce18f8853507798071b599 (patch)
treeacd983a5485c8561d72ba9510645109e23f35308
parent568ce860264e63f86ae45258eb106fb7a74a33a3 (diff)
Handle displays which don't match the local endianness by byteswapping on GetImage/PutImage. (#4321, reported by Sjoerd Simons)
-rw-r--r--ChangeLog8
-rw-r--r--src/cairo-xlib-surface.c170
2 files changed, 145 insertions, 33 deletions
diff --git a/ChangeLog b/ChangeLog
index 0191739bb..ab0cf9837 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,9 @@
-2005-08-31 Carl Worth <cworth@cworth.org>
+2005-08-31 Owen Taylor <otaylor@redhat.com>
- * configure.in: Increment CAIRO_VERSION to 1.1.1 after making
- branch tag BRANCH_1_0.
+ * 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)
2005-08-31 Carl Worth <cworth@cworth.org>
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index f1f68d726..e3955ecad 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -60,6 +60,9 @@ _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface);
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
@@ -302,6 +305,116 @@ _CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
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,
@@ -405,6 +518,8 @@ _get_image_surface (cairo_xlib_surface_t *surface,
}
if (!ximage)
return CAIRO_STATUS_NO_MEMORY;
+
+ _swap_ximage_to_native (ximage);
/*
* Compute the pixel format masks from either a visual or a
@@ -545,40 +660,35 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
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;
}