[cairo-commit] 16 commits - src/cairo-clip.c src/cairo-glitz-surface.c src/cairoint.h src/cairo-pattern.c src/cairo-surface.c src/cairo-xlib-private.h src/cairo-xlib-surface.c src/cairo-xlib-visual.c

Behdad Esfahbod behdad at kemper.freedesktop.org
Thu Jun 19 19:28:30 PDT 2008


 src/cairo-clip.c          |    3 
 src/cairo-glitz-surface.c |    8 
 src/cairo-pattern.c       |   91 +++++------
 src/cairo-surface.c       |   63 +++++--
 src/cairo-xlib-private.h  |   12 +
 src/cairo-xlib-surface.c  |  374 ++++++++++++++++++++++++++++++++--------------
 src/cairo-xlib-visual.c   |  103 ++++++++----
 src/cairoint.h            |   26 ++-
 8 files changed, 456 insertions(+), 224 deletions(-)

New commits:
commit d9784c8c37a2c6dbcccd3e96e746f32b12a2b468
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 19 22:24:13 2008 -0400

    [cairo-xlib] Don't undither pseudocolor, doesn't look good

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index ca4fad9..a3d3851 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -521,24 +521,17 @@ _pseudocolor_from_rgb888_dither (cairo_xlib_visual_info_t *visual_info,
 }
 
 static inline uint32_t
-_pseudocolor_to_rgb888_undither (cairo_xlib_visual_info_t *visual_info,
-				 uint32_t pixel,
-				 int8_t dither_adjustment)
+_pseudocolor_to_rgb888 (cairo_xlib_visual_info_t *visual_info,
+			uint32_t pixel)
 {
     uint32_t r, g, b;
     pixel &= 0xff;
     r = visual_info->colors[pixel].r;
     g = visual_info->colors[pixel].g;
     b = visual_info->colors[pixel].b;
-    if (r == g && g == b) {
-	dither_adjustment /= RAMP_SIZE;
-	return _adjust_field (r, - dither_adjustment) * 0x010101;
-    } else {
-	dither_adjustment = - visual_info->dither8_to_cube[dither_adjustment+128];
-	return (_adjust_field (r, dither_adjustment) << 16) |
-	       (_adjust_field (g, dither_adjustment) <<  8) |
-	       (_adjust_field (b, dither_adjustment)      );
-    }
+    return (r << 16) |
+	   (g <<  8) |
+	   (b      );
 }
 
 
@@ -773,7 +766,8 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 			_field_to_8_undither (in_pixel & g_mask, g_width, g_shift, dither_adjustment) << 8 |
 			_field_to_8_undither (in_pixel & b_mask, b_width, b_shift, dither_adjustment));
 		} else {
-		    out_pixel = _pseudocolor_to_rgb888_undither (visual_info, in_pixel, dither_adjustment);
+		    /* Undithering pseudocolor does not look better */
+		    out_pixel = _pseudocolor_to_rgb888 (visual_info, in_pixel);
 		}
 		row[x] = out_pixel;
 	    }
commit fe41d100aa5cddb56b8a5f043c01fdf1f1a1e4c5
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jun 13 21:39:19 2008 -0400

    [cairo-xlib-surface] Fix core solid_fill_rectangles to do dithering
    
    Do this by tiling the surface form the solid pattern.  The pattern in
    turn calls into xlib's create_solid_surface which returns a dithered
    pattern.
    
    This can get into infinite loop right now, because of the way solid
    surface cache tries to repaint cached surfaces.

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 0d22e07..ca4fad9 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -702,7 +702,7 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 	int x, y, x0, y0, x_off, y_off;
 	cairo_xlib_visual_info_t *visual_info;
 
-	if (surface->visual->class == TrueColor) {
+	if (surface->visual == NULL || surface->visual->class == TrueColor) {
 	    cairo_bool_t has_alpha;
 	    cairo_bool_t has_color;
 
@@ -766,7 +766,7 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 		int dither_adjustment = dither_row[x_off];
 
 		in_pixel = XGetPixel (ximage, x, y);
-		if (surface->visual->class == TrueColor) {
+		if (surface->visual == NULL || surface->visual->class == TrueColor) {
 		    out_pixel = (
 			_field_to_8 (in_pixel & a_mask, a_width, a_shift) << 24 |
 			_field_to_8_undither (in_pixel & r_mask, r_width, r_shift, dither_adjustment) << 16 |
@@ -955,7 +955,7 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
 	_characterize_field (image_masks.green_mask, &i_g_width, &i_g_shift);
 	_characterize_field (image_masks.blue_mask , &i_b_width, &i_b_shift);
 
-	if (surface->visual->class == TrueColor) {
+	if (surface->visual == NULL || surface->visual->class == TrueColor) {
 
 	    _characterize_field (surface->a_mask, &o_a_width, &o_a_shift);
 	    _characterize_field (surface->r_mask, &o_r_width, &o_r_shift);
@@ -997,7 +997,7 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
 		r = _field_to_8 (in_pixel & image_masks.red_mask  , i_r_width, i_r_shift);
 		g = _field_to_8 (in_pixel & image_masks.green_mask, i_g_width, i_g_shift);
 		b = _field_to_8 (in_pixel & image_masks.blue_mask , i_b_width, i_b_shift);
-		if (surface->visual->class == TrueColor) {
+		if (surface->visual == NULL || surface->visual->class == TrueColor) {
 		    out_pixel = (_field_from_8        (a, o_a_width, o_a_shift) |
 				 _field_from_8_dither (r, o_r_width, o_r_shift, dither_adjustment) |
 				 _field_from_8_dither (g, o_g_width, o_g_shift, dither_adjustment) |
@@ -1778,50 +1778,48 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t    *surface,
 					   cairo_rectangle_int_t   *rects,
 					   int			   num_rects)
 {
-    GC xgc;
-    XGCValues gcv;
-    int a_width=0, r_width=0, g_width=0, b_width=0;
-    int a_shift=0, r_shift=0, g_shift=0, b_shift=0;
-    int a = color->alpha_short >> 8;
-    int r = color->red_short   >> 8;
-    int g = color->green_short >> 8;
-    int b = color->blue_short  >> 8;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+    cairo_solid_pattern_t solid;
+    cairo_surface_t *solid_surface = NULL;
+    cairo_surface_attributes_t attrs;
     int i;
 
-    if (surface->visual == NULL || surface->visual->class == TrueColor) {
-	_characterize_field (surface->a_mask, &a_width, &a_shift);
-	_characterize_field (surface->r_mask, &r_width, &r_shift);
-	_characterize_field (surface->g_mask, &g_width, &g_shift);
-	_characterize_field (surface->b_mask, &b_width, &b_shift);
-	gcv.foreground = (_field_from_8 (a, a_width, a_shift) |
-			  _field_from_8 (r, r_width, r_shift) |
-			  _field_from_8 (g, g_width, g_shift) |
-			  _field_from_8 (b, b_width, b_shift));
-    } else {
-	cairo_xlib_visual_info_t *visual_info;
-	cairo_int_status_t status;
+    _cairo_pattern_init_solid (&solid, color, CAIRO_CONTENT_COLOR);
 
-	status = _cairo_xlib_screen_get_visual_info (surface->screen_info,
-						     surface->visual,
-						     &visual_info);
-	if (status)
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
+    status = _cairo_xlib_surface_ensure_gc (surface);
+    if (status)
+        return status;
+
+    status = _cairo_pattern_acquire_surface (&solid.base, (cairo_surface_t *) surface,
+					     0, 0,
+					     ARRAY_LENGTH (dither_pattern[0]),
+					     ARRAY_LENGTH (dither_pattern),
+					     &solid_surface,
+					     &attrs);
+    if (status)
+        return status;
 
-	gcv.foreground = _pseudocolor_from_rgb888 (visual_info, r, g, b);
+    if (!_cairo_surface_is_xlib (solid_surface)) {
+	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	goto BAIL;
     }
 
-    xgc = XCreateGC (surface->dpy, surface->drawable, GCForeground, &gcv);
-    if (xgc == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    XSetTSOrigin (surface->dpy, surface->gc,
+		  - (surface->base.device_transform.x0 + attrs.x_offset),
+		  - (surface->base.device_transform.y0 + attrs.y_offset));
+    XSetTile (surface->dpy, surface->gc, ((cairo_xlib_surface_t *) solid_surface)->drawable);
+    XSetFillStyle (surface->dpy, surface->gc, FillTiled);
 
     for (i = 0; i < num_rects; i++) {
-	XFillRectangle (surface->dpy, surface->drawable, xgc,
+	XFillRectangle (surface->dpy, surface->drawable, surface->gc,
 			rects[i].x, rects[i].y,
 			rects[i].width, rects[i].height);
     }
-    XFreeGC (surface->dpy, xgc);
 
-    return CAIRO_STATUS_SUCCESS;
+  BAIL:
+    _cairo_pattern_release_surface (&solid.base, solid_surface, &attrs);
+
+    return status;
 }
 
 static cairo_int_status_t
commit abac0f96cb39b60a88433918d193f6d5091ea8d9
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jun 13 21:37:45 2008 -0400

    [cairo-xlib-surface] Implement create_solid_pattern_surface
    
    If render is disabled, this will create a surface the size of the
    dither pattern and paint it with dithering.

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 28e5627..0d22e07 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1161,6 +1161,75 @@ _cairo_xlib_surface_clone_similar (void			*abstract_surface,
     return CAIRO_INT_STATUS_UNSUPPORTED;
 }
 
+static cairo_surface_t *
+_cairo_xlib_surface_create_solid_pattern_surface (void                  *abstract_surface,
+						  cairo_solid_pattern_t *solid_pattern)
+{
+    /* This function's only responsibility is to create a proper surface
+     * for when XRender is not available.  The proper surface is a xlib
+     * surface (as opposed to image surface which is what create_similar
+     * returns in those cases) and the size of the dithering pattern, not
+     * 1x1.  This surface can then be used in
+     * _cairo_xlib_surface_solid_fill_rectangles() to do dithered "solid"
+     * fills using core protocol */
+
+    cairo_xlib_surface_t *other = abstract_surface;
+    cairo_image_surface_t *image;
+    cairo_xlib_surface_t *surface = NULL;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+    Pixmap pixmap;
+
+    if (CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other))
+	return NULL;
+
+    image = (cairo_image_surface_t *)
+	    _cairo_image_surface_create_with_content (solid_pattern->content,
+						      ARRAY_LENGTH (dither_pattern[0]),
+						      ARRAY_LENGTH (dither_pattern));
+    status = image->base.status;
+    if (status)
+	goto BAIL;
+
+    pixmap = XCreatePixmap (other->dpy,
+			    other->drawable,
+			    image->width, image->height,
+			    other->depth);
+
+    surface = (cairo_xlib_surface_t *)
+	      cairo_xlib_surface_create (other->dpy,
+					 pixmap,
+					 other->visual,
+					 image->width, image->height);
+    status = surface->base.status;
+    if (status)
+	goto BAIL;
+    surface->owns_pixmap = TRUE;
+
+    status = _cairo_surface_paint (&image->base, CAIRO_OPERATOR_SOURCE, &solid_pattern->base);
+    if (status)
+	goto BAIL;
+
+    status = _draw_image_surface (surface, image,
+				  0, 0,
+				  image->width, image->height,
+				  0, 0);
+    if (status)
+	goto BAIL;
+
+
+  BAIL:
+    cairo_surface_destroy (&image->base);
+
+    if (status && surface) {
+	XFreePixmap (other->dpy, pixmap);
+	cairo_surface_destroy (&surface->base);
+	surface = NULL;
+    }
+
+    return (cairo_surface_t *) surface;
+}
+
 static cairo_status_t
 _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
 				cairo_matrix_t	     *matrix)
@@ -2260,10 +2329,11 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
     NULL, /* stroke */
     NULL, /* fill */
     _cairo_xlib_surface_show_glyphs,
-    NULL,  /* snapshot */
+    NULL, /* snapshot */
     _cairo_xlib_surface_is_similar,
-
-    _cairo_xlib_surface_reset
+    _cairo_xlib_surface_reset,
+    NULL, /* fill_stroke */
+    _cairo_xlib_surface_create_solid_pattern_surface
 };
 
 /**
commit fb8f2b3854114a653d11263e8868eae042ee4b94
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jun 13 02:35:30 2008 -0400

    [cairo-xlib-surface] Make _draw_image_surface handle arbitrary image formats
    
    This is not a useful change.  Just committing because I already did it.

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 70ce979..28e5627 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -924,8 +924,10 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
 	unsigned int stride, rowstride;
 	int x, y, x0, y0, x_off, y_off;
 	uint32_t in_pixel, out_pixel, *row;
-	int a_width=0, r_width=0, g_width=0, b_width=0;
-	int a_shift=0, r_shift=0, g_shift=0, b_shift=0;
+	int i_a_width=0, i_r_width=0, i_g_width=0, i_b_width=0;
+	int i_a_shift=0, i_r_shift=0, i_g_shift=0, i_b_shift=0;
+	int o_a_width=0, o_r_width=0, o_g_width=0, o_b_width=0;
+	int o_a_shift=0, o_r_shift=0, o_g_shift=0, o_b_shift=0;
 	cairo_xlib_visual_info_t *visual_info = NULL;
 
 	if (surface->depth > 16) {
@@ -948,12 +950,17 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
 
 	XInitImage (&ximage);
 
+	_characterize_field (image_masks.alpha_mask, &i_a_width, &i_a_shift);
+	_characterize_field (image_masks.red_mask  , &i_r_width, &i_r_shift);
+	_characterize_field (image_masks.green_mask, &i_g_width, &i_g_shift);
+	_characterize_field (image_masks.blue_mask , &i_b_width, &i_b_shift);
+
 	if (surface->visual->class == TrueColor) {
 
-	    _characterize_field (surface->a_mask, &a_width, &a_shift);
-	    _characterize_field (surface->r_mask, &r_width, &r_shift);
-	    _characterize_field (surface->g_mask, &g_width, &g_shift);
-	    _characterize_field (surface->b_mask, &b_width, &b_shift);
+	    _characterize_field (surface->a_mask, &o_a_width, &o_a_shift);
+	    _characterize_field (surface->r_mask, &o_r_width, &o_r_shift);
+	    _characterize_field (surface->g_mask, &o_g_width, &o_g_shift);
+	    _characterize_field (surface->b_mask, &o_b_width, &o_b_shift);
 
 	} else {
 
@@ -980,16 +987,21 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
 
 		int a, r, g, b;
 
-		in_pixel = row[x];
-		a = (in_pixel >> 24) & 0xff;
-		r = (in_pixel >> 16) & 0xff;
-		g = (in_pixel >>  8) & 0xff;
-		b = (in_pixel      ) & 0xff;
+		if (image_masks.bpp <= 8)
+		    in_pixel = ((uint8_t*)row)[x];
+		else if (image_masks.bpp <= 16)
+		    in_pixel = ((uint16_t*)row)[x];
+		else
+		    in_pixel = row[x];
+		a = _field_to_8 (in_pixel & image_masks.alpha_mask, i_a_width, i_a_shift);
+		r = _field_to_8 (in_pixel & image_masks.red_mask  , i_r_width, i_r_shift);
+		g = _field_to_8 (in_pixel & image_masks.green_mask, i_g_width, i_g_shift);
+		b = _field_to_8 (in_pixel & image_masks.blue_mask , i_b_width, i_b_shift);
 		if (surface->visual->class == TrueColor) {
-		    out_pixel = (_field_from_8 (a, a_width, a_shift) |
-				 _field_from_8_dither (r, r_width, r_shift, dither_adjustment) |
-				 _field_from_8_dither (g, g_width, g_shift, dither_adjustment) |
-				 _field_from_8_dither (b, b_width, b_shift, dither_adjustment));
+		    out_pixel = (_field_from_8        (a, o_a_width, o_a_shift) |
+				 _field_from_8_dither (r, o_r_width, o_r_shift, dither_adjustment) |
+				 _field_from_8_dither (g, o_g_width, o_g_shift, dither_adjustment) |
+				 _field_from_8_dither (b, o_b_width, o_b_shift, dither_adjustment));
 		} else {
 		    out_pixel = _pseudocolor_from_rgb888_dither (visual_info, r, g, b, dither_adjustment);
 		}
commit bc4b788ec187c84c2f8a6c0f68c1892ecaab3bcc
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jun 13 02:44:37 2008 -0400

    [cairo-xlib-surface] In _get_image_surface only use pixman formats >= 24bpp
    
    Otherwise we can't do dithering.  This drastically improves gradient rendering
    on 16bit displays, essentially making them indistinguishable from 32bit ones
    with a naked eye.

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 820b557..70ce979 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -672,7 +672,7 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
     xlib_masks.blue_mask = surface->b_mask;
 
     status = _pixman_format_from_masks (&xlib_masks, &pixman_format);
-    if (status == CAIRO_STATUS_SUCCESS) {
+    if (xlib_masks.bpp >= 24 &&status == CAIRO_STATUS_SUCCESS) {
 	image = (cairo_image_surface_t*)
 	    _cairo_image_surface_create_with_pixman_format ((unsigned char *) ximage->data,
 							    pixman_format,
commit 5faf8663b228eafa60fee1f0a1ac9e9f9406134d
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jun 13 00:46:01 2008 -0400

    [cairo-xlib-surface] Force buggy_repeat to TRUE if Render is not available
    
    So we use more core protocol paths.

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 0115838..820b557 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1642,9 +1642,9 @@ _cairo_xlib_surface_composite (cairo_operator_t		op,
 	break;
 
     case DO_XTILE:
-	/* This case is only used for bug fallbacks, though it is theoretically
-	 * applicable to the case where we don't have the RENDER extension as
-	 * well.
+	/* This case is only used for bug fallbacks, though we also use it for
+	 * the case where we don't have the RENDER extension, by forcing
+	 * buggy_repeat to TRUE.
 	 *
 	 * We've checked that we have a repeating unscaled source in
 	 * _recategorize_composite_operation.
@@ -2381,6 +2381,10 @@ _cairo_xlib_surface_create_internal (Display		       *dpy,
     surface->height = height;
 
     surface->buggy_repeat = screen_info->display->buggy_repeat;
+    if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
+	/* so we can use the XTile fallback */
+	surface->buggy_repeat = TRUE;
+    }
 
     surface->dst_picture = None;
     surface->src_picture = None;
commit e7c1fc5bf53b4adf16f2d0c7e613c848bede6824
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Tue Mar 25 17:50:37 2008 +0430

    [xlib] Implement dithering
    
    Remove the intermediate rgb333 for PseudoColor and work on the
    cube directly.  Also upgrade to a 6x6x6 cube instead of 5x5x5.
    Do dithering on both PseudoColor and TrueColor, using a 4x4 pattern.
    
    This only affects X servers with no XRender.

diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index a88e6b5..b8ca027 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -73,10 +73,18 @@ struct _cairo_xlib_display {
     unsigned int closed :1;
 };
 
+/* size of color cube */
+#define CUBE_SIZE 6
+/* size of gray ramp */
+#define RAMP_SIZE 16
+
 typedef struct _cairo_xlib_visual_info {
     VisualID visualid;
-    XColor colors[256];
-    unsigned long rgb333_to_pseudocolor[512];
+    struct { uint8_t a, r, g, b; } colors[256];
+    uint8_t cube_to_pseudocolor[CUBE_SIZE][CUBE_SIZE][CUBE_SIZE];
+    uint8_t field8_to_cube[256];
+    int8_t  dither8_to_cube[256];
+    uint8_t gray8_to_pseudocolor[256];
 } cairo_xlib_visual_info_t;
 
 struct _cairo_xlib_screen_info {
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 8dbf7b7..0115838 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -430,10 +430,11 @@ _swap_ximage_to_native (XImage *ximage)
     }
 }
 
+
 /* Given a mask, (with a single sequence of contiguous 1 bits), return
  * the number of 1 bits in 'width' and the number of 0 bits to its
  * right in 'shift'. */
-static inline void
+static void
 _characterize_field (uint32_t mask, int *width, int *shift)
 {
     *width = _cairo_popcount (mask);
@@ -441,6 +442,7 @@ _characterize_field (uint32_t mask, int *width, int *shift)
     *shift = _cairo_popcount ((mask - 1) & ~mask) & 31;
 }
 
+
 /* Convert a field of 'width' bits to 'new_width' bits with correct
  * rounding. */
 static inline uint32_t
@@ -462,6 +464,12 @@ _resize_field (uint32_t field, int width, int new_width)
     }
 }
 
+static inline uint32_t
+_adjust_field (uint32_t field, int adjustment)
+{
+    return MIN (255, MAX(0, (int)field + adjustment));
+}
+
 /* Given a shifted field value, (described by 'width' and 'shift),
  * resize it 8-bits and return that value.
  *
@@ -474,6 +482,13 @@ _field_to_8 (uint32_t field, int width, int shift)
     return _resize_field (field >> shift, width, 8);
 }
 
+static inline uint32_t
+_field_to_8_undither (uint32_t field, int width, int shift,
+		      int dither_adjustment)
+{
+    return _adjust_field (_field_to_8 (field, width, shift), - dither_adjustment>>width);
+}
+
 /* Given an 8-bit value, convert it to a field of 'width', shift it up
  *  to 'shift, and return it. */
 static inline uint32_t
@@ -482,6 +497,62 @@ _field_from_8 (uint32_t field, int width, int shift)
     return _resize_field (field, 8, width) << shift;
 }
 
+static inline uint32_t
+_field_from_8_dither (uint32_t field, int width, int shift,
+		      int8_t dither_adjustment)
+{
+    return _field_from_8 (_adjust_field (field, dither_adjustment>>width), width, shift);
+}
+
+static inline uint32_t
+_pseudocolor_from_rgb888_dither (cairo_xlib_visual_info_t *visual_info,
+				 uint32_t r, uint32_t g, uint32_t b,
+				 int8_t dither_adjustment)
+{
+    if (r == g && g == b) {
+	dither_adjustment /= RAMP_SIZE;
+	return visual_info->gray8_to_pseudocolor[_adjust_field (r, dither_adjustment)];
+    } else {
+	dither_adjustment = visual_info->dither8_to_cube[dither_adjustment+128];
+	return visual_info->cube_to_pseudocolor[visual_info->field8_to_cube[_adjust_field (r, dither_adjustment)]]
+					       [visual_info->field8_to_cube[_adjust_field (g, dither_adjustment)]]
+					       [visual_info->field8_to_cube[_adjust_field (b, dither_adjustment)]];
+    }
+}
+
+static inline uint32_t
+_pseudocolor_to_rgb888_undither (cairo_xlib_visual_info_t *visual_info,
+				 uint32_t pixel,
+				 int8_t dither_adjustment)
+{
+    uint32_t r, g, b;
+    pixel &= 0xff;
+    r = visual_info->colors[pixel].r;
+    g = visual_info->colors[pixel].g;
+    b = visual_info->colors[pixel].b;
+    if (r == g && g == b) {
+	dither_adjustment /= RAMP_SIZE;
+	return _adjust_field (r, - dither_adjustment) * 0x010101;
+    } else {
+	dither_adjustment = - visual_info->dither8_to_cube[dither_adjustment+128];
+	return (_adjust_field (r, dither_adjustment) << 16) |
+	       (_adjust_field (g, dither_adjustment) <<  8) |
+	       (_adjust_field (b, dither_adjustment)      );
+    }
+}
+
+
+/* should range from -128 to 127 */
+#define X 16
+static const int8_t dither_pattern[4][4] = {
+    {-8*X, +0*X, -6*X, +2*X},
+    {+4*X, -4*X, +6*X, -2*X},
+    {-5*X, +4*X, -7*X, +1*X},
+    {+7*X, -1*X, +5*X, -3*X}
+};
+#undef X
+
+
 static cairo_status_t
 _get_image_surface (cairo_xlib_surface_t    *surface,
 		    cairo_rectangle_int_t   *interest_rect,
@@ -489,7 +560,7 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 		    cairo_rectangle_int_t   *image_rect)
 {
     cairo_int_status_t status;
-    cairo_image_surface_t *image;
+    cairo_image_surface_t *image = NULL;
     XImage *ximage;
     unsigned short x1, y1, x2, y2;
     pixman_format_code_t pixman_format;
@@ -609,15 +680,17 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 							    ximage->height,
 							    ximage->bytes_per_line);
 	status = image->base.status;
-	if (status) {
-	    XDestroyImage (ximage);
-	    return status;
-	}
+	if (status)
+	    goto BAIL;
 
 	/* Let the surface take ownership of the data */
 	_cairo_image_surface_assume_ownership_of_data (image);
 	ximage->data = NULL;
     } else {
+	/* The visual we are dealing with is not supported by the
+	 * standard pixman formats. So we must first convert the data
+	 * to a supported format. */
+
 	cairo_format_t format;
 	unsigned char *data;
 	uint32_t *row;
@@ -626,20 +699,17 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 	uint32_t a_mask=0, r_mask=0, g_mask=0, b_mask=0;
 	int a_width=0, r_width=0, g_width=0, b_width=0;
 	int a_shift=0, r_shift=0, g_shift=0, b_shift=0;
-	int x, y;
-	XColor *colors = NULL;
+	int x, y, x0, y0, x_off, y_off;
+	cairo_xlib_visual_info_t *visual_info;
 
-	/* The visual we are dealing with is not supported by the
-	 * standard pixman formats. So we must first convert the data
-	 * to a supported format. */
 	if (surface->visual->class == TrueColor) {
-	    cairo_bool_t has_color;
 	    cairo_bool_t has_alpha;
+	    cairo_bool_t has_color;
 
+	    has_alpha =  surface->a_mask;
 	    has_color = (surface->r_mask ||
 			 surface->g_mask ||
 			 surface->b_mask);
-	    has_alpha = surface->a_mask;
 
 	    if (has_color) {
 		if (has_alpha) {
@@ -666,48 +736,44 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 	    _characterize_field (b_mask, &b_width, &b_shift);
 
 	} else {
-	    cairo_xlib_visual_info_t *visual_info;
-
 	    format = CAIRO_FORMAT_RGB24;
 
 	    status = _cairo_xlib_screen_get_visual_info (surface->screen_info,
 							 surface->visual,
 							 &visual_info);
-	    if (status) {
-		XDestroyImage (ximage);
-		return status;
-	    }
-
-	    colors = visual_info->colors;
+	    if (status)
+		goto BAIL;
 	}
 
 	image = (cairo_image_surface_t *) cairo_image_surface_create
 	    (format, ximage->width, ximage->height);
 	status = image->base.status;
-	if (status) {
-	    XDestroyImage (ximage);
-	    return status;
-	}
+	if (status)
+	    goto BAIL;
 
 	data = cairo_image_surface_get_data (&image->base);
 	rowstride = cairo_image_surface_get_stride (&image->base) >> 2;
 	row = (uint32_t *) data;
-	for (y = 0; y < ximage->height; y++) {
-	    for (x = 0; x < ximage->width; x++) {
+	x0 = x1 + surface->base.device_transform.x0;
+	y0 = y1 + surface->base.device_transform.y0;
+	for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern);
+	     y < ximage->height;
+	     y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern)) {
+	    const int8_t *dither_row = dither_pattern[y_off];
+	    for (x = 0, x_off = x0 % ARRAY_LENGTH (dither_pattern[0]);
+		 x < ximage->width;
+		 x++, x_off = (x_off+1) % ARRAY_LENGTH (dither_pattern[0])) {
+		int dither_adjustment = dither_row[x_off];
+
 		in_pixel = XGetPixel (ximage, x, y);
 		if (surface->visual->class == TrueColor) {
 		    out_pixel = (
 			_field_to_8 (in_pixel & a_mask, a_width, a_shift) << 24 |
-			_field_to_8 (in_pixel & r_mask, r_width, r_shift) << 16 |
-			_field_to_8 (in_pixel & g_mask, g_width, g_shift) << 8 |
-			_field_to_8 (in_pixel & b_mask, b_width, b_shift));
+			_field_to_8_undither (in_pixel & r_mask, r_width, r_shift, dither_adjustment) << 16 |
+			_field_to_8_undither (in_pixel & g_mask, g_width, g_shift, dither_adjustment) << 8 |
+			_field_to_8_undither (in_pixel & b_mask, b_width, b_shift, dither_adjustment));
 		} else {
-		    XColor *color;
-		    color = &colors[in_pixel & 0xff];
-		    out_pixel = (
-			_field_to_8 (color->red,   16, 0) << 16 |
-			_field_to_8 (color->green, 16, 0) << 8 |
-			_field_to_8 (color->blue,  16, 0));
+		    out_pixel = _pseudocolor_to_rgb888_undither (visual_info, in_pixel, dither_adjustment);
 		}
 		row[x] = out_pixel;
 	    }
@@ -715,10 +781,17 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 	}
     }
 
+ BAIL:
     XDestroyImage (ximage);
 
+    if (status) {
+	if (image) {
+	    cairo_surface_destroy (&image->base);
+	    image = NULL;
+	}
+    }
     *image_out = image;
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
 static void
@@ -822,7 +895,6 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
     int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
     cairo_status_t status;
     cairo_bool_t own_data;
-    unsigned long *rgb333_to_pseudocolor = NULL;
 
     _pixman_format_to_masks (image->pixman_format, &image_masks);
 
@@ -850,10 +922,11 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
 	XInitImage (&ximage);
     } else {
 	unsigned int stride, rowstride;
-	int x, y;
+	int x, y, x0, y0, x_off, y_off;
 	uint32_t in_pixel, out_pixel, *row;
 	int a_width=0, r_width=0, g_width=0, b_width=0;
 	int a_shift=0, r_shift=0, g_shift=0, b_shift=0;
+	cairo_xlib_visual_info_t *visual_info = NULL;
 
 	if (surface->depth > 16) {
 	    ximage.bits_per_pixel = 32;
@@ -876,12 +949,13 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
 	XInitImage (&ximage);
 
 	if (surface->visual->class == TrueColor) {
+
 	    _characterize_field (surface->a_mask, &a_width, &a_shift);
 	    _characterize_field (surface->r_mask, &r_width, &r_shift);
 	    _characterize_field (surface->g_mask, &g_width, &g_shift);
 	    _characterize_field (surface->b_mask, &b_width, &b_shift);
+
 	} else {
-	    cairo_xlib_visual_info_t *visual_info;
 
 	    status = _cairo_xlib_screen_get_visual_info (surface->screen_info,
 							 surface->visual,
@@ -889,28 +963,36 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
 	    if (status)
 		goto BAIL;
 
-	    rgb333_to_pseudocolor = visual_info->rgb333_to_pseudocolor;
 	}
 
 	rowstride = cairo_image_surface_get_stride (&image->base) >> 2;
 	row = (uint32_t *) cairo_image_surface_get_data (&image->base);
-	for (y = 0; y < ximage.height; y++) {
-	    for (x = 0; x < ximage.width; x++) {
+	x0 = dst_x + surface->base.device_transform.x0;
+	y0 = dst_y + surface->base.device_transform.y0;
+	for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern);
+	     y < ximage.height;
+	     y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern)) {
+	    const int8_t *dither_row = dither_pattern[y_off];
+	    for (x = 0, x_off = x0 % ARRAY_LENGTH (dither_pattern[0]);
+		 x < ximage.width;
+		 x++, x_off = (x_off+1) % ARRAY_LENGTH (dither_pattern[0])) {
+		int dither_adjustment = dither_row[x_off];
+
 		int a, r, g, b;
+
 		in_pixel = row[x];
 		a = (in_pixel >> 24) & 0xff;
 		r = (in_pixel >> 16) & 0xff;
 		g = (in_pixel >>  8) & 0xff;
 		b = (in_pixel      ) & 0xff;
-		if (surface->visual->class == TrueColor)
+		if (surface->visual->class == TrueColor) {
 		    out_pixel = (_field_from_8 (a, a_width, a_shift) |
-				 _field_from_8 (r, r_width, r_shift) |
-				 _field_from_8 (g, g_width, g_shift) |
-				 _field_from_8 (b, b_width, b_shift));
-		else
-		    out_pixel = rgb333_to_pseudocolor[_field_from_8 (r, 3, 6) |
-						      _field_from_8 (g, 3, 3) |
-						      _field_from_8 (b, 3, 0)];
+				 _field_from_8_dither (r, r_width, r_shift, dither_adjustment) |
+				 _field_from_8_dither (g, g_width, g_shift, dither_adjustment) |
+				 _field_from_8_dither (b, b_width, b_shift, dither_adjustment));
+		} else {
+		    out_pixel = _pseudocolor_from_rgb888_dither (visual_info, r, g, b, dither_adjustment);
+		}
 		XPutPixel (&ximage, x, y, out_pixel);
 	    }
 	    row += rowstride;
@@ -1644,10 +1726,7 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t    *surface,
 	if (status)
 	    return CAIRO_INT_STATUS_UNSUPPORTED;
 
-	gcv.foreground =
-	    visual_info->rgb333_to_pseudocolor[_field_from_8 (r, 3, 6) |
-					       _field_from_8 (g, 3, 3) |
-					       _field_from_8 (b, 3, 0)];
+	gcv.foreground = _pseudocolor_from_rgb888 (visual_info, r, g, b);
     }
 
     xgc = XCreateGC (surface->dpy, surface->drawable, GCForeground, &gcv);
diff --git a/src/cairo-xlib-visual.c b/src/cairo-xlib-visual.c
index 3a7b586..f6eb1ee 100644
--- a/src/cairo-xlib-visual.c
+++ b/src/cairo-xlib-visual.c
@@ -66,15 +66,16 @@ _cairo_xlib_visual_info_create (Display *dpy,
     Colormap colormap = DefaultColormap (dpy, screen);
     XColor color;
     int gray, red, green, blue;
-    int i, index, distance, min_distance = 0;
+    int i, j, distance, min_distance = 0;
+    XColor colors[256];
+    unsigned short cube_index_to_short[CUBE_SIZE];
+    unsigned short ramp_index_to_short[RAMP_SIZE];
+    unsigned char  gray_to_pseudocolor[RAMP_SIZE];
 
-    const unsigned short index5_to_short[5] = {
-	0x0000, 0x36db, 0x8000, 0xc925, 0xffff
-    };
-    const unsigned short index8_to_short[8] = {
-	0x0000, 0x2492, 0x4924, 0x6db6,
-	0x9249, 0xb6db, 0xdb6d, 0xffff
-    };
+    for (i = 0; i < CUBE_SIZE; i++)
+	cube_index_to_short[i] = (0xffff * i + ((CUBE_SIZE-1)>>1)) / (CUBE_SIZE-1);
+    for (i = 0; i < RAMP_SIZE; i++)
+	ramp_index_to_short[i] = (0xffff * i + ((RAMP_SIZE-1)>>1)) / (RAMP_SIZE-1);
 
     info = malloc (sizeof (cairo_xlib_visual_info_t));
     if (info == NULL)
@@ -82,10 +83,11 @@ _cairo_xlib_visual_info_create (Display *dpy,
 
     info->visualid = visualid;
 
-    /* Allocate a 8-entry gray ramp and a 5x5x5 color cube. Give up
-     * as soon as failures start. */
-    for (gray = 0; gray < 8; gray++) {
-	color.red = color.green = color.blue = index8_to_short[gray];
+    /* Allocate a gray ramp and a color cube.
+     * Give up as soon as failures start. */
+
+    for (gray = 0; gray < RAMP_SIZE; gray++) {
+	color.red = color.green = color.blue = ramp_index_to_short[gray];
 	if (! XAllocColor (dpy, colormap, &color))
 	    goto DONE_ALLOCATE;
     }
@@ -93,12 +95,12 @@ _cairo_xlib_visual_info_create (Display *dpy,
     /* XXX: Could do this in a more clever order to have the best
      * possible results from early failure. Could also choose a cube
      * uniformly distributed in a better space than RGB. */
-    for (red = 0; red < 5; red++) {
-	for (green = 0; green < 5; green++) {
-	    for (blue = 0; blue < 5; blue++) {
-		color.red = index5_to_short[red];
-		color.green = index5_to_short[green];
-		color.blue = index5_to_short[blue];
+    for (red = 0; red < CUBE_SIZE; red++) {
+	for (green = 0; green < CUBE_SIZE; green++) {
+	    for (blue = 0; blue < CUBE_SIZE; blue++) {
+		color.red = cube_index_to_short[red];
+		color.green = cube_index_to_short[green];
+		color.blue = cube_index_to_short[blue];
 		color.pixel = 0;
 		color.flags = 0;
 		color.pad = 0;
@@ -109,31 +111,68 @@ _cairo_xlib_visual_info_create (Display *dpy,
     }
   DONE_ALLOCATE:
 
-    for (i = 0; i < ARRAY_LENGTH (info->colors); i++)
-	info->colors[i].pixel = i;
-    XQueryColors (dpy, colormap, info->colors, ARRAY_LENGTH (info->colors));
+    for (i = 0; i < ARRAY_LENGTH (colors); i++)
+	colors[i].pixel = i;
+    XQueryColors (dpy, colormap, colors, ARRAY_LENGTH (colors));
 
     /* Search for nearest colors within allocated colormap. */
-    for (red = 0; red < 8; red++) {
-	for (green = 0; green < 8; green++) {
-	    for (blue = 0; blue < 8; blue++) {
-		index = (red << 6) | (green << 3) | (blue);
+    for (gray = 0; gray < RAMP_SIZE; gray++) {
+	for (i = 0; i < 256; i++) {
+	    distance = _color_distance (ramp_index_to_short[gray],
+					ramp_index_to_short[gray],
+					ramp_index_to_short[gray],
+					colors[i].red,
+					colors[i].green,
+					colors[i].blue);
+	    if (i == 0 || distance < min_distance) {
+		gray_to_pseudocolor[gray] = colors[i].pixel;
+		min_distance = distance;
+		if (!min_distance)
+		    break;
+	    }
+	}
+    }
+    for (red = 0; red < CUBE_SIZE; red++) {
+	for (green = 0; green < CUBE_SIZE; green++) {
+	    for (blue = 0; blue < CUBE_SIZE; blue++) {
 		for (i = 0; i < 256; i++) {
-		    distance = _color_distance (index8_to_short[red],
-						index8_to_short[green],
-						index8_to_short[blue],
-						info->colors[i].red,
-						info->colors[i].green,
-						info->colors[i].blue);
+		    distance = _color_distance (cube_index_to_short[red],
+						cube_index_to_short[green],
+						cube_index_to_short[blue],
+						colors[i].red,
+						colors[i].green,
+						colors[i].blue);
 		    if (i == 0 || distance < min_distance) {
-			info->rgb333_to_pseudocolor[index] = info->colors[i].pixel;
+			info->cube_to_pseudocolor[red][green][blue] = colors[i].pixel;
 			min_distance = distance;
+			if (!min_distance)
+			    break;
 		    }
 		}
 	    }
 	}
     }
 
+    for (i = 0, j = 0; i < 256; i++) {
+	if (j < CUBE_SIZE - 1 && (((i<<8)+i) - (int)cube_index_to_short[j]) > ((int)cube_index_to_short[j+1] - ((i<<8)+i)))
+	    j++;
+	info->field8_to_cube[i] = j;
+
+	info->dither8_to_cube[i] = ((int)i - 128) / (CUBE_SIZE - 1);
+    }
+    for (i = 0, j = 0; i < 256; i++) {
+	if (j < RAMP_SIZE - 1 && (((i<<8)+i) - (int)ramp_index_to_short[j]) > ((int)ramp_index_to_short[j+1] - ((i<<8)+i)))
+	    j++;
+	info->gray8_to_pseudocolor[i] = gray_to_pseudocolor[j];
+    }
+
+    for (i = 0; i < 256; i++) {
+	info->colors[i].a = 0xff;
+	info->colors[i].r = colors[i].red   >> 8;
+	info->colors[i].g = colors[i].green >> 8;
+	info->colors[i].b = colors[i].blue  >> 8;
+    }
+
     *out = info;
     return CAIRO_STATUS_SUCCESS;
 }
commit c0176dc54cf16a3a9504977d80184e4608783052
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jun 13 00:43:31 2008 -0400

    [cairo-xlib-surface] Remove unused macro

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 8b1cdfe..8dbf7b7 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -105,7 +105,6 @@ static const XTransform identity = { {
 #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
 #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(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)
@@ -1680,7 +1679,7 @@ _cairo_xlib_surface_fill_rectangles (void		     *abstract_surface,
 
     _cairo_xlib_display_notify (surface->screen_info->display);
 
-    if (! CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface)) {
+    if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
 	if (op == CAIRO_OPERATOR_CLEAR ||
 	    ((op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER) &&
 	     CAIRO_COLOR_IS_OPAQUE (color)))
commit 93efdce43a05299abef4f2b8220d3b7d9869597b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Fri Jun 13 21:36:14 2008 -0400

    Add a create_solid_pattern_surface surface backend method
    
    This can be used by _cairo_pattern_acquire_surface_for_solid() to let
    the backend create custom surfaces for solid fill instead of a 1x1
    similar surface.

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 7c94265..e603b63 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1463,10 +1463,7 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t	     *pattern,
 	    if (status)
 		goto EVICT;
 
-	    status = _cairo_surface_paint (surface,
-					   &pattern->color == CAIRO_COLOR_TRANSPARENT ?
-					   CAIRO_OPERATOR_CLEAR :
-					   CAIRO_OPERATOR_SOURCE, &pattern->base);
+	    status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern);
 	    if (status)
 		goto EVICT;
 
@@ -1485,10 +1482,7 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t	     *pattern,
 
     if (surface == NULL) {
 	/* Not cached, need to create new */
-	surface = _cairo_surface_create_similar_solid (dst,
-						       pattern->content,
-						       1, 1,
-						       &pattern->color);
+	surface = _cairo_surface_create_solid_pattern_surface (dst, pattern);
 	if (surface->status) {
 	    status = surface->status;
 	    goto UNLOCK;
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index f5112d6..e35cd1d 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -338,6 +338,43 @@ _cairo_surface_create_similar_solid (cairo_surface_t	 *other,
     return surface;
 }
 
+cairo_surface_t *
+_cairo_surface_create_solid_pattern_surface (cairo_surface_t	   *other,
+					     cairo_solid_pattern_t *solid_pattern)
+{
+    cairo_surface_t *surface;
+
+    if (other->backend->create_solid_pattern_surface) {
+	surface = other->backend->create_solid_pattern_surface (other, solid_pattern);
+	if (surface)
+	    return surface;
+    }
+
+    surface = _cairo_surface_create_similar_solid (other,
+						   solid_pattern->content,
+						   1, 1,
+						   &solid_pattern->color);
+    return surface;
+}
+
+cairo_int_status_t
+_cairo_surface_repaint_solid_pattern_surface (cairo_surface_t	    *other,
+					      cairo_surface_t       *solid_surface,
+					      cairo_solid_pattern_t *solid_pattern)
+{
+    if (other->backend->create_solid_pattern_surface)
+	/* Solid pattern surface for this backend are not trivial to make.
+	 * Skip repainting.
+	 *
+	 * This does not work optimally with things like analysis surface that
+	 * are proxies.  But returning UNSUPPORTED is *safe* as it only
+	 * disables some caching.
+	 */
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    return _cairo_surface_paint (solid_surface, CAIRO_OPERATOR_SOURCE, &solid_pattern->base);
+}
+
 cairo_clip_mode_t
 _cairo_surface_get_clip_mode (cairo_surface_t *surface)
 {
diff --git a/src/cairoint.h b/src/cairoint.h
index e1451ab..192c803 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -481,6 +481,8 @@ extern const cairo_private struct _cairo_scaled_font_backend cairo_quartz_scaled
 
 #endif
 
+typedef struct _cairo_solid_pattern cairo_solid_pattern_t;
+
 struct _cairo_surface_backend {
     cairo_surface_type_t type;
 
@@ -744,6 +746,11 @@ struct _cairo_surface_backend {
 				 cairo_matrix_t		*stroke_ctm_inverse,
 				 double			 stroke_tolerance,
 				 cairo_antialias_t	 stroke_antialias);
+
+    cairo_surface_t *
+    (*create_solid_pattern_surface)
+			        (void			*surface,
+				 cairo_solid_pattern_t  *solid_pattern);
 };
 
 #include "cairo-surface-private.h"
@@ -801,11 +808,11 @@ struct _cairo_pattern {
     cairo_extend_t		extend;
 };
 
-typedef struct _cairo_solid_pattern {
+struct _cairo_solid_pattern {
     cairo_pattern_t base;
     cairo_color_t color;
     cairo_content_t content;
-} cairo_solid_pattern_t;
+};
 
 extern const cairo_private cairo_solid_pattern_t _cairo_pattern_nil;
 extern const cairo_private cairo_solid_pattern_t _cairo_pattern_none;
@@ -1610,6 +1617,15 @@ _cairo_surface_create_similar_solid (cairo_surface_t	 *other,
 				     int		  height,
 				     const cairo_color_t *color);
 
+cairo_private cairo_surface_t *
+_cairo_surface_create_solid_pattern_surface (cairo_surface_t	   *other,
+					     cairo_solid_pattern_t *solid_pattern);
+
+cairo_private cairo_int_status_t
+_cairo_surface_repaint_solid_pattern_surface (cairo_surface_t	    *other,
+					      cairo_surface_t       *solid_surface,
+					      cairo_solid_pattern_t *solid_pattern);
+
 cairo_private void
 _cairo_surface_init (cairo_surface_t			*surface,
 		     const cairo_surface_backend_t	*backend,
commit ff1371a0a7494f986385730a82823cbf56790d5b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 19 21:06:07 2008 -0400

    [cairo-surface] Remove optional pattern argument from create_similar_solid()
    
    This was added in 41c6eebcd1fab94fd3a91d09f1ef6ee0d8c7a044, to avoid
    allocating short-lived patterns.  However, this was error prune as the
    color information was duplicated in the pattern and could get out of
    sync.  Indeed, it was out of sync before this commit in the call from
    cairo-clip.c.
    
    By allocating the solid pattern on the stack we fix the original problem
    without creating new ones.

diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 3cee398..8a7c98a 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -485,8 +485,7 @@ _cairo_clip_intersect_mask (cairo_clip_t      *clip,
 						   CAIRO_CONTENT_ALPHA,
 						   surface_rect.width,
 						   surface_rect.height,
-						   CAIRO_COLOR_TRANSPARENT,
-						   &pattern.base);
+						   CAIRO_COLOR_TRANSPARENT);
     if (surface->status) {
 	_cairo_pattern_fini (&pattern.base);
 	return surface->status;
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 83e3e20..d067e28 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -1161,8 +1161,7 @@ _cairo_glitz_surface_fill_rectangles (void		      *abstract_dst,
 	    _cairo_surface_create_similar_solid (&dst->base,
 						 CAIRO_CONTENT_COLOR_ALPHA,
 						 1, 1,
-						 (cairo_color_t *) color,
-						 NULL);
+						 (cairo_color_t *) color);
 	if (src->base.status)
 	    return src->base.status;
 
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 0ac047c..7c94265 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1488,8 +1488,7 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t	     *pattern,
 	surface = _cairo_surface_create_similar_solid (dst,
 						       pattern->content,
 						       1, 1,
-						       &pattern->color,
-						       &pattern->base);
+						       &pattern->color);
 	if (surface->status) {
 	    status = surface->status;
 	    goto UNLOCK;
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index b3e457b..f5112d6 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -301,8 +301,7 @@ cairo_surface_create_similar (cairo_surface_t  *other,
 
     return _cairo_surface_create_similar_solid (other, content,
 						width, height,
-						CAIRO_COLOR_TRANSPARENT,
-						NULL);
+						CAIRO_COLOR_TRANSPARENT);
 }
 slim_hidden_def (cairo_surface_create_similar);
 
@@ -311,34 +310,25 @@ _cairo_surface_create_similar_solid (cairo_surface_t	 *other,
 				     cairo_content_t	  content,
 				     int		  width,
 				     int		  height,
-				     const cairo_color_t *color,
-				     cairo_pattern_t	 *pattern)
+				     const cairo_color_t *color)
 {
     cairo_status_t status;
     cairo_surface_t *surface;
-    cairo_pattern_t *source;
+    cairo_solid_pattern_t solid_pattern;
 
     surface = _cairo_surface_create_similar_scratch (other, content,
 						     width, height);
     if (surface->status)
 	return surface;
 
-    if (pattern == NULL) {
-	source = _cairo_pattern_create_solid (color, content);
-	if (source->status) {
-	    cairo_surface_destroy (surface);
-	    return _cairo_surface_create_in_error (source->status);
-	}
-    } else
-	source = pattern;
+    _cairo_pattern_init_solid (&solid_pattern, color, content);
 
     status = _cairo_surface_paint (surface,
 				   color == CAIRO_COLOR_TRANSPARENT ?
-				   CAIRO_OPERATOR_CLEAR :
-				   CAIRO_OPERATOR_SOURCE, source);
+				   CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
+				   &solid_pattern.base);
 
-    if (source != pattern)
-	cairo_pattern_destroy (source);
+    _cairo_pattern_fini (&solid_pattern.base);
 
     if (status) {
 	cairo_surface_destroy (surface);
diff --git a/src/cairoint.h b/src/cairoint.h
index fe58ff8..e1451ab 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1603,16 +1603,12 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other,
 				       int		width,
 				       int		height);
 
-/* Note: the color_pattern argument is optional - if provided it will reuse
- * that pattern instead of creating a very short-lived fresh solid pattern
- */
 cairo_private cairo_surface_t *
 _cairo_surface_create_similar_solid (cairo_surface_t	 *other,
 				     cairo_content_t	  content,
 				     int		  width,
 				     int		  height,
-				     const cairo_color_t *color,
-				     cairo_pattern_t     *color_pattern);
+				     const cairo_color_t *color);
 
 cairo_private void
 _cairo_surface_init (cairo_surface_t			*surface,
commit 240cb59fe8706b1b0d3aae4a4ed3d13472033d1d
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 19 19:49:23 2008 -0400

    [cairo-pattern] Clean up _cairo_pattern_acquire_surface_for_solid()

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index ea35ad6..0ac047c 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1380,13 +1380,10 @@ _cairo_pattern_solid_surface_matches (
 	const cairo_solid_pattern_t			    *pattern,
 	cairo_surface_t					    *dst)
 {
-    if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
-	return FALSE;
-
     if (cache->content != pattern->content)
 	return FALSE;
 
-    if (! _cairo_color_equal (&cache->color, &pattern->color))
+    if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
 	return FALSE;
 
     if (! _cairo_surface_is_similar (cache->surface, dst, pattern->content))
@@ -1395,6 +1392,18 @@ _cairo_pattern_solid_surface_matches (
     return TRUE;
 }
 
+static cairo_bool_t
+_cairo_pattern_solid_surface_matches_color (
+	const struct _cairo_pattern_solid_surface_cache	    *cache,
+	const cairo_solid_pattern_t			    *pattern,
+	cairo_surface_t					    *dst)
+{
+    if (! _cairo_color_equal (&cache->color, &pattern->color))
+	return FALSE;
+
+    return _cairo_pattern_solid_surface_matches (cache, pattern, dst);
+}
+
 static cairo_int_status_t
 _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t	     *pattern,
 					  cairo_surface_t	     *dst,
@@ -1414,9 +1423,9 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t	     *pattern,
 
     /* Check cache first */
     if (i < solid_surface_cache.size &&
-	_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
-		                              pattern,
-					      dst))
+	_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
+						    pattern,
+						    dst))
     {
 	status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
 	if (status)
@@ -1426,9 +1435,9 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t	     *pattern,
     }
 
     for (i = 0 ; i < solid_surface_cache.size; i++) {
-	if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
-		                                  pattern,
-						  dst))
+	if (_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
+							pattern,
+							dst))
 	{
 	    status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
 	    if (status)
@@ -1444,27 +1453,35 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t	     *pattern,
 	i = rand () % MAX_SURFACE_CACHE_SIZE;
 	surface = solid_surface_cache.cache[i].surface;
 
-	if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count) == 1 &&
-	    solid_surface_cache.cache[i].content == pattern->content &&
-	    _cairo_surface_is_similar (surface, dst, pattern->content))
+	if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
+						  pattern,
+						  dst))
 	{
+	    /* Reuse the surface instead of evicting */
+
 	    status = _cairo_surface_reset (surface);
 	    if (status)
-		goto UNLOCK;
+		goto EVICT;
 
 	    status = _cairo_surface_paint (surface,
 					   &pattern->color == CAIRO_COLOR_TRANSPARENT ?
 					   CAIRO_OPERATOR_CLEAR :
 					   CAIRO_OPERATOR_SOURCE, &pattern->base);
 	    if (status)
-		goto UNLOCK;
+		goto EVICT;
 
 	    cairo_surface_reference (surface);
-	} else {
-	    /* Unable to reuse, evict */
+	}
+	else
+	{
+	  EVICT:
 	    surface = NULL;
 	}
     }
+    else
+    {
+	i = solid_surface_cache.size++;
+    }
 
     if (surface == NULL) {
 	/* Not cached, need to create new */
@@ -1486,9 +1503,6 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t	     *pattern,
 	}
     }
 
-    if (solid_surface_cache.size < MAX_SURFACE_CACHE_SIZE)
-	i = solid_surface_cache.size++;
-
     to_destroy = solid_surface_cache.cache[i].surface;
     solid_surface_cache.cache[i].surface = surface;
     solid_surface_cache.cache[i].color   = pattern->color;
commit 2a592877110f34753da0b9e61d5c5f8c83f4ddd9
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 19 19:28:49 2008 -0400

    Fix comment

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index a20009b..b3e457b 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -417,7 +417,7 @@ cairo_surface_destroy (cairo_surface_t *surface)
 slim_hidden_def(cairo_surface_destroy);
 
 /**
- * cairo_surface_reset:
+ * _cairo_surface_reset:
  * @surface: a #cairo_surface_t
  *
  * Resets the surface back to defaults such that it may be reused in lieu
commit b0d112756f1f8af7cf38d1e7542cb2e4453e7b07
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 19 19:25:33 2008 -0400

    Remove opaque solid pattern COLOR_ALPHA optimization from call sites
    
    As we do this in _cairo_pattern_init_solid() now.

diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 44e560c..83e3e20 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -977,10 +977,7 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t	                *src,
 	combined = src_solid->color;
 	_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
 
-	_cairo_pattern_init_solid (&tmp, &combined,
-				   CAIRO_COLOR_IS_OPAQUE (&combined) ?
-				   CAIRO_CONTENT_COLOR :
-				   CAIRO_CONTENT_COLOR_ALPHA);
+	_cairo_pattern_init_solid (&tmp, &combined, CAIRO_CONTENT_COLOR_ALPHA);
 
 	mask = NULL;
     } else {
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index b78c040..ea35ad6 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1844,10 +1844,7 @@ _cairo_pattern_acquire_surface (cairo_pattern_t		   *pattern,
 					src->stops->color.blue,
 					src->stops->color.alpha);
 
-		_cairo_pattern_init_solid (&solid, &color,
-					   CAIRO_COLOR_IS_OPAQUE (&color) ?
-					   CAIRO_CONTENT_COLOR :
-					   CAIRO_CONTENT_COLOR_ALPHA);
+		_cairo_pattern_init_solid (&solid, &color, CAIRO_CONTENT_COLOR_ALPHA);
 	    }
 	    else
 	    {
@@ -1954,10 +1951,7 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t	    *src,
 	combined = src_solid->color;
 	_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
 
-	_cairo_pattern_init_solid (&src_tmp.solid, &combined,
-				   CAIRO_COLOR_IS_OPAQUE (&combined) ?
-				   CAIRO_CONTENT_COLOR :
-				   CAIRO_CONTENT_COLOR_ALPHA);
+	_cairo_pattern_init_solid (&src_tmp.solid, &combined, CAIRO_CONTENT_COLOR_ALPHA);
 
 	mask = NULL;
     }
commit e93e9903241bc0996bfce7c43d030f33cd33730b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 19 19:22:02 2008 -0400

    [cairo-pattern] In init_solid() convert COLOR_ALPHA to COLOR if color is opaque
    
    Moving this further than, so it benefits all callers.

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 67e5180..b78c040 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -252,6 +252,9 @@ _cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
 			   const cairo_color_t	 *color,
 			   cairo_content_t	  content)
 {
+    if (content == CAIRO_CONTENT_COLOR_ALPHA && CAIRO_COLOR_IS_OPAQUE (color))
+	content = CAIRO_CONTENT_COLOR;
+
     _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID);
     pattern->color = *color;
     pattern->content = content;
@@ -448,9 +451,6 @@ cairo_pattern_create_rgba (double red, double green, double blue,
 {
     cairo_color_t color;
 
-    if (alpha >= 1.0)
-	return cairo_pattern_create_rgb (red, green, blue);
-
     _cairo_restrict_value (&red,   0.0, 1.0);
     _cairo_restrict_value (&green, 0.0, 1.0);
     _cairo_restrict_value (&blue,  0.0, 1.0);
commit 333a49d01d431a808c754cfa900e83a733010083
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 19 19:18:57 2008 -0400

    [cairo-pattern] Don't call _cairo_stock_color() directly

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 845a798..67e5180 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -377,8 +377,7 @@ _cairo_pattern_create_in_error (cairo_status_t status)
 
     CAIRO_MUTEX_INITIALIZE ();
 
-    pattern = _cairo_pattern_create_solid (_cairo_stock_color (CAIRO_STOCK_BLACK),
-					   CAIRO_CONTENT_COLOR);
+    pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK, CAIRO_CONTENT_COLOR);
     if (pattern->status == CAIRO_STATUS_SUCCESS)
 	status = _cairo_pattern_set_error (pattern, status);
 
@@ -1852,11 +1851,7 @@ _cairo_pattern_acquire_surface (cairo_pattern_t		   *pattern,
 	    }
 	    else
 	    {
-		const cairo_color_t *color;
-
-		color =	_cairo_stock_color (CAIRO_STOCK_TRANSPARENT);
-		_cairo_pattern_init_solid (&solid, color,
-					   CAIRO_CONTENT_ALPHA);
+		_cairo_pattern_init_solid (&solid, CAIRO_COLOR_TRANSPARENT, CAIRO_CONTENT_ALPHA);
 	    }
 
 	    status = _cairo_pattern_acquire_surface_for_solid (&solid, dst,
commit 4eae72317f117941617b426daa682fa4f1bf3d25
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Thu Jun 19 19:08:50 2008 -0400

    [cairo-pattern] Remove stale comment

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index a6c3ec3..845a798 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1487,7 +1487,6 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t	     *pattern,
 	}
     }
 
-    /* Increment after recursion by _cairo_surface_create_similar_solid() */
     if (solid_surface_cache.size < MAX_SURFACE_CACHE_SIZE)
 	i = solid_surface_cache.size++;
 


More information about the cairo-commit mailing list