[cairo-commit] 8 commits - boilerplate/cairo-boilerplate.c doc/tutorial src/cairo-bentley-ottmann.c src/cairo-pattern.c src/cairo-skiplist.c src/cairo-skiplist-private.h test/joins.c test/joins.ps.ref.png test/Makefile.am test/path-precision.c test/rectilinear-dash.c test/rectilinear-dash.ref.png

Chris Wilson ickle at kemper.freedesktop.org
Fri Dec 12 05:52:24 PST 2008


 boilerplate/cairo-boilerplate.c |    2 
 doc/tutorial/src/twin.c         |    2 
 src/cairo-bentley-ottmann.c     |   33 +++++--
 src/cairo-pattern.c             |    3 
 src/cairo-skiplist-private.h    |    3 
 src/cairo-skiplist.c            |   85 +++++++++++++++----
 test/Makefile.am                |   13 ++
 test/joins.c                    |  109 ++++++++++++++++++++++++
 test/joins.ps.ref.png           |binary
 test/path-precision.c           |  108 ++++++++++++++++++++++++
 test/rectilinear-dash.c         |  176 ++++++++++++++++++++++++++++++++++++++++
 test/rectilinear-dash.ref.png   |binary
 12 files changed, 500 insertions(+), 34 deletions(-)

New commits:
commit 2b7c6f361a3cfe309ff0bcb606b808acbf36aa0f
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Nov 26 12:33:12 2008 +0000

    [skiplist] Allocate elements in chunks.
    
    Use a pool allocator to preallocate a chunk from which to allocate the
    skiplist elements (if we failed to reallocate from the freelists).

diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c
index cd15021..c115419 100644
--- a/src/cairo-bentley-ottmann.c
+++ b/src/cairo-bentley-ottmann.c
@@ -966,10 +966,13 @@ _cairo_bo_event_queue_init (cairo_bo_event_queue_t	*event_queue,
     int i;
     cairo_bo_event_t *events, **sorted_event_ptrs;
     unsigned num_events = 2*num_edges;
+    cairo_status_t status;
 
-    _cairo_skip_list_init (&event_queue->intersection_queue,
-			   cairo_bo_event_compare_abstract,
-			   sizeof (cairo_bo_event_t));
+    status = _cairo_skip_list_init (&event_queue->intersection_queue,
+				    cairo_bo_event_compare_abstract,
+				    sizeof (cairo_bo_event_t));
+    if (unlikely (status))
+	return status;
 
     /* The skip_elt_t field of a cairo_bo_event_t isn't used for start
      * or stop events, so this allocation is safe.  XXX: make the
@@ -1053,15 +1056,22 @@ _cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_
     return _cairo_bo_event_queue_insert (event_queue, &event);
 }
 
-static void
+static cairo_status_t
 _cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line)
 {
-    _cairo_skip_list_init (&sweep_line->active_edges,
-		    _sweep_line_elt_compare,
-		    sizeof (sweep_line_elt_t));
+    cairo_status_t status;
+
+    status = _cairo_skip_list_init (&sweep_line->active_edges,
+				    _sweep_line_elt_compare,
+				    sizeof (sweep_line_elt_t));
+    if (unlikely (status))
+	return status;
+
     sweep_line->head = NULL;
     sweep_line->tail = NULL;
     sweep_line->current_y = 0;
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static void
@@ -1110,7 +1120,8 @@ _cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t	*sweep_line,
 {
     cairo_bo_edge_t **left_next, **right_prev;
 
-    _cairo_skip_list_delete_given (&sweep_line->active_edges, &edge->sweep_line_elt->elt);
+    _cairo_skip_list_delete_given (&sweep_line->active_edges,
+				   &edge->sweep_line_elt->elt);
 
     left_next = &sweep_line->head;
     if (edge->prev)
@@ -1495,7 +1506,10 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_edge_t	*edges,
     if (status)
 	return status;
 
-    _cairo_bo_sweep_line_init (&sweep_line);
+    status = _cairo_bo_sweep_line_init (&sweep_line);
+    if (unlikely (status))
+	goto CLEANUP_EVENT_QUEUE;
+
     _cairo_bo_traps_init (&bo_traps, traps, xmin, ymin, xmax, ymax);
 
 #if DEBUG_PRINT_STATE
@@ -1621,6 +1635,7 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_edge_t	*edges,
     }
     _cairo_bo_traps_fini (&bo_traps);
     _cairo_bo_sweep_line_fini (&sweep_line);
+  CLEANUP_EVENT_QUEUE:
     _cairo_bo_event_queue_fini (&event_queue);
     return status;
 }
diff --git a/src/cairo-skiplist-private.h b/src/cairo-skiplist-private.h
index 3a948af..8c7dc97 100644
--- a/src/cairo-skiplist-private.h
+++ b/src/cairo-skiplist-private.h
@@ -70,6 +70,7 @@ typedef struct _skip_list {
     size_t data_size;
     skip_elt_t *chains[MAX_LEVEL];
     skip_elt_t *freelists[MAX_FREELIST_LEVEL];
+    struct pool *pool;
     int		max_level;
 } cairo_skip_list_t;
 
@@ -81,7 +82,7 @@ typedef struct _skip_list {
  * sizeof) is passed for elt_size. Note that the structure used for
  * list elements must have as its final member a skip_elt_t
  */
-cairo_private void
+cairo_private cairo_status_t
 _cairo_skip_list_init (cairo_skip_list_t		*list,
 		cairo_skip_list_compare_t	 compare,
 		size_t			 elt_size);
diff --git a/src/cairo-skiplist.c b/src/cairo-skiplist.c
index d03a6bf..5fe2bd0 100644
--- a/src/cairo-skiplist.c
+++ b/src/cairo-skiplist.c
@@ -38,10 +38,42 @@ hars_petruska_f54_1_random (void)
 #  undef rol
 }
 
+struct pool {
+    struct pool *next;
+    char *ptr;
+    unsigned int rem;
+};
+
+static struct pool *
+pool_new (void)
+{
+    struct pool *pool;
+
+    pool = malloc (8192 - 8);
+    if (unlikely (pool == NULL))
+	return NULL;
+
+    pool->next = NULL;
+    pool->rem = 8192 - 8 - sizeof (struct pool);
+    pool->ptr = (char *) (pool + 1);
+
+    return pool;
+}
+
+static void
+pools_destroy (struct pool *pool)
+{
+    while (pool != NULL) {
+	struct pool *next = pool->next;
+	free (pool);
+	pool = next;
+    }
+}
+
 /*
  * Initialize an empty skip list
  */
-void
+cairo_status_t
 _cairo_skip_list_init (cairo_skip_list_t	*list,
                        cairo_skip_list_compare_t compare,
                        size_t			 elt_size)
@@ -51,6 +83,9 @@ _cairo_skip_list_init (cairo_skip_list_t	*list,
     list->compare = compare;
     list->elt_size = elt_size;
     list->data_size = elt_size - sizeof (skip_elt_t);
+    list->pool = pool_new ();
+    if (unlikely (list->pool == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     for (i = 0; i < MAX_LEVEL; i++) {
 	list->chains[i] = NULL;
@@ -61,25 +96,14 @@ _cairo_skip_list_init (cairo_skip_list_t	*list,
     }
 
     list->max_level = 0;
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 void
 _cairo_skip_list_fini (cairo_skip_list_t *list)
 {
-    skip_elt_t *elt;
-    int i;
-
-    while ((elt = list->chains[0])) {
-	_cairo_skip_list_delete_given (list, elt);
-    }
-    for (i=0; i<MAX_FREELIST_LEVEL; i++) {
-	elt = list->freelists[i];
-	while (elt) {
-	    skip_elt_t *nextfree = elt->prev;
-	    free (ELT_DATA(elt));
-	    elt = nextfree;
-	}
-    }
+    pools_destroy (list->pool);
 }
 
 /*
@@ -110,6 +134,34 @@ random_level (void)
 }
 
 static void *
+pool_alloc (cairo_skip_list_t *list,
+	    unsigned int level)
+{
+    unsigned int size;
+    struct pool *pool;
+    void *ptr;
+
+    size = list->elt_size +
+	(FREELIST_MAX_LEVEL_FOR (level) - 1) * sizeof (skip_elt_t *);
+
+    pool = list->pool;
+    if (size > pool->rem) {
+	pool = pool_new ();
+	if (unlikely (pool == NULL))
+	    return NULL;
+
+	pool->next = list->pool;
+	list->pool = pool;
+    }
+
+    ptr = pool->ptr;
+    pool->ptr += size;
+    pool->rem -= size;
+
+    return ptr;
+}
+
+static void *
 alloc_node_for_level (cairo_skip_list_t *list, unsigned level)
 {
     int freelist_level = FREELIST_FOR_LEVEL (level);
@@ -118,8 +170,7 @@ alloc_node_for_level (cairo_skip_list_t *list, unsigned level)
 	list->freelists[freelist_level] = elt->prev;
 	return ELT_DATA(elt);
     }
-    return malloc (list->elt_size
-		   + (FREELIST_MAX_LEVEL_FOR (level) - 1) * sizeof (skip_elt_t *));
+    return pool_alloc (list, level);
 }
 
 static void
commit 903b39c30448d62e2cbf9d075c5256a333bd5d8f
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Dec 4 15:22:01 2008 +0000

    [test] Make the xlib-fallback use the image refs.
    
    The xlib-fallback is closer to the image than the xlib backend, so prefer
    not to use the xlib.ref.png.

diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index f6f68f9..0f37451 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -523,7 +523,7 @@ static cairo_boilerplate_target_t targets[] =
     /* This is a fallback surface which uses xlib fallbacks instead of
      * the Render extension. */
     {
-	"xlib-fallback", "xlib", NULL,
+	"xlib-fallback", "image", NULL,
 	CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1,
 	_cairo_boilerplate_xlib_fallback_create_surface, NULL,
 	NULL,
commit 792057539bf814cc00447a0a53978e0af3efe270
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Dec 3 10:52:59 2008 +0000

    [test] Only delete output images beneath output.
    
    We were using an overly-liberal find that also deleted copied output for
    use in CAIRO_REF_DIR if that directory was below test/. So only delete
    files below output/ (which should only be used by cairo-test).

diff --git a/test/Makefile.am b/test/Makefile.am
index fb4a9b8..40a4843 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1251,14 +1251,13 @@ CLEANFILES +=					\
 # most systems cannot handle all of our clean files together.
 # Then it became a fancy find using many GNU extensions, but then the ugly
 # reality of portability was raised and it became....
-clean-local: clean-caches
+clean-local:
 	rm -rf output
-	-${FIND} . -name '*.out.*'    -print | ${XARGS} ${RM}
 	-${FIND} . -name '*.log'      -print | ${XARGS} ${RM}
 	-${FIND} . -name '*.[is]'     -print | ${XARGS} ${RM}
 clean-caches:
-	-${FIND} . -name '*.pass.*'   -print | ${XARGS} ${RM}
-	-${FIND} . -name '*.fail.*'   -print | ${XARGS} ${RM}
+	-${FIND} output -name '*.fail.*' -print | ${XARGS} ${RM}
+	-${FIND} output -name '*.pass.*' -print | ${XARGS} ${RM}
 
 # The following definitions both should work.
 #FAILED_TESTS = `grep -l '\<FAIL\>' $(test_sources:.c=.log) 2>/dev/null | sed -e 's/[.]log$$//' | xargs echo`
commit 913cbad25e08a07c05b8c2e6ddd3c343ca2462b2
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Dec 2 13:06:50 2008 +0000

    [test] Add a simple joins test case
    
    Exercise joins between short (<LINE_WIDTH) lines - used in debugging
    stroke-to-path.

diff --git a/test/Makefile.am b/test/Makefile.am
index bb2d788..fb4a9b8 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -90,6 +90,7 @@ test_sources = \
 	in-fill-empty-trapezoid.c			\
 	in-fill-trapezoid.c				\
 	invalid-matrix.c				\
+	joins.c						\
 	large-clip.c					\
 	large-font.c					\
 	large-source.c					\
@@ -615,6 +616,8 @@ REFERENCE_IMAGES = \
 	infinite-join.ref.png	\
 	infinite-join.ps2.ref.png	\
 	infinite-join.ps3.ref.png	\
+	joins.ref.png		\
+	joins.ps.ref.png	\
 	large-clip.ref.png	\
 	large-font.ref.png	\
 	large-source.ref.png	\
diff --git a/test/joins.c b/test/joins.c
new file mode 100644
index 0000000..10f9fe7
--- /dev/null
+++ b/test/joins.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2008 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+#define LINE_WIDTH	12.
+#define SIZE		(5 * LINE_WIDTH)
+#define PAD		(2 * LINE_WIDTH)
+
+static void
+make_path (cairo_t *cr)
+{
+    const struct {
+	double x, y;
+    } scales[] = {
+	{  1,  1 },
+	{ -1,  1 },
+	{  1, -1 },
+	{ -1, -1 },
+    };
+    unsigned int i, j;
+
+    for (j = 0; j < sizeof (scales) / sizeof (scales[0]); j++) {
+	cairo_save (cr);
+	/* include reflections to flip the orientation of the join */
+	cairo_scale (cr, scales[j].x, scales[j].y);
+	for (i = 0; i < 3; i++) {
+	    cairo_new_sub_path (cr);
+	    cairo_move_to (cr, 0, -9*LINE_WIDTH/4 - 2);
+	    cairo_line_to (cr,  0, -2*LINE_WIDTH - 2);
+	    cairo_line_to (cr,  LINE_WIDTH/4, -2*LINE_WIDTH - 2);
+	    cairo_rotate (cr, M_PI / 4.);
+	}
+	cairo_restore (cr);
+    }
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_line_join_t join;
+
+    cairo_save (cr);
+    cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+    cairo_paint (cr);
+    cairo_restore (cr);
+
+    cairo_set_line_width (cr, LINE_WIDTH);
+    cairo_translate (cr, PAD + SIZE / 2., PAD + SIZE / 2.);
+
+    for (join = CAIRO_LINE_JOIN_MITER; join <= CAIRO_LINE_JOIN_BEVEL; join++) {
+	cairo_save (cr);
+
+	cairo_set_line_join (cr, join);
+
+	cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
+	make_path (cr);
+	cairo_stroke (cr);
+
+	cairo_translate (cr, 0, SIZE + PAD);
+
+	cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+	make_path (cr);
+	cairo_stroke (cr);
+
+	cairo_translate (cr, 0, SIZE + PAD);
+
+	cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
+	make_path (cr);
+	cairo_stroke (cr);
+
+	cairo_restore (cr);
+
+	cairo_translate (cr, SIZE + PAD, 0);
+    }
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (joins,
+	    "Test joins",
+	    "stroke joins", /* keywords */
+	    NULL, /* requirements */
+	    3 * (PAD + SIZE) + PAD,
+	    3 * (PAD + SIZE) + PAD,
+	    NULL, draw)
+
diff --git a/test/joins.ps.ref.png b/test/joins.ps.ref.png
new file mode 100644
index 0000000..5730080
Binary files /dev/null and b/test/joins.ps.ref.png differ
commit 9f4f41de7d20ee46ee8ca06716cbc18e55cfcf86
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Dec 2 13:05:30 2008 +0000

    [tutorial] Correct twin font name
    
    We changed the name for the builtin font  from "cairo" to "<cairo>" to
    reduce possible naming conflicts - update the tutorial to match.

diff --git a/doc/tutorial/src/twin.c b/doc/tutorial/src/twin.c
index fe0e90e..e167f26 100644
--- a/doc/tutorial/src/twin.c
+++ b/doc/tutorial/src/twin.c
@@ -20,7 +20,7 @@ draw (cairo_t *cr, int width, int height)
 
     cairo_set_source_rgb (cr, 0, 0, 0);
     cairo_select_font_face (cr,
-			    "cairo",
+			    "<cairo>",
 			    CAIRO_FONT_SLANT_NORMAL,
 			    CAIRO_FONT_WEIGHT_NORMAL);
 
commit 4ff884fe4df64234a7da4635d78ffafabe00f18c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Nov 30 19:18:15 2008 +0000

    [test] Check idempotency of append_path() -> copy_path()
    
    The API should preserve the precision across the public interface so that
    the user is able to retrieve the co-ordinates that he used to construct
    the path. However since we transform the path to a 24.8 fixed-point
    internal represent we currently incur a precision-loss - the affects of
    which can be seen in the miter-precision test case for example. It is
    planned to move to keeping the path as doubles until the backend
    explicitly requests the fixed-point coodinates (and some backends, e.g.
    pdf, might only ever use the doubles). Then, barring rounding errors
    during path transformations, we should be able to return the exact path
    the user set (under an identity CTM, of course ;-).

diff --git a/test/Makefile.am b/test/Makefile.am
index 0d1a9f2..bb2d788 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -128,6 +128,7 @@ test_sources = \
 	paint-repeat.c					\
 	paint-source-alpha.c				\
 	paint-with-alpha.c				\
+	path-precision.c				\
 	pattern-get-type.c				\
 	pattern-getters.c				\
 	pixman-rotate.c					\
diff --git a/test/path-precision.c b/test/path-precision.c
new file mode 100644
index 0000000..447b7a2
--- /dev/null
+++ b/test/path-precision.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright © 2008 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris at chris-wilson.co.uk>
+ *
+ * Based on an example by Dirk "krit" Schulze found during WebKit integration.
+ */
+
+#include "cairo-test.h"
+
+/* Test the idempotency of path construction and copying */
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_path_data_t path_data[] = {
+	{ .header = { CAIRO_PATH_MOVE_TO, 2 }, },
+	{ .point = { 95.000000, 40.000000 }, },
+
+	{ .header = { CAIRO_PATH_LINE_TO, 2 }, },
+	{ .point = { 94.960533, 41.255810 }, },
+
+	{ .header = { CAIRO_PATH_LINE_TO, 2 }, },
+	{ .point = { 94.842293, 42.50666 }, },
+
+	{ .header = { CAIRO_PATH_LINE_TO, 2 }, },
+	{ .point = { 94.645744, 43.747627 }, },
+
+	{ .header = { CAIRO_PATH_LINE_TO, 2 }, },
+	{ .point = { 94.371666, 44.973797 }, },
+    };
+    const cairo_test_context_t *ctx = cairo_test_get_context (cr);
+    cairo_path_t path, *path_copy;
+    int i, j, n;
+    cairo_test_status_t result = CAIRO_TEST_SUCCESS;
+
+    path.status = CAIRO_STATUS_SUCCESS;
+    path.num_data = sizeof (path_data) / sizeof (path_data[0]);
+    path.data = path_data;
+
+    cairo_new_path (cr);
+    cairo_append_path (cr, &path);
+    path_copy = cairo_copy_path (cr);
+
+    if (path_copy->status)
+	return cairo_test_status_from_status (ctx, path_copy->status);
+
+    for (i = j = n = 0;
+	 i < path.num_data && j < path_copy->num_data;
+	 i += path.data[i].header.length,
+	 j += path_copy->data[j].header.length,
+	 n++)
+    {
+	const cairo_path_data_t *src, *dst;
+
+	src = &path.data[i];
+	dst = &path_copy->data[j];
+
+	if (src->header.type != dst->header.type) {
+	    cairo_test_log (ctx,
+			    "Paths differ in header type after %d operations.\n"
+			    "Expected path operation %d, found %d.\n",
+			    n, src->header.type, dst->header.type);
+	    result = CAIRO_TEST_FAILURE;
+	    break;
+	}
+
+	if (memcmp (&src[1].point, &dst[1].point, sizeof (src->point))) {
+	    cairo_test_log (ctx,
+			    "Paths differ in coordinates after %d operations.\n"
+			    "Expected point (%f, %f), found (%f, %f).\n",
+			    n,
+			    src[1].point.x, src[1].point.y,
+			    dst[1].point.x, dst[1].point.y);
+	    result = CAIRO_TEST_FAILURE;
+	    break;
+	}
+    }
+
+    cairo_path_destroy (path_copy);
+    return result;
+}
+
+CAIRO_TEST (path_precision,
+	    "Check that the path append/copy is idempotent.",
+	    "XFAIL api", /* keywords */
+	    NULL, /* requirements */
+	    0, 0,
+	    NULL, draw)
commit fe4af195a7880336894a5fbae86740ef55c14cbf
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Nov 30 13:48:11 2008 +0000

    [test] Add a rectilinear-dash test case.
    
    Exercise dashing on pixel-aligned boundaries to test extending the
    rectilinear stroker to handle dashes.

diff --git a/test/Makefile.am b/test/Makefile.am
index 769493b..0d1a9f2 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -138,6 +138,7 @@ test_sources = \
 	rectangle-rounding-error.c			\
 	rectilinear-fill.c				\
 	rectilinear-miter-limit.c			\
+	rectilinear-dash.c				\
 	rectilinear-stroke.c				\
 	reflected-stroke.c				\
 	rel-path.c					\
@@ -791,6 +792,7 @@ REFERENCE_IMAGES = \
 	rectilinear-miter-limit.ref.png		\
 	rectilinear-miter-limit.ps2.ref.png	\
 	rectilinear-miter-limit.ps3.ref.png	\
+	rectilinear-dash.ref.png	\
 	rectilinear-stroke.ref.png	\
 	reflected-stroke.ref.png	\
 	reflected-stroke.ps2.ref.png	\
diff --git a/test/rectilinear-dash.c b/test/rectilinear-dash.c
new file mode 100644
index 0000000..fe998bb
--- /dev/null
+++ b/test/rectilinear-dash.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright © 2006 Red Hat, Inc.
+ * Copyright © 2008 Chris Wilson
+ *
+ * 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.
+ *
+ * Author: Carl D. Worth <cworth at cworth.org>
+ *         Chris Wilson <chris at chris-wilson.co.uk>
+ *
+ * Based on the original test/rectilinear-stroke.c by Carl D. Worth.
+ */
+
+#include "cairo-test.h"
+
+#define SIZE 50
+
+static void
+draw_dashes (cairo_t *cr)
+{
+    const double dash_square[4] = {4, 2, 2, 2};
+    const double dash_butt[4] = {5, 1, 3, 1};
+
+    cairo_save (cr);
+
+    cairo_set_dash (cr, dash_square, 4, 0);
+
+    cairo_set_line_width (cr, 1.0);
+    cairo_translate (cr, 1, 1);
+
+    /* Draw everything first with square caps. */
+    cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
+
+    /* Draw horizontal and vertical segments, each in both
+     * directions. */
+    cairo_move_to     (cr,  4.5,  0.5);
+    cairo_rel_line_to (cr,  2.0,  0.0);
+
+    cairo_move_to     (cr, 10.5,  4.5);
+    cairo_rel_line_to (cr,  0.0,  2.0);
+
+    cairo_move_to     (cr,  6.5, 10.5);
+    cairo_rel_line_to (cr, -2.0,  0.0);
+
+    cairo_move_to     (cr,  0.5,  6.5);
+    cairo_rel_line_to (cr,  0.0, -2.0);
+
+    /* Draw right angle turns in four directions. */
+    cairo_move_to     (cr,  0.5,  2.5);
+    cairo_rel_line_to (cr,  0.0, -2.0);
+    cairo_rel_line_to (cr,  2.0,  0.0);
+
+    cairo_move_to     (cr,  8.5,  0.5);
+    cairo_rel_line_to (cr,  2.0,  0.0);
+    cairo_rel_line_to (cr,  0.0,  2.0);
+
+    cairo_move_to     (cr, 10.5,  8.5);
+    cairo_rel_line_to (cr,  0.0,  2.0);
+    cairo_rel_line_to (cr, -2.0,  0.0);
+
+    cairo_move_to     (cr,  2.5, 10.5);
+    cairo_rel_line_to (cr, -2.0,  0.0);
+    cairo_rel_line_to (cr,  0.0, -2.0);
+
+    cairo_stroke (cr);
+
+    /* Draw a closed-path rectangle */
+    cairo_rectangle (cr, 0.5, 12.5, 10.0, 10.0);
+    cairo_set_dash (cr, dash_square, 4, 2);
+    cairo_stroke (cr);
+
+    cairo_translate (cr, 12, 0);
+
+    /* Now draw the same results, but with butt caps. */
+    cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
+    cairo_set_dash (cr, dash_butt, 4, 0.0);
+
+    /* Draw horizontal and vertical segments, each in both
+     * directions. */
+    cairo_move_to     (cr,  4.0,  0.5);
+    cairo_rel_line_to (cr,  3.0,  0.0);
+
+    cairo_move_to     (cr, 10.5,  4.0);
+    cairo_rel_line_to (cr,  0.0,  3.0);
+
+    cairo_move_to     (cr,  7.0, 10.5);
+    cairo_rel_line_to (cr, -3.0,  0.0);
+
+    cairo_move_to     (cr,  0.5,  7.0);
+    cairo_rel_line_to (cr,  0.0, -3.0);
+
+    /* Draw right angle turns in four directions. */
+    cairo_move_to     (cr,  0.5,  3.0);
+    cairo_rel_line_to (cr,  0.0, -2.5);
+    cairo_rel_line_to (cr,  2.5,  0.0);
+
+    cairo_move_to     (cr,  8.0,  0.5);
+    cairo_rel_line_to (cr,  2.5,  0.0);
+    cairo_rel_line_to (cr,  0.0,  2.5);
+
+    cairo_move_to     (cr, 10.5,  8.0);
+    cairo_rel_line_to (cr,  0.0,  2.5);
+    cairo_rel_line_to (cr, -2.5,  0.0);
+
+    cairo_move_to     (cr,  3.0, 10.5);
+    cairo_rel_line_to (cr, -2.5,  0.0);
+    cairo_rel_line_to (cr,  0.0, -2.5);
+
+    cairo_stroke (cr);
+
+    /* Draw a closed-path rectangle */
+    cairo_set_dash (cr, dash_butt, 4, 2.5);
+    cairo_rectangle (cr, 0.5, 12.5, 10.0, 10.0);
+    cairo_stroke (cr);
+
+    cairo_restore (cr);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    /* Paint background white, then draw in black. */
+    cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+    cairo_paint (cr);
+
+    cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+    draw_dashes (cr);
+
+    cairo_save (cr);
+    cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
+    cairo_translate (cr, 0, height);
+    cairo_scale (cr, 1, -1);
+    draw_dashes (cr);
+    cairo_restore (cr);
+
+    cairo_save (cr);
+    cairo_set_source_rgb (cr, 0.0, 1.0, 0.0);
+    cairo_translate (cr, width, 0);
+    cairo_scale (cr, -1, 1);
+    draw_dashes (cr);
+    cairo_restore (cr);
+
+    cairo_save (cr);
+    cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
+    cairo_translate (cr, width, height);
+    cairo_scale (cr, -1, -1);
+    draw_dashes (cr);
+    cairo_restore (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (rectilinear_dash,
+	    "Test dashed rectilinear stroke operations (covering only whole pixels)",
+	    "stroke dash", /* keywords */
+	    NULL, /* requirements */
+	    SIZE, SIZE,
+	    NULL, draw)
+
diff --git a/test/rectilinear-dash.ref.png b/test/rectilinear-dash.ref.png
new file mode 100644
index 0000000..33e7851
Binary files /dev/null and b/test/rectilinear-dash.ref.png differ
commit 1d68ee73f8d406671d25a1ab6c3cfb096a7a6ce7
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Nov 23 08:59:56 2008 +0000

    [pattern] Compute the combined color content.
    
    When multiplying two colors together, the combined content is simply the
    or of the their contents.

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index aa580d5..9477f87 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -2174,7 +2174,8 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t	    *src,
 	combined = src_solid->color;
 	_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
 
-	_cairo_pattern_init_solid (&src_tmp.solid, &combined, CAIRO_CONTENT_COLOR_ALPHA);
+	_cairo_pattern_init_solid (&src_tmp.solid, &combined,
+				   src_solid->content | mask_solid->content);
 
 	src = &src_tmp.base;
 	mask = NULL;


More information about the cairo-commit mailing list