diff options
Diffstat (limited to 'src/cairo-path-stroke.c')
-rw-r--r--[-rwxr-xr-x] | src/cairo-path-stroke.c | 87 |
1 files changed, 61 insertions, 26 deletions
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c index 73c554bd8..5c260c915 100755..100644 --- a/src/cairo-path-stroke.c +++ b/src/cairo-path-stroke.c @@ -54,6 +54,7 @@ typedef struct cairo_stroker { const cairo_matrix_t *ctm_inverse; double half_line_width; double tolerance; + double spline_cusp_tolerance; double ctm_determinant; cairo_bool_t ctm_det_positive; @@ -177,6 +178,18 @@ _cairo_stroker_init (cairo_stroker_t *stroker, stroker->tolerance = tolerance; stroker->half_line_width = stroke_style->line_width / 2.0; + /* 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 - tolerance / stroker->half_line_width; + stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance; + stroker->spline_cusp_tolerance *= 2; + stroker->spline_cusp_tolerance -= 1; + stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm); stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0; @@ -1052,39 +1065,61 @@ _cairo_stroker_spline_to (void *closure, slope_dy = _cairo_fixed_to_double (tangent->dy); if (! _compute_normalized_device_slope (&slope_dx, &slope_dy, - stroker->ctm_inverse, NULL)) + stroker->ctm_inverse, NULL)) return CAIRO_STATUS_SUCCESS; _compute_face (point, tangent, slope_dx, slope_dy, stroker, &new_face); - assert(stroker->has_current_face); - - if (_cairo_stroke_segment_intersect (&stroker->current_face.cw, - &stroker->current_face.ccw, - &new_face.cw, - &new_face.ccw, - &intersect_point)) { - points[0] = stroker->current_face.ccw; - points[1] = new_face.ccw; - points[2] = intersect_point; - stroker->add_triangle (stroker->closure, points); - - points[0] = stroker->current_face.cw; - points[1] = new_face.cw; - stroker->add_triangle (stroker->closure, points); + assert (stroker->has_current_face); + + if ((new_face.dev_slope.x * stroker->current_face.dev_slope.x + + new_face.dev_slope.y * stroker->current_face.dev_slope.y) < stroker->spline_cusp_tolerance) { + + const cairo_point_t *inpt, *outpt; + int clockwise = _cairo_stroker_join_is_clockwise (&new_face, + &stroker->current_face); + + if (clockwise) { + inpt = &stroker->current_face.cw; + outpt = &new_face.cw; + } else { + inpt = &stroker->current_face.ccw; + outpt = &new_face.ccw; + } + + _tessellate_fan (stroker, + &stroker->current_face.dev_vector, + &new_face.dev_vector, + &stroker->current_face.point, + inpt, outpt, + clockwise); } - else { - points[0] = stroker->current_face.ccw; - points[1] = stroker->current_face.cw; - points[2] = new_face.cw; - stroker->add_triangle (stroker->closure, points); - - points[0] = stroker->current_face.ccw; - points[1] = new_face.cw; - points[2] = new_face.ccw; - stroker->add_triangle (stroker->closure, points); + + if (_slow_segment_intersection (&stroker->current_face.cw, + &stroker->current_face.ccw, + &new_face.cw, + &new_face.ccw, + &intersect_point)) { + points[0] = stroker->current_face.ccw; + points[1] = new_face.ccw; + points[2] = intersect_point; + stroker->add_triangle (stroker->closure, points); + + points[0] = stroker->current_face.cw; + points[1] = new_face.cw; + stroker->add_triangle (stroker->closure, points); + } else { + points[0] = stroker->current_face.ccw; + points[1] = stroker->current_face.cw; + points[2] = new_face.cw; + stroker->add_triangle (stroker->closure, points); + + points[0] = stroker->current_face.ccw; + points[1] = new_face.cw; + points[2] = new_face.ccw; + stroker->add_triangle (stroker->closure, points); } /* compute join */ |