[cairo-commit] cairo/src cairo-xlib-surface.c,1.81,1.82
Owen Taylor
commit at pdx.freedesktop.org
Mon Jun 20 15:48:49 PDT 2005
Committed by: otaylor
Update of /cvs/cairo/cairo/src
In directory gabe:/tmp/cvs-serv2501/src
Modified Files:
cairo-xlib-surface.c
Log Message:
2005-06-20 Owen Taylor <otaylor at redhat.com>
Workaround for https://bugs.freedesktop.org/show_bug.cgi?id=3566
* src/cairo-xlib-surface.c: Detect servers with a bug in
repeating surfaces by checking vendor string and version.
* src/cairo-xlib-surface.c: For such surfaces
* src/cairo-xlib-surface.c: Save clip rects when setting a
clip region on a surface so that we set the right clip for the
surface's GC if we create it later.
Index: cairo-xlib-surface.c
===================================================================
RCS file: /cvs/cairo/cairo/src/cairo-xlib-surface.c,v
retrieving revision 1.81
retrieving revision 1.82
diff -u -d -r1.81 -r1.82
--- cairo-xlib-surface.c 17 Jun 2005 23:19:08 -0000 1.81
+++ cairo-xlib-surface.c 20 Jun 2005 22:48:46 -0000 1.82
@@ -55,6 +55,9 @@
static void
_cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface);
+static cairo_bool_t
+_cairo_surface_is_xlib (cairo_surface_t *surface);
+
/*
* Instead of taking two round trips for each blending request,
* assume that if a particular drawable fails GetImage that it will
@@ -77,12 +80,25 @@
int render_major;
int render_minor;
+ /* TRUE if the server has a bug with repeating pictures
+ *
+ * https://bugs.freedesktop.org/show_bug.cgi?id=3566
+ *
+ * We can't test for this because it depends on whether the
+ * picture is in video memory or not.
+ */
+ cairo_bool_t buggy_repeat;
+
int width;
int height;
int depth;
Picture dst_picture, src_picture;
+ cairo_bool_t have_clip_rects;
+ XRectangle *clip_rects;
+ int num_clip_rects;
+
XRenderPictFormat *format;
};
@@ -216,6 +232,9 @@
if (surface->gc)
XFreeGC (surface->dpy, surface->gc);
+ if (surface->clip_rects)
+ free (surface->clip_rects);
+
surface->dpy = NULL;
return CAIRO_STATUS_SUCCESS;
@@ -450,13 +469,36 @@
}
static void
+_cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface)
+{
+ if (surface->have_clip_rects)
+ XRenderSetPictureClipRectangles (surface->dpy, surface->dst_picture,
+ 0, 0,
+ surface->clip_rects,
+ surface->num_clip_rects);
+}
+
+static void
+_cairo_xlib_surface_set_gc_clip_rects (cairo_xlib_surface_t *surface)
+{
+ if (surface->have_clip_rects)
+ XSetClipRectangles(surface->dpy, surface->gc,
+ 0, 0,
+ surface->clip_rects,
+ surface->num_clip_rects, YXSorted);
+}
+
+static void
_cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface)
{
- if (!surface->dst_picture)
+ if (!surface->dst_picture) {
surface->dst_picture = XRenderCreatePicture (surface->dpy,
surface->drawable,
surface->format,
0, NULL);
+ _cairo_xlib_surface_set_picture_clip_rects (surface);
+ }
+
}
static void
@@ -470,6 +512,7 @@
gcv.graphics_exposures = False;
surface->gc = XCreateGC (surface->dpy, surface->drawable,
GCGraphicsExposures, &gcv);
+ _cairo_xlib_surface_set_gc_clip_rects (surface);
}
static cairo_status_t
@@ -744,6 +787,139 @@
return CAIRO_STATUS_SUCCESS;
}
+/* Checks whether we can can directly draw from src to dst with
+ * the core protocol: either with CopyArea or using src as a
+ * a tile in a GC.
+ */
+static cairo_bool_t
+_surfaces_compatible (cairo_xlib_surface_t *src,
+ cairo_xlib_surface_t *dst)
+{
+
+ if (src->dpy != dst->dpy)
+ return FALSE;
+
+ /* We must not only match depth and format/visual, we must also
+ * match screen. We don't have that information, and rather than
+ * asking for it round-trip, we'll just return FALSE if we have
+ * more than one screen on the display.
+ */
+ if (ScreenCount (dst->dpy) > 1)
+ return FALSE;
+
+ return (src->depth == dst->depth &&
+ ((src->format != NULL && src->format == dst->format) ||
+ (src->visual != NULL && src->visual == dst->visual)));
+}
+
+static cairo_bool_t
+_surface_has_alpha (cairo_xlib_surface_t *surface)
+{
+ if (surface->format) {
+ if (surface->format->type == PictTypeDirect &&
+ surface->format->direct.alphaMask != 0)
+ return TRUE;
+ else
+ return FALSE;
+ } else {
+
+ /* In the no-render case, we never have alpha */
+ return FALSE;
+ }
+}
+
+/* There is a bug in most older X servers with compositing using a repeating
+ * source pattern when the source is in off-screen video memory. When that
+ * bug could be triggered, we need a fallback: in the common case where we have no
+ * transformation and the source and destination have the same format/visual,
+ * we can do the operation using the core protocol, otherwise, we need
+ * a software fallback.
+ */
+typedef enum {
+ DO_RENDER, /* use render */
+ DO_XLIB, /* core protocol fallback */
+ DO_UNSUPPORTED /* software fallback */
+} composite_operation_t;
+
+/* Initial check for the bug; we need to recheck after we turn
+ * patterns into surfaces, since that may introduce a repeating
+ * pattern for gradient patterns.
+ *
+ * All we do here is reject cases where we *know* are going to
+ * hit the bug and won't be able to use a core protocol fallback.
+ */
+static composite_operation_t
+_categorize_composite_repeat (cairo_xlib_surface_t *dst,
+ cairo_operator_t operator,
+ cairo_pattern_t *src_pattern,
+ cairo_bool_t have_mask)
+
+{
+ if (!dst->buggy_repeat)
+ return DO_RENDER;
+
+ if (src_pattern->type == CAIRO_PATTERN_SURFACE)
+ {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src_pattern;
+
+ if (_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
+ src_pattern->extend == CAIRO_EXTEND_REPEAT)
+ {
+ /* This is the case where we have a bug; reject some cases where a
+ * core protocol fallback is impossible.
+ */
+ if (have_mask ||
+ !(operator == CAIRO_OPERATOR_SOURCE || operator == CAIRO_OPERATOR_OVER))
+ return DO_UNSUPPORTED;
+
+ if (_cairo_surface_is_xlib (surface_pattern->surface)) {
+ cairo_xlib_surface_t *src = (cairo_xlib_surface_t *)surface_pattern->surface;
+
+ if (operator == CAIRO_OPERATOR_OVER && _surface_has_alpha (src))
+ return DO_UNSUPPORTED;
+
+ if (src->dpy == dst->dpy && !_surfaces_compatible (src, dst))
+ return DO_UNSUPPORTED;
+ }
+ }
+ }
+
+ return DO_RENDER;
+}
+
+/* Recheck for composite-repeat once we've turned patterns into Xlib surfaces
+ * If we end up returning DO_UNSUPPORTED here, we're throwing away work we
+ * did to turn gradients into a pattern, but most of the time we can handle
+ * that case with core protocol fallback.
+ */
+static composite_operation_t
+_recategorize_composite_repeat (cairo_xlib_surface_t *dst,
+ cairo_operator_t operator,
+ cairo_xlib_surface_t *src,
+ cairo_surface_attributes_t *src_attr,
+ cairo_bool_t have_mask)
+{
+ if (!dst->buggy_repeat)
+ return DO_RENDER;
+
+ if (_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) &&
+ src_attr->extend == CAIRO_EXTEND_REPEAT &&
+ (src->width != 1 || src->height != 1))
+ {
+ if (!have_mask &&
+ (operator == CAIRO_OPERATOR_SOURCE ||
+ (operator == CAIRO_OPERATOR_OVER && !_surface_has_alpha (src))))
+ {
+ if (_surfaces_compatible (dst, src))
+ return DO_XLIB;
+ }
+
+ return DO_UNSUPPORTED;
+ }
+
+ return DO_RENDER;
+}
+
static int
_render_operator (cairo_operator_t operator)
{
@@ -803,10 +979,16 @@
cairo_xlib_surface_t *src;
cairo_xlib_surface_t *mask;
cairo_int_status_t status;
+ composite_operation_t operation;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ operation = _categorize_composite_repeat (dst, operator, src_pattern,
+ mask_pattern != NULL);
+ if (operation == DO_UNSUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
&dst->base,
src_x, src_y,
@@ -818,9 +1000,19 @@
if (status)
return status;
+ operation = _recategorize_composite_repeat (dst, operator, src, &src_attr,
+ mask_pattern != NULL);
+ if (operation == DO_UNSUPPORTED) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto FAIL;
+ }
+
status = _cairo_xlib_surface_set_attributes (src, &src_attr);
+ if (status)
+ goto FAIL;
- if (status == CAIRO_STATUS_SUCCESS) {
+ if (operation == DO_RENDER)
+ {
_cairo_xlib_surface_ensure_dst_picture (dst);
if (mask) {
status = _cairo_xlib_surface_set_attributes (mask, &mask_attr);
@@ -849,6 +1041,30 @@
width, height);
}
}
+ else /* DO_XLIB */
+ {
+ /* 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.
+ *
+ * We've checked that we have a repeating unscaled source in
+ * _recategorize_composite_repeat.
+ */
+ int itx, ity;
+
+ _cairo_xlib_surface_ensure_gc (dst);
+ _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
+
+ XSetTSOrigin (dst->dpy, dst->gc,
+ - (itx + src_attr.x_offset), - (ity + src_attr.y_offset));
+ XSetTile (dst->dpy, dst->gc, src->drawable);
+ XSetFillStyle (dst->dpy, dst->gc, FillTiled);
+
+ XFillRectangle (dst->dpy, dst->drawable, dst->gc,
+ dst_x, dst_y, width, height);
+ }
+
+ FAIL:
if (mask)
_cairo_pattern_release_surface (&dst->base, &mask->base, &mask_attr);
@@ -903,11 +1119,16 @@
cairo_xlib_surface_t *dst = abstract_dst;
cairo_xlib_surface_t *src;
cairo_int_status_t status;
+ composite_operation_t operation;
int render_reference_x, render_reference_y;
int render_src_x, render_src_y;
if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ operation = _categorize_composite_repeat (dst, operator, pattern, TRUE);
+ if (operation == DO_UNSUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_pattern_acquire_surface (pattern, &dst->base,
src_x, src_y, width, height,
@@ -915,7 +1136,13 @@
&attributes);
if (status)
return status;
-
+
+ operation = _recategorize_composite_repeat (dst, operator, src, &attributes, TRUE);
+ if (operation == DO_UNSUPPORTED) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto FAIL;
+ }
+
if (traps[0].left.p1.y < traps[0].left.p2.y) {
render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
@@ -939,6 +1166,7 @@
render_src_y + attributes.y_offset,
(XTrapezoid *) traps, num_traps);
+ FAIL:
_cairo_pattern_release_surface (&dst->base, &src->base, &attributes);
return status;
@@ -950,14 +1178,21 @@
{
cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
+ if (surface->clip_rects) {
+ free (surface->clip_rects);
+ surface->clip_rects = NULL;
+ }
+
+ surface->have_clip_rects = FALSE;
+ surface->num_clip_rects = 0;
+
if (region == NULL) {
if (surface->gc)
XSetClipMask (surface->dpy, surface->gc, None);
- if (surface->format) {
+ if (surface->format && surface->dst_picture) {
XRenderPictureAttributes pa;
pa.clip_mask = None;
- _cairo_xlib_surface_ensure_dst_picture (surface);
XRenderChangePicture (surface->dpy, surface->dst_picture,
CPClipMask, &pa);
}
@@ -984,17 +1219,15 @@
rects[i].height = boxes[i].y2 - boxes[i].y1;
}
+ surface->have_clip_rects = TRUE;
+ surface->clip_rects = rects;
+ surface->num_clip_rects = n_boxes;
+
if (surface->gc)
- XSetClipRectangles(surface->dpy, surface->gc,
- 0, 0, rects, n_boxes, YXSorted);
- if (surface->format) {
- _cairo_xlib_surface_ensure_dst_picture (surface);
- XRenderSetPictureClipRectangles (surface->dpy, surface->dst_picture,
- 0, 0, rects, n_boxes);
- }
+ _cairo_xlib_surface_set_gc_clip_rects (surface);
- if (rects)
- free (rects);
+ if (surface->dst_picture)
+ _cairo_xlib_surface_set_picture_clip_rects (surface);
}
return CAIRO_STATUS_SUCCESS;
@@ -1118,6 +1351,12 @@
surface->render_minor = -1;
}
+ surface->buggy_repeat = FALSE;
+ if (strcmp (ServerVendor (dpy), "The X.Org Foundation") == 0) {
+ if (VendorRelease (dpy) <= 60802000)
+ surface->buggy_repeat = TRUE;
+ }
+
surface->dst_picture = None;
surface->src_picture = None;
@@ -1136,6 +1375,10 @@
surface->format = format;
surface->depth = depth;
+ surface->have_clip_rects = FALSE;
+ surface->clip_rects = NULL;
+ surface->num_clip_rects = 0;
+
return (cairo_surface_t *) surface;
}
@@ -1718,11 +1961,16 @@
cairo_glyph_cache_key_t key;
glyphset_cache_entry_t **entries;
glyphset_cache_entry_t *stack_entries [N_STACK_BUF];
+ composite_operation_t operation;
int i;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self) || !self->format)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ operation = _categorize_composite_repeat (self, operator, pattern, TRUE);
+ if (operation == DO_UNSUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
status = _cairo_pattern_acquire_surface (pattern, &self->base,
source_x, source_y, width, height,
(cairo_surface_t **) &src,
@@ -1730,6 +1978,12 @@
if (status)
return status;
+ operation = _recategorize_composite_repeat (self, operator, src, &attributes, TRUE);
+ if (operation == DO_UNSUPPORTED) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto FAIL;
+ }
+
status = _cairo_xlib_surface_set_attributes (src, &attributes);
if (status)
goto FAIL;
More information about the cairo-commit
mailing list