[cairo-commit] 6 commits - src/cairo-clip.c src/cairo-clip-private.h src/cairoint.h src/cairo-scaled-font.c src/cairo-surface.c src/cairo-xlib-screen.c src/cairo-xlib-surface.c src/cairo-xlib-surface-private.h test/big-line.c test/big-line.ps.argb32.ref.png test/big-line.ps.rgb24.ref.png test/big-line.quartz.ref.png test/big-line.quartz.rgb24.ref.png test/big-line.ref.png test/big-line.xlib-fallback.ref.png test/big-line.xlib.ref.png test/Makefile.am

Chris Wilson ickle at kemper.freedesktop.org
Fri Sep 11 07:05:40 PDT 2009


 dev/null                            |binary
 src/cairo-clip-private.h            |    3 
 src/cairo-clip.c                    |   84 +++----
 src/cairo-scaled-font.c             |   36 +++
 src/cairo-surface.c                 |    7 
 src/cairo-xlib-screen.c             |    8 
 src/cairo-xlib-surface-private.h    |    2 
 src/cairo-xlib-surface.c            |  425 +++++++++++++++---------------------
 src/cairoint.h                      |    6 
 test/Makefile.am                    |    8 
 test/big-line.c                     |   16 -
 test/big-line.ref.png               |binary
 test/big-line.xlib-fallback.ref.png |binary
 test/big-line.xlib.ref.png          |binary
 14 files changed, 297 insertions(+), 298 deletions(-)

New commits:
commit 33be73dfb76c26e3bb0ab59b2f570d00d9c7be62
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Sep 11 14:59:58 2009 +0100

    [xlib] Fix big-line.
    
    Project lines that exceed the 16.16 limits onto the XFixedLine, as we know
    that top/bottom must fit within the confines of the surface and so will be
    less than 16 bits.
    
    Sadly this is a run-on patch that also does:
    1. Make FillTiled the default for new GCs.
    2. Stores extend mode as opposed to repeat, and thereby cleaning up some
    inconsistent code.
    3. Remove the special casing for unbounded trapezoids, as it is redundant
    with the polygon clipping.
    4. Tidy the logic for deciding when to use the core protocol
    (_categorize_composite_operation)

diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c
index 331fdb3..79d8c0d 100644
--- a/src/cairo-xlib-screen.c
+++ b/src/cairo-xlib-screen.c
@@ -414,9 +414,10 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info,
     }
 
     gcv.graphics_exposures = False;
+    gcv.fill_style = FillTiled;
     return XCreateGC (_cairo_xlib_display_get_dpy (info->display),
 		      drawable,
-		      GCGraphicsExposures, &gcv);
+		      GCGraphicsExposures | GCFillStyle, &gcv);
 }
 
 void
@@ -481,9 +482,10 @@ _cairo_xlib_screen_get_gc (cairo_xlib_screen_t *info,
 	XGCValues gcv;
 
 	gcv.graphics_exposures = False;
+	gcv.fill_style = FillTiled;
 	gc = XCreateGC (_cairo_xlib_display_get_dpy (info->display),
 			drawable,
-			GCGraphicsExposures, &gcv);
+			GCGraphicsExposures | GCFillStyle, &gcv);
     }
 
     return gc;
diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h
index f821569..92107e7 100644
--- a/src/cairo-xlib-surface-private.h
+++ b/src/cairo-xlib-surface-private.h
@@ -94,7 +94,7 @@ struct _cairo_xlib_surface {
 
     XRenderPictFormat *xrender_format;
     cairo_filter_t filter;
-    int repeat;
+    cairo_extend_t extend;
     XTransform xtransform;
 
     uint32_t a_mask;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 2b5b801..4b2fd1f 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1472,39 +1472,18 @@ _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
     return CAIRO_STATUS_SUCCESS;
 }
 
-static void
-_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat)
+static cairo_status_t
+_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface,
+				cairo_extend_t extend)
 {
     XRenderPictureAttributes pa;
     unsigned long	     mask;
-
-    if (surface->repeat == repeat)
-	return;
-
-    mask = CPRepeat;
-    pa.repeat = repeat;
-
-    XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa);
-    surface->repeat = repeat;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_set_attributes (cairo_xlib_surface_t	    *surface,
-				    cairo_surface_attributes_t	    *attributes,
-				    double			     xc,
-				    double			     yc)
-{
-    cairo_int_status_t status;
     int repeat;
 
-    _cairo_xlib_surface_ensure_src_picture (surface);
-
-    status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix,
-					     xc, yc);
-    if (unlikely (status))
-	return status;
+    if (surface->extend == extend)
+	return CAIRO_STATUS_SUCCESS;
 
-    switch (attributes->extend) {
+    switch (extend) {
     case CAIRO_EXTEND_NONE:
 	repeat = RepeatNone;
 	break;
@@ -1519,7 +1498,7 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t	    *surface,
 	break;
     case CAIRO_EXTEND_PAD:
 	if (surface->buggy_pad_reflect)
-	    return UNSUPPORTED ("buggy reflect");
+	    return UNSUPPORTED ("buggy pad");
 
 	repeat = RepeatPad;
 	break;
@@ -1527,7 +1506,34 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t	    *surface,
 	ASSERT_NOT_REACHED;
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
-    _cairo_xlib_surface_set_repeat (surface, repeat);
+
+    mask = CPRepeat;
+    pa.repeat = repeat;
+
+    XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa);
+    surface->extend = extend;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_xlib_surface_set_attributes (cairo_xlib_surface_t	    *surface,
+				    cairo_surface_attributes_t	    *attributes,
+				    double			     xc,
+				    double			     yc)
+{
+    cairo_int_status_t status;
+
+    _cairo_xlib_surface_ensure_src_picture (surface);
+
+    status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix,
+					     xc, yc);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_xlib_surface_set_repeat (surface, attributes->extend);
+    if (unlikely (status))
+	return status;
 
     status = _cairo_xlib_surface_set_filter (surface, attributes->filter);
     if (unlikely (status))
@@ -1640,24 +1646,32 @@ _categorize_composite_operation (cairo_xlib_surface_t *dst,
     if (! dst->buggy_repeat)
 	return DO_RENDER;
 
-    if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
+    if (src_pattern->type != CAIRO_PATTERN_TYPE_SOLID &&
+	src_pattern->extend == CAIRO_EXTEND_REPEAT)
     {
-	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src_pattern;
+	/* Check for the bug with repeat patterns nad general transforms. */
+	if (! _cairo_matrix_is_integer_translation (&src_pattern->matrix,
+						    NULL, NULL))
+	{
+	    return DO_UNSUPPORTED;
+	}
 
-	if (_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
-	    src_pattern->extend == CAIRO_EXTEND_REPEAT)
+	if (have_mask ||
+	    !(op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
 	{
+	    return DO_UNSUPPORTED;
+	}
+
+	if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	    cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) src_pattern;
+
 	    /* This is the case where we have the bug involving
 	     * untransformed repeating source patterns with off-screen
 	     * video memory; reject some cases where a core protocol
 	     * fallback is impossible.
 	     */
-	    if (have_mask ||
-		!(op == CAIRO_OPERATOR_SOURCE || op == 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;
+		cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) surface_pattern->surface;
 
 		if (op == CAIRO_OPERATOR_OVER && _surface_has_alpha (src))
 		    return DO_UNSUPPORTED;
@@ -1668,15 +1682,11 @@ _categorize_composite_operation (cairo_xlib_surface_t *dst,
 		 */
 		if (_cairo_xlib_surface_same_screen (dst, src) &&
 		    !_surfaces_compatible (dst, src))
+		{
 		    return DO_UNSUPPORTED;
+		}
 	    }
 	}
-
-	/* Check for the other bug involving repeat patterns with general
-	 * transforms. */
-	if (!_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
-	    src_pattern->extend == CAIRO_EXTEND_REPEAT)
-	    return DO_UNSUPPORTED;
     }
 
     return DO_RENDER;
@@ -1697,40 +1707,24 @@ _recategorize_composite_operation (cairo_xlib_surface_t	      *dst,
 				   cairo_surface_attributes_t *src_attr,
 				   cairo_bool_t		       have_mask)
 {
-    cairo_bool_t is_integer_translation =
-	_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL);
-    cairo_bool_t needs_alpha_composite;
-
-    needs_alpha_composite =
-	_operator_needs_alpha_composite (op,
-					 _surface_has_alpha (dst),
-					 _surface_has_alpha (src));
-
+    /* Can we use the core protocol? */
     if (! have_mask &&
-	is_integer_translation &&
-	src_attr->extend == CAIRO_EXTEND_NONE &&
-	! needs_alpha_composite &&
         src->owns_pixmap &&
-	_surfaces_compatible (src, dst))
+	src->depth == dst->depth &&
+	_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) &&
+	! _operator_needs_alpha_composite (op,
+					   _surface_has_alpha (dst),
+					   _surface_has_alpha (src)))
     {
-	return DO_XCOPYAREA;
-    }
+	if (src_attr->extend == CAIRO_EXTEND_NONE)
+	    return DO_XCOPYAREA;
 
-    if (dst->buggy_repeat &&
-	is_integer_translation &&
-	src_attr->extend == CAIRO_EXTEND_REPEAT &&
-	(src->width != 1 || src->height != 1))
-    {
-	if (! have_mask &&
-	    ! needs_alpha_composite &&
-            src->owns_pixmap &&
-	    _surfaces_compatible (dst, src))
-	{
+	if (dst->buggy_repeat && src_attr->extend == CAIRO_EXTEND_REPEAT)
 	    return DO_XTILE;
-	}
+    }
 
+    if (dst->buggy_repeat && src_attr->extend == CAIRO_EXTEND_REPEAT)
 	return DO_UNSUPPORTED;
-    }
 
     if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src))
 	return DO_UNSUPPORTED;
@@ -2187,8 +2181,8 @@ _cairo_xlib_surface_composite (cairo_operator_t		op,
 	if (unlikely (status))
 	    goto BAIL;
 
-	is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix,
-								       &itx, &ity);
+	is_integer_translation =
+	    _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
 	/* This is a pre-condition for DO_XCOPYAREA. */
 	assert (is_integer_translation);
 
@@ -2210,8 +2204,7 @@ _cairo_xlib_surface_composite (cairo_operator_t		op,
 
 		cairo_region_get_rectangle (clip_region, n, &rect);
 		XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
-			   rect.x + src_x,
-			   rect.y + src_y,
+			   rect.x + src_x, rect.y + src_y,
 			   rect.width, rect.height,
 			   rect.x, rect.y);
 	    }
@@ -2233,15 +2226,14 @@ _cairo_xlib_surface_composite (cairo_operator_t		op,
 	if (unlikely (status))
 	    goto BAIL;
 
-	is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix,
-								       &itx, &ity);
+	is_integer_translation =
+	    _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
 	/* This is a pre-condition for DO_XTILE. */
 	assert (is_integer_translation);
 
 	XSetTSOrigin (dst->dpy, gc,
 		      - (itx + src_attr.x_offset), - (ity + src_attr.y_offset));
 	XSetTile (dst->dpy, gc, src->drawable);
-	XSetFillStyle (dst->dpy, gc, FillTiled);
 
 	if (clip_region == NULL) {
 	    XFillRectangle (dst->dpy, dst->drawable, gc,
@@ -2254,8 +2246,6 @@ _cairo_xlib_surface_composite (cairo_operator_t		op,
 		cairo_rectangle_int_t rect;
 
 		cairo_region_get_rectangle (clip_region, n, &rect);
-		rect.x -= dst_x;
-		rect.y -= dst_y;
 		XFillRectangle (dst->dpy, dst->drawable, gc,
 				rect.x, rect.y, rect.width, rect.height);
 	    }
@@ -2329,7 +2319,6 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t    *surface,
 		  - (surface->base.device_transform.y0 + attrs.y_offset));
     XSetTile (surface->dpy, gc,
 	      ((cairo_xlib_surface_t *) solid_surface)->drawable);
-    XSetFillStyle (surface->dpy, gc, FillTiled);
 
     for (i = 0; i < num_rects; i++) {
 	XFillRectangle (surface->dpy, surface->drawable, gc,
@@ -2423,117 +2412,41 @@ _cairo_xlib_surface_fill_rectangles (void		     *abstract_surface,
     return CAIRO_STATUS_SUCCESS;
 }
 
-/* Creates an A8 picture of size @width x @height, initialized with @color
- */
-static Picture
-_create_a8_picture (cairo_xlib_surface_t *surface,
-		    XRenderColor         *color,
-		    int                   width,
-		    int                   height,
-		    cairo_bool_t          repeat)
-{
-    XRenderPictureAttributes pa;
-    unsigned long mask = 0;
-
-    Pixmap pixmap;
-    Picture picture;
-    XRenderPictFormat *xrender_format;
-
-    if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
-	return None;
-
-    xrender_format =
-	_cairo_xlib_display_get_xrender_format (surface->display,
-						CAIRO_FORMAT_A8);
-    if (xrender_format == NULL)
-	return None;
-
-    pixmap = XCreatePixmap (surface->dpy, surface->drawable,
-			    width <= 0 ? 1 : width,
-			    height <= 0 ? 1 : height,
-			    8);
+#define CAIRO_FIXED_16_16_MIN -32768
+#define CAIRO_FIXED_16_16_MAX 32767
 
-    if (repeat) {
-	pa.repeat = TRUE;
-	mask = CPRepeat;
-    }
-
-    picture = XRenderCreatePicture (surface->dpy, pixmap,
-				    xrender_format, mask, &pa);
-    XRenderFillRectangle (surface->dpy, PictOpSrc, picture, color,
-			  0, 0, width, height);
-    XFreePixmap (surface->dpy, pixmap);
-
-    return picture;
+static cairo_bool_t
+_line_exceeds_16_16 (const cairo_line_t *line)
+{
+    return
+	line->p1.x < CAIRO_FIXED_16_16_MIN ||
+	line->p1.x > CAIRO_FIXED_16_16_MAX ||
+	line->p2.x < CAIRO_FIXED_16_16_MIN ||
+	line->p2.x > CAIRO_FIXED_16_16_MAX ||
+	line->p1.y < CAIRO_FIXED_16_16_MIN ||
+	line->p1.y > CAIRO_FIXED_16_16_MAX ||
+	line->p2.y < CAIRO_FIXED_16_16_MIN ||
+	line->p2.y > CAIRO_FIXED_16_16_MAX;
 }
 
-/* Creates a temporary mask for the trapezoids covering the area
- * [@dst_x, @dst_y, @width, @height] of the destination surface.
- */
-static Picture
-_create_trapezoid_mask (cairo_xlib_surface_t *dst,
-			cairo_trapezoid_t    *traps,
-			int                   num_traps,
-			int                   dst_x,
-			int                   dst_y,
-			int                   width,
-			int                   height,
-			XRenderPictFormat     *pict_format)
+static void
+_project_line_x_onto_16_16 (const cairo_line_t *line,
+			    cairo_fixed_t top,
+			    cairo_fixed_t bottom,
+			    XLineFixed *out)
 {
-    XRenderColor transparent = { 0, 0, 0, 0 };
-    XRenderColor solid = { 0xffff, 0xffff, 0xffff, 0xffff };
-    Picture mask_picture, solid_picture;
-    XTrapezoid *offset_traps;
-    int i;
-
-    /* This would be considerably simpler using XRenderAddTraps(), but since
-     * we are only using this in the unbounded-operator case, we stick with
-     * XRenderCompositeTrapezoids, which is available on older versions
-     * of RENDER rather than conditionalizing. We should still hit an
-     * optimization that avoids creating another intermediate surface on
-     * the servers that have XRenderAddTraps().
-     */
-    mask_picture = _create_a8_picture (dst, &transparent, width, height, FALSE);
-    if (mask_picture == None || num_traps == 0)
-	return mask_picture;
-
-    offset_traps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
-    if (!offset_traps) {
-	XRenderFreePicture (dst->dpy, mask_picture);
-	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
-	return None;
-    }
-
-    for (i = 0; i < num_traps; i++) {
-	offset_traps[i].top = _cairo_fixed_to_16_16(traps[i].top) - 0x10000 * dst_y;
-	offset_traps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom) - 0x10000 * dst_y;
-	offset_traps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x) - 0x10000 * dst_x;
-	offset_traps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y) - 0x10000 * dst_y;
-	offset_traps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x) - 0x10000 * dst_x;
-	offset_traps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y) - 0x10000 * dst_y;
-	offset_traps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x) - 0x10000 * dst_x;
-	offset_traps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y) - 0x10000 * dst_y;
-	offset_traps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x) - 0x10000 * dst_x;
-	offset_traps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y) - 0x10000 * dst_y;
-    }
-
-    solid_picture = _create_a8_picture (dst, &solid, 1, 1, TRUE);
-    if (solid_picture == None) {
-	XRenderFreePicture (dst->dpy, mask_picture);
-	free (offset_traps);
-	return None;
-    }
+    cairo_point_double_t p1, p2;
+    double m;
 
-    XRenderCompositeTrapezoids (dst->dpy, PictOpAdd,
-				solid_picture, mask_picture,
-				pict_format,
-				0, 0,
-				offset_traps, num_traps);
+    p1.x = _cairo_fixed_to_double (line->p1.x);
+    p1.y = _cairo_fixed_to_double (line->p1.y);
 
-    XRenderFreePicture (dst->dpy, solid_picture);
-    free (offset_traps);
+    p2.x = _cairo_fixed_to_double (line->p2.x);
+    p2.y = _cairo_fixed_to_double (line->p2.y);
 
-    return mask_picture;
+    m = (p2.x - p1.x) / (p2.y - p1.y);
+    out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
+    out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
 }
 
 static cairo_int_status_t
@@ -2559,6 +2472,9 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t	op,
     int				render_reference_x, render_reference_y;
     int				render_src_x, render_src_y;
     XRenderPictFormat		*pict_format;
+    XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
+    XTrapezoid *xtraps = xtraps_stack;
+    int i;
 
     _cairo_xlib_display_notify (dst->display);
 
@@ -2624,6 +2540,63 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t	op,
     if (unlikely (status))
 	goto BAIL;
 
+    if (num_traps > ARRAY_LENGTH (xtraps_stack)) {
+	xtraps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
+	if (unlikely (xtraps == NULL)) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto BAIL;
+	}
+    }
+
+    for (i = 0; i < num_traps; i++) {
+	/* top/bottom will be clamped to surface bounds */
+	xtraps[i].top = _cairo_fixed_to_16_16(traps[i].top);
+	xtraps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom);
+
+	/* However, all the other coordinates will have been left untouched so
+	 * as not to introduce numerical error. Recompute them if they
+	 * exceed the 16.16 limits.
+	 */
+	if (unlikely (_line_exceeds_16_16 (&traps[i].left))) {
+	    _project_line_x_onto_16_16 (&traps[i].left,
+					traps[i].top,
+					traps[i].bottom,
+					&xtraps[i].left);
+	    xtraps[i].left.p1.y = xtraps[i].top;
+	    xtraps[i].left.p2.y = xtraps[i].bottom;
+	} else {
+	    xtraps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x);
+	    xtraps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y);
+	    xtraps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x);
+	    xtraps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y);
+	}
+
+	if (unlikely (_line_exceeds_16_16 (&traps[i].right))) {
+	    _project_line_x_onto_16_16 (&traps[i].right,
+					traps[i].top,
+					traps[i].bottom,
+					&xtraps[i].right);
+	    xtraps[i].right.p1.y = xtraps[i].top;
+	    xtraps[i].right.p2.y = xtraps[i].bottom;
+	} else {
+	    xtraps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x);
+	    xtraps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y);
+	    xtraps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x);
+	    xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y);
+	}
+    }
+
+    XRenderCompositeTrapezoids (dst->dpy,
+				_render_operator (op),
+				src->src_picture, dst->dst_picture,
+				pict_format,
+				render_src_x + attributes.x_offset,
+				render_src_y + attributes.y_offset,
+				xtraps, num_traps);
+
+    if (xtraps != xtraps_stack)
+	free(xtraps);
+
     if (!_cairo_operator_bounded_by_mask (op)) {
 	/* XRenderCompositeTrapezoids() creates a mask only large enough for the
 	 * trapezoids themselves, but if the operator is unbounded, then we need
@@ -2634,27 +2607,6 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t	op,
 	 * bounds and clip. (XRenderAddTraps() could be used to make creating
 	 * the mask somewhat cheaper.)
 	 */
-	Picture mask_picture = _create_trapezoid_mask (dst, traps, num_traps,
-						       dst_x, dst_y, width, height,
-						       pict_format);
-	if (!mask_picture) {
-	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    goto BAIL;
-	}
-
-	XRenderComposite (dst->dpy,
-			  _render_operator (op),
-			  src->src_picture,
-			  mask_picture,
-			  dst->dst_picture,
-			  src_x + attributes.x_offset,
-			  src_y + attributes.y_offset,
-			  0, 0,
-			  dst_x, dst_y,
-			  width, height);
-
-	XRenderFreePicture (dst->dpy, mask_picture);
-
 	status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
 								 &attributes, src->width, src->height,
 								 width, height,
@@ -2663,42 +2615,6 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t	op,
 								 dst_x, dst_y, width, height,
 								 clip_region);
 
-    } else {
-        XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
-        XTrapezoid *xtraps = xtraps_stack;
-        int i;
-
-        if (num_traps > ARRAY_LENGTH (xtraps_stack)) {
-            xtraps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
-            if (unlikely (xtraps == NULL)) {
-                status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-                goto BAIL;
-            }
-        }
-
-        for (i = 0; i < num_traps; i++) {
-            xtraps[i].top = _cairo_fixed_to_16_16(traps[i].top);
-            xtraps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom);
-            xtraps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x);
-            xtraps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y);
-            xtraps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x);
-            xtraps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y);
-            xtraps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x);
-            xtraps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y);
-            xtraps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x);
-            xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y);
-        }
-
-	XRenderCompositeTrapezoids (dst->dpy,
-				    _render_operator (op),
-				    src->src_picture, dst->dst_picture,
-				    pict_format,
-				    render_src_x + attributes.x_offset,
-				    render_src_y + attributes.y_offset,
-				    xtraps, num_traps);
-
-        if (xtraps != xtraps_stack)
-            free(xtraps);
     }
 
  BAIL:
@@ -2956,7 +2872,7 @@ _cairo_xlib_surface_create_internal (cairo_xlib_screen_t	*screen,
     surface->xrender_format = xrender_format;
     surface->depth = depth;
     surface->filter = CAIRO_FILTER_NEAREST;
-    surface->repeat = FALSE;
+    surface->extend = CAIRO_EXTEND_NONE;
     surface->xtransform = identity;
 
     surface->clip_region = NULL;
commit 6960162c5eae30e2d48992023be35e3dbf502a03
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Sep 11 14:56:17 2009 +0100

    [xlib] Discard clip if larger than glyph extents
    
    Implement cheap calculation of glyph extents to see whether we can discard
    the clip region. This is effective around 50% of the time for firefox (and
    makes the xtrace so much neater).

diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 74a2c88..199ad39 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -2021,6 +2021,42 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t	 *scaled_font,
     return CAIRO_STATUS_SUCCESS;
 }
 
+void
+_cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t	 *scaled_font,
+					      const cairo_glyph_t	 *glyphs,
+					      int                      num_glyphs,
+					      cairo_rectangle_int_t   *extents)
+{
+    double x0 = HUGE_VAL, x1 = -HUGE_VAL;
+    double y0 = HUGE_VAL, y1 = -HUGE_VAL;
+    int i;
+
+    for (i = 0; i < num_glyphs; i++) {
+	double g;
+
+	g = glyphs[i].x;
+	if (g < x0) x0 = g;
+	if (g > x1) x1 = g;
+
+	g = glyphs[i].y;
+	if (g < y0) y0 = g;
+	if (g > y1) y1 = g;
+    }
+
+    if (x0 <= x1 && y0 <= y1) {
+	extents->x = floor (x0 - scaled_font->extents.max_x_advance);
+	extents->width = ceil (x1 + scaled_font->extents.max_x_advance);
+	extents->width -= extents->x;
+
+	extents->y = floor (y0 - scaled_font->extents.ascent);
+	extents->height = ceil (y1 + scaled_font->extents.descent);
+	extents->height -= extents->y;
+    } else {
+	extents->x = extents->y = 0;
+	extents->width = extents->height = 0;
+    }
+}
+
 cairo_status_t
 _cairo_scaled_font_show_glyphs (cairo_scaled_font_t	*scaled_font,
 				cairo_operator_t	 op,
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 375c660..2b5b801 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -4413,6 +4413,29 @@ _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
     if (! _cairo_xlib_surface_owns_font (dst, scaled_font))
 	return UNSUPPORTED ("unowned font");
 
+    if (clip_region != NULL &&
+	cairo_region_num_rectangles (clip_region) == 1)
+    {
+	cairo_rectangle_int_t glyph_extents;
+	const cairo_rectangle_int_t *clip_extents;
+
+	/* Can we do without the clip?
+	 * Around 50% of the time the clip is redundant (firefox).
+	 */
+	_cairo_scaled_font_glyph_approximate_extents (scaled_font,
+						      glyphs, num_glyphs,
+						      &glyph_extents);
+
+	clip_extents = &clip->path->extents;
+	if (clip_extents->x <= glyph_extents.x &&
+	    clip_extents->y <= glyph_extents.y &&
+	    clip_extents->x + clip_extents->width  >= glyph_extents.x + glyph_extents.width &&
+	    clip_extents->y + clip_extents->height >= glyph_extents.y + glyph_extents.height)
+	{
+	    clip_region = NULL;
+	}
+    }
+
     status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
     if (unlikely (status))
 	return status;
diff --git a/src/cairoint.h b/src/cairoint.h
index f6a4559..8b82454 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1726,6 +1726,12 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t	 *scaled_font,
 					 cairo_rectangle_int_t   *extents,
 					 cairo_bool_t		 *overlap);
 
+cairo_private void
+_cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t	 *scaled_font,
+					      const cairo_glyph_t	 *glyphs,
+					      int                      num_glyphs,
+					      cairo_rectangle_int_t   *extents);
+
 cairo_private cairo_status_t
 _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
 				cairo_operator_t     op,
commit 6e78409417117ad4de1aec65bb4753ff32e1e7a6
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Sep 11 14:19:38 2009 +0100

    [test] Update big-line and remove XFAIL
    
    Now that we use polygon clipping, output geometry should no longer exceed
    the 2^16 limits imposed by pixman. For the image backend, we now use spans
    for stroking and for the xlib backend we have to double check the range on
    the output trapezoids. In short, cairo should pass this test.

diff --git a/test/Makefile.am b/test/Makefile.am
index 5e1972f..2a01270 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -138,10 +138,10 @@ REFERENCE_IMAGES = \
 	alpha-similar.rgb24.ref.png \
 	alpha-similar.svg.argb32.xfail.png \
 	alpha-similar.svg.rgb24.xfail.png \
-	big-line.ps.argb32.ref.png \
-	big-line.ps.rgb24.ref.png \
-	big-line.quartz.ref.png \
-	big-line.quartz.rgb24.ref.png \
+	big-line.ref.png \
+	big-line.ps.ref.png \
+	big-line.xlib.png \
+	big-line.xlib-fallback.png \
 	bilevel-image.ref.png \
 	bitmap-font.ref.png \
 	bitmap-font.rgb24.ref.png \
diff --git a/test/big-line.c b/test/big-line.c
index 105e7ee..6260fba 100644
--- a/test/big-line.c
+++ b/test/big-line.c
@@ -28,35 +28,35 @@
 static cairo_test_status_t
 draw (cairo_t *cr, int width, int height)
 {
-    cairo_new_path (cr);
+    cairo_set_source_rgb (cr, 1, 1, 1);
+    cairo_paint (cr);
 
     cairo_set_source_rgb (cr, 1, 1, 0);
     cairo_move_to (cr, 50, 50);
-    cairo_line_to (cr, 50000, 50000);
+    cairo_rel_line_to (cr, 50000, 50000);
     cairo_stroke (cr);
 
     cairo_set_source_rgb (cr, 1, 0, 0);
     cairo_move_to (cr, 50, 50);
-    cairo_line_to (cr, -50000, 50000);
+    cairo_rel_line_to (cr, -50000, 50000);
     cairo_stroke (cr);
 
     cairo_set_source_rgb (cr, 0, 1, 0);
     cairo_move_to (cr, 50, 50);
-    cairo_line_to (cr, 50000, -50000);
+    cairo_rel_line_to (cr, 50000, -50000);
     cairo_stroke (cr);
 
     cairo_set_source_rgb (cr, 0, 0, 1);
     cairo_move_to (cr, 50, 50);
-    cairo_line_to (cr, -50000, -50000);
+    cairo_rel_line_to (cr, -50000, -50000);
     cairo_stroke (cr);
 
     return CAIRO_TEST_SUCCESS;
 }
 
 CAIRO_TEST (big_line,
-	    "Test drawing of simple lines with positive and negative coordinates > 2^16\n"
-	    "This currently fails because of 16-bit limitations in pixman.",
-	    "line", /* keywords */
+	    "Test drawing of simple lines with positive and negative coordinates > 2^16",
+	    "stroke, line", /* keywords */
 	    NULL, /* requirements */
 	    100, 100,
 	    NULL, draw)
diff --git a/test/big-line.ps.argb32.ref.png b/test/big-line.ps.argb32.ref.png
deleted file mode 100644
index 60e7321..0000000
Binary files a/test/big-line.ps.argb32.ref.png and /dev/null differ
diff --git a/test/big-line.ps.rgb24.ref.png b/test/big-line.ps.rgb24.ref.png
deleted file mode 100644
index 8be5f9f..0000000
Binary files a/test/big-line.ps.rgb24.ref.png and /dev/null differ
diff --git a/test/big-line.quartz.ref.png b/test/big-line.quartz.ref.png
deleted file mode 100644
index b8dfe8b..0000000
Binary files a/test/big-line.quartz.ref.png and /dev/null differ
diff --git a/test/big-line.quartz.rgb24.ref.png b/test/big-line.quartz.rgb24.ref.png
deleted file mode 100644
index c4fc158..0000000
Binary files a/test/big-line.quartz.rgb24.ref.png and /dev/null differ
diff --git a/test/big-line.ref.png b/test/big-line.ref.png
new file mode 100644
index 0000000..1bcde8f
Binary files /dev/null and b/test/big-line.ref.png differ
diff --git a/test/big-line.xlib-fallback.ref.png b/test/big-line.xlib-fallback.ref.png
new file mode 100644
index 0000000..99cd1e2
Binary files /dev/null and b/test/big-line.xlib-fallback.ref.png differ
diff --git a/test/big-line.xlib.ref.png b/test/big-line.xlib.ref.png
new file mode 100644
index 0000000..66a3877
Binary files /dev/null and b/test/big-line.xlib.ref.png differ
commit b495e7eb2ee2521a400d4b42e04242023bdb1e44
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Sep 10 19:25:14 2009 +0100

    [surface] Early return for (region IN white)
    
    Fill a region using IN and a white source is a frequent reduction of a
    complex clip (viz a path that covers the whole operation extents will be
    reduced to a single rectangle), and we can simply discard the fill (as it
    always has bounded semantics).

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 6dab8e2..25ce0b9 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1846,6 +1846,13 @@ _cairo_surface_fill_region (cairo_surface_t	   *surface,
     if (num_rects == 0)
 	return CAIRO_STATUS_SUCCESS;
 
+    /* catch a common reduction of _cairo_clip_combine_with_surface() */
+    if (op == CAIRO_OPERATOR_IN &&
+	_cairo_color_equal (color, CAIRO_COLOR_WHITE))
+    {
+	return CAIRO_STATUS_SUCCESS;
+    }
+
     if (num_rects > ARRAY_LENGTH (stack_rects)) {
 	rects = _cairo_malloc_ab (num_rects,
 				  sizeof (cairo_rectangle_int_t));
commit 94aeae9b2ec563201a0e65705504d1d70c33a619
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Sep 10 19:11:36 2009 +0100

    [clip] Simplify applying a box clip
    
    If the clip path is a simple box, then for many operations it is entirely
    representation by the alteration of extents and so we can skip a few steps
    during reconstruction.

diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
index 131d4c7..15b4a4b 100644
--- a/src/cairo-clip-private.h
+++ b/src/cairo-clip-private.h
@@ -45,7 +45,8 @@ extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil;
 
 enum {
     CAIRO_CLIP_PATH_HAS_REGION = 0x1,
-    CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED = 0x2
+    CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED = 0x2,
+    CAIRO_CLIP_PATH_IS_BOX = 0x4
 };
 
 struct _cairo_clip_path {
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index fde4121..fd1e9e8 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -213,16 +213,12 @@ _cairo_clip_intersect_rectangle (cairo_clip_t *clip,
     cairo_status_t status;
 
     if (clip->path != NULL) {
-	cairo_box_t box;
-
-	if (_cairo_path_fixed_is_box (&clip->path->path, &box)) {
-	    if (box.p1.x >= _cairo_fixed_from_int (rect->x) &&
-		box.p1.y >= _cairo_fixed_from_int (rect->y) &&
-		box.p2.x <= _cairo_fixed_from_int (rect->x + rect->width) &&
-		box.p2.y <= _cairo_fixed_from_int (rect->y + rect->height))
-	    {
-		return CAIRO_STATUS_SUCCESS;
-	    }
+	if (rect->x <= clip->path->extents.x &&
+	    rect->y <= clip->path->extents.y &&
+	    rect->x + rect->width >= clip->path->extents.x + clip->path->extents.width &&
+	    rect->y + rect->height >= clip->path->extents.y + clip->path->extents.height)
+	{
+	    return CAIRO_STATUS_SUCCESS;
 	}
     }
 
@@ -255,6 +251,7 @@ _cairo_clip_intersect_rectangle (cairo_clip_t *clip,
     clip_path->fill_rule = CAIRO_FILL_RULE_WINDING;
     clip_path->tolerance = 1;
     clip_path->antialias = CAIRO_ANTIALIAS_NONE;
+    clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX;
 
     /* could preallocate the region if it proves worthwhile */
 
@@ -317,6 +314,8 @@ _cairo_clip_intersect_path (cairo_clip_t       *clip,
     cairo_clip_path_t *clip_path;
     cairo_status_t status;
     cairo_rectangle_int_t extents;
+    cairo_box_t box;
+    cairo_bool_t is_box = FALSE;
 
     if (clip->path != NULL) {
 	if (clip->path->fill_rule == fill_rule &&
@@ -335,23 +334,21 @@ _cairo_clip_intersect_path (cairo_clip_t       *clip,
 	return CAIRO_STATUS_SUCCESS;
     }
 
+    is_box = _cairo_path_fixed_is_box (path, &box);
     if (clip->path != NULL) {
-	cairo_box_t box;
-
 	if (! _cairo_rectangle_intersect (&extents, &clip->path->extents)) {
 	    _cairo_clip_set_all_clipped (clip);
 	    return CAIRO_STATUS_SUCCESS;
 	}
 
 	/* does this clip wholly subsume the others? */
-	if (_cairo_path_fixed_is_box (path, &box)) {
-	    if (box.p1.x <= _cairo_fixed_from_int (clip->path->extents.x) &&
-		box.p2.x >= _cairo_fixed_from_int (clip->path->extents.x + clip->path->extents.width) &&
-		box.p1.y <= _cairo_fixed_from_int (clip->path->extents.y) &&
-		box.p2.y >= _cairo_fixed_from_int (clip->path->extents.y + clip->path->extents.height))
-	    {
-		return CAIRO_STATUS_SUCCESS;
-	    }
+	if (is_box &&
+	    box.p1.x <= _cairo_fixed_from_int (clip->path->extents.x) &&
+	    box.p2.x >= _cairo_fixed_from_int (clip->path->extents.x + clip->path->extents.width) &&
+	    box.p1.y <= _cairo_fixed_from_int (clip->path->extents.y) &&
+	    box.p2.y >= _cairo_fixed_from_int (clip->path->extents.y + clip->path->extents.height))
+	{
+	    return CAIRO_STATUS_SUCCESS;
 	}
     }
 
@@ -370,6 +367,8 @@ _cairo_clip_intersect_path (cairo_clip_t       *clip,
     clip_path->fill_rule = fill_rule;
     clip_path->tolerance = tolerance;
     clip_path->antialias = antialias;
+    if (is_box)
+	clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1126,6 +1125,8 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
 	    status = _combine_region (surface, prev->region, clip_extents);
 	    if (unlikely (status))
 		goto BAIL;
+	} else if (prev->flags & CAIRO_CLIP_PATH_IS_BOX) {
+	    /* a simple box only affects the extents */
 	} else if (prev->path.is_rectilinear) {
 	    if (need_translate) {
 		_cairo_path_fixed_translate (&prev->path,
@@ -1281,23 +1282,30 @@ _cairo_clip_combine_with_surface (cairo_clip_t *clip,
 	    return status;
 	}
 
-	if (need_translate) {
-	    _cairo_path_fixed_translate (&clip_path->path,
-					_cairo_fixed_from_int (-extents->x),
-					_cairo_fixed_from_int (-extents->y));
-	}
-	status = _cairo_surface_fill (dst,
-				      CAIRO_OPERATOR_IN,
-				      &pattern.base,
-				      &clip_path->path,
-				      clip_path->fill_rule,
-				      clip_path->tolerance,
-				      clip_path->antialias,
-				      NULL);
-	if (need_translate) {
-	    _cairo_path_fixed_translate (&clip_path->path,
-					_cairo_fixed_from_int (extents->x),
-					_cairo_fixed_from_int (extents->y));
+	if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX) {
+	    cairo_region_t clip_region;
+
+	    _cairo_region_init_rectangle (&clip_region, &clip_path->extents);
+	    status = _combine_region (dst, &clip_region, extents);
+	} else {
+	    if (need_translate) {
+		_cairo_path_fixed_translate (&clip_path->path,
+					     _cairo_fixed_from_int (-extents->x),
+					     _cairo_fixed_from_int (-extents->y));
+	    }
+	    status = _cairo_surface_fill (dst,
+					  CAIRO_OPERATOR_IN,
+					  &pattern.base,
+					  &clip_path->path,
+					  clip_path->fill_rule,
+					  clip_path->tolerance,
+					  clip_path->antialias,
+					  NULL);
+	    if (need_translate) {
+		_cairo_path_fixed_translate (&clip_path->path,
+					     _cairo_fixed_from_int (extents->x),
+					     _cairo_fixed_from_int (extents->y));
+	    }
 	}
 
 	if (unlikely (status))
@@ -1336,7 +1344,7 @@ _cairo_clip_drop_cache (cairo_clip_t  *clip)
 	    clip_path->surface = NULL;
 	}
 
-	clip_path->flags = 0;
+	clip_path->flags &= ~CAIRO_CLIP_PATH_HAS_REGION;
     } while ((clip_path = clip_path->prev) != NULL);
 }
 
commit 496e79b63762c70fd022b2d9e2d6107bcce1807a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Sep 10 17:36:46 2009 +0100

    [xlib] Fix extraction of GC during XCloseDisplay()
    
    Jeff Muizelaar reported a bug from his firefox builds that was causing a
    double free during XCloseDisplay, and suggested it was related to
    c0e01d9cd. Reviewing the cleanup, suggested that the cause may just be a
    pair of missing parenthesis.

diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c
index 800c6d2..331fdb3 100644
--- a/src/cairo-xlib-screen.c
+++ b/src/cairo-xlib-screen.c
@@ -284,7 +284,7 @@ _cairo_xlib_screen_close_display (cairo_xlib_screen_t *info)
 #endif
 
     for (i = 0; i < ARRAY_LENGTH (info->gc); i++) {
-	if (old >> (8*i) & 0x7f)
+	if ((old >> (8*i)) & 0xff)
 	    XFreeGC (dpy, info->gc[i]);
     }
 


More information about the cairo-commit mailing list