[PATCH 3/5] xlib: Use server-side gradients when available.

David Reveman davidr at novell.com
Tue Jun 13 17:12:05 PDT 2006


No server-side gradients are used if the X server VendorName is
XFree86 or if it is X.Org with a VendorRelease of 70000000 (7.0)
or less, (since those X servers are known to have bugs with
gradients).
---
 src/cairo-xlib-display.c         |    5 +-
 src/cairo-xlib-private.h         |    1 +
 src/cairo-xlib-surface-private.h |    1 +
 src/cairo-xlib-surface.c         |  242 ++++++++++++++++++++++++++++++++++----
 4 files changed, 226 insertions(+), 23 deletions(-)

diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
index af244ab..1707cb6 100644
--- a/src/cairo-xlib-display.c
+++ b/src/cairo-xlib-display.c
@@ -285,6 +285,7 @@ _cairo_xlib_display_get (Display *dpy,
 	    sizeof (display->cached_xrender_formats));
 
     display->buggy_repeat = FALSE;
+    display->buggy_gradients = FALSE;
 
     /* This buggy_repeat condition is very complicated because there
      * are multiple X server code bases (with multiple versioning
@@ -331,8 +332,10 @@ _cairo_xlib_display_get (Display *dpy,
      *    (just using VendorRelase < 70000000), as buggy_repeat=TRUE.
      */
     if (strstr (ServerVendor (dpy), "X.Org") != NULL) {
-	if (VendorRelease (dpy) >= 60700000 && VendorRelease (dpy) < 70000000)
+	if (VendorRelease (dpy) >= 60700000 && VendorRelease (dpy) < 70000000) {
 	    display->buggy_repeat = TRUE;
+	    display->buggy_gradients = TRUE;
+	}
 	if (VendorRelease (dpy) < 10400000)
 	    display->buggy_repeat = TRUE;
     } else if (strstr (ServerVendor (dpy), "XFree86") != NULL) {
diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index b9c84b8..a1a0c37 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -73,6 +73,7 @@ struct _cairo_xlib_display {
 
     cairo_xlib_hook_t *close_display_hooks;
     unsigned int buggy_repeat :1;
+    unsigned int buggy_gradients :1;
     unsigned int closed :1;
 };
 
diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h
index fe37e5f..1366d36 100644
--- a/src/cairo-xlib-surface-private.h
+++ b/src/cairo-xlib-surface-private.h
@@ -76,6 +76,7 @@ struct _cairo_xlib_surface {
      * we can reuse the test for now.
      */
     cairo_bool_t buggy_repeat;
+    cairo_bool_t buggy_gradients;
 
     int width;
     int height;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 7d2032d..e24972e 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -89,6 +89,16 @@ _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
 				 int		     *remaining_glyphs,
 				 cairo_rectangle_int_t *extents);
 
+static cairo_surface_t *
+_cairo_xlib_surface_create_internal (Display		       *dpy,
+				     Drawable		        drawable,
+				     Screen		       *screen,
+				     Visual		       *visual,
+				     XRenderPictFormat	       *format,
+				     int			width,
+				     int			height,
+				     int			depth);
+
 /*
  * Instead of taking two round trips for each blending request,
  * assume that if a particular drawable fails GetImage that it will
@@ -125,6 +135,7 @@ static const XTransform identity = { {
 #define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)	CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
 #define CAIRO_SURFACE_RENDER_HAS_REPEAT_PAD(surface)	CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
 #define CAIRO_SURFACE_RENDER_HAS_REPEAT_REFLECT(surface)	CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
+#define CAIRO_SURFACE_RENDER_HAS_GRADIENTS(surface)	CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
 
 static cairo_surface_t *
 _cairo_xlib_surface_create_similar_with_format (void	       *abstract_src,
@@ -1712,6 +1723,194 @@ _render_operator (cairo_operator_t op)
 }
 
 static cairo_int_status_t
+_cairo_xlib_pattern_acquire_surface (const cairo_pattern_t	*pattern,
+				     cairo_xlib_surface_t       *dst,
+				     int		        x,
+				     int		        y,
+				     unsigned int	        width,
+				     unsigned int	        height,
+				     cairo_xlib_surface_t	**surface_out,
+				     cairo_surface_attributes_t *attributes)
+{
+    switch (pattern->type) {
+    case CAIRO_PATTERN_TYPE_LINEAR:
+    case CAIRO_PATTERN_TYPE_RADIAL: {
+	cairo_gradient_pattern_t *gradient =
+	    (cairo_gradient_pattern_t *) pattern;
+	cairo_xlib_surface_t     *surface;
+	XFixed			 *stops;
+	XRenderColor		 *colors;
+	XRenderPictFormat	 *format;
+	Picture			 picture;
+	unsigned int		 i;
+
+	if (!CAIRO_SURFACE_RENDER_HAS_GRADIENTS (dst))
+	    break;
+
+	if (dst->buggy_gradients)
+	    break;
+
+	if (gradient->n_stops < 2)
+	    break;
+
+	stops = malloc ((sizeof (XFixed) + sizeof (XRenderColor)) *
+			gradient->n_stops);
+	if (!stops)
+	    return CAIRO_STATUS_NO_MEMORY;
+
+	colors = (XRenderColor *) (stops + gradient->n_stops);
+
+	for (i = 0; i < gradient->n_stops; i++)
+	{
+	    stops[i] = gradient->stops[i].offset;
+
+	    colors[i].red   = gradient->stops[i].color.red;
+	    colors[i].green = gradient->stops[i].color.green;
+	    colors[i].blue  = gradient->stops[i].color.blue;
+	    colors[i].alpha = gradient->stops[i].color.alpha;
+	}
+
+	/* For some weird reason the X server is sometimes getting
+	   CreateGradient requests with bad length. So far I've only seen
+	   XRenderCreateLinearGradient request with 4 stops sometime end up
+	   with length field matching 0 stops at the server side. I've looked
+	   at the libXrender code and I can't see anything that could
+	   cause this behavior. However, for some reason having a XSync call
+	   here seems to avoid the issue so I'll keep it here until it's
+	   solved. */
+	XSync (dst->dpy, False);
+
+	if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR)
+	{
+	    cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern;
+
+	    picture = XRenderCreateLinearGradient (dst->dpy,
+						   (XLinearGradient *)
+						   &grad->base,
+						   stops, colors,
+						   gradient->n_stops);
+	}
+	else
+	{
+	    cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
+
+	    picture = XRenderCreateRadialGradient (dst->dpy,
+						   (XRadialGradient *)
+						   &grad->base,
+						   stops, colors,
+						   gradient->n_stops);
+	}
+
+	if (!picture)
+	{
+	    free (stops);
+	    break;
+	}
+
+	format = XRenderFindStandardFormat (dst->dpy, PictStandardARGB32);
+
+	surface = (cairo_xlib_surface_t *)
+	    _cairo_xlib_surface_create_internal (dst->dpy, None,
+						 dst->screen, NULL,
+						 format, 0, 0, 32);
+	if (!surface)
+	{
+	    XRenderFreePicture (dst->dpy, picture);
+	    free (stops);
+	    return CAIRO_STATUS_NO_MEMORY;
+	}
+
+	surface->src_picture = picture;
+
+	attributes->matrix   = pattern->matrix;
+	attributes->extend   = pattern->extend;
+	attributes->filter   = pattern->filter;
+	attributes->x_offset = 0;
+	attributes->y_offset = 0;
+
+	free (stops);
+
+	*surface_out = surface;
+
+	return CAIRO_STATUS_SUCCESS;
+    }
+    case CAIRO_PATTERN_TYPE_SOLID:
+    case CAIRO_PATTERN_TYPE_SURFACE:
+    default:
+	break;
+    }
+
+    return _cairo_pattern_acquire_surface (pattern, &dst->base,
+					   x, y, width, height,
+					   (cairo_surface_t **) surface_out,
+					   attributes);
+}
+
+static cairo_int_status_t
+_cairo_xlib_pattern_acquire_surfaces (const cairo_pattern_t	 *src,
+				      const cairo_pattern_t	 *mask,
+				      cairo_xlib_surface_t	 *dst,
+				      int			 src_x,
+				      int			 src_y,
+				      int			 mask_x,
+				      int			 mask_y,
+				      unsigned int		 width,
+				      unsigned int		 height,
+				      cairo_xlib_surface_t	 **src_out,
+				      cairo_xlib_surface_t	 **mask_out,
+				      cairo_surface_attributes_t *src_attr,
+				      cairo_surface_attributes_t *mask_attr)
+{
+    if (CAIRO_SURFACE_RENDER_HAS_GRADIENTS (dst))
+    {
+	if (src->type == CAIRO_PATTERN_TYPE_LINEAR		 ||
+	    src->type == CAIRO_PATTERN_TYPE_RADIAL		 ||
+	    (mask && (mask->type == CAIRO_PATTERN_TYPE_LINEAR ||
+		      mask->type == CAIRO_PATTERN_TYPE_RADIAL)))
+	{
+	    cairo_int_status_t status;
+
+	    status = _cairo_xlib_pattern_acquire_surface (src, dst,
+							  src_x, src_y,
+							  width, height,
+							  src_out,
+							  src_attr);
+	    if (status)
+		return status;
+
+	    if (mask)
+	    {
+		status = _cairo_xlib_pattern_acquire_surface (mask, dst,
+							      mask_x, mask_y,
+							      width, height,
+							      mask_out,
+							      mask_attr);
+		if (status)
+		{
+		    _cairo_pattern_release_surface (src, &(*src_out)->base,
+						    src_attr);
+		    return status;
+		}
+	    }
+	    else
+	    {
+		*mask_out = NULL;
+	    }
+
+	    return CAIRO_STATUS_SUCCESS;
+	}
+    }
+
+    return _cairo_pattern_acquire_surfaces (src, mask, &dst->base,
+					    src_x, src_y,
+					    mask_x, mask_y,
+					    width, height,
+					    (cairo_surface_t **) src_out,
+					    (cairo_surface_t **) mask_out,
+					    src_attr, mask_attr);
+}
+
+static cairo_int_status_t
 _cairo_xlib_surface_composite (cairo_operator_t		op,
 			       const cairo_pattern_t	*src_pattern,
 			       const cairo_pattern_t	*mask_pattern,
@@ -1741,14 +1940,13 @@ _cairo_xlib_surface_composite (cairo_operator_t		op,
     if (operation == DO_UNSUPPORTED)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
-					      &dst->base,
-					      src_x, src_y,
-					      mask_x, mask_y,
-					      width, height,
-					      (cairo_surface_t **) &src,
-					      (cairo_surface_t **) &mask,
-					      &src_attr, &mask_attr);
+    status = _cairo_xlib_pattern_acquire_surfaces (src_pattern, mask_pattern,
+						   dst,
+						   src_x, src_y,
+						   mask_x, mask_y,
+						   width, height,
+						   &src, &mask,
+						   &src_attr, &mask_attr);
     if (unlikely (status))
 	return status;
 
@@ -1904,11 +2102,11 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t    *surface,
         return status;
 
     status = _cairo_pattern_acquire_surface (&solid.base, &surface->base,
-					     0, 0,
-					     ARRAY_LENGTH (dither_pattern[0]),
-					     ARRAY_LENGTH (dither_pattern),
-					     &solid_surface,
-					     &attrs);
+                                            0, 0,
+                                            ARRAY_LENGTH (dither_pattern[0]),
+                                            ARRAY_LENGTH (dither_pattern),
+                                            &solid_surface,
+                                            &attrs);
     if (unlikely (status))
         return status;
 
@@ -2153,10 +2351,9 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t	op,
     if (operation == DO_UNSUPPORTED)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    status = _cairo_pattern_acquire_surface (pattern, &dst->base,
-					     src_x, src_y, width, height,
-					     (cairo_surface_t **) &src,
-					     &attributes);
+    status = _cairo_xlib_pattern_acquire_surface (pattern, dst,
+						  src_x, src_y, width, height,
+						  &src, &attributes);
     if (unlikely (status))
 	return status;
 
@@ -2658,6 +2855,8 @@ _cairo_xlib_surface_create_internal (Display		       *dpy,
 	surface->buggy_repeat = TRUE;
     }
 
+    surface->buggy_gradients = screen_info->display->buggy_gradients;
+
     surface->dst_picture = None;
     surface->src_picture = None;
 
@@ -4098,11 +4297,10 @@ _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
         if (unlikely (status))
 	    goto BAIL0;
 
-        status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
-                                                 glyph_extents.x, glyph_extents.y,
-                                                 glyph_extents.width, glyph_extents.height,
-                                                 (cairo_surface_t **) &src,
-                                                 &attributes);
+        status = _cairo_xlib_pattern_acquire_surface (src_pattern, dst,
+						      glyph_extents.x, glyph_extents.y,
+						      glyph_extents.width, glyph_extents.height,
+						      &src, &attributes);
         if (unlikely (status))
 	    goto BAIL0;
     }
-- 
1.6.3


--------------010101010805020406070805
Content-Type: text/x-patch;
 name="0004-pattern-factor-out-gradient-rescaling-code.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename*0="0004-pattern-factor-out-gradient-rescaling-code.patch"



More information about the cairo mailing list