[cairo] [cairo/glitz] glitz patches?
Luo Jinghua
sunmoon1997 at gmail.com
Fri Nov 21 22:02:13 PST 2008
On Fri, Nov 21, 2008 at 11:13 PM, Paolo Bonzini <bonzini at gnu.org> wrote:
> Hi all,
>
> I have taken a look at glitz recently and here are my observations:
>
> 1) is there a reason why the infamous 16.6/24.8 fixed point patch has
> never been applied to Cairo (attached)? With this patch I can run
> cairogears pretty well with only a failure on the GRAD test.
>
Hi Paolo,
The patch looks trivial except it has some coding style problems. I attached
a patch with my modifies which I would like to commit to cairo repository.
Do you has any further comment?
> 2) I took a look at Nicolas Bruguier's branch and it looks like some
> things are not fleshed out yet and should probably not be applied to the
> freedesktop.org repository. For example, the BindTexImage extension
> should be replicable in the EGL/AGL backends (don't know about GLX) but
> I am not sure the API should be the same one that Nicolas used.
>
> I placed the others at http://www.inf.unisi.ch/~bonzini/webdav/glitz.git
> (branch master) together with a couple of fixes of mine. Who could
> review them and apply them at freedesktop.org?
>
> 3) I also have a patch to embed cairogears in the glitz repository, and
> a new backend for Apple's Cocoa OpenGL bindings (NSOpenGL). Would these
> be accepted? Again, who should review them and apply them at
> freedesktop.org? In the meanwhile, I placed them in the same repository
> in branch paolo.
>
> Paolo
>
> commit d25638fe1e74cd508a43e39d48ac47b353b9459c
> Author: Paolo Bonzini <bonzini at gnu.org>
> Date: Thu Nov 20 12:11:47 2008 +0100
>
> fix-glitz-backend-fixed-point
>
> diff --git a/boilerplate/cairo-boilerplate-glitz.c b/boilerplate/cairo-boilerplate-glitz.c
> index f988d16..a761148 100644
> --- a/boilerplate/cairo-boilerplate-glitz.c
> +++ b/boilerplate/cairo-boilerplate-glitz.c
> @@ -115,10 +115,12 @@ _cairo_boilerplate_glitz_glx_create_surface_internal (glitz_format_name_t form
>
> xswa.colormap = XCreateColormap (dpy, RootWindow(dpy, scr),
> vinfo->visual, AllocNone);
> + xswa.override_redirect = True;
> closure->win = XCreateWindow (dpy, RootWindow(dpy, scr),
> xsh.x, xsh.y, xsh.width, xsh.height,
> 0, vinfo->depth, CopyFromParent,
> - vinfo->visual, CWColormap, &xswa);
> + vinfo->visual,
> + CWColormap | CWOverrideRedirect, &xswa);
> XFree (vinfo);
>
> drawable =
> diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
> index 5bdfa70..ed3d727 100644
> --- a/src/cairo-glitz-surface.c
> +++ b/src/cairo-glitz-surface.c
> @@ -106,59 +106,17 @@ _cairo_glitz_surface_create_similar (void *abstract_src,
> return crsurface;
> }
>
> -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 cairo_status_t
> _cairo_glitz_get_boxes_from_region (cairo_region_t *region, glitz_box_t **boxes, int *nboxes)
> {
> - cairo_box_int_t *cboxes;
> - cairo_status_t status;
> + pixman_box32_t *pboxes;
> + cairo_status_t status = CAIRO_STATUS_SUCCESS;
> int n, i;
>
> - status = _cairo_region_get_boxes (region, &n, &cboxes);
> - if (status)
> - return status;
> -
> + pboxes = pixman_region32_rectangles (®ion->rgn, &n);
> if (n == 0) {
> - status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
> + *nboxes = 0;
> + *boxes = NULL;
> goto done;
> }
>
> @@ -169,18 +127,19 @@ _cairo_glitz_get_boxes_from_region (cairo_region_t *region, glitz_box_t **boxes,
> }
>
> for (i = 0; i < n; i++) {
> - (*boxes)[i].x1 = cboxes[i].p1.x;
> - (*boxes)[i].y1 = cboxes[i].p1.y;
> - (*boxes)[i].x2 = cboxes[i].p2.x;
> - (*boxes)[i].y2 = cboxes[i].p2.y;
> + (*boxes)[i].x1 = pboxes[i].x1;
> + (*boxes)[i].y1 = pboxes[i].y1;
> + (*boxes)[i].x2 = pboxes[i].x2;
> + (*boxes)[i].y2 = pboxes[i].y2;
> }
>
> *nboxes = n;
> done:
> - _cairo_region_boxes_fini (region, cboxes);
> return status;
> }
>
> +#define STRIDE_ALIGNMENT (sizeof (uint32_t))
> +
> static cairo_status_t
> _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
> cairo_rectangle_int_t *interest,
> @@ -194,7 +153,8 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
> cairo_format_masks_t masks;
> glitz_buffer_t *buffer;
> glitz_pixel_format_t pf;
> - cairo_format_t format;
> + cairo_status_t status;
> + pixman_format_code_t pixman_format;
>
> x1 = 0;
> y1 = 0;
> @@ -207,9 +167,9 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
> x1 = interest->x;
> if (interest->y > y1)
> y1 = interest->y;
> - if (interest->x + interest->width < x2)
> + if (interest->x + interest->width < (unsigned int)x2)
> x2 = interest->x + interest->width;
> - if (interest->y + interest->height < y2)
> + if (interest->y + interest->height < (unsigned int)y2)
> y2 = interest->y + interest->height;
>
> if (x1 >= x2 || y1 >= y2)
> @@ -266,7 +226,7 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
>
> /* XXX: we should eventually return images with negative stride,
> need to verify that libpixman have no problem with this first. */
> - pf.bytes_per_line = (((width * masks.bpp) / 8) + 3) & -4;
> + pf.bytes_per_line = ((masks.bpp*width+7)/8 + STRIDE_ALIGNMENT-1) & ~(STRIDE_ALIGNMENT-1);
> pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
>
> pixels = _cairo_malloc_ab (height, pf.bytes_per_line);
> @@ -295,8 +255,7 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
> /* restore the clip, if any */
> if (surface->has_clip) {
> glitz_box_t *box;
> - cairo_status_t status;
> - int n;
> + int n;
>
> status = _cairo_glitz_get_boxes_from_region (&surface->clip, &box, &n);
> if (status) {
> @@ -309,35 +268,19 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
> free (box);
> }
>
> - /*
> - * 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 (pixels,
> - format,
> - x2 - x1,
> - y2 - y1,
> - pf.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 (pixels,
> - &masks,
> - x2 - x1,
> - y2 - y1,
> - pf.bytes_per_line);
> - if (image->base.status)
> - goto FAIL;
> + status = _pixman_format_from_masks (&masks, &pixman_format);
> + if (status) {
> + free (pixels);
> + return status;
> }
> + image = (cairo_image_surface_t*)
> + _cairo_image_surface_create_with_pixman_format ((unsigned char *) pixels,
> + pixman_format,
> + width,
> + height,
> + pf.bytes_per_line);
> + if (image->base.status)
> + goto FAIL;
>
> _cairo_image_surface_assume_ownership_of_data (image);
>
> @@ -582,17 +525,17 @@ _cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface,
> {
> glitz_transform_t transform;
>
> - transform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx);
> - transform.matrix[0][1] = _cairo_fixed_from_double (matrix->xy);
> - transform.matrix[0][2] = _cairo_fixed_from_double (matrix->x0);
> + transform.matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx);
> + transform.matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy);
> + transform.matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0);
>
> - transform.matrix[1][0] = _cairo_fixed_from_double (matrix->yx);
> - transform.matrix[1][1] = _cairo_fixed_from_double (matrix->yy);
> - transform.matrix[1][2] = _cairo_fixed_from_double (matrix->y0);
> + transform.matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx);
> + transform.matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy);
> + transform.matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0);
>
> transform.matrix[2][0] = 0;
> transform.matrix[2][1] = 0;
> - transform.matrix[2][2] = _cairo_fixed_from_double (1);
> + transform.matrix[2][2] = _cairo_fixed_16_16_from_double (1);
>
> glitz_surface_set_transform (surface->surface, &transform);
> }
> @@ -1120,6 +1063,22 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
> {
> cairo_glitz_surface_t *dst = abstract_dst;
> cairo_glitz_surface_t *src;
> + glitz_rectangle_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (glitz_rectangle_t)];
> + glitz_rectangle_t *glitz_rects = stack_rects;
> + int i;
> +
> + if (n_rects > ARRAY_LENGTH (stack_rects)) {
> + glitz_rects = _cairo_malloc_ab (n_rects, sizeof (glitz_rectangle_t));
> + if (glitz_rects == NULL)
> + return _cairo_error (CAIRO_STATUS_NO_MEMORY);
> + }
> +
> + for (i = 0; i < n_rects; i++) {
> + glitz_rects[i].x = rects[i].x;
> + glitz_rects[i].y = rects[i].y;
> + glitz_rects[i].width = rects[i].width;
> + glitz_rects[i].height = rects[i].height;
> + }
>
> switch (op) {
> case CAIRO_OPERATOR_SOURCE: {
> @@ -1131,13 +1090,13 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
> glitz_color.alpha = color->alpha_short;
>
> glitz_set_rectangles (dst->surface, &glitz_color,
> - (glitz_rectangle_t *) rects, n_rects);
> + glitz_rects, n_rects);
> } break;
> case CAIRO_OPERATOR_CLEAR: {
> static const glitz_color_t glitz_color = { 0, 0, 0, 0 };
>
> glitz_set_rectangles (dst->surface, &glitz_color,
> - (glitz_rectangle_t *) rects, n_rects);
> + glitz_rects, n_rects);
> } break;
> case CAIRO_OPERATOR_SATURATE:
> return CAIRO_INT_STATUS_UNSUPPORTED;
> @@ -1154,7 +1113,11 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
> case CAIRO_OPERATOR_ADD:
> default:
> if (_glitz_ensure_target (dst->surface))
> + {
> + if (glitz_rects != stack_rects)
> + free (glitz_rects);
> return CAIRO_INT_STATUS_UNSUPPORTED;
> + }
>
> src = (cairo_glitz_surface_t *)
> _cairo_surface_create_similar_solid (&dst->base,
> @@ -1162,7 +1125,11 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
> 1, 1,
> (cairo_color_t *) color);
> if (src->base.status)
> + {
> + if (glitz_rects != stack_rects)
> + free (glitz_rects);
> return src->base.status;
> + }
>
> glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT);
>
> @@ -1174,8 +1141,8 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
> dst->surface,
> 0, 0,
> 0, 0,
> - rects->x, rects->y,
> - rects->width, rects->height);
> + glitz_rects->x, glitz_rects->y,
> + glitz_rects->width, glitz_rects->height);
> rects++;
> }
>
> @@ -1183,6 +1150,9 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
> break;
> }
>
> + if (glitz_rects != stack_rects)
> + free (glitz_rects);
> +
> if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
> return CAIRO_INT_STATUS_UNSUPPORTED;
>
> @@ -1213,25 +1183,60 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
> void *data = NULL;
> cairo_int_status_t status;
> unsigned short alpha;
> + pixman_trapezoid_t stack_traps[CAIRO_STACK_ARRAY_LENGTH (pixman_trapezoid_t)];
> + pixman_trapezoid_t *pixman_traps = stack_traps;
> + int i;
> +
> + /* Convert traps to pixman traps */
> + if (n_traps > ARRAY_LENGTH (stack_traps)) {
> + pixman_traps = _cairo_malloc_ab (n_traps, sizeof (pixman_trapezoid_t));
> + if (pixman_traps == NULL)
> + return _cairo_error (CAIRO_STATUS_NO_MEMORY);
> + }
> +
> + for (i = 0; i < n_traps; i++) {
> + pixman_traps[i].top = _cairo_fixed_to_16_16 (traps[i].top);
> + pixman_traps[i].bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
> + pixman_traps[i].left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
> + pixman_traps[i].left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
> + pixman_traps[i].left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
> + pixman_traps[i].left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
> + pixman_traps[i].right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
> + pixman_traps[i].right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
> + pixman_traps[i].right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
> + pixman_traps[i].right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
> + }
>
> if (antialias != CAIRO_ANTIALIAS_DEFAULT &&
> antialias != CAIRO_ANTIALIAS_GRAY)
> - return CAIRO_INT_STATUS_UNSUPPORTED;
> + {
> + status = CAIRO_INT_STATUS_UNSUPPORTED;
> + goto finish;
> + }
>
> if (dst->base.status)
> - return dst->base.status;
> + {
> + status = dst->base.status;
> + goto finish;
> + }
>
> if (op == CAIRO_OPERATOR_SATURATE)
> - return CAIRO_INT_STATUS_UNSUPPORTED;
> + {
> + status = CAIRO_INT_STATUS_UNSUPPORTED;
> + goto finish;
> + }
>
> if (_glitz_ensure_target (dst->surface))
> - return CAIRO_INT_STATUS_UNSUPPORTED;
> + {
> + status = CAIRO_INT_STATUS_UNSUPPORTED;
> + goto finish;
> + }
>
> if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
> {
> status = _cairo_pattern_init_copy (&tmp_src_pattern.base, pattern);
> if (status)
> - return status;
> + goto finish;
>
> status = _cairo_glitz_pattern_acquire_surface (&tmp_src_pattern.base,
> dst,
> @@ -1251,7 +1256,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
> alpha = 0xffff;
>
> if (status)
> - return status;
> + goto finish;
>
> if (op == CAIRO_OPERATOR_ADD || n_traps <= 1)
> {
> @@ -1286,7 +1291,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
> if (src_pattern == &tmp_src_pattern.base)
> _cairo_pattern_fini (&tmp_src_pattern.base);
>
> - return mask->base.status;
> + status = mask->base.status;
> + goto finish;
> }
>
> color.red = color.green = color.blue = color.alpha = 0xffff;
> @@ -1328,7 +1334,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
> &attributes);
> if (src_pattern == &tmp_src_pattern.base)
> _cairo_pattern_fini (&tmp_src_pattern.base);
> - return _cairo_error (CAIRO_STATUS_NO_MEMORY);
> + status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
> + goto finish;
> }
> }
>
> @@ -1336,7 +1343,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
> glitz_add_trapezoids (buffer,
> offset, size - offset,
> format.vertex.type, mask->surface,
> - (glitz_trapezoid_t *) traps, n_traps,
> + (glitz_trapezoid_t *) pixman_traps, n_traps,
> &n_trap_added);
>
> n_traps -= n_trap_added;
> @@ -1364,7 +1371,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
> _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
> if (src_pattern == &tmp_src_pattern.base)
> _cairo_pattern_fini (&tmp_src_pattern.base);
> - return _cairo_error (CAIRO_STATUS_NO_MEMORY);
> + status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
> + goto finish;
> }
>
> /* using negative stride */
> @@ -1379,11 +1387,12 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
> {
> cairo_surface_destroy (&src->base);
> free (data);
> - return image->base.status;
> + status = image->base.status;
> + goto finish;
> }
>
> pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y,
> - n_traps, (pixman_trapezoid_t *) traps);
> + n_traps, (pixman_trapezoid_t *) pixman_traps);
>
> mask = (cairo_glitz_surface_t *)
> _cairo_surface_create_similar_scratch (&dst->base,
> @@ -1393,7 +1402,8 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
> _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
> free (data);
> cairo_surface_destroy (&image->base);
> - return mask->base.status;
> + status = mask->base.status;
> + goto finish;
> }
>
> status = _cairo_glitz_surface_set_image (mask, image,
> @@ -1402,7 +1412,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
> cairo_surface_destroy(&image->base);
>
> if (status)
> - return status;
> + goto finish;
> }
>
> _cairo_glitz_surface_set_attributes (src, &attributes);
> @@ -1437,9 +1447,13 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
> cairo_surface_destroy (&mask->base);
>
> if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
> - return CAIRO_INT_STATUS_UNSUPPORTED;
> + status = CAIRO_INT_STATUS_UNSUPPORTED;
>
> - return CAIRO_STATUS_SUCCESS;
> +finish:
> + if (pixman_traps != stack_traps)
> + free (pixman_traps);
> +
> + return status;
> }
>
> static cairo_int_status_t
> @@ -1995,8 +2009,8 @@ _cairo_glitz_surface_add_glyph (cairo_glitz_surface_t *surface,
> cairo_glitz_surface_glyph_private_t *glyph_private;
> glitz_point_fixed_t p1, p2;
> glitz_pixel_format_t pf;
> - glitz_buffer_t *buffer;
> - unsigned int bpp, am, rm, gm, bm;
> + glitz_buffer_t *buffer;
> + cairo_format_masks_t masks;
> cairo_int_status_t status;
>
> glyph_private = scaled_glyph->surface_private;
> @@ -2051,14 +2065,14 @@ _cairo_glitz_surface_add_glyph (cairo_glitz_surface_t *surface,
> return _cairo_error (CAIRO_STATUS_NO_MEMORY);
> }
>
> - cairo_format_get_masks (glyph_surface->format, &bpp, &am, &rm, &gm, &bm);
> + _pixman_format_to_masks (glyph_surface->pixman_format, &masks);
>
> pf.fourcc = GLITZ_FOURCC_RGB;
> - pf.masks.bpp = bpp;
> - pf.masks.alpha_mask = am;
> - pf.masks.red_mask = rm;
> - pf.masks.green_mask = gm;
> - pf.masks.blue_mask = bm;
> + pf.masks.bpp = masks.bpp;
> + pf.masks.alpha_mask = masks.alpha_mask;
> + pf.masks.red_mask = masks.red_mask;
> + pf.masks.green_mask = masks.green_mask;
> + pf.masks.blue_mask = masks.blue_mask;
>
> pf.bytes_per_line = glyph_surface->stride;
> pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
> diff --git a/test/glitz-surface-source.c b/test/glitz-surface-source.c
> index 2dfa735..44e32fe 100644
> --- a/test/glitz-surface-source.c
> +++ b/test/glitz-surface-source.c
> @@ -126,10 +126,11 @@ _glitz_glx_create_surface (glitz_format_name_t formatname,
>
> xswa.colormap = XCreateColormap (dpy, RootWindow(dpy, scr),
> vinfo->visual, AllocNone);
> + xswa.override_redirect = True;
> closure->win = XCreateWindow (dpy, RootWindow(dpy, scr),
> xsh.x, xsh.y, xsh.width, xsh.height,
> 0, vinfo->depth, CopyFromParent,
> - vinfo->visual, CWColormap, &xswa);
> + vinfo->visual, CWColormap | CWOverrideRedirect, &xswa);
> XFree (vinfo);
>
> drawable =
>
> _______________________________________________
> cairo mailing list
> cairo at cairographics.org
> http://lists.cairographics.org/mailman/listinfo/cairo
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-glitz-bring-glitz-backend-up-to-date-with-others.patch
Type: application/octet-stream
Size: 17840 bytes
Desc: not available
Url : http://lists.cairographics.org/archives/cairo/attachments/20081122/60a968b0/attachment-0001.obj
More information about the cairo
mailing list