Index: ChangeLog =================================================================== RCS file: /cvs/cairo/cairo/ChangeLog,v retrieving revision 1.1023 diff -u -p -r1.1023 ChangeLog --- ChangeLog 30 Aug 2005 17:50:27 -0000 1.1023 +++ ChangeLog 31 Aug 2005 17:38:04 -0000 @@ -1,3 +1,10 @@ +2005-08-31 Owen Taylor + + * 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-30 Owen Taylor * src/cairo-xlib-surface.c (_cairo_xlib_surface_create_internal): Index: src/cairo-xlib-surface.c =================================================================== RCS file: /cvs/cairo/cairo/src/cairo-xlib-surface.c,v retrieving revision 1.118 diff -u -p -r1.118 cairo-xlib-surface.c --- src/cairo-xlib-surface.c 30 Aug 2005 17:50:27 -0000 1.118 +++ src/cairo-xlib-surface.c 31 Aug 2005 17:38:04 -0000 @@ -302,6 +302,96 @@ _CAIRO_MASK_FORMAT (cairo_format_masks_t return False; } +static int +_native_byte_order (void) +{ + union { + short vshort; + char vchar[2]; + } endiantest = { 0x1234 }; + + return (endiantest.vchar[0] == 0x12) ? MSBFirst : LSBFirst; +} + +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_to_native (XImage *ximage) +{ + int bytes_per_pixel = 0; + + if (ximage->byte_order == _native_byte_order ()) + return; + + switch (ximage->bits_per_pixel) { + case 1: + bytes_per_pixel = ximage->bitmap_unit / 8; + break; + case 2: + case 4: + /* pixman can't actually handle these formats, but we can + * byte-swap them anyways ... */ + bytes_per_pixel = 1; + break; + case 8: + case 16: + case 32: + bytes_per_pixel = ximage->bits_per_pixel / 8; + break; + default: + ASSERT_NOT_REACHED; + } + + switch (bytes_per_pixel) { + 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 +495,8 @@ _get_image_surface (cairo_xlib_surface_t } 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 +637,35 @@ _draw_image_surface (cairo_xlib_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 byte_order = _native_byte_order (); + + 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 = byte_order; + ximage.bitmap_unit = 32; /* always for libpixman */ + ximage.bitmap_bit_order = 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; }