[PATCH] [stroke] Improve ROUND line caps and line joins.

Chris Wilson chris at chris-wilson.co.uk
Thu Oct 2 07:39:49 PDT 2008


Ensure a "leak-free" fan between the initial point and the end point by
including those points in the pen. (From which we compute the convex hull
and proceed to convert into a triangle-fan.)
---
 src/cairo-path-stroke.c |  160 ++++++++++++++++++++++++++++------------------
 1 files changed, 97 insertions(+), 63 deletions(-)

diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 2d488d5..c460796 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -255,12 +255,88 @@ _cairo_slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
     return 0;
 }
 
+static inline int
+_range_step (int i, int step, int max)
+{
+    i += step;
+    if (i < 0)
+	i = max - 1;
+    if (i >= max)
+	i = 0;
+    return i;
+}
+
+/*
+ * Construct a fan around the midpoint using the vertices from pen between
+ * inpt and outpt.
+ */
+static cairo_status_t
+_tessellate_fan (cairo_stroker_t *stroker,
+		 cairo_slope_t *in_vector,
+		 cairo_slope_t *out_vector,
+		 cairo_point_t *midpt,
+		 cairo_point_t *inpt,
+		 cairo_point_t *outpt,
+		 cairo_bool_t clockwise)
+{
+    int start, stop, step;
+    cairo_point_t tri[3];
+    cairo_status_t status;
+    int i;
+    cairo_pen_t pen;
+    cairo_point_t extra_points[2];
+
+    status = _cairo_pen_init_copy (&pen, &stroker->pen);
+    if (status)
+	return status;
+
+    extra_points[0] = *inpt;
+    extra_points[0].x -= midpt->x;
+    extra_points[0].y -= midpt->y;
+    extra_points[1] = *outpt;
+    extra_points[1].x -= midpt->x;
+    extra_points[1].y -= midpt->y;
+    status = _cairo_pen_add_points (&pen, extra_points, 2);
+    if (status)
+	goto CLEANUP_PEN;
+
+    if (clockwise) {
+	_cairo_pen_find_active_ccw_vertex_index (&pen, in_vector, &start);
+	_cairo_pen_find_active_ccw_vertex_index (&pen, out_vector, &stop);
+	step = -1;
+    } else {
+	_cairo_pen_find_active_cw_vertex_index (&pen, in_vector, &start);
+	_cairo_pen_find_active_cw_vertex_index (&pen, out_vector, &stop);
+	step = 1;
+    }
+
+    /* Construct the fan. */
+    i = start;
+    tri[0] = *midpt;
+    tri[1] = *inpt;
+    while (i != stop) {
+	tri[2] = *midpt;
+	_translate_point (&tri[2], &pen.vertices[i].point);
+	status = _cairo_traps_tessellate_triangle (stroker->traps, tri);
+	if (status)
+	    goto CLEANUP_PEN;
+	tri[1] = tri[2];
+	i = _range_step (i, step, pen.num_vertices);
+    }
+
+    tri[2] = *outpt;
+    status = _cairo_traps_tessellate_triangle (stroker->traps, tri);
+
+  CLEANUP_PEN:
+    _cairo_pen_fini (&pen);
+    return status;
+}
+
 static cairo_status_t
 _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_stroke_face_t *out)
 {
     int			clockwise = _cairo_stroker_face_clockwise (out, in);
     cairo_point_t	*inpt, *outpt;
-    cairo_status_t status;
 
     if (in->cw.x == out->cw.x
 	&& in->cw.y == out->cw.y
@@ -271,51 +347,23 @@ _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_st
     }
 
     if (clockwise) {
-    	inpt = &in->ccw;
-    	outpt = &out->ccw;
+	inpt = &in->ccw;
+	outpt = &out->ccw;
     } else {
-    	inpt = &in->cw;
-    	outpt = &out->cw;
+	inpt = &in->cw;
+	outpt = &out->cw;
     }
 
     switch (stroker->style->line_join) {
     case CAIRO_LINE_JOIN_ROUND: {
-	int i;
-	int start, step, stop;
-	cairo_point_t tri[3];
-	cairo_pen_t *pen = &stroker->pen;
-
-	tri[0] = in->point;
-	if (clockwise) {
-	    _cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector, &start);
-	    step = -1;
-	    _cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector, &stop);
-	} else {
-	    _cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector, &start);
-	    step = +1;
-	    _cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector, &stop);
-	}
-
-	i = start;
-	tri[1] = *inpt;
-	while (i != stop) {
-	    tri[2] = in->point;
-	    _translate_point (&tri[2], &pen->vertices[i].point);
-	    status = _cairo_traps_tessellate_triangle (stroker->traps, tri);
-	    if (status)
-		return status;
-	    tri[1] = tri[2];
-	    i += step;
-	    if (i < 0)
-		i = pen->num_vertices - 1;
-	    if (i >= pen->num_vertices)
-		i = 0;
-	}
-
-	tri[2] = *outpt;
-
-	return _cairo_traps_tessellate_triangle (stroker->traps, tri);
+	/* construct a fan around the common midpoint */
+	return _tessellate_fan (stroker,
+				&in->dev_vector,
+				&out->dev_vector,
+				&in->point, inpt, outpt,
+				clockwise);
     }
+
     case CAIRO_LINE_JOIN_MITER:
     default: {
 	/* dot product of incoming slope vector with outgoing slope vector */
@@ -491,31 +539,17 @@ _cairo_stroker_add_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f)
 
     switch (stroker->style->line_cap) {
     case CAIRO_LINE_CAP_ROUND: {
-	int i;
-	int start, stop;
 	cairo_slope_t slope;
-	cairo_point_t tri[3];
-	cairo_pen_t *pen = &stroker->pen;
-
-	slope = f->dev_vector;
-	_cairo_pen_find_active_cw_vertex_index (pen, &slope, &start);
-	slope.dx = -slope.dx;
-	slope.dy = -slope.dy;
-	_cairo_pen_find_active_cw_vertex_index (pen, &slope, &stop);
-
-	tri[0] = f->point;
-	tri[1] = f->cw;
-	for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
-	    tri[2] = f->point;
-	    _translate_point (&tri[2], &pen->vertices[i].point);
-	    status = _cairo_traps_tessellate_triangle (stroker->traps, tri);
-	    if (status)
-		return status;
-	    tri[1] = tri[2];
-	}
-	tri[2] = f->ccw;
 
-	return _cairo_traps_tessellate_triangle (stroker->traps, tri);
+	slope.dx = -f->dev_vector.dx;
+	slope.dy = -f->dev_vector.dy;
+
+	return _tessellate_fan (stroker,
+				&f->dev_vector,
+				&slope,
+				&f->point, &f->cw, &f->ccw,
+				FALSE);
+
     }
     case CAIRO_LINE_CAP_SQUARE: {
 	double dx, dy;
-- 
1.5.6.3


--=-zsf7QRg9ayfzzPZlSMZp--



More information about the cairo mailing list