[Cairo] virtualizing the surface interface

Jamey Sharp jamey at minilop.net
Fri Sep 26 02:29:33 PDT 2003


So I first started reading Cairo sources less than 24 hours ago, and
here I have a fairly significant patch I'd like to propose for it. It's
an attempt to resolve this TODO item:

* Virtualize the backend interface so that the various backends can be
compiled conditionally.

I need it in order to port Cairo to XCB, and I hope it'll help the
Windows porting folks too. But since I've never looked at Cairo before,
my patch may need a little work. I believe I have sufficient privs to
commit this to CVS myself, but I'd rather have it reviewed first. If
people tell me it's good, I'll be happy to commit it.

The big changes are the introduction of the 'struct cairo_surface_impl'
type, with function pointers for implementations of the operations on
surfaces; and the removal of almost all of Cairo's Xlib-specific code to
a new source file called cairo_surface_xlib.c. The remaining X
dependencies are on Xft (in cairo_gstate.c and cairo_font.c), and this
patch #if 0's those bits into no-ops. I don't understand fonts well
enough to fix that yet, so I'm hoping somebody else will. :-)

The demos in the cairo-demo CVS module compile and run against my
patched cairo library, and appear to have the same behavior as against
current CVS. valgrind reports no new memory leaks or errors in these
demos, either. I haven't tested on any other code.

The remainder of this note has some observations I had while reading
cairo_surface.c.

I notice a couple places in cairo_surface.c that pull_image is called on
a surface without a corresponding push_image. Is that OK? It seems like
it would lead to the client doing extra work when accessing those
surfaces, then discarding that work on the next pull_image. I'm
imagining it would be useful to have a "discard_image" interface whose
semantics were to do everything push_image does, except not to cause any
data to leave the library. (No PutImage call writing to the server, for
instance.)

If either the source or the mask are not on the same display as the
destination of a composite operation, is it better to pull_image all
three, composite on the client, and push_image? or to just pull_image as
needed, push_image in new surfaces created on the destination display,
and composite on the server? For the moment, I've chosen to prefer the
server, compositing on the client only if the server can't do it or the
destination is not on an X display. The existing code chose the other
way.

I think current CVS has some memory leaks when compositing together
surfaces that are not already on the same display. The result of calling
cairo_surface_create_similar doesn't seem to be freed anywhere. I think
I can see how to use reference counting to manage this easily, but I'd
like someone to confirm that there's a problem first. If there is a
problem, my patch will probably show it even more than the current
library (but is anyone actually using Cairo with multiple Displays in a
single client?).

I think this patch fixes the problem with GetGeometry being called on an
already-freed Pixmap, without re-adding the pixmap leak. See
_cairo_surface_xlib_create_similar and _cairo_surface_xlib_destroy; I
think the problem was that create_similar was calling XFreePixmap
immediately after cairo_surface_create_for_drawable. Instead I flag that
this drawable is an internal pixmap and needs to be freed when the
surface is destroyed.

I'm looking forward to hearing thoughts from those who understand this
better than I do. Thanks in advance.
-- 
Jamey Sharp <jamey at minilop.net> - http://minilop.net/
-------------- next part --------------
Index: cairo/src/Makefile.am
===================================================================
RCS file: /local/src/CVS/cairo/src/Makefile.am,v
retrieving revision 1.8
diff -a -c -r1.8 Makefile.am
*** cairo/src/Makefile.am	5 Sep 2003 22:29:49 -0000	1.8
--- cairo/src/Makefile.am	26 Sep 2003 09:13:57 -0000
***************
*** 18,23 ****
--- 18,24 ----
  	cairo_slope.c \
  	cairo_spline.c \
  	cairo_surface.c \
+ 	cairo_surface_xlib.c \
  	cairo_traps.c \
  	cairoint.h
  
Index: cairo/src/cairo_font.c
===================================================================
RCS file: /local/src/CVS/cairo/src/cairo_font.c,v
retrieving revision 1.6
diff -a -c -r1.6 cairo_font.c
*** cairo/src/cairo_font.c	5 Sep 2003 22:29:49 -0000	1.6
--- cairo/src/cairo_font.c	26 Sep 2003 09:13:57 -0000
***************
*** 158,164 ****
--- 158,170 ----
  
      /* XXX: Need to make a generic (non-Xft) backend for text. */
      /*      When I do that I can throw away these Display pointers */
+ /* XXX: NYI - so far, too X dependent. -jamey */
+ #if 0
      font->dpy = gstate->surface->dpy;
+ #else
+     return 0;
+ #endif
+ 
      match = XftFontMatch (font->dpy, DefaultScreen (font->dpy), pattern, &result);
      if (!match)
  	return 0;
Index: cairo/src/cairo_gstate.c
===================================================================
RCS file: /local/src/CVS/cairo/src/cairo_gstate.c,v
retrieving revision 1.14
diff -a -c -r1.14 cairo_gstate.c
*** cairo/src/cairo_gstate.c	25 Sep 2003 22:01:28 -0000	1.14
--- cairo/src/cairo_gstate.c	26 Sep 2003 09:13:57 -0000
***************
*** 1091,1096 ****
--- 1091,1098 ----
  			    double *width, double *height,
  			    double *dx, double *dy)
  {
+ /* XXX: NYI - so far, too X dependent. -jamey */
+ #if 0
      XftFont *xft_font;
      XGlyphInfo extents;
  
***************
*** 1115,1120 ****
--- 1117,1123 ----
      *height = extents.height;
      *dx = extents.xOff;
      *dy = extents.yOff;
+ #endif
  
      return CAIRO_STATUS_SUCCESS;
  }
***************
*** 1122,1127 ****
--- 1125,1132 ----
  cairo_status_t
  _cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8)
  {
+ /* XXX: NYI - so far, too X dependent. -jamey */
+ #if 0
      cairo_status_t status;
      XftFont *xft_font;
      double x, y;
***************
*** 1171,1176 ****
--- 1176,1182 ----
      /* restore the matrix originally in the source surface */
      if (! gstate->source_is_solid)
  	cairo_surface_set_matrix (gstate->source, &user_to_source);
+ #endif
  
      return CAIRO_STATUS_SUCCESS;
  }
Index: cairo/src/cairo_surface.c
===================================================================
RCS file: /local/src/CVS/cairo/src/cairo_surface.c,v
retrieving revision 1.10
diff -a -c -r1.10 cairo_surface.c
*** cairo/src/cairo_surface.c	16 Sep 2003 17:28:46 -0000	1.10
--- cairo/src/cairo_surface.c	26 Sep 2003 09:13:57 -0000
***************
*** 37,71 ****
      }
  };
  
- #define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
- 	(((surface)->render_major > major) ? 1		  \
- 	 : ((surface)->render_major == major) ? ((surface)->render_minor >= minor) : 0)
- 
- #define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
- #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
- 
- #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
- #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
- 
- #define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface)			CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
- #define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface)			CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
- 
- #define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
- #define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
- #define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface)			CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
- #define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface)			CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
- 
- #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface)	CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
- 
- static IcFormat *
- _create_icformat_for_visual (Visual *visual)
- {
-     return IcFormatCreateMasks (32, 0,
- 				visual->red_mask,
- 				visual->green_mask,
- 				visual->blue_mask);
- }
- 
  static IcFormat *
  _create_icformat_for_format (cairo_format_t format)
  {
--- 37,42 ----
***************
*** 87,152 ****
      }
  }
  
! cairo_surface_t *
! cairo_surface_create_for_drawable (Display		*dpy,
! 				   Drawable		drawable,
! 				   Visual		*visual,
! 				   cairo_format_t	format,
! 				   Colormap		colormap)
  {
!     cairo_surface_t *surface;
  
!     surface = malloc (sizeof (cairo_surface_t));
!     if (surface == NULL)
! 	return NULL;
  
      /* XXX: We should really get this value from somewhere like Xft.dpy */
      surface->ppm = 3780;
      surface->ref_count = 1;
      surface->repeat = 0;
  
-     surface->dpy = dpy;
-     surface->image_data = NULL;
-     surface->icimage = NULL;
- 
-     surface->type = CAIRO_SURFACE_TYPE_DRAWABLE;
      surface->xtransform = CAIRO_XTRANSFORM_IDENTITY;
  
!     surface->gc = 0;
!     surface->drawable = drawable;
!     surface->visual = visual;
! 
!     if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
! 	surface->render_major = -1;
! 	surface->render_minor = -1;
!     }
! 
!     if (visual)
! 	surface->icformat = _create_icformat_for_visual (visual);
!     else
! 	surface->icformat = _create_icformat_for_format (format);
! 
!     /* XXX: I'm currently ignoring the colormap. Is that bad? */
!     if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
! 	surface->picture = XRenderCreatePicture (dpy, drawable,
! 						 visual ?
! 						 XRenderFindVisualFormat (dpy, visual) :
! 						 XRenderFindStandardFormat (dpy, format),
! 						 0, NULL);
!     else
! 	surface->picture = 0;
! 
!     surface->ximage = NULL;
! 
!     /* XXX: How to get the proper width/height? Force a roundtrip? And
!        how can we track the width/height properly? Shall we give up on
!        supporting Windows and only allow drawing to pixmaps? */
!     surface->width = 0;
!     surface->height = 0;
  
!     return surface;
  }
- slim_hidden_def(cairo_surface_create_for_drawable);
  
  static int
  cairo_format_bpp (cairo_format_t format)
--- 58,88 ----
      }
  }
  
! void
! _cairo_surface_init (cairo_surface_t			*surface,
! 		     int				width,
! 		     int				height,
! 		     cairo_format_t			format,
! 		     const struct cairo_surface_impl	*impl)
  {
!     surface->width = width;
!     surface->height = height;
  
!     surface->image_data = NULL;
  
      /* XXX: We should really get this value from somewhere like Xft.dpy */
+     /* Assume a default until the user lets us know otherwise */
      surface->ppm = 3780;
      surface->ref_count = 1;
      surface->repeat = 0;
  
      surface->xtransform = CAIRO_XTRANSFORM_IDENTITY;
  
!     surface->icimage = NULL;
!     surface->icformat = _create_icformat_for_format (format);
  
!     surface->impl = impl;
  }
  
  static int
  cairo_format_bpp (cairo_format_t format)
***************
*** 166,171 ****
--- 102,109 ----
      }
  }
  
+ static const struct cairo_surface_impl cairo_surface_icimage_impl;
+ 
  cairo_surface_t *
  cairo_surface_create_for_image (char		*data,
  				cairo_format_t	format,
***************
*** 179,196 ****
      if (surface == NULL)
  	return NULL;
  
!     surface->icformat = _create_icformat_for_format (format);
! 
!     /* Assume a default until the user lets us know otherwise */
!     surface->ppm = 3780;
!     surface->ref_count = 1;
!     surface->repeat = 0;
! 
!     surface->dpy = NULL;
!     surface->image_data = NULL;
! 
!     surface->width = width;
!     surface->height = height;
  
      surface->icimage = IcImageCreateForData ((IcBits *) data,
  					     surface->icformat,
--- 117,123 ----
      if (surface == NULL)
  	return NULL;
  
!     _cairo_surface_init (surface, width, height, format, &cairo_surface_icimage_impl);
  
      surface->icimage = IcImageCreateForData ((IcBits *) data,
  					     surface->icformat,
***************
*** 202,219 ****
  	return NULL;
      }
  
-     surface->type = CAIRO_SURFACE_TYPE_ICIMAGE;
-     surface->xtransform = CAIRO_XTRANSFORM_IDENTITY;
- 
-     surface->gc = 0;
-     surface->drawable = 0;
-     surface->visual = NULL;
-     surface->render_major = -1;
-     surface->render_minor = -1;
- 
-     surface->picture = 0;
-     surface->ximage = NULL;
- 
      return surface;
  }
  slim_hidden_def(cairo_surface_create_for_image);
--- 129,134 ----
***************
*** 227,248 ****
      return cairo_surface_create_similar_solid (other, format, width, height, 0, 0, 0, 0);
  }
  
- static int
- _CAIRO_FORMAT_DEPTH (cairo_format_t format)
- {
-     switch (format) {
-     case CAIRO_FORMAT_A1:
- 	return 1;
-     case CAIRO_FORMAT_A8:
- 	return 8;
-     case CAIRO_FORMAT_RGB24:
- 	return 24;
-     case CAIRO_FORMAT_ARGB32:
-     default:
- 	return 32;
-     }
- }
- 
  cairo_surface_t *
  cairo_surface_create_similar_solid (cairo_surface_t	*other,
  				    cairo_format_t	format,
--- 142,147 ----
***************
*** 256,283 ****
      cairo_surface_t *surface = NULL;
      cairo_color_t color;
  
!     /* XXX: There's a pretty lame heuristic here. This assumes that
!      * all non-Render X servers do not support depth-32 pixmaps, (and
!      * that they do support depths 1, 8, and 24). Obviously, it would
!      * be much better to check the depths that are actually
!      * supported. */
!     if (other->dpy
! 	&& (CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other)
! 	    || format != CAIRO_FORMAT_ARGB32)) {
! 	Display *dpy = other->dpy;
! 	int scr = DefaultScreen (dpy);
! 
! 	Pixmap pix = XCreatePixmap (dpy,
! 				    DefaultRootWindow (dpy),
! 				    width, height,
! 				    _CAIRO_FORMAT_DEPTH (format));
! 
! 	surface = cairo_surface_create_for_drawable (dpy, pix,
! 						     NULL,
! 						     format,
! 						     DefaultColormap (dpy, scr));
! 	XFreePixmap (surface->dpy, pix);
!     } else {
  	char *data;
  	int stride;
  
--- 155,164 ----
      cairo_surface_t *surface = NULL;
      cairo_color_t color;
  
!     if (other->impl->create_similar)
! 	surface = other->impl->create_similar (other, format, width, height);
! 
!     if (!surface) {
  	char *data;
  	int stride;
  
***************
*** 323,468 ****
      if (surface->ref_count)
  	return;
  
-     if (surface->picture)
- 	XRenderFreePicture (surface->dpy, surface->picture);
- 
      if (surface->icformat)
  	IcFormatDestroy (surface->icformat);
! 	
      if (surface->icimage)
  	IcImageDestroy (surface->icimage);
  
      if (surface->image_data)
  	free (surface->image_data);
      surface->image_data = NULL;
  
-     surface->dpy = 0;
- 
      free (surface);
  }
  slim_hidden_def(cairo_surface_destroy);
  
- static void
- _cairo_surface_ensure_gc (cairo_surface_t *surface)
- {
-     if (surface->gc)
- 	return;
- 
-     surface->gc = XCreateGC (surface->dpy, surface->drawable, 0, NULL);
- }
- 
- static cairo_status_t
- _cairo_x11_surface_put_image (cairo_surface_t       *surface,
- 			      char                   *data,
- 			      int                    width,
- 			      int                    height,
- 			      int                    stride)
- {
-     if (surface->picture) {
- 	XImage *image;
- 	unsigned bitmap_pad;
- 	
- 	/* XXX: This is obviously bogus. depth needs to be figured out for real */
- 	int depth = 32;
- 
- 	if (depth > 16)
- 	    bitmap_pad = 32;
- 	else if (depth > 8)
- 	    bitmap_pad = 16;
- 	else
- 	    bitmap_pad = 8;
- 
- 	image = XCreateImage(surface->dpy,
- 			     DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)),
- 			     depth, ZPixmap, 0,
- 			     data, width, height,
- 			     bitmap_pad,
- 			     stride);
- 	if (image == NULL)
- 	    return CAIRO_STATUS_NO_MEMORY;
- 
- 	_cairo_surface_ensure_gc (surface);
- 	XPutImage(surface->dpy, surface->drawable, surface->gc,
- 		  image, 0, 0, 0, 0, width, height);
- 
- 	/* Foolish XDestroyImage thinks it can free my data, but I won't
- 	   stand for it. */
- 	image->data = NULL;
- 	XDestroyImage(image);
-     } else {
- 	/* XXX: Need to implement the IcImage method of setting a picture. memcpy? */
-     }
-     
-     return CAIRO_STATUS_SUCCESS;
- }
- 
  void
  _cairo_surface_pull_image (cairo_surface_t *surface)
  {
!     Window root_ignore;
!     int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
! 
!     if (surface == NULL)
! 	return;
! 
!     if (surface->type == CAIRO_SURFACE_TYPE_ICIMAGE)
! 	return;
! 
!     if (surface->icimage) {
! 	IcImageDestroy (surface->icimage);
! 	surface->icimage = NULL;
!     }
! 
!     XGetGeometry(surface->dpy, 
! 		 surface->drawable, 
! 		 &root_ignore, &x_ignore, &y_ignore,
! 		 &surface->width, &surface->height,
! 		 &bwidth_ignore, &depth_ignore);
! 
!     surface->ximage = XGetImage (surface->dpy,
! 				 surface->drawable,
! 				 0, 0,
! 				 surface->width, surface->height,
! 				 AllPlanes, ZPixmap);
! 
!     surface->icimage = IcImageCreateForData ((IcBits *)(surface->ximage->data),
! 					     surface->icformat,
! 					     surface->ximage->width, 
! 					     surface->ximage->height,
! 					     surface->ximage->bits_per_pixel, 
! 					     surface->ximage->bytes_per_line);
!      
!     IcImageSetRepeat (surface->icimage, surface->repeat);
!     /* XXX: Evil cast here... */
!     IcImageSetTransform (surface->icimage, (IcTransform *) &(surface->xtransform));
!     
!     /* XXX: Add support here for pictures with external alpha. */
  }
  
  void
  _cairo_surface_push_image (cairo_surface_t *surface)
  {
!     if (surface == NULL)
! 	return;
! 
!     if (surface->type == CAIRO_SURFACE_TYPE_ICIMAGE)
! 	return;
! 
!     if (surface->ximage == NULL)
! 	return;
! 
!     _cairo_surface_ensure_gc (surface);
!     XPutImage (surface->dpy,
! 	       surface->drawable,
! 	       surface->gc,
! 	       surface->ximage,
! 	       0, 0,
! 	       0, 0,
! 	       surface->width,
! 	       surface->height);
! 
!     XDestroyImage(surface->ximage);
!     surface->ximage = NULL;
  }
  
  /* XXX: We may want to move to projective matrices at some point. If
--- 204,238 ----
      if (surface->ref_count)
  	return;
  
      if (surface->icformat)
  	IcFormatDestroy (surface->icformat);
! 
      if (surface->icimage)
  	IcImageDestroy (surface->icimage);
  
+     if (surface->impl->destroy)
+ 	surface->impl->destroy (surface);
+ 
      if (surface->image_data)
  	free (surface->image_data);
      surface->image_data = NULL;
  
      free (surface);
  }
  slim_hidden_def(cairo_surface_destroy);
  
  void
  _cairo_surface_pull_image (cairo_surface_t *surface)
  {
!     if (surface->impl->pull_image)
! 	surface->impl->pull_image (surface);
  }
  
  void
  _cairo_surface_push_image (cairo_surface_t *surface)
  {
!     if (surface->impl->push_image)
! 	surface->impl->push_image (surface);
  }
  
  /* XXX: We may want to move to projective matrices at some point. If
***************
*** 471,476 ****
--- 241,247 ----
  cairo_status_t
  cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
  {
+     cairo_status_t ret;
      XTransform *xtransform = &surface->xtransform;
  
      xtransform->matrix[0][0] = XDoubleToFixed (matrix->m[0][0]);
***************
*** 485,503 ****
      xtransform->matrix[2][1] = 0;
      xtransform->matrix[2][2] = XDoubleToFixed (1);
  
!     if (surface->picture) {
! 	if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
! 	    XRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
! 	/* XXX: Need support here if using an old RENDER without support
!            for SetPictureTransform */
!     }
  
      /* XXX: This cast should only occur with a #define hint from libic that it is OK */
      if (surface->icimage) {
  	IcImageSetTransform (surface->icimage, (IcTransform *) xtransform);
      }
  
!     return CAIRO_STATUS_SUCCESS;
  }
  slim_hidden_def(cairo_surface_set_matrix);
  
--- 256,270 ----
      xtransform->matrix[2][1] = 0;
      xtransform->matrix[2][2] = XDoubleToFixed (1);
  
!     if (surface->impl->set_matrix)
! 	ret = surface->impl->set_matrix (surface);
  
      /* XXX: This cast should only occur with a #define hint from libic that it is OK */
      if (surface->icimage) {
  	IcImageSetTransform (surface->icimage, (IcTransform *) xtransform);
      }
  
!     return ret;
  }
  slim_hidden_def(cairo_surface_set_matrix);
  
***************
*** 518,558 ****
  }
  slim_hidden_def(cairo_surface_get_matrix);
  
- /* XXX: The Render specification has capitalized versions of these
-    strings. However, the current implementation is case-sensitive and
-    expects lowercase versions. */
- static char *
- _render_filter_name (cairo_filter_t filter)
- {
-     switch (filter) {
-     case CAIRO_FILTER_FAST:
- 	return "fast";
-     case CAIRO_FILTER_GOOD:
- 	return "good";
-     case CAIRO_FILTER_BEST:
- 	return "best";
-     case CAIRO_FILTER_NEAREST:
- 	return "nearest";
-     case CAIRO_FILTER_BILINEAR:
- 	return "bilinear";
-     default:
- 	return "best";
-     }
- }
- 
  cairo_status_t
  cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
  {
-     if (surface->picture) {
- 	XRenderSetPictureFilter (surface->dpy, surface->picture,
- 				 _render_filter_name (filter), NULL, 0);
-     }
- 
      if (surface->icimage) {
  	IcImageSetFilter (surface->icimage, filter);
      }
  
!     return CAIRO_STATUS_SUCCESS;
  }
  
  /* XXX: NYI
--- 285,301 ----
  }
  slim_hidden_def(cairo_surface_get_matrix);
  
  cairo_status_t
  cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
  {
      if (surface->icimage) {
  	IcImageSetFilter (surface->icimage, filter);
      }
  
!     if (!surface->impl->set_filter)
! 	return CAIRO_STATUS_SUCCESS;
! 
!     return surface->impl->set_filter (surface, filter);
  }
  
  /* XXX: NYI
***************
*** 575,595 ****
  {
      surface->repeat = repeat;
  
-     if (surface->picture) {
- 	unsigned long mask;
- 	XRenderPictureAttributes pa;
- 	
- 	mask = CPRepeat;
- 	pa.repeat = repeat;
- 
- 	XRenderChangePicture (surface->dpy, surface->picture, mask, &pa);
-     }
- 
      if (surface->icimage) {
  	IcImageSetRepeat (surface->icimage, repeat);
      }
  
!     return CAIRO_STATUS_SUCCESS;
  }
  slim_hidden_def(cairo_surface_set_repeat);
  
--- 318,331 ----
  {
      surface->repeat = repeat;
  
      if (surface->icimage) {
  	IcImageSetRepeat (surface->icimage, repeat);
      }
  
!     if (!surface->impl->set_repeat)
! 	return CAIRO_STATUS_SUCCESS;
! 
!     return surface->impl->set_repeat (surface, repeat);
  }
  slim_hidden_def(cairo_surface_set_repeat);
  
***************
*** 607,664 ****
  			  unsigned int		width,
  			  unsigned int		height)
  {
!     if (dst->type == CAIRO_SURFACE_TYPE_DRAWABLE
! 	&& CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)
! 	&& (mask == NULL || mask->dpy == dst->dpy)
! 	&& (src->type == CAIRO_SURFACE_TYPE_ICIMAGE || src->dpy == dst->dpy)) {
! 
! 	cairo_surface_t *src_on_server = NULL;
! 
! 	if (src->type == CAIRO_SURFACE_TYPE_ICIMAGE) {
! 	    cairo_matrix_t matrix;
! 	    src_on_server = cairo_surface_create_similar (dst, CAIRO_FORMAT_ARGB32,
! 							  IcImageGetWidth (src->icimage),
! 							  IcImageGetWidth (src->icimage));
! 	    if (src_on_server == NULL)
! 		return;
! 
! 	    cairo_surface_get_matrix (src, &matrix);
! 	    cairo_surface_set_matrix (src_on_server, &matrix);
! 
! 	    _cairo_x11_surface_put_image (src_on_server,
! 					  (char *) IcImageGetData (src->icimage),
! 					  IcImageGetWidth (src->icimage),
! 					  IcImageGetHeight (src->icimage),
! 					  IcImageGetStride (src->icimage));
! 	}
! 
! 	XRenderComposite (dst->dpy, operator,
! 			  src_on_server ? src_on_server->picture : src->picture,
! 			  mask ? mask->picture : 0,
! 			  dst->picture,
! 			  src_x, src_y,
! 			  mask_x, mask_y,
! 			  dst_x, dst_y,
! 			  width, height);
! 	
! 	
!     } else {
! 	_cairo_surface_pull_image (src);
! 	if (mask)
! 	    _cairo_surface_pull_image (mask);
! 	_cairo_surface_pull_image (dst);
! 
! 	IcComposite (operator,
! 		     src->icimage,
! 		     mask ? mask->icimage : NULL,
! 		     dst->icimage,
! 		     src_x, src_y,
! 		     mask_x, mask_y,
! 		     dst_x, dst_y,
! 		     width, height);
  
! 	_cairo_surface_push_image (dst);
!     }
  }
  
  void
--- 343,367 ----
  			  unsigned int		width,
  			  unsigned int		height)
  {
!     if (dst->impl->composite
! 	&& (dst->impl->composite (operator, src, mask, dst, src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height) >= 0))
! 	return;
  
!     _cairo_surface_pull_image (src);
!     if (mask)
! 	_cairo_surface_pull_image (mask);
!     _cairo_surface_pull_image (dst);
! 
!     IcComposite (operator,
! 		 src->icimage,
! 		 mask ? mask->icimage : NULL,
! 		 dst->icimage,
! 		 src_x, src_y,
! 		 mask_x, mask_y,
! 		 dst_x, dst_y,
! 		 width, height);
! 
!     _cairo_surface_push_image (dst);
  }
  
  void
***************
*** 687,724 ****
  				cairo_rectangle_t	*rects,
  				int			num_rects)
  {
      if (num_rects == 0)
  	return;
  
!     if (surface->type == CAIRO_SURFACE_TYPE_DRAWABLE
! 	&& CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface)) {
  
! 	XRenderColor render_color;
! 	render_color.red   = color->red_short;
! 	render_color.green = color->green_short;
! 	render_color.blue  = color->blue_short;
! 	render_color.alpha = color->alpha_short;
! 
! 	/* XXX: This XRectangle cast is evil... it needs to go away somehow. */
! 	XRenderFillRectangles (surface->dpy, operator, surface->picture,
! 			       &render_color, (XRectangle *) rects, num_rects);
! 
!     } else {
! 	IcColor ic_color;
! 
! 	ic_color.red   = color->red_short;
! 	ic_color.green = color->green_short;
! 	ic_color.blue  = color->blue_short;
! 	ic_color.alpha = color->alpha_short;
! 
! 	_cairo_surface_pull_image (surface);
! 
! 	/* XXX: The IcRectangle cast is evil... it needs to go away somehow. */
! 	IcFillRectangles (operator, surface->icimage,
! 			  &ic_color, (IcRectangle *) rects, num_rects);
  
! 	_cairo_surface_push_image (surface);
!     }
  }
  
  void
--- 390,416 ----
  				cairo_rectangle_t	*rects,
  				int			num_rects)
  {
+     IcColor ic_color;
+ 
      if (num_rects == 0)
  	return;
  
!     if (surface->impl->fill_rectangles
! 	&& (surface->impl->fill_rectangles (surface, operator, color, rects, num_rects) >= 0))
! 	return;
  
!     ic_color.red   = color->red_short;
!     ic_color.green = color->green_short;
!     ic_color.blue  = color->blue_short;
!     ic_color.alpha = color->alpha_short;
! 
!     _cairo_surface_pull_image (surface);
! 
!     /* XXX: The IcRectangle cast is evil... it needs to go away somehow. */
!     IcFillRectangles (operator, surface->icimage,
! 		      &ic_color, (IcRectangle *) rects, num_rects);
  
!     _cairo_surface_push_image (surface);
  }
  
  void
***************
*** 730,752 ****
  				     cairo_trapezoid_t		*traps,
  				     int			num_traps)
  {
!     if (dst->type == CAIRO_SURFACE_TYPE_DRAWABLE
! 	&& CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)
! 	&& src->dpy == dst->dpy) {
! 
! 	/* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
! 	XRenderCompositeTrapezoids (dst->dpy, operator, src->picture, dst->picture,
! 				    XRenderFindStandardFormat (dst->dpy, PictStandardA8),
! 				    xSrc, ySrc, (XTrapezoid *) traps, num_traps);
!     } else {
! 	_cairo_surface_pull_image (src);
! 	_cairo_surface_pull_image (dst);
! 
! 	/* XXX: The IcTrapezoid cast is evil and needs to go away somehow. */
! 	IcCompositeTrapezoids (operator, src->icimage, dst->icimage,
! 			       xSrc, ySrc, (IcTrapezoid *) traps, num_traps);
  
! 	_cairo_surface_push_image (dst);
!     }
  }
  
--- 422,438 ----
  				     cairo_trapezoid_t		*traps,
  				     int			num_traps)
  {
!     if (dst->impl->composite_trapezoids
! 	&& (dst->impl->composite_trapezoids (operator, src, dst, xSrc, ySrc, traps, num_traps) >= 0))
! 	return;
  
!     _cairo_surface_pull_image (src);
!     _cairo_surface_pull_image (dst);
! 
!     /* XXX: The IcTrapezoid cast is evil and needs to go away somehow. */
!     IcCompositeTrapezoids (operator, src->icimage, dst->icimage,
! 			   xSrc, ySrc, (IcTrapezoid *) traps, num_traps);
! 
!     _cairo_surface_push_image (dst);
  }
  
Index: cairo/src/cairo_surface_xlib.c
===================================================================
RCS file: cairo/src/cairo_surface_xlib.c
diff -N cairo/src/cairo_surface_xlib.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- cairo/src/cairo_surface_xlib.c	26 Sep 2003 09:13:57 -0000
***************
*** 0 ****
--- 1,501 ----
+ /*
+  * Copyright ? 2002 USC, Information Sciences Institute
+  *
+  * Permission to use, copy, modify, distribute, and sell this software
+  * and its documentation for any purpose is hereby granted without
+  * fee, provided that the above copyright notice appear in all copies
+  * and that both that copyright notice and this permission notice
+  * appear in supporting documentation, and that the name of the
+  * University of Southern California not be used in advertising or
+  * publicity pertaining to distribution of the software without
+  * specific, written prior permission. The University of Southern
+  * California makes no representations about the suitability of this
+  * software for any purpose.  It is provided "as is" without express
+  * or implied warranty.
+  *
+  * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
+  * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+  * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
+  * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  *
+  * Author: Carl D. Worth <cworth at isi.edu>
+  */
+ 
+ #include "cairoint.h"
+ 
+ typedef struct cairo_surface_xlib {
+     cairo_surface_t base;
+ 
+     Display *dpy;
+     GC gc;
+     Drawable drawable;
+     int free_pixmap;
+     Visual *visual;
+ 
+     int render_major;
+     int render_minor;
+ 
+     Picture picture;
+     XImage *ximage;
+ } cairo_surface_xlib;
+ 
+ #define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor)	\
+ 	(((surface)->render_major > major) ||			\
+ 	 ((surface)->render_major == major) && ((surface)->render_minor >= minor))
+ 
+ #define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
+ #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
+ 
+ #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
+ #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
+ 
+ #define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface)			CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
+ #define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface)			CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
+ 
+ #define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+ #define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+ #define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface)			CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+ #define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface)			CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+ 
+ #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface)	CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
+ 
+ static int
+ _CAIRO_FORMAT_DEPTH (cairo_format_t format)
+ {
+     switch (format) {
+     case CAIRO_FORMAT_A1:
+ 	return 1;
+     case CAIRO_FORMAT_A8:
+ 	return 8;
+     case CAIRO_FORMAT_RGB24:
+ 	return 24;
+     case CAIRO_FORMAT_ARGB32:
+     default:
+ 	return 32;
+     }
+ }
+ 
+ static cairo_surface_xlib *
+ _cairo_surface_xlib_create_similar (cairo_surface_xlib	*other,
+ 				    cairo_format_t	format,
+ 				    int			width,
+ 				    int			height)
+ {
+     Display *dpy = other->dpy;
+     int scr;
+     Pixmap pix;
+     cairo_surface_xlib *surface;
+ 
+     /* XXX: There's a pretty lame heuristic here. This assumes that
+      * all non-Render X servers do not support depth-32 pixmaps, (and
+      * that they do support depths 1, 8, and 24). Obviously, it would
+      * be much better to check the depths that are actually
+      * supported. */
+     if (!dpy
+ 	|| (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other)
+ 	    && format == CAIRO_FORMAT_ARGB32))
+ 	return 0;
+ 
+     scr = DefaultScreen (dpy);
+ 
+     pix = XCreatePixmap (dpy, DefaultRootWindow (dpy),
+ 			 width, height,
+ 			 _CAIRO_FORMAT_DEPTH (format));
+ 
+     surface = (cairo_surface_xlib *)
+ 	cairo_surface_create_for_drawable (dpy, pix, NULL, format,
+ 					   DefaultColormap (dpy, scr));
+     surface->free_pixmap = 1;
+ 
+     return surface;
+ }
+ 
+ static void
+ _cairo_surface_xlib_destroy (cairo_surface_xlib *surface)
+ {
+     if (surface->picture)
+ 	XRenderFreePicture (surface->dpy, surface->picture);
+ 
+     if (surface->free_pixmap)
+ 	XFreePixmap (surface->dpy, surface->drawable);
+ 
+     surface->dpy = 0;
+ }
+ 
+ static void
+ _cairo_surface_xlib_pull_image (cairo_surface_xlib *surface)
+ {
+     Window root_ignore;
+     int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
+ 
+     if (surface == NULL)
+ 	return;
+ 
+     if (surface->base.icimage) {
+ 	IcImageDestroy (surface->base.icimage);
+ 	surface->base.icimage = NULL;
+     }
+ 
+     XGetGeometry(surface->dpy, 
+ 		 surface->drawable, 
+ 		 &root_ignore, &x_ignore, &y_ignore,
+ 		 &surface->base.width, &surface->base.height,
+ 		 &bwidth_ignore, &depth_ignore);
+ 
+     surface->ximage = XGetImage (surface->dpy,
+ 				 surface->drawable,
+ 				 0, 0,
+ 				 surface->base.width, surface->base.height,
+ 				 AllPlanes, ZPixmap);
+ 
+     surface->base.icimage = IcImageCreateForData ((IcBits *)(surface->ximage->data),
+ 						  surface->base.icformat,
+ 						  surface->ximage->width, 
+ 						  surface->ximage->height,
+ 						  surface->ximage->bits_per_pixel, 
+ 						  surface->ximage->bytes_per_line);
+      
+     IcImageSetRepeat (surface->base.icimage, surface->base.repeat);
+     /* XXX: Evil cast here... */
+     IcImageSetTransform (surface->base.icimage, (IcTransform *) &(surface->base.xtransform));
+     
+     /* XXX: Add support here for pictures with external alpha. */
+ }
+ 
+ static void
+ _cairo_surface_ensure_gc (cairo_surface_xlib *surface)
+ {
+     if (surface->gc)
+ 	return;
+ 
+     surface->gc = XCreateGC (surface->dpy, surface->drawable, 0, NULL);
+ }
+ 
+ void
+ _cairo_surface_xlib_push_image (cairo_surface_xlib *surface)
+ {
+     if (surface == NULL)
+ 	return;
+ 
+     if (surface->ximage == NULL)
+ 	return;
+ 
+     _cairo_surface_ensure_gc (surface);
+     XPutImage (surface->dpy,
+ 	       surface->drawable,
+ 	       surface->gc,
+ 	       surface->ximage,
+ 	       0, 0,
+ 	       0, 0,
+ 	       surface->base.width,
+ 	       surface->base.height);
+ 
+     XDestroyImage(surface->ximage);
+     surface->ximage = NULL;
+ }
+ 
+ static cairo_status_t
+ _cairo_surface_xlib_set_matrix (cairo_surface_xlib *surface)
+ {
+     if (!surface->picture)
+ 	return CAIRO_STATUS_SUCCESS;
+ 
+     if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
+     {
+ 	XRenderSetPictureTransform (surface->dpy, surface->picture, &surface->base.xtransform);
+     } else {
+ 	/* XXX: Need support here if using an old RENDER without support
+ 	   for SetPictureTransform */
+     }
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ /* XXX: The Render specification has capitalized versions of these
+    strings. However, the current implementation is case-sensitive and
+    expects lowercase versions. */
+ static char *
+ _render_filter_name (cairo_filter_t filter)
+ {
+     switch (filter) {
+     case CAIRO_FILTER_FAST:
+ 	return "fast";
+     case CAIRO_FILTER_GOOD:
+ 	return "good";
+     case CAIRO_FILTER_BEST:
+ 	return "best";
+     case CAIRO_FILTER_NEAREST:
+ 	return "nearest";
+     case CAIRO_FILTER_BILINEAR:
+ 	return "bilinear";
+     default:
+ 	return "best";
+     }
+ }
+ 
+ cairo_status_t
+ _cairo_surface_xlib_set_filter (cairo_surface_xlib *surface, cairo_filter_t filter)
+ {
+     if (!surface->picture)
+ 	return CAIRO_STATUS_SUCCESS;
+ 
+     XRenderSetPictureFilter (surface->dpy, surface->picture,
+ 			     _render_filter_name (filter), NULL, 0);
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ cairo_status_t
+ _cairo_surface_xlib_set_repeat (cairo_surface_xlib *surface, int repeat)
+ {
+     unsigned long mask;
+     XRenderPictureAttributes pa;
+ 
+     if (!surface->picture)
+ 	return CAIRO_STATUS_SUCCESS;
+     
+     mask = CPRepeat;
+     pa.repeat = repeat;
+ 
+     XRenderChangePicture (surface->dpy, surface->picture, mask, &pa);
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static cairo_status_t
+ _cairo_surface_xlib_put_image (cairo_surface_xlib	*surface,
+ 			      char			*data,
+ 			      int			width,
+ 			      int			height,
+ 			      int			stride)
+ {
+     XImage *image;
+     unsigned bitmap_pad;
+     
+     if (!surface->picture)
+ 	return CAIRO_STATUS_SUCCESS;
+ 
+     /* XXX: This is obviously bogus. depth needs to be figured out for real */
+     int depth = 32;
+ 
+     if (depth > 16)
+ 	bitmap_pad = 32;
+     else if (depth > 8)
+ 	bitmap_pad = 16;
+     else
+ 	bitmap_pad = 8;
+ 
+     image = XCreateImage(surface->dpy,
+ 			 DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)),
+ 			 depth, ZPixmap, 0,
+ 			 data, width, height,
+ 			 bitmap_pad,
+ 			 stride);
+     if (image == NULL)
+ 	return CAIRO_STATUS_NO_MEMORY;
+ 
+     _cairo_surface_ensure_gc (surface);
+     XPutImage(surface->dpy, surface->drawable, surface->gc,
+ 	      image, 0, 0, 0, 0, width, height);
+ 
+     /* Foolish XDestroyImage thinks it can free my data, but I won't
+        stand for it. */
+     image->data = NULL;
+     XDestroyImage(image);
+     
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static cairo_surface_xlib *
+ _cairo_surface_xlib_clone_from (cairo_surface_t *src, cairo_surface_xlib *tmpl)
+ {
+     cairo_matrix_t matrix;
+     cairo_surface_xlib *src_on_server;
+ 
+     _cairo_surface_pull_image (src);
+ 
+     src_on_server = _cairo_surface_xlib_create_similar (tmpl, CAIRO_FORMAT_ARGB32,
+ 							IcImageGetWidth (src->icimage),
+ 							IcImageGetHeight (src->icimage));
+     if (src_on_server == NULL)
+ 	return NULL;
+ 
+     cairo_surface_get_matrix (src, &matrix);
+     cairo_surface_set_matrix (&src_on_server->base, &matrix);
+ 
+     _cairo_surface_xlib_put_image (src_on_server,
+ 				  (char *) IcImageGetData (src->icimage),
+ 				  IcImageGetWidth (src->icimage),
+ 				  IcImageGetHeight (src->icimage),
+ 				  IcImageGetStride (src->icimage));
+     return src_on_server;
+ }
+ 
+ static int
+ _cairo_surface_xlib_composite (cairo_operator_t		operator,
+ 			       cairo_surface_xlib	*src,
+ 			       cairo_surface_xlib	*mask,
+ 			       cairo_surface_xlib	*dst,
+ 			       int			src_x,
+ 			       int			src_y,
+ 			       int			mask_x,
+ 			       int			mask_y,
+ 			       int			dst_x,
+ 			       int			dst_y,
+ 			       unsigned int		width,
+ 			       unsigned int		height)
+ {
+     if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
+ 	return -1;
+ 
+     if (src->base.impl != dst->base.impl || src->dpy != dst->dpy) {
+ 	src = _cairo_surface_xlib_clone_from (&src->base, dst);
+ 	if (!src)
+ 	    return -1;
+     }
+     if (mask && (mask->base.impl != dst->base.impl || mask->dpy != dst->dpy)) {
+ 	mask = _cairo_surface_xlib_clone_from (&mask->base, dst);
+ 	if (!mask)
+ 	    return -1;
+     }
+ 
+     XRenderComposite (dst->dpy, operator,
+ 		      src->picture,
+ 		      mask ? mask->picture : 0,
+ 		      dst->picture,
+ 		      src_x, src_y,
+ 		      mask_x, mask_y,
+ 		      dst_x, dst_y,
+ 		      width, height);
+ 
+     return 0;
+ }
+ 
+ static int
+ _cairo_surface_xlib_fill_rectangles (cairo_surface_xlib		*surface,
+ 				     cairo_operator_t		operator,
+ 				     const cairo_color_t	*color,
+ 				     cairo_rectangle_t		*rects,
+ 				     int			num_rects)
+ {
+     XRenderColor render_color;
+ 
+     if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
+ 	return -1;
+ 
+     render_color.red   = color->red_short;
+     render_color.green = color->green_short;
+     render_color.blue  = color->blue_short;
+     render_color.alpha = color->alpha_short;
+ 
+     /* XXX: This XRectangle cast is evil... it needs to go away somehow. */
+     XRenderFillRectangles (surface->dpy, operator, surface->picture,
+ 			   &render_color, (XRectangle *) rects, num_rects);
+ 
+     return 0;
+ }
+ 
+ static int
+ _cairo_surface_xlib_composite_trapezoids (cairo_operator_t	operator,
+ 					  cairo_surface_xlib	*src,
+ 					  cairo_surface_xlib	*dst,
+ 					  int			xSrc,
+ 					  int			ySrc,
+ 					  cairo_trapezoid_t	*traps,
+ 					  int			num_traps)
+ {
+     if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
+ 	return -1;
+ 
+     if (src->base.impl != dst->base.impl || src->dpy != dst->dpy) {
+ 	src = _cairo_surface_xlib_clone_from (&src->base, dst);
+ 	if (!src)
+ 	    return -1;
+     }
+ 
+     /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
+     XRenderCompositeTrapezoids (dst->dpy, operator, src->picture, dst->picture,
+ 				XRenderFindStandardFormat (dst->dpy, PictStandardA8),
+ 				xSrc, ySrc, (XTrapezoid *) traps, num_traps);
+ 
+     return 0;
+ }
+ 
+ static const struct cairo_surface_impl cairo_surface_xlib_impl = {
+     create_similar:		(void *) _cairo_surface_xlib_create_similar,
+     destroy:			(void *) _cairo_surface_xlib_destroy,
+     pull_image:			(void *) _cairo_surface_xlib_pull_image,
+     push_image:			(void *) _cairo_surface_xlib_push_image,
+     set_matrix:			(void *) _cairo_surface_xlib_set_matrix,
+     set_filter:			(void *) _cairo_surface_xlib_set_filter,
+     set_repeat:			(void *) _cairo_surface_xlib_set_repeat,
+     composite:			(void *) _cairo_surface_xlib_composite,
+     fill_rectangles:		(void *) _cairo_surface_xlib_fill_rectangles,
+     composite_trapezoids:	(void *) _cairo_surface_xlib_composite_trapezoids,
+ };
+ 
+ static IcFormat *
+ _create_icformat_for_visual (Visual *visual)
+ {
+     return IcFormatCreateMasks (32, 0,
+ 				visual->red_mask,
+ 				visual->green_mask,
+ 				visual->blue_mask);
+ }
+ 
+ cairo_surface_t *
+ cairo_surface_create_for_drawable (Display		*dpy,
+ 				   Drawable		drawable,
+ 				   Visual		*visual,
+ 				   cairo_format_t	format,
+ 				   Colormap		colormap)
+ {
+     cairo_surface_xlib *surface;
+     IcFormat *icformat;
+ 
+     surface = malloc (sizeof (cairo_surface_xlib));
+     if (surface == NULL)
+ 	return NULL;
+ 
+     /* XXX: How to get the proper width/height? Force a roundtrip? And
+        how can we track the width/height properly? Shall we give up on
+        supporting Windows and only allow drawing to pixmaps? */
+     _cairo_surface_init (&surface->base, 0, 0, format, &cairo_surface_xlib_impl);
+ 
+     if (visual) {
+ 	if (surface->base.icformat)
+ 	    IcFormatDestroy (surface->base.icformat);
+ 	surface->base.icformat = _create_icformat_for_visual (visual);
+     }
+ 
+     surface->dpy = dpy;
+ 
+     surface->gc = 0;
+     surface->drawable = drawable;
+     surface->free_pixmap = 0;
+     surface->visual = visual;
+ 
+     if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
+ 	surface->render_major = -1;
+ 	surface->render_minor = -1;
+     }
+ 
+     /* XXX: I'm currently ignoring the colormap. Is that bad? */
+     if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
+ 	surface->picture = XRenderCreatePicture (dpy, drawable,
+ 						 visual ?
+ 						 XRenderFindVisualFormat (dpy, visual) :
+ 						 XRenderFindStandardFormat (dpy, format),
+ 						 0, NULL);
+     else
+ 	surface->picture = 0;
+ 
+     surface->ximage = NULL;
+ 
+     return (cairo_surface_t *) surface;
+ }
+ slim_hidden_def(cairo_surface_create_for_drawable);
Index: cairo/src/cairoint.h
===================================================================
RCS file: /local/src/CVS/cairo/src/cairoint.h,v
retrieving revision 1.19
diff -a -c -r1.19 cairoint.h
*** cairo/src/cairoint.h	25 Sep 2003 22:01:28 -0000	1.19
--- cairo/src/cairoint.h	26 Sep 2003 09:13:57 -0000
***************
*** 232,241 ****
      cairo_pen_vertex_t *vertex;
  } cairo_pen_t;
  
! typedef enum cairo_surface_type {
!     CAIRO_SURFACE_TYPE_DRAWABLE,
!     CAIRO_SURFACE_TYPE_ICIMAGE
! } cairo_surface_type_t;
  
  struct cairo_surface {
      int width;
--- 232,275 ----
      cairo_pen_vertex_t *vertex;
  } cairo_pen_t;
  
! typedef struct cairo_color cairo_color_t;
! 
! struct cairo_surface_impl {
!     cairo_surface_t *(*create_similar) (cairo_surface_t	*surface,
! 					cairo_format_t	format,
! 					int		width,
! 					int		height);
!     void (*destroy) (cairo_surface_t *surface);
!     void (*pull_image) (cairo_surface_t *surface);
!     void (*push_image) (cairo_surface_t *surface);
!     cairo_status_t (*set_matrix) (cairo_surface_t *surface);
!     cairo_status_t (*set_filter) (cairo_surface_t *surface, cairo_filter_t filter);
!     cairo_status_t (*set_repeat) (cairo_surface_t *surface, int repeat);
!     int (*composite) (cairo_operator_t	operator,
! 		      cairo_surface_t	*src,
! 		      cairo_surface_t	*mask,
! 		      cairo_surface_t	*dst,
! 		      int		src_x,
! 		      int		src_y,
! 		      int		mask_x,
! 		      int		mask_y,
! 		      int		dst_x,
! 		      int		dst_y,
! 		      unsigned int	width,
! 		      unsigned int	height);
!     int (*fill_rectangles) (cairo_surface_t	*surface,
! 			    cairo_operator_t	operator,
! 			    const cairo_color_t	*color,
! 			    cairo_rectangle_t	*rects,
! 			    int			num_rects);
!     int (*composite_trapezoids) (cairo_operator_t	operator,
! 				 cairo_surface_t	*src,
! 				 cairo_surface_t	*dst,
! 				 int			xSrc,
! 				 int			ySrc,
! 				 cairo_trapezoid_t	*traps,
! 				 int			num_traps);
! };
  
  struct cairo_surface {
      int width;
***************
*** 247,270 ****
      unsigned int ref_count;
      int repeat;
  
-     cairo_surface_type_t type;
      XTransform xtransform;
  
-     /* For TYPE_DRAWABLE */
-     Display *dpy;
-     GC gc;
-     Drawable drawable;
-     Visual *visual;
- 
-     int render_major;
-     int render_minor;
- 
-     Picture picture;
-     XImage *ximage;
- 
-     /* For TYPE_ICIMAGE */
      IcImage *icimage;
      IcFormat *icformat;
  };
  
  /* XXX: Right now, the cairo_color structure puts unpremultiplied
--- 281,292 ----
      unsigned int ref_count;
      int repeat;
  
      XTransform xtransform;
  
      IcImage *icimage;
      IcFormat *icformat;
+ 
+     const struct cairo_surface_impl *impl;
  };
  
  /* XXX: Right now, the cairo_color structure puts unpremultiplied
***************
*** 273,279 ****
     madness). I'm still working on a cleaner API, but in the meantime,
     at least this does prevent precision loss in color when changing
     alpha. */
! typedef struct cairo_color {
      double red;
      double green;
      double blue;
--- 295,301 ----
     madness). I'm still working on a cleaner API, but in the meantime,
     at least this does prevent precision loss in color when changing
     alpha. */
! struct cairo_color {
      double red;
      double green;
      double blue;
***************
*** 283,289 ****
      unsigned short green_short;
      unsigned short blue_short;
      unsigned short alpha_short;
! } cairo_color_t;
  
  struct cairo_matrix {
      double m[3][2];
--- 305,311 ----
      unsigned short green_short;
      unsigned short blue_short;
      unsigned short alpha_short;
! };
  
  struct cairo_matrix {
      double m[3][2];
***************
*** 692,697 ****
--- 714,726 ----
  
  /* cairo_surface.c */
  extern void __internal_linkage
+ _cairo_surface_init (cairo_surface_t			*surface,
+ 		     int				width,
+ 		     int				height,
+ 		     cairo_format_t			format,
+ 		     const struct cairo_surface_impl	*impl);
+ 
+ extern void __internal_linkage
  _cairo_surface_fill_rectangle (cairo_surface_t	*surface,
  			       cairo_operator_t	operator,
  			       cairo_color_t	*color,


More information about the cairo mailing list