[cairo-commit] 3 commits - src/cairo.c src/cairo-path-stroke.c test/get-path-extents.c test/.gitignore test/Makefile.am test/rectilinear-miter-limit.c test/rectilinear-miter-limit-ref.png

Carl Worth cworth at kemper.freedesktop.org
Mon Jan 21 16:47:23 PST 2008


 src/cairo-path-stroke.c              |    6 ++
 src/cairo.c                          |    4 -
 test/.gitignore                      |    1 
 test/Makefile.am                     |    2 
 test/get-path-extents.c              |   49 +++++++++++++++++++++
 test/rectilinear-miter-limit-ref.png |binary
 test/rectilinear-miter-limit.c       |   80 +++++++++++++++++++++++++++++++++++
 7 files changed, 140 insertions(+), 2 deletions(-)

New commits:
commit 47cf7ed769891b00abf96d14de6e79c0fa893cf9
Author: Carl Worth <cworth at cworth.org>
Date:   Mon Jan 21 16:45:41 2008 -0800

    Test and document that fill rule has no effect on cairo_path_extents

diff --git a/src/cairo.c b/src/cairo.c
index 3011125..9535174 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -1879,8 +1879,8 @@ slim_hidden_def(cairo_close_path);
  *
  * Computes a bounding box in user-space coordinates covering the
  * points on the current path. If the current path is empty, returns
- * an empty rectangle ((0,0), (0,0)).  Stroke parameters, surface
- * dimensions and clipping are not taken into account.
+ * an empty rectangle ((0,0), (0,0)). Stroke parameters, fill rule,
+ * surface dimensions and clipping are not taken into account.
  *
  * Contrast with cairo_fill_extents() and cairo_stroke_extents() which
  * return the extents of only the area that would be "inked" by
diff --git a/test/get-path-extents.c b/test/get-path-extents.c
index 5e82c1e..12901fd 100644
--- a/test/get-path-extents.c
+++ b/test/get-path-extents.c
@@ -244,6 +244,55 @@ draw (cairo_t *cr, int width, int height)
     cairo_new_path (cr2);
     cairo_restore (cr2);
 
+    cairo_save (cr2);
+
+    cairo_set_line_width (cr2, 4);
+
+    cairo_rectangle (cr2, 10, 10, 30, 30);
+    cairo_rectangle (cr2, 25, 10, 15, 30);
+
+    cairo_set_fill_rule (cr2, CAIRO_FILL_RULE_EVEN_ODD);
+    phase = "EVEN_ODD overlapping rectangles";
+    if (!check_extents (phase, cr2, FILL, EQUALS, 10, 10, 15, 30) ||
+	!check_extents (phase, cr2, STROKE, EQUALS, 8, 8, 34, 34) ||
+	!check_extents (phase, cr2, PATH, EQUALS, 10, 10, 30, 30))
+	ret = CAIRO_TEST_FAILURE;
+
+    /* Test other fill rule with the same path. */
+
+    cairo_set_fill_rule (cr2, CAIRO_FILL_RULE_WINDING);
+    phase = "WINDING overlapping rectangles";
+    if (!check_extents (phase, cr2, FILL, EQUALS, 10, 10, 30, 30) ||
+	!check_extents (phase, cr2, STROKE, EQUALS, 8, 8, 34, 34) ||
+	!check_extents (phase, cr2, PATH, EQUALS, 10, 10, 30, 30))
+	ret = CAIRO_TEST_FAILURE;
+
+    /* Now, change the direction of the second rectangle and test both
+     * fill rules again. */
+    cairo_new_path (cr2);
+    cairo_rectangle (cr2, 10, 10, 30, 30);
+    cairo_rectangle (cr2, 25, 40, 15, -30);
+
+    cairo_set_fill_rule (cr2, CAIRO_FILL_RULE_EVEN_ODD);
+    phase = "EVEN_ODD overlapping rectangles";
+    if (!check_extents (phase, cr2, FILL, EQUALS, 10, 10, 15, 30) ||
+	!check_extents (phase, cr2, STROKE, EQUALS, 8, 8, 34, 34) ||
+	!check_extents (phase, cr2, PATH, EQUALS, 10, 10, 30, 30))
+	ret = CAIRO_TEST_FAILURE;
+
+    /* Test other fill rule with the same path. */
+
+    cairo_set_fill_rule (cr2, CAIRO_FILL_RULE_WINDING);
+    phase = "WINDING overlapping rectangles";
+    if (!check_extents (phase, cr2, FILL, EQUALS, 10, 10, 15, 30) ||
+	!check_extents (phase, cr2, STROKE, EQUALS, 8, 8, 34, 34) ||
+	!check_extents (phase, cr2, PATH, EQUALS, 10, 10, 30, 30))
+	ret = CAIRO_TEST_FAILURE;
+
+    cairo_new_path (cr2);
+
+    cairo_restore (cr2);
+
     /* http://bugs.freedesktop.org/show_bug.cgi?id=7245 */
     phase = "Arc";
     cairo_save (cr2);
commit 1ca186f51134e7d5969937760b068caba0070d31
Author: Carl Worth <cworth at cworth.org>
Date:   Mon Jan 21 16:34:24 2008 -0800

    Disable rectilinear stroke optimization for small miter limit values
    
    This fixes the bug that was causing the recently added
    rectilinear-miter-limit test case to fail. It passes
    quite happily now.

diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 6464e3d..9ebfce3 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -1358,6 +1358,12 @@ _cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t	*path,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     if (stroke_style->line_join	!= CAIRO_LINE_JOIN_MITER)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
+    /* If the miter limit turns right angles into bevels, then we
+     * can't usethis optimization. Remember, the ratio is
+     * 1/sin(ɸ/2). So the cutoff is 1/sin(π/4.0) or ⎷2 or
+     * approximately 1.414213562373095, which we round for safety. */
+    if (stroke_style->miter_limit < 1.415)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
     if (stroke_style->dash)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     if (! (stroke_style->line_cap == CAIRO_LINE_CAP_BUTT ||
commit 32efcc94627e8890969c4b36a78c831ced6f8d62
Author: Carl Worth <cworth at cworth.org>
Date:   Mon Jan 21 16:32:48 2008 -0800

    Add new rectilinear-miter-limit test to demonstrate bug
    
    We're failing to respect the miter limit in the rectilinear
    stroke optimization code.

diff --git a/test/.gitignore b/test/.gitignore
index a02b29d..15e66c2 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -131,6 +131,7 @@ svg-surface.svg
 pixman-rotate
 pthread-show-text
 rectangle-rounding-error
+rectilinear-miter-limit
 rectilinear-stroke
 rel-path
 rotate-image-surface-paint
diff --git a/test/Makefile.am b/test/Makefile.am
index 14bafc3..79a5b2c 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -98,6 +98,7 @@ push-group$(EXEEXT)					\
 radial-gradient$(EXEEXT)				\
 random-intersections$(EXEEXT)				\
 rectangle-rounding-error$(EXEEXT)			\
+rectilinear-miter-limit$(EXEEXT)			\
 rectilinear-stroke$(EXEEXT)				\
 rel-path$(EXEEXT)					\
 rgb24-ignore-alpha$(EXEEXT)				\
@@ -427,6 +428,7 @@ REFERENCE_IMAGES = \
 	random-intersections-ref.png	\
 	rgb24-ignore-alpha-ref.png \
 	rectangle-rounding-error-ref.png	\
+	rectilinear-miter-limit-ref.png		\
 	rectilinear-stroke-ref.png	\
 	rel-path-quartz-ref.png	\
 	rel-path-quartz-rgb24-ref.png	\
diff --git a/test/rectilinear-miter-limit-ref.png b/test/rectilinear-miter-limit-ref.png
new file mode 100644
index 0000000..53bfee0
Binary files /dev/null and b/test/rectilinear-miter-limit-ref.png differ
diff --git a/test/rectilinear-miter-limit.c b/test/rectilinear-miter-limit.c
new file mode 100644
index 0000000..78d0512
--- /dev/null
+++ b/test/rectilinear-miter-limit.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2009 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.
+ *
+ * Author: Carl D. Worth <cworth at cworth.org>
+ */
+
+#include "cairo-test.h"
+
+#define LINE_WIDTH  10
+#define PAD	    2
+#define WIDTH	    (PAD + LINE_WIDTH + PAD)
+#define HEIGHT	    (WIDTH)
+
+static cairo_test_draw_function_t draw;
+
+cairo_test_t test = {
+    "rectilinear-miter-limit",
+    "Test that the rectilinear stroke optimization doesn't break cairo_set_miter_limit",
+    WIDTH, HEIGHT,
+    draw
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_translate (cr, PAD, PAD);
+
+    /* Paint background white, then draw in black. */
+    cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+    cairo_paint (cr);
+    cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
+
+    cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
+    cairo_set_line_width (cr, LINE_WIDTH);
+
+    /* The default miter limit value of 10.0 guarantees that
+     * right-angle turns, (in fact, any angle greater than 11
+     * degrees), gets a miter rather than a bevel join. The
+     * rectilinear stroke optimization was originally written in a
+     * buggy way that did not respect the miter limit, (that is,
+     * inappropriately drawing miter joins when the miter limit would
+     * turn them into bevels). So we draw here with a miter limit of
+     * 1.0 to force all miter joins into bevels. */
+    cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
+    cairo_set_miter_limit (cr, 1.0);
+
+    cairo_move_to (cr, LINE_WIDTH / 2.0, LINE_WIDTH);
+    cairo_rel_line_to (cr, 0, - LINE_WIDTH / 2.0);
+    cairo_rel_line_to (cr, LINE_WIDTH / 2.0, 0);
+
+    cairo_stroke (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+    return cairo_test (&test);
+}


More information about the cairo-commit mailing list