1 diff -Nrup cairo-1.2.4-old/src/cairo-xlib-surface.c cairo-1.2.4/src/cairo-xlib-surface.c 2 --- cairo-1.2.4-old/src/cairo-xlib-surface.c 2007-03-09 11:11:09.769585000 +0800 3 +++ cairo-1.2.4/src/cairo-xlib-surface.c 2007-03-09 11:10:13.642282000 +0800 4 @@ -81,6 +81,8 @@ _cairo_xlib_surface_show_glyphs (void 5 6 #define CAIRO_ASSUME_PIXMAP 20 7 8 +struct clut_r3g3b2; 9 + 10 struct _cairo_xlib_surface { 11 cairo_surface_t base; 12 13 @@ -126,6 +128,9 @@ struct _cairo_xlib_surface { 14 int num_clip_rects; 15 16 XRenderPictFormat *xrender_format; 17 + 18 + struct clut_r3g3b2 *clut; 19 + int workaround; 20 }; 21 22 #define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \ 23 @@ -504,6 +509,158 @@ _swap_ximage_to_native (XImage *ximage) 24 } 25 } 26 27 +#if 0 28 +static void _set_optimal_cmap(Display *dpy, Colormap cmap) { 29 + int i, r, g, b; 30 + XColor cm[256]; 31 + 32 + for (i = 0; i < 256; i++) { 33 + r = i >> 5; 34 + g = (i >> 2) & 0x7; 35 + b = (i << 1) & 0x7; 36 + cm[i].pixel = i; 37 + cm[i].flags = DoRed | DoGreen | DoBlue; 38 + cm[i].red = r << 13 | r << 10 | r << 7 | r << 4 | r << 1 | r >> 2; 39 + cm[i].green = g << 13 | g << 10 | g << 7 | g << 4 | g << 1 | g >> 2; 40 + cm[i].blue = b << 13 | b << 10 | b << 7 | b << 4 | b << 1 | b >> 2; 41 + } 42 + XStoreColors(dpy, cmap, cm, 256); 43 +} 44 +#endif 45 + 46 +struct clut_r3g3b2 { 47 + struct clut_r3g3b2 *next; 48 + Display *dpy; 49 + Colormap cmap; 50 + uint32_t clut[256]; 51 + unsigned char ilut[256]; 52 +}; 53 + 54 +static struct clut_r3g3b2 * _get_clut_r3g3b2(Display *dpy, Colormap cmap) { 55 + static struct clut_r3g3b2 *first = NULL; 56 + int i,j, min, d; 57 + struct clut_r3g3b2 *clut; 58 + unsigned char r,g,b, r2,g2,b2; 59 + 60 + clut = first; 61 + while(clut) { 62 + if ( clut->dpy == dpy && clut->cmap == cmap ) 63 + return clut; 64 + clut = clut->next; 65 + } 66 + 67 + clut = calloc(1, sizeof(*clut)); 68 + if(clut == NULL) 69 + return NULL; 70 + 71 + clut->next = first; 72 + clut->dpy = dpy; 73 + clut->cmap = cmap; 74 + first = clut; 75 + 76 + /* Construct the clut from Colormap */ 77 + for (i = 0; i < 256; i++) { 78 + XColor xcol; 79 + xcol.pixel = i; 80 + XQueryColor(dpy, cmap, &xcol); 81 + clut->clut[i] = ( ( ((uint32_t)xcol.red & 0xff00 ) << 8) | 82 + ( ((uint32_t)xcol.green & 0xff00 ) ) | 83 + ( ((uint32_t)xcol.blue & 0xff00 ) >> 8) ); 84 + } 85 + /* 86 + 87 + Find the best matching color in the colormap for all r3g3b2 88 + values. The distance is maybe not perceptively valid, but it 89 + should not be too bad. 90 + 91 + */ 92 + for (i = 0; i < 256; i++) { 93 + r = i >> 5; 94 + g = (i >> 2) & 0x7; 95 + b = (i << 1) & 0x7; 96 + min = 255; 97 + for(j = 0; j < 256; j++) { 98 + r2 = (clut->clut[j] & 0xff0000) >> 21; 99 + g2 = (clut->clut[j] & 0x00ff00) >> 13; 100 + b2 = (clut->clut[j] & 0x0000ff) >> 5; 101 + if ( r2 == r && g2 == g && (b2 & 0x6) == b ) { 102 + clut->ilut[i] = j; 103 + break; 104 + } 105 + /* 106 + Squares make higher bits much more important than lower 107 + ones. 108 + */ 109 + d = (r2 ^ r) * (r2 ^ r); 110 + d += (g2 ^ g) * (g2 ^ g); 111 + d += (b2 ^ b) * (b2 ^ b); 112 + if(d < min) { 113 + clut->ilut[i] = j; 114 + min = d; 115 + } 116 + } 117 + } 118 + 119 + return clut; 120 +} 121 + 122 +static const char * _visualClass[] = { 123 + "StaticGray", 124 + "GrayScale", 125 + "StaticColor", 126 + "PseudoColor", 127 + "TrueColor", 128 + "DirectColor" 129 +}; 130 + 131 + 132 +static void _print_visual(Visual *v) { 133 + printf("Visual: class=%s, bpRGB=%i, CM=%i, r=%lx, g=%lx, b=%lx\n", 134 + _visualClass[v->class], 135 + v->bits_per_rgb, 136 + v->map_entries, 137 + v->red_mask, v->green_mask, v->blue_mask); 138 +} 139 + 140 + 141 +#if 0 142 +static void _print_ximage(XImage *x) { 143 + const char * format[] = { "XYBitmap", "XYPixmap", "ZPixmap" }; 144 + printf("XImage: size=(%i,%i), xoffset=%i, format=%s, depth=%i, bpp=%i, stride=%i\n r=%lx, g=%lx, b=%lx, unit=%i, pad=%i\n", 145 + x->width, 146 + x->height, 147 + x->xoffset, 148 + format[x->format], 149 + x->depth, 150 + x->bits_per_pixel, 151 + x->bytes_per_line, 152 + x->red_mask, x->green_mask, x->blue_mask, 153 + x->bitmap_unit, x->bitmap_pad); 154 +} 155 + 156 +const char * _cairoFormats[] = { "ARGB32", "RGB24", "A8", "A1" }; 157 + 158 +static void _print_cairoimage(cairo_image_surface_t *i) { 159 + 160 + printf("CairoImage: size=(%i,%i), format=%s, depth=%i, stride=%i\n", 161 + i->width, 162 + i->height, 163 + _cairoFormats[i->format], 164 + i->depth, 165 + i->stride); 166 +} 167 + 168 +static void _print_cairomasks(cairo_format_masks_t *m) { 169 + printf("CairoFormatMask: bpp=%i, a=%lx, r=%lx, g=%lx, b=%lx\n", 170 + m->bpp, m->alpha_mask, m->red_mask, m->green_mask, m->blue_mask); 171 +} 172 +#endif 173 + 174 +#define WORKAROUND_NONE 0 175 +#define WORKAROUND_8BIT_GRAYLEVEL 1 176 +#define WORKAROUND_8BIT_PALETTE 2 177 +#define WORKAROUND_R5G6B5 3 178 + 179 static cairo_status_t 180 _get_image_surface (cairo_xlib_surface_t *surface, 181 cairo_rectangle_int16_t *interest_rect, 182 @@ -657,20 +814,127 @@ _get_image_surface (cairo_xlib_surface_t 183 } 184 else 185 { 186 + /* 187 + * Otherwise, we construct a buffer containing RGB24 data 188 + * using the specified workaround. 189 + */ 190 + uint32_t *data, *dst, *clut; 191 + uint8_t *src8; 192 + uint16_t *src16; 193 + int i,j; 194 + 195 + if(surface->visual == NULL) { 196 + printf("No visual for surface\n"); 197 + goto FAIL; 198 + } 199 + 200 + if (surface->workaround == WORKAROUND_NONE) { 201 + /*printf("No workaround for this pixel format: "); 202 + _print_visual(surface->visual); 203 + goto FAIL;*/ 204 /* 205 * XXX This can't work. We must convert the data to one of the 206 * supported pixman formats. Pixman needs another function 207 * which takes data in an arbitrary format and converts it 208 * to something supported by that library. 209 */ 210 - image = (cairo_image_surface_t*) 211 - _cairo_image_surface_create_with_masks ((unsigned char *) ximage->data, 212 - &masks, 213 - ximage->width, 214 - ximage->height, 215 - ximage->bytes_per_line); 216 - if (image->base.status) 217 - goto FAIL; 218 + image = (cairo_image_surface_t*) _cairo_image_surface_create_with_masks ((unsigned char *) ximage->data, 219 + &masks, 220 + ximage->width, 221 + ximage->height, 222 + ximage->bytes_per_line); 223 + 224 + if (image->base.status) 225 + goto FAIL; 226 + /* Let the surface take ownership of the data */ 227 + _cairo_image_surface_assume_ownership_of_data (image); 228 + ximage->data = NULL; 229 + XDestroyImage (ximage); 230 + 231 + *image_out = image; 232 + return CAIRO_STATUS_SUCCESS; 233 + } 234 + 235 + data = (uint32_t*)malloc(ximage->height * ximage->width * 4); 236 + if(data == NULL) { 237 + printf("Cannot allocate RGB buffer\n"); 238 + goto FAIL; 239 + } 240 + 241 + switch (surface->workaround) { 242 + 243 + case WORKAROUND_8BIT_GRAYLEVEL: 244 + 245 + dst = data; 246 + for(j = 0; j < ximage->height; j++) { 247 + src8 = (uint8_t *) (ximage->data + ximage->bytes_per_line * j); 248 + for(i = 0; i < ximage->width; i++) { 249 + *dst++ = (*src8 << 16) | (*src8 << 8) | *src8; 250 + src8++; 251 + } 252 + } 253 + break; 254 + 255 + case WORKAROUND_8BIT_PALETTE: 256 + 257 + if(surface->clut == NULL) { 258 + surface->clut = _get_clut_r3g3b2( 259 + surface->dpy, 260 + DefaultColormapOfScreen(surface->screen)); 261 + } 262 + 263 + if(surface->clut == NULL) { 264 + free(data); 265 + goto FAIL; 266 + } 267 + 268 + clut = surface->clut->clut; 269 + src8 = (uint8_t*) ximage->data; 270 + dst = data; 271 + for(j = 0; j < ximage->height; j++) { 272 + for(i = 0; i < ximage->width; i++) 273 + *dst++ = clut[src8[i]]; 274 + src8 += ximage->bytes_per_line; 275 + } 276 + break; 277 + 278 + case WORKAROUND_R5G6B5: 279 + 280 + src16 = (uint16_t*)ximage->data; 281 + dst = data; 282 + for(j = 0; j < ximage->height; j++) { 283 + for(i = 0; i < ximage->width; i++) { 284 + *dst++ = ( ( ((src16[i] & 0xf800) << 8) | ((src16[i] & 0xe000) << 3) ) | 285 + ( ((src16[i] & 0x07e0) << 5) | ((src16[i] & 0x0600) >> 1) ) | 286 + ( ((src16[i] & 0x001f) << 3) | ((src16[i] & 0x001f) >> 2) ) ); 287 + } 288 + src16 += ximage->bytes_per_line / sizeof(*src16); 289 + } 290 + break; 291 + 292 + default: 293 + printf("Dunno what to do with: "); 294 + _print_visual(surface->visual); 295 + goto FAIL; 296 + } 297 + free(ximage->data); 298 + image = (cairo_image_surface_t*) 299 + cairo_image_surface_create_for_data((unsigned char *)data, CAIRO_FORMAT_RGB24, ximage->width, ximage->height, ximage->width*4); 300 + 301 + if (image->base.status) { 302 + printf("Failed!\n"); 303 + free(data); 304 + goto FAIL; 305 + } 306 + 307 + cairo_image_surface_create_for_data((unsigned char *)data, CAIRO_FORMAT_RGB24, ximage->width, ximage->height, ximage->width*4); 308 + 309 + if (image->base.status) { 310 + printf("Failed!\n"); 311 + free(data); 312 + goto FAIL; 313 + } 314 + 315 } 316 317 /* Let the surface take ownership of the data */ 318 @@ -743,29 +1007,139 @@ _cairo_xlib_surface_ensure_gc (cairo_xli 319 _cairo_xlib_surface_set_gc_clip_rects (surface); 320 } 321 322 +static int 323 +make_space_for(unsigned char ** buf, int *size, int *stride, int width, int height, int Bpp) { 324 + unsigned char * data; 325 + int l; 326 + 327 + *stride = width * Bpp; 328 + if(*stride%4) 329 + *stride += 4 - *stride % 4; 330 + l = (*stride * height); 331 + if (*size < l) { 332 + if(*buf) 333 + data = realloc(*buf, l); 334 + else 335 + data = malloc(l); 336 + if(data) { 337 + *buf = data; 338 + *size = l; 339 + } else { 340 + return -1; 341 + } 342 + } 343 + return 0; 344 +} 345 + 346 static cairo_status_t 347 _draw_image_surface (cairo_xlib_surface_t *surface, 348 cairo_image_surface_t *image, 349 int dst_x, 350 int dst_y) 351 { 352 + static unsigned char *buf = NULL; 353 + static int size = 0; 354 XImage ximage; 355 - unsigned int bpp, alpha, red, green, blue; 356 + unsigned int bpp, alpha, red, green, blue, stride, depth, i, j; 357 + unsigned char *data, *c, *ilut; 358 + uint32_t *src; 359 + uint8_t *dst8; 360 + uint16_t *dst16; 361 int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst; 362 363 pixman_format_get_masks (pixman_image_get_format (image->pixman_image), 364 &bpp, &alpha, &red, &green, &blue); 365 366 + switch(surface->workaround) { 367 + case WORKAROUND_NONE: 368 + /* Default behaviour is supposed to work */ 369 + stride = image->stride; 370 + depth = image->depth; 371 + data = image->data; 372 + break; 373 + 374 + case WORKAROUND_8BIT_GRAYLEVEL: 375 + 376 + if (make_space_for(&buf, &size, &stride, image->width, image->height, 1)) 377 + return CAIRO_STATUS_NO_MEMORY; 378 + data = buf; 379 + 380 + for(j=0;j<image->height;j++) { 381 + src = image->data; 382 + dst8 = data + j * stride; 383 + for(i=0;i<image->width;i++) { 384 + /* XXX use correct factor for each channel */ 385 + dst8[i] = ( ((*src >> 16) & 0xff) + 386 + ((*src >> 8) & 0xff) + 387 + (*src & 0xff) ) / 3; 388 + src++; 389 + } 390 + } 391 + 392 + alpha = red = green = blue = 0; 393 + depth = bpp = 8; 394 + break; 395 + 396 + case WORKAROUND_8BIT_PALETTE: 397 + 398 + if(surface->clut == NULL) { 399 + surface->clut = _get_clut_r3g3b2( 400 + surface->dpy, 401 + DefaultColormapOfScreen(surface->screen)); 402 + } 403 + 404 + if(surface->clut == NULL) { 405 + free(data); 406 + break; 407 + } 408 + if (make_space_for(&buf, &size, &stride, image->width, image->height, 1)) 409 + return CAIRO_STATUS_NO_MEMORY; 410 + data = buf; 411 + src = image->data; 412 + ilut = surface->clut->ilut; 413 + for(j=0;j<image->height;j++) { 414 + dst8 = data + j * stride; 415 + for(i=0;i<image->width;i++) { 416 + dst8[i] = ilut[ ((*src >> 16) & 0xe0) | 417 + ((*src >> 11) & 0x1c) | 418 + ((*src >> 6) & 0x03) ]; 419 + src++; 420 + } 421 + } 422 + alpha = red = green = blue = 0; 423 + depth = bpp = 8; 424 + break; 425 + 426 + case WORKAROUND_R5G6B5: 427 + if (make_space_for(&buf, &size, &stride, image->width, image->height, 2)) 428 + return CAIRO_STATUS_NO_MEMORY; 429 + data = buf; 430 + src = image->data; 431 + for(j=0;j<image->height;j++) { 432 + dst16 = (uint16_t*)(data + j * stride); 433 + for(i=0;i<image->width;i++) { 434 + dst16[i] = ( ((*src >> 8) & 0xf800) | 435 + ((*src >> 5) & 0x07e0) | 436 + ((*src >> 3) & 0x001f) ); 437 + src++; 438 + } 439 + } 440 + alpha = 0; red = 0xf800; green = 0x07e0; blue = 0x001f; 441 + depth = bpp = 16; 442 + break; 443 + 444 + } 445 + 446 ximage.width = image->width; 447 ximage.height = image->height; 448 ximage.format = ZPixmap; 449 - ximage.data = (char *)image->data; 450 + ximage.data = data; 451 ximage.byte_order = native_byte_order; 452 ximage.bitmap_unit = 32; /* always for libpixman */ 453 ximage.bitmap_bit_order = native_byte_order; 454 ximage.bitmap_pad = 32; /* always for libpixman */ 455 - ximage.depth = image->depth; 456 - ximage.bytes_per_line = image->stride; 457 + ximage.depth = depth; 458 + ximage.bytes_per_line = stride; 459 ximage.bits_per_pixel = bpp; 460 ximage.red_mask = red; 461 ximage.green_mask = green; 462 @@ -1891,6 +2265,36 @@ _cairo_xlib_surface_create_internal (Dis 463 surface->clip_rects = NULL; 464 surface->num_clip_rects = 0; 465 466 + surface->clut = NULL; 467 + surface->workaround = WORKAROUND_NONE; 468 + 469 + if (surface->xrender_format == NULL) { 470 + /* Install the correct workaround */ 471 + if (visual) { 472 + switch (visual->class) { 473 + case StaticGray: 474 + case GrayScale: 475 + surface->workaround = WORKAROUND_8BIT_GRAYLEVEL; 476 + break; 477 + case PseudoColor: 478 + case StaticColor: 479 + surface->workaround = WORKAROUND_8BIT_PALETTE; 480 + break; 481 + case TrueColor: 482 + if (visual->red_mask == 0xf800 && 483 + visual->green_mask == 0x07e0 && 484 + visual->blue_mask == 0x001f) { 485 + surface->workaround = WORKAROUND_R5G6B5; 486 + } 487 + 488 + } 489 + } 490 + } 491 + else if (depth == 8) 492 + { 493 + surface->workaround = WORKAROUND_8BIT_PALETTE; 494 + } 495 + 496 return (cairo_surface_t *) surface; 497 } 498 499