--- cairo-1.4.6/src/cairo-xlib-surface-private.h-orig 2007-05-02 14:43:14.184165000 +0800 +++ cairo-1.4.6/src/cairo-xlib-surface-private.h 2007-05-02 14:50:38.143706000 +0800 @@ -39,6 +39,14 @@ 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; @@ -88,6 +96,8 @@ struct _cairo_xlib_surface { cairo_filter_t filter; int repeat; XTransform xtransform; + + struct clut_r3g3b2 *clut; }; #endif /* CAIRO_XLIB_SURFACE_PRIVATE_H */ --- cairo-1.4.6/src/cairo-xlib-surface.c-orig 2007-05-02 14:55:09.281677000 +0800 +++ cairo-1.4.6/src/cairo-xlib-surface.c 2007-05-02 14:53:31.401179000 +0800 @@ -446,6 +446,74 @@ _swap_ximage_to_native (XImage *ximage) } } +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, @@ -607,6 +675,36 @@ _get_image_surface (cairo_xlib_surface_t } else { + if (surface->clut != NULL) { + + /* + * 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) { + printf("Cannot allocate RGB buffer\n"); + 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 { /* * XXX This can't work. We must convert the data to one of the * supported pixman formats. Pixman needs another function @@ -619,6 +717,8 @@ _get_image_surface (cairo_xlib_surface_t ximage->width, ximage->height, ximage->bytes_per_line); + } + if (image->base.status) goto FAIL; } @@ -698,6 +798,31 @@ _cairo_xlib_surface_ensure_gc (cairo_xli 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, @@ -710,22 +835,54 @@ _draw_image_surface (cairo_xlib_surface_ { XImage ximage; unsigned int bpp, alpha, red, green, blue; + unsigned int depth = image->depth; + unsigned 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) { + static unsigned char *buf = NULL; + static int size = 0; + int i, j; + unsigned char *data, *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 = data; + + } else { + ximage.data = (char *)image->data; + } + ximage.width = image->width; ximage.height = image->height; ximage.format = ZPixmap; - ximage.data = (char *)image->data; + // ximage.data is assigned above 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.depth = depth; + ximage.bytes_per_line = stride; ximage.bits_per_pixel = bpp; ximage.red_mask = red; ximage.green_mask = green; @@ -1885,6 +2042,13 @@ _cairo_xlib_surface_create_internal (Dis 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->class == PseudoColor || visual->class == StaticColor)) { + surface->clut = _get_clut_r3g3b2(dpy, + DefaultColormapOfScreen(surface->screen)); + } return (cairo_surface_t *) surface; }