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 20:10:58 -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 20:10:58 -0000 @@ -60,6 +60,9 @@ _cairo_xlib_surface_ensure_dst_picture ( 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,118 @@ _CAIRO_MASK_FORMAT (cairo_format_masks_t 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 2: + case 4: + /* pixman can't actually handle these formats, but we can + * byte-swap them anyways ... */ + unit_bytes = 1; + break; + case 8: + case 16: + case 32: + unit_bytes = ximage->bits_per_pixel / 8; + break; + default: + 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 +520,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 +662,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 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; }