[cairo-commit] 4 commits - src/cairo-pattern.c src/cairo-xlib-display.c test/filter-bilinear-extents.c test/filter-bilinear-extents-ref.png test/.gitignore test/Makefile.am

Carl Worth cworth at kemper.freedesktop.org
Fri Apr 4 19:00:48 PDT 2008


 src/cairo-pattern.c                  |   83 ++++++++++++++++++-------------
 src/cairo-xlib-display.c             |   11 ++++
 test/.gitignore                      |    1 
 test/Makefile.am                     |    2 
 test/filter-bilinear-extents-ref.png |binary
 test/filter-bilinear-extents.c       |   91 +++++++++++++++++++++++++++++++++++
 6 files changed, 154 insertions(+), 34 deletions(-)

New commits:
commit 731e121c802a7b1c3429d1bde7a93bc471d70880
Author: Carl Worth <cworth at cworth.org>
Date:   Fri Apr 4 19:00:28 2008 -0700

    _cairo_pattern_get_extents: Fix to allow for expansion based on filter
    
    This fixes the filter-bilinear-extents test case and the
    related bug entry:
    
    	bad clipping with EXTEND_NONE
    	http://bugs.freedesktop.org/show_bug.cgi?id=15349
    
    Though there are still differences in the PDF and PostScript
    backends, (primarily because we can't capture cairo's filter
    modes in those file formats).

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 0eb90ae..e1d4b5c 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1991,6 +1991,28 @@ _cairo_pattern_get_extents (cairo_pattern_t         *pattern,
 	x2 = x1 + surface_extents.width;
 	y2 = y1 + surface_extents.height;
 
+	/* The filter can effectively enlarge the extents of the
+	 * pattern, so extend as necessary. Note: We aren't doing any
+	 * backend-specific querying of filter box sizes at this time,
+	 * (since currently no specific backends that could do custom
+	 * filters are calling _cairo_pattern_get_extents). */
+	switch (pattern->filter) {
+	case CAIRO_FILTER_GOOD:
+	case CAIRO_FILTER_BEST:
+	case CAIRO_FILTER_BILINEAR:
+	    x1 -= 0.5;
+	    y1 -= 0.5;
+	    x2 += 0.5;
+	    y2 += 0.5;
+	    break;
+	case CAIRO_FILTER_FAST:
+	case CAIRO_FILTER_NEAREST:
+	case CAIRO_FILTER_GAUSSIAN:
+	default:
+	    /* Nothing to do */
+	    break;
+	}
+
 	imatrix = pattern->matrix;
 	status = cairo_matrix_invert (&imatrix);
 	/* cairo_pattern_set_matrix ensures the matrix is invertible */
commit 04608952e2efb9bffaa131ab39780c3e1a7430ba
Author: Carl Worth <cworth at cworth.org>
Date:   Fri Apr 4 18:56:38 2008 -0700

    Replace open-coded transformation with a call to _cairo_matrix_transform_bounding_box
    
    It's a wonderful feeiling to remove duplicate code.

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index bd67163..0eb90ae 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1980,50 +1980,43 @@ _cairo_pattern_get_extents (cairo_pattern_t         *pattern,
 	    (cairo_surface_pattern_t *) pattern;
 	cairo_surface_t *surface = surface_pattern->surface;
 	cairo_matrix_t imatrix;
-	double x, y;
-	/* Initialize to keep the compiler quiet. */
-	int left=0, right=0, top=0, bottom=0;
-	int lx, rx, ty, by;
-	int sx, sy;
-	cairo_bool_t set = FALSE;
+	double x1, y1, x2, y2;
 
 	status = _cairo_surface_get_extents (surface, &surface_extents);
 	if (status)
 	    return status;
 
+	x1 = surface_extents.x;
+	y1 = surface_extents.y;
+	x2 = x1 + surface_extents.width;
+	y2 = y1 + surface_extents.height;
+
 	imatrix = pattern->matrix;
 	status = cairo_matrix_invert (&imatrix);
 	/* cairo_pattern_set_matrix ensures the matrix is invertible */
 	assert (status == CAIRO_STATUS_SUCCESS);
 
-	/* XXX Use _cairo_matrix_transform_bounding_box here */
-	for (sy = 0; sy <= 1; sy++) {
-	    for (sx = 0; sx <= 1; sx++) {
-		x = surface_extents.x + sx * surface_extents.width;
-		y = surface_extents.y + sy * surface_extents.height;
-		cairo_matrix_transform_point (&imatrix, &x, &y);
-		if (x < 0) x = 0;
-		if (x > CAIRO_RECT_INT_MAX) x = CAIRO_RECT_INT_MAX;
-		if (y < 0) y = 0;
-		if (y > CAIRO_RECT_INT_MAX) y = CAIRO_RECT_INT_MAX;
-		lx = floor (x); rx = ceil (x);
-		ty = floor (y); by = ceil (y);
-		if (!set) {
-		    left = lx;
-		    right = rx;
-		    top = ty;
-		    bottom = by;
-		    set = TRUE;
-		} else {
-		    if (lx < left) left = lx;
-		    if (rx > right) right = rx;
-		    if (ty < top) top = ty;
-		    if (by > bottom) bottom = by;
-		}
-	    }
-	}
-	extents->x = left; extents->width = right - left;
-	extents->y = top; extents->height = bottom - top;
+	_cairo_matrix_transform_bounding_box (&imatrix,
+					      &x1, &y1, &x2, &y2,
+					      NULL);
+
+	x1 = floor (x1);
+	if (x1 < 0)
+	    x1 = 0;
+	y1 = floor (y1);
+	if (y1 < 0)
+	    y1 = 0;
+
+	x2 = ceil (x2);
+	if (x2 > CAIRO_RECT_INT_MAX)
+	    x2 = CAIRO_RECT_INT_MAX;
+	y2 = ceil (y2);
+	if (y2 > CAIRO_RECT_INT_MAX)
+	    y2 = CAIRO_RECT_INT_MAX;
+
+	extents->x = x1; extents->width = x2 - x1;
+	extents->y = y1; extents->height = y2 - y1;
+
 	return CAIRO_STATUS_SUCCESS;
     }
 
commit 89567f9278c002ac5e4e25ddccec88b1b1eea420
Author: Carl Worth <cworth at cworth.org>
Date:   Fri Apr 4 18:28:23 2008 -0700

    Add new filter-bilinear-extents test
    
    This test exercises code that computes the extents of a surface
    pattern with CAIRO_FILTER_BILINEAR, (where the filtering
    effectively increases the extents of the pattern).
    
    The original bug was reported by Owen Taylor here:
    
        bad clipping with EXTEND_NONE
        http://bugs.freedesktop.org/show_bug.cgi?id=15349

diff --git a/test/.gitignore b/test/.gitignore
index af0387a..564a8ed 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -63,6 +63,7 @@ fill-and-stroke-alpha-add
 fill-degenerate-sort-order
 fill-missed-stop
 fill-rule
+filter-bilinear-extents
 filter-nearest-offset
 finer-grained-fallbacks
 ft-text-antialias-none
diff --git a/test/Makefile.am b/test/Makefile.am
index f02a5ac..a6f0bd9 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -51,6 +51,7 @@ fill-and-stroke-alpha-add$(EXEEXT)			\
 fill-degenerate-sort-order$(EXEEXT)			\
 fill-missed-stop$(EXEEXT)				\
 fill-rule$(EXEEXT)					\
+filter-bilinear-extents$(EXEEXT)			\
 filter-nearest-offset$(EXEEXT)				\
 finer-grained-fallbacks$(EXEEXT)			\
 font-face-get-type$(EXEEXT)				\
@@ -383,6 +384,7 @@ REFERENCE_IMAGES = \
 	fill-rule-ref.png	\
 	fill-rule-rgb24-ref.png	\
 	fill-rule-ps-rgb24-ref.png \
+	filter-bilinear-extents-ref.png \
 	filter-nearest-offset-ref.png	\
 	finer-grained-fallbacks-ref.png			\
 	finer-grained-fallbacks-rgb24-ref.png		\
diff --git a/test/filter-bilinear-extents-ref.png b/test/filter-bilinear-extents-ref.png
new file mode 100644
index 0000000..61e416b
Binary files /dev/null and b/test/filter-bilinear-extents-ref.png differ
diff --git a/test/filter-bilinear-extents.c b/test/filter-bilinear-extents.c
new file mode 100644
index 0000000..a39a37c
--- /dev/null
+++ b/test/filter-bilinear-extents.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors: Carl D. Worth <cworth at cworth.org>
+ *	    Owen Taylor <otaylor at redhat.com>
+ */
+
+#include "cairo-test.h"
+
+static cairo_test_draw_function_t draw;
+
+/* This test exercises code that computes the extents of a surface
+ * pattern with CAIRO_FILTER_BILINEAR, (where the filtering
+ * effectively increases the extents of the pattern).
+ *
+ * The original bug was reported by Owen Taylor here:
+ *
+ *	bad clipping with EXTEND_NONE
+ *	http://bugs.freedesktop.org/show_bug.cgi?id=15349
+ */
+
+#define SCALE	10
+#define PAD 	3
+#define WIDTH	(PAD + 3 * SCALE + PAD)
+#define HEIGHT	WIDTH
+
+cairo_test_t test = {
+    "filter-bilinear-extents",
+    "Test that pattern extents are properly computed for CAIRO_FILTER_BILINEAR",
+    WIDTH, HEIGHT,
+    draw
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_surface_t *checker;
+    cairo_t *cr2;
+
+    /* Create a 2x2 blue+red checker */
+    checker = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 2, 2);
+    cr2 = cairo_create (checker);
+
+    cairo_set_source_rgb (cr2, 1, 0 ,0); /* red */
+    cairo_paint (cr2);
+    cairo_set_source_rgb (cr2, 0, 0, 1); /* blue */
+    cairo_rectangle (cr2, 0, 1, 1, 1);
+    cairo_rectangle (cr2, 1, 0, 1, 1);
+    cairo_fill (cr2);
+    cairo_destroy (cr2);
+
+    /* Draw our surface scaled with EXTEND_NONE */
+    cairo_set_source_rgb (cr, 0, 0, 0);
+    cairo_paint (cr);
+
+    cairo_save (cr);
+    cairo_translate (cr, PAD, PAD);
+    cairo_scale (cr, SCALE, SCALE);
+    cairo_translate (cr, 0.5, 0.5);
+    cairo_set_source_surface (cr, checker, 0, 0);
+    cairo_paint (cr);
+    cairo_restore (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+    return cairo_test (&test);
+}
commit 80f7aa03b35921a96683a0442f885c4b8335f3d9
Author: Carl Worth <cworth at cworth.org>
Date:   Fri Apr 4 11:29:47 2008 -0700

    Enable buggy_repeat workaround for X.Org servers < 1.4
    
    This covers the known-to-broken 1.3 servers such as appeared
    in Fedora 8. It also leaves the workaround off, (since it's
    a severe slowdown), for the known-to-be-working 1.4.99.901
    server as appears in Fedora 9 Betas.

diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
index 20bad2e..b1fc67e 100644
--- a/src/cairo-xlib-display.c
+++ b/src/cairo-xlib-display.c
@@ -298,6 +298,17 @@ _cairo_xlib_display_get (Display *dpy)
 	 * back up to 6.7 or 6.8. */
 	if (VendorRelease (dpy) >= 60700000 && VendorRelease (dpy) <= 60802000)
 	    display->buggy_repeat = TRUE;
+
+	/* But even the new modular server has bugs, (bad enough to
+	 * crash the X server), that it so happens we can avoid with
+	 * the exact same buggy_repeat workaround. We've verified that
+	 * this bug exists as least as late as version 1.3.0.0, (which
+	 * is in Fedora 8), and is gone again in version 1.4.99.901
+	 * (from a Fedora 9 Beta). Versions between those are still
+	 * unknown, but until we learn more, we'll assume that any 1.3
+	 * version is buggy.  */
+	if (VendorRelease (dpy) < 10400000)
+	    display->buggy_repeat = TRUE;
     } else if (strstr (ServerVendor (dpy), "XFree86") != NULL) {
 	if (VendorRelease (dpy) <= 40500000)
 	    display->buggy_repeat = TRUE;


More information about the cairo-commit mailing list