*** cairo-1.4.10/src/cairo-xlib-surface.c 2007-06-28 00:05:33.000000000 +0600 --- cairo-1.4.10-with-8-bit-fix/src/cairo-xlib-surface.c 2008-02-05 02:10:26.000000000 +0500 *************** *** 108,113 **** --- 108,117 ---- #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) #define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) + #define WORKAROUND_NONE 0 + #define WORKAROUND_8BIT_PALETTE 1 + #define WORKAROUND_8BIT_DIRECT 2 + static int _CAIRO_FORMAT_DEPTH (cairo_format_t format) { *************** *** 494,499 **** --- 498,571 ---- } } + static struct clut_r3g3b2 * _get_clut_r3g3b2(Display *dpy, Colormap cmap) { + static struct clut_r3g3b2 *first = NULL; + int i,j, min, d; + struct clut_r3g3b2 *clut; + unsigned char r,g,b, r2,g2,b2; + + clut = first; + while(clut) { + if ( clut->dpy == dpy && clut->cmap == cmap ) + return clut; + clut = clut->next; + } + + clut = calloc(1, sizeof(*clut)); + if(clut == NULL) + return NULL; + + clut->next = first; + clut->dpy = dpy; + clut->cmap = cmap; + first = clut; + + /* Construct the clut from Colormap */ + for (i = 0; i < 256; i++) { + XColor xcol; + xcol.pixel = i; + XQueryColor(dpy, cmap, &xcol); + clut->clut[i] = ( ( ((uint32_t)xcol.red & 0xff00 ) << 8) | + ( ((uint32_t)xcol.green & 0xff00 ) ) | + ( ((uint32_t)xcol.blue & 0xff00 ) >> 8) ); + } + /* + + Find the best matching color in the colormap for all r3g3b2 + values. The distance is maybe not perceptively valid, but it + should not be too bad. + + */ + for (i = 0; i < 256; i++) { + r = i >> 5; + g = (i >> 2) & 0x7; + b = (i << 1) & 0x7; + min = 255; + for(j = 0; j < 256; j++) { + r2 = (clut->clut[j] & 0xff0000) >> 21; + g2 = (clut->clut[j] & 0x00ff00) >> 13; + b2 = (clut->clut[j] & 0x0000ff) >> 5; + if ( r2 == r && g2 == g && (b2 & 0x6) == b ) { + clut->ilut[i] = j; + break; + } + /* + Squares make higher bits much more important than lower + ones. + */ + d = (r2 ^ r) * (r2 ^ r); + d += (g2 ^ g) * (g2 ^ g); + d += (b2 ^ b) * (b2 ^ b); + if(d < min) { + clut->ilut[i] = j; + min = d; + } + } + } + + return clut; + } + static cairo_status_t _get_image_surface (cairo_xlib_surface_t *surface, cairo_rectangle_int16_t *interest_rect, *************** *** 655,660 **** --- 727,789 ---- } else { + if ((surface->clut != NULL) && (surface->workaround == WORKAROUND_8BIT_PALETTE)) { + + /* + * Otherwise, we construct a buffer containing RGB24 data + * using the specified workaround. + */ + uint32_t *data, *dst, *clut; + uint8_t *src8; + int i,j; + + data = (uint32_t*)malloc(ximage->height * ximage->width * 4); + if (data == NULL) { + _cairo_error(CAIRO_STATUS_NO_MEMORY); + goto FAIL; + } + + clut = surface->clut->clut; + src8 = (uint8_t*) ximage->data; + dst = data; + for (j = 0; j < ximage->height; j++) { + for (i = 0; i < ximage->width; i++) + *dst++ = clut[src8[i]]; + src8 += ximage->bytes_per_line; + } + free(ximage->data); + image = (cairo_image_surface_t*) + cairo_image_surface_create_for_data ((unsigned char *)data, + CAIRO_FORMAT_RGB24, ximage->width, ximage->height, + ximage->width*4); + } else if (surface->workaround == WORKAROUND_8BIT_DIRECT) { + + uint32_t *data, *dst; + uint8_t *src8; + int i,j; + + data = (uint32_t*)malloc(ximage->height * ximage->width * 4); + if (data == NULL) { + _cairo_error(CAIRO_STATUS_NO_MEMORY); + goto FAIL; + } + + src8 = (uint8_t*) ximage->data; + dst = data; + for (j = 0; j < ximage->height; j++) { + for (i = 0; i < ximage->width; i++) + *dst++ = (src8[i] & masks.red_mask << 21) | + (src8[i] & masks.green_mask << 10 ) | + (src8[i] & masks.blue_mask ); + + src8 += ximage->bytes_per_line; + } + free(ximage->data); + image = (cairo_image_surface_t*) + cairo_image_surface_create_for_data ((unsigned char *)data, + CAIRO_FORMAT_RGB24, ximage->width, ximage->height, + ximage->width*4); + }else if (surface->workaround == WORKAROUND_NONE){ /* * XXX This can't work. We must convert the data to one of the * supported pixman formats. Pixman needs another function *************** *** 667,672 **** --- 796,803 ---- ximage->width, ximage->height, ximage->bytes_per_line); + } + if (image->base.status) goto FAIL; } *************** *** 770,775 **** --- 901,931 ---- return CAIRO_STATUS_SUCCESS; } + static int + _make_space_for(unsigned char ** buf, int *size, int *stride, int width, int height, int Bpp) + { + unsigned char * data; + int l; + + *stride = width * Bpp; + if(*stride%4) + *stride += 4 - *stride % 4; + l = (*stride * height); + if (*size < l) { + if(*buf) + data = realloc(*buf, l); + else + data = malloc(l); + if(data) { + *buf = data; + *size = l; + } else { + return -1; + } + } + return 0; + } + static cairo_status_t _draw_image_surface (cairo_xlib_surface_t *surface, cairo_image_surface_t *image, *************** *** 782,803 **** { XImage ximage; unsigned int bpp, alpha, red, green, blue; int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst; cairo_status_t status; 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; --- 938,1016 ---- { XImage ximage; unsigned int bpp, alpha, red, green, blue; + unsigned int depth = image->depth; + int stride = image->stride; int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst; cairo_status_t status; pixman_format_get_masks (pixman_image_get_format (image->pixman_image), &bpp, &alpha, &red, &green, &blue); + if ((surface->clut != NULL) && (surface->workaround == WORKAROUND_8BIT_PALETTE)) { + static unsigned char *buf = NULL; + static int size = 0; + int i, j; + unsigned char *data; + unsigned char *ilut; + uint32_t *src; + uint8_t *dst8; + + if (_make_space_for(&buf, &size, &stride, image->width, image->height, 1)) + return CAIRO_STATUS_NO_MEMORY; + data = buf; + src = (uint32_t*)image->data; + ilut = surface->clut->ilut; + for (j=0;jheight;j++) { + dst8 = data + j * stride; + for (i=0;iwidth;i++) { + dst8[i] = ilut[ ((*src >> 16) & 0xe0) | + ((*src >> 11) & 0x1c) | + ((*src >> 6) & 0x03) ]; + src++; + } + } + alpha = red = green = blue = 0; + depth = bpp = 8; + ximage.data = (char *) data; + + }else if (surface->workaround == WORKAROUND_8BIT_DIRECT){ + static unsigned char *buf = NULL; + static int size = 0; + int i, j; + unsigned char *data; + uint32_t *src; + uint8_t *dst8; + + if (_make_space_for(&buf, &size, &stride, image->width, image->height, 1)) + return CAIRO_STATUS_NO_MEMORY; + data = buf; + src = (uint32_t*)image->data; + for (j=0;jheight;j++) { + dst8 = data + j * stride; + for (i=0;iwidth;i++) { + dst8[i] = ((*src >> 16) & 0xe0) | + ((*src >> 11) & 0x1c) | + ((*src >> 6) & 0x03) ; + src++; + } + } + alpha = red = green = blue = 0; + depth = bpp = 8; + ximage.data = (char *) data; + } else if( surface->workaround == WORKAROUND_NONE){ + ximage.data = (char *)image->data; + } + ximage.width = image->width; ximage.height = image->height; ximage.format = ZPixmap; ! 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 = depth; ! ximage.bytes_per_line = stride; ximage.bits_per_pixel = bpp; ximage.red_mask = red; ximage.green_mask = green; *************** *** 2042,2047 **** --- 2255,2276 ---- surface->have_clip_rects = FALSE; surface->clip_rects = surface->embedded_clip_rects; surface->num_clip_rects = 0; + surface->clut = NULL; + + if (xrender_format == NULL && + (visual==NULL?FALSE:(visual->class == PseudoColor || visual->class == StaticColor))) { + surface->workaround = WORKAROUND_8BIT_DIRECT; + }else if (xrender_format == NULL && + (visual==NULL?FALSE:((visual->class == TrueColor) + && (surface->visual->red_mask == 0x07) + && (surface->visual->green_mask == 0x38) + && (surface->visual->blue_mask == 0xc0)))) + surface->workaround = WORKAROUND_8BIT_DIRECT; + else if (xrender_format == NULL && + (visual==NULL?FALSE:(visual->class == TrueColor))) + surface->workaround = WORKAROUND_8BIT_DIRECT; + else + surface->workaround = WORKAROUND_NONE; return (cairo_surface_t *) surface; } *** cairo-1.4.10/src/cairo-xlib-surface-private.h 2007-05-09 19:37:39.000000000 +0600 --- cairo-1.4.10-with-8-bit-fix/src/cairo-xlib-surface-private.h 2008-02-04 05:30:11.000000000 +0500 *************** *** 39,44 **** --- 39,52 ---- typedef struct _cairo_xlib_surface cairo_xlib_surface_t; + struct clut_r3g3b2 { + struct clut_r3g3b2 *next; + Display *dpy; + Colormap cmap; + uint32_t clut[256]; + unsigned char ilut[256]; + }; + struct _cairo_xlib_surface { cairo_surface_t base; *************** *** 89,94 **** --- 97,105 ---- cairo_filter_t filter; int repeat; XTransform xtransform; + + struct clut_r3g3b2 *clut; + int workaround; }; enum {