Home | History | Annotate | Download | only in patches
      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