Use a pixman_format_code to describe the image surface used for xlib fallbacks

Previously, the code was just using cairo_format_t which is much more limited
than the formats supported by pixman, (so many "odd" X server visuals would
just fall over).
This commit is contained in:
Carl Worth 2007-08-17 10:29:37 -07:00
parent a9662d0aae
commit 72fab3675c
3 changed files with 87 additions and 136 deletions

View file

@ -71,6 +71,7 @@ static const cairo_image_surface_t _cairo_image_surface_nil_invalid_format = {
CAIRO_HINT_METRICS_DEFAULT
} /* font_options */
}, /* base */
PIXMAN_a8r8g8b8, /* pixman_format */
CAIRO_FORMAT_ARGB32, /* format */
NULL, /* data */
FALSE, /* owns_data */
@ -173,6 +174,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
surface->pixman_image = pixman_image;
surface->pixman_format = pixman_format;
surface->format = _cairo_format_from_pixman_format (pixman_format);
surface->data = (unsigned char *) pixman_image_get_data (pixman_image);
surface->owns_data = FALSE;
@ -186,49 +188,79 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
return &surface->base;
}
static cairo_bool_t
_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
/* XXX: This function should really live inside pixman. */
pixman_format_code_t
_pixman_format_from_masks (cairo_format_masks_t *masks)
{
/* XXX: many formats are simply not supported by pixman, so this function
* converts the masks into something we know will be supported.
*/
switch (masks->bpp) {
case 32:
if (masks->alpha_mask == 0xff000000 &&
masks->red_mask == 0x00ff0000 &&
masks->red_mask == 0x00ff0000 &&
masks->green_mask == 0x0000ff00 &&
masks->blue_mask == 0x000000ff)
masks->blue_mask == 0x000000ff)
{
*format = CAIRO_FORMAT_ARGB32;
return TRUE;
return PIXMAN_a8r8g8b8;
}
if (masks->alpha_mask == 0x00000000 &&
masks->red_mask == 0x00ff0000 &&
masks->red_mask == 0x00ff0000 &&
masks->green_mask == 0x0000ff00 &&
masks->blue_mask == 0x000000ff)
masks->blue_mask == 0x000000ff)
{
*format = CAIRO_FORMAT_RGB24;
return TRUE;
return PIXMAN_x8r8g8b8;
}
break;
case 8:
if (masks->alpha_mask == 0xff)
{
*format = CAIRO_FORMAT_A8;
return TRUE;
return PIXMAN_a8;
}
break;
case 1:
if (masks->alpha_mask == 0x1)
{
*format = CAIRO_FORMAT_A1;
return TRUE;
return PIXMAN_a1;
}
break;
}
return FALSE;
ASSERT_NOT_REACHED;
return 0;
}
/* XXX: This function should really live inside pixman. */
void
_pixman_format_to_masks (pixman_format_code_t pixman_format,
uint32_t *bpp,
uint32_t *red,
uint32_t *green,
uint32_t *blue)
{
*red = 0x0;
*green = 0x0;
*blue = 0x0;
switch (pixman_format)
{
case PIXMAN_a8r8g8b8:
case PIXMAN_x8r8g8b8:
default:
*bpp = 32;
*red = 0x00ff0000;
*green = 0x0000ff00;
*blue = 0x000000ff;
break;
case PIXMAN_a8:
*bpp = 8;
break;
case PIXMAN_a1:
*bpp = 1;
break;
}
}
/* XXX: This function really should be eliminated. We don't really
* want to advertise a cairo image surface that supports any possible
* format. A minimal step would be to replace this function with one
@ -240,18 +272,15 @@ _cairo_image_surface_create_with_masks (unsigned char *data,
int height,
int stride)
{
cairo_format_t format;
pixman_format_code_t pixman_format;
if (!_CAIRO_MASK_FORMAT (masks, &format)) {
_cairo_error (CAIRO_STATUS_INVALID_FORMAT);
return (cairo_surface_t*) &_cairo_surface_nil;
}
pixman_format = _pixman_format_from_masks (masks);
return cairo_image_surface_create_for_data (data,
format,
width,
height,
stride);
return _cairo_image_surface_create_with_pixman_format (data,
pixman_format,
width,
height,
stride);
}
static pixman_format_code_t
@ -277,7 +306,7 @@ _cairo_format_to_pixman_format_code (cairo_format_t format)
return ret;
}
static cairo_surface_t *
cairo_surface_t *
_cairo_image_surface_create_with_pixman_format (unsigned char *data,
pixman_format_code_t pixman_format,
int width,

View file

@ -344,46 +344,6 @@ _noop_error_handler (Display *display,
return False; /* return value is ignored */
}
static cairo_bool_t
_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
{
switch (masks->bpp) {
case 32:
if (masks->alpha_mask == 0xff000000 &&
masks->red_mask == 0x00ff0000 &&
masks->green_mask == 0x0000ff00 &&
masks->blue_mask == 0x000000ff)
{
*format = CAIRO_FORMAT_ARGB32;
return True;
}
if (masks->alpha_mask == 0x00000000 &&
masks->red_mask == 0x00ff0000 &&
masks->green_mask == 0x0000ff00 &&
masks->blue_mask == 0x000000ff)
{
*format = CAIRO_FORMAT_RGB24;
return True;
}
break;
case 8:
if (masks->alpha_mask == 0xff)
{
*format = CAIRO_FORMAT_A8;
return True;
}
break;
case 1:
if (masks->alpha_mask == 0x1)
{
*format = CAIRO_FORMAT_A1;
return True;
}
break;
}
return False;
}
static void
_swap_ximage_2bytes (XImage *ximage)
{
@ -504,7 +464,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
XImage *ximage;
short x1, y1, x2, y2;
cairo_format_masks_t masks;
cairo_format_t format;
pixman_format_code_t pixman_format;
x1 = 0;
y1 = 0;
@ -638,38 +598,15 @@ _get_image_surface (cairo_xlib_surface_t *surface,
masks.alpha_mask = 0xffffffff;
}
/*
* Prefer to use a standard pixman format instead of the
* general masks case.
*/
if (_CAIRO_MASK_FORMAT (&masks, &format))
{
image = (cairo_image_surface_t*)
cairo_image_surface_create_for_data ((unsigned char *) ximage->data,
format,
ximage->width,
ximage->height,
ximage->bytes_per_line);
if (image->base.status)
goto FAIL;
}
else
{
/*
* XXX This can't work. We must convert the data to one of the
* supported pixman formats. Pixman needs another function
* which takes data in an arbitrary format and converts it
* to something supported by that library.
*/
image = (cairo_image_surface_t*)
_cairo_image_surface_create_with_masks ((unsigned char *) ximage->data,
&masks,
ximage->width,
ximage->height,
ximage->bytes_per_line);
if (image->base.status)
goto FAIL;
}
pixman_format = _pixman_format_from_masks (&masks);
image = (cairo_image_surface_t*)
_cairo_image_surface_create_with_pixman_format ((unsigned char *) ximage->data,
pixman_format,
ximage->width,
ximage->height,
ximage->bytes_per_line);
if (image->base.status)
goto FAIL;
/* Let the surface take ownership of the data */
_cairo_image_surface_assume_ownership_of_data (image);
@ -770,38 +707,6 @@ _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
return CAIRO_STATUS_SUCCESS;
}
static void
cairo_format_get_masks (cairo_format_t format,
uint32_t *bpp,
uint32_t *red,
uint32_t *green,
uint32_t *blue)
{
*red = 0x0;
*green = 0x0;
*blue = 0x0;
switch (format)
{
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
default:
*bpp = 32;
*red = 0x00ff0000;
*green = 0x0000ff00;
*blue = 0x000000ff;
break;
case CAIRO_FORMAT_A8:
*bpp = 8;
break;
case CAIRO_FORMAT_A1:
*bpp = 1;
break;
}
}
static cairo_status_t
_draw_image_surface (cairo_xlib_surface_t *surface,
cairo_image_surface_t *image,
@ -817,7 +722,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
cairo_status_t status;
cairo_format_get_masks (image->format, &bpp, &red, &green, &blue);
_pixman_format_to_masks (image->pixman_format, &bpp, &red, &green, &blue);
ximage.width = image->width;
ximage.height = image->height;

View file

@ -915,7 +915,7 @@ typedef struct _cairo_format_masks {
struct _cairo_image_surface {
cairo_surface_t base;
/* libic-specific fields */
pixman_format_code_t pixman_format;
cairo_format_t format;
unsigned char *data;
cairo_bool_t owns_data;
@ -2005,6 +2005,23 @@ cairo_private cairo_surface_t *
_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
pixman_format_code_t pixman_format);
cairo_private pixman_format_code_t
_pixman_format_from_masks (cairo_format_masks_t *masks);
void
_pixman_format_to_masks (pixman_format_code_t pixman_format,
uint32_t *bpp,
uint32_t *red,
uint32_t *green,
uint32_t *blue);
cairo_private cairo_surface_t *
_cairo_image_surface_create_with_pixman_format (unsigned char *data,
pixman_format_code_t pixman_format,
int width,
int height,
int stride);
cairo_private cairo_surface_t *
_cairo_image_surface_create_with_masks (unsigned char *data,
cairo_format_masks_t *format,