summaryrefslogtreecommitdiff
path: root/src/cairo-path-stroke.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-path-stroke.c')
-rw-r--r--[-rwxr-xr-x]src/cairo-path-stroke.c87
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 */