[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
--------------000209070203020007040404
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