[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