[cairo-commit] 3 commits - src/cairo-path-stroke-polygon.c test/bug-spline.c test/Makefile.sources test/reference
Chris Wilson
ickle at kemper.freedesktop.org
Sun Jun 24 04:05:48 PDT 2012
src/cairo-path-stroke-polygon.c | 31 +++++++++---
test/Makefile.sources | 1
test/bug-spline.c | 96 ++++++++++++++++++++++++++++++++++++++
test/reference/bug-spline.ref.png |binary
4 files changed, 120 insertions(+), 8 deletions(-)
New commits:
commit 166e6f199e909d8aea13cdd4c858d48faad26247
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sun Jun 24 11:33:47 2012 +0100
stroke: Skip inserting a round-join if within tolerance
If the angle between two segments is small we can simply replace the
round-join with a bevel-join. This is done automatically by the
insertion of the triangle fan as it will not be able to find a point
around the pen between the two vectors. However, we can make that search
cheaper by inspecting whether the bisection angle is small enough that
the bevel-join will be within geometric tolerance of the round-join.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index e8e7bb2..b7c18b7 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -424,11 +424,15 @@ outer_close (struct stroker *stroker,
switch (stroker->style.line_join) {
case CAIRO_LINE_JOIN_ROUND:
/* construct a fan around the common midpoint */
- add_fan (stroker,
- &in->dev_vector,
- &out->dev_vector,
- &in->point, inpt, outpt,
- clockwise, outer);
+ if ((in->dev_slope.x * out->dev_slope.x +
+ in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
+ {
+ add_fan (stroker,
+ &in->dev_vector,
+ &out->dev_vector,
+ &in->point, inpt, outpt,
+ clockwise, outer);
+ }
break;
case CAIRO_LINE_JOIN_MITER:
commit b7bd5ae4f3da44131261711bb236cd7aa24a3ae3
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sun Jun 24 11:27:16 2012 +0100
stroke: Use round-joins near inflection points of splines
Near an inflection, the angle between two segments of a spline increases
rapidly (as the radius of curvature decreases for the cusp). The angle
may increase so much that a simple line connecting the two outside
points of the spline is not within the user specified geometric
tolerance (with the result that you can generate severe ugliness around
a cusp). Extend the current detection of the exact inflection to cover
the sharp joins near the cusp by inspecting whether the bisection angle
is larger than acceptable.
Fixes bug-spline.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index 88527f5..e8e7bb2 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -67,6 +67,7 @@ struct stroker {
const cairo_matrix_t *ctm;
const cairo_matrix_t *ctm_inverse;
double tolerance;
+ double spline_cusp_tolerance;
cairo_bool_t ctm_det_positive;
cairo_pen_t pen;
@@ -1152,8 +1153,8 @@ spline_to (void *closure,
} else {
compute_face (point, tangent, stroker, &face);
- if (face.dev_slope.x * stroker->current_face.dev_slope.x +
- face.dev_slope.y * stroker->current_face.dev_slope.y < 0)
+ if ((face.dev_slope.x * stroker->current_face.dev_slope.x +
+ face.dev_slope.y * stroker->current_face.dev_slope.y) < stroker->spline_cusp_tolerance)
{
const cairo_point_t *inpt, *outpt;
struct stroke_contour *outer;
@@ -1304,7 +1305,17 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
stroker.ctm = ctm;
stroker.ctm_inverse = ctm_inverse;
stroker.tolerance = tolerance;
-
+ /* To test whether we need to join two segments of a spline using
+ * a round-join or a bevel-join, we can inspect the angle between the
+ * two segments. If the difference between the chord distance
+ * (half-line-width times the cosine of the bisection angle) and the
+ * half-line-width itself is greater than tolerance then we need to
+ * inject a point.
+ */
+ stroker.spline_cusp_tolerance = 1 - 2 * tolerance / style->line_width;
+ stroker.spline_cusp_tolerance *= stroker.spline_cusp_tolerance;
+ stroker.spline_cusp_tolerance *= 2;
+ stroker.spline_cusp_tolerance -= 1;
stroker.ctm_det_positive =
_cairo_matrix_compute_determinant (ctm) >= 0.0;
commit 3d482e266febcf7da75f5662e518380460068ce1
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sun Jun 24 11:50:26 2012 +0100
test: Exercise bug in joining together spline segments around cusps
Carl Worth demonstrated a glaring bug in the new stroking code,
introduced in commit 545f30856aac98199 (stroke: Convert the outlines
into contour and then into a polygon), whereby only a bevel join was
being used to connect segments around a sharp inflection point.
This adds the two examples he reported to the test suite.
diff --git a/test/Makefile.sources b/test/Makefile.sources
index ddb41b5..9aada62 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -21,6 +21,7 @@ test_sources = \
big-empty-triangle.c \
big-little-box.c \
big-little-triangle.c \
+ bug-spline.c \
big-trap.c \
bilevel-image.c \
bug-40410.c \
diff --git a/test/bug-spline.c b/test/bug-spline.c
new file mode 100644
index 0000000..00a915c
--- /dev/null
+++ b/test/bug-spline.c
@@ -0,0 +1,96 @@
+/* cc `pkg-config --cflags --libs cairo` cairo-spline-image.c -o cairo-spline-image */
+
+/* Copyright © 2005 Carl Worth
+ * Copyright © 2012 Intel Corporation
+ *
+ * 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.
+ */
+
+#include "cairo-test.h"
+
+#define WIDE_LINE_WIDTH 160
+#define NARROW_LINE_WIDTH 2
+
+/* A spline showing bugs in the "contour-based stroking" in cairo 1.12 */
+static const struct spline {
+ struct { double x, y; } pt[5];
+ double line_width;
+ double rgba[4];
+} splines[] = {
+ {
+ {
+ { 172.25, 156.185 },
+ { 177.225, 164.06 },
+ { 176.5, 157.5 },
+ { 175.5, 159.5 },
+ },
+ WIDE_LINE_WIDTH,
+ { 1, 1, 1, 1 },
+ },
+ {
+ {
+ { 571.25, 247.185 },
+ { 78.225, 224.06 },
+ { 129.5, 312.5 },
+ { 210.5, 224.5 },
+ },
+ NARROW_LINE_WIDTH,
+ { 1, 0, 0, 1 },
+ }
+};
+#define NUM_SPLINES (sizeof(splines)/sizeof(splines[0]))
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ unsigned n;
+
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_paint (cr);
+
+ cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
+
+ for (n = 0; n < NUM_SPLINES; n++) {
+ cairo_set_line_width (cr, splines[n].line_width);
+ cairo_set_source_rgba (cr,
+ splines[n].rgba[0],
+ splines[n].rgba[1],
+ splines[n].rgba[2],
+ splines[n].rgba[3]);
+
+ cairo_move_to (cr, splines[n].pt[0].x, splines[n].pt[0].y);
+ cairo_curve_to (cr,
+ splines[n].pt[1].x, splines[n].pt[1].y,
+ splines[n].pt[2].x, splines[n].pt[2].y,
+ splines[n].pt[3].x, splines[n].pt[3].y);
+
+ cairo_stroke (cr);
+ }
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (bug_spline,
+ "Exercises a bug in the stroking of splines",
+ "spline, stroke", /* keywords */
+ NULL, /* requirements */
+ 300, 300,
+ NULL, draw)
diff --git a/test/reference/bug-spline.ref.png b/test/reference/bug-spline.ref.png
new file mode 100644
index 0000000..ebef261
Binary files /dev/null and b/test/reference/bug-spline.ref.png differ
More information about the cairo-commit
mailing list