diff options
author | Martin Robinson <mrobinson@igalia.com> | 2013-03-12 15:16:01 -0700 |
---|---|---|
committer | Martin Robinson <mrobinson@igalia.com> | 2013-03-14 10:32:43 -0700 |
commit | aadece05fb1cf80f0a1138368f4664e878a59204 (patch) | |
tree | 04039a3e6b70f88359cc1227821e49cf0ada76b7 | |
parent | c60e23feb16a8745eaa6d213a89f61ded5707731 (diff) |
stroke: Fix large line widths for fallback stroke shaper
Fix the test case line-width-tolerance for the fallback stroke shaper.
Instead of drawing quads between spline points, draw triangle based on
the actual spline edges. This roughly follows the approach of the
tristrip and polygonal shapers.
-rw-r--r-- | src/cairo-fixed-private.h | 34 | ||||
-rw-r--r-- | src/cairo-path-stroke.c | 90 |
2 files changed, 116 insertions, 8 deletions
diff --git a/src/cairo-fixed-private.h b/src/cairo-fixed-private.h index b6cc6be7..352ca39d 100644 --- a/src/cairo-fixed-private.h +++ b/src/cairo-fixed-private.h @@ -352,6 +352,40 @@ _cairo_edge_compute_intersection_x_for_y (const cairo_point_t *p1, return x; } +/* Intersect two segments based on the algorithm described at + * http://paulbourke.net/geometry/pointlineplane/. This implementation + * uses floating point math. */ +static inline cairo_bool_t +_slow_segment_intersection (const cairo_point_t *seg1_p1, + const cairo_point_t *seg1_p2, + const cairo_point_t *seg2_p1, + const cairo_point_t *seg2_p2, + cairo_point_t *intersection) +{ + double denominator, u_a, u_b; + double seg1_dx, seg1_dy, seg2_dx, seg2_dy, seg_start_dx, seg_start_dy; + + seg1_dx = _cairo_fixed_to_double (seg1_p2->x - seg1_p1->x); + seg1_dy = _cairo_fixed_to_double (seg1_p2->y - seg1_p1->y); + seg2_dx = _cairo_fixed_to_double (seg2_p2->x - seg2_p1->x); + seg2_dy = _cairo_fixed_to_double (seg2_p2->y - seg2_p1->y); + denominator = (seg2_dy * seg1_dx) - (seg2_dx * seg1_dy); + if (denominator == 0) + return FALSE; + + seg_start_dx = _cairo_fixed_to_double (seg1_p1->x - seg2_p1->x); + seg_start_dy = _cairo_fixed_to_double (seg1_p1->y - seg2_p1->y); + u_a = ((seg2_dx * seg_start_dy) - (seg2_dy * seg_start_dx)) / denominator; + u_b = ((seg1_dx * seg_start_dy) - (seg1_dy * seg_start_dx)) / denominator; + + if (u_a <= 0 || u_a >= 1 || u_b <= 0 || u_b >= 1) + return FALSE; + + intersection->x = seg1_p1->x + _cairo_fixed_from_double ((u_a * seg1_dx)); + intersection->y = seg1_p1->y + _cairo_fixed_from_double ((u_a * seg1_dy)); + return TRUE; +} + #else # error Please define multiplication and other operands for your fixed-point type size #endif diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c index cd6b3a27..6fae093d 100644 --- a/src/cairo-path-stroke.c +++ b/src/cairo-path-stroke.c @@ -761,9 +761,12 @@ _compute_normalized_device_slope (double *dx, double *dy, } static void -_compute_face (const cairo_point_t *point, cairo_slope_t *dev_slope, - double slope_dx, double slope_dy, - cairo_stroker_t *stroker, cairo_stroke_face_t *face) +_compute_face (const cairo_point_t *point, + const cairo_slope_t *dev_slope, + double slope_dx, + double slope_dy, + cairo_stroker_t *stroker, + cairo_stroke_face_t *face) { double face_dx, face_dy; cairo_point_t offset_ccw, offset_cw; @@ -979,6 +982,68 @@ _cairo_stroker_line_to (void *closure, return CAIRO_STATUS_SUCCESS; } +static cairo_status_t +_cairo_stroker_spline_to (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent) +{ + cairo_stroker_t *stroker = closure; + cairo_stroke_face_t new_face; + double slope_dx, slope_dy; + cairo_point_t points[3]; + cairo_point_t intersect_point; + + stroker->has_initial_sub_path = TRUE; + + if (stroker->current_point.x == point->x && + stroker->current_point.y == point->y) + return CAIRO_STATUS_SUCCESS; + + slope_dx = _cairo_fixed_to_double (tangent->dx); + slope_dy = _cairo_fixed_to_double (tangent->dy); + + if (! _compute_normalized_device_slope (&slope_dx, &slope_dy, + 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 (_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); + } + + stroker->current_face = new_face; + stroker->has_current_face = TRUE; + stroker->current_point = *point; + + return CAIRO_STATUS_SUCCESS; +} + /* * Dashed lines. Cap each dash end, join around turns when on */ @@ -1135,18 +1200,27 @@ _cairo_stroker_curve_to (void *closure, cairo_line_join_t line_join_save; cairo_stroke_face_t face; double slope_dx, slope_dy; - cairo_path_fixed_line_to_func_t *line_to; + cairo_spline_add_point_func_t line_to; + cairo_spline_add_point_func_t spline_to; cairo_status_t status = CAIRO_STATUS_SUCCESS; line_to = stroker->dash.dashed ? - _cairo_stroker_line_to_dashed : - _cairo_stroker_line_to; + (cairo_spline_add_point_func_t) _cairo_stroker_line_to_dashed : + (cairo_spline_add_point_func_t) _cairo_stroker_line_to; + + /* spline_to is only capable of rendering non-degenerate splines. */ + spline_to = stroker->dash.dashed ? + (cairo_spline_add_point_func_t) _cairo_stroker_line_to_dashed : + (cairo_spline_add_point_func_t) _cairo_stroker_spline_to; if (! _cairo_spline_init (&spline, - (cairo_spline_add_point_func_t)line_to, stroker, + spline_to, + stroker, &stroker->current_point, b, c, d)) { - return line_to (closure, d); + cairo_slope_t fallback_slope; + _cairo_slope_init (&fallback_slope, &stroker->current_point, d); + return line_to (closure, d, &fallback_slope); } /* If the line width is so small that the pen is reduced to a |