From 36eabcbb9abee463a33b365387eeefd7e8806d24 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 22 Sep 2014 12:53:08 +0100 Subject: [PATCH] stroke,traps: Emit join without loss of precision Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=84115 Signed-off-by: Chris Wilson --- src/cairo-path-stroke-traps.c | 18 +++++++++-- src/cairo-traps-private.h | 5 +++ src/cairo-traps.c | 72 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 3 deletions(-) diff --git a/src/cairo-path-stroke-traps.c b/src/cairo-path-stroke-traps.c index 304dea7..c2e290c 100644 --- a/src/cairo-path-stroke-traps.c +++ b/src/cairo-path-stroke-traps.c @@ -929,15 +929,27 @@ spline_to (void *closure, join (stroker, &stroker->current_face, &face); } else { - cairo_point_t rectangle[4]; + cairo_point_t rectangle[4], triangle[3]; compute_face (&stroker->current_face.point, tangent, stroker, &face); - join (stroker, &stroker->current_face, &face); - rectangle[0] = face.cw; rectangle[1] = face.ccw; + rectangle[2] = stroker->current_face.cw; + rectangle[3] = stroker->current_face.ccw; + + triangle[0] = face.point; + if (join_is_clockwise (&face, &stroker->current_face)) { + triangle[1] = rectangle[1]; + triangle[2] = rectangle[3]; + } else { + triangle[1] = rectangle[0]; + triangle[2] = rectangle[2]; + } + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, + triangle, rectangle); + rectangle[2].x = point->x - face.point.x; rectangle[2].y = point->y - face.point.y; face.point = *point; diff --git a/src/cairo-traps-private.h b/src/cairo-traps-private.h index 7fef062..196d33e 100644 --- a/src/cairo-traps-private.h +++ b/src/cairo-traps-private.h @@ -95,6 +95,11 @@ _cairo_traps_tessellate_triangle (cairo_traps_t *traps, const cairo_point_t t[3]); cairo_private void +_cairo_traps_tessellate_triangle_with_edges (cairo_traps_t *traps, + const cairo_point_t t[3], + const cairo_point_t edges[4]); + +cairo_private void _cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, const cairo_point_t q[4]); diff --git a/src/cairo-traps.c b/src/cairo-traps.c index 9f1d4a7..cea96d5 100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -403,6 +403,78 @@ _cairo_traps_tessellate_triangle (cairo_traps_t *traps, _cairo_traps_tessellate_convex_quad (traps, quad); } +static void add_tri (cairo_traps_t *traps, + int y1, int y2, + cairo_line_t *left, + cairo_line_t *right) +{ + cairo_slope_t a, b; + + if (y2 < y1) { + int tmp = y1; + y1 = y2; + y2 = tmp; + } + + _cairo_slope_init (&a, &left->p1, &left->p2); + _cairo_slope_init (&b, &right->p1, &right->p2); + + if (_cairo_slope_compare (&a, &b) < 0) { + cairo_line_t *tmp = left; + left = right; + right = tmp; + } + + _cairo_traps_add_clipped_trap (traps, y1, y2, left, right); +} + +void +_cairo_traps_tessellate_triangle_with_edges (cairo_traps_t *traps, + const cairo_point_t t[3], + const cairo_point_t edges[4]) +{ + cairo_line_t lines[3]; + + if (edges[0].y <= edges[1].y) { + lines[0].p1 = edges[0]; + lines[0].p2 = edges[1]; + } else { + lines[0].p1 = edges[1]; + lines[0].p2 = edges[0]; + } + + if (edges[2].y <= edges[3].y) { + lines[1].p1 = edges[2]; + lines[1].p2 = edges[3]; + } else { + lines[1].p1 = edges[3]; + lines[1].p2 = edges[2]; + } + + if (t[1].y == t[2].y) { + add_tri (traps, t[0].y, t[1].y, &lines[0], &lines[1]); + return; + } + + if (t[1].y <= t[2].y) { + lines[2].p1 = t[1]; + lines[2].p2 = t[2]; + } else { + lines[2].p1 = t[2]; + lines[2].p2 = t[1]; + } + + if (((t[1].y - t[0].y) < 0) ^ ((t[2].y - t[0].y) < 0)) { + add_tri (traps, t[0].y, t[1].y, &lines[0], &lines[2]); + add_tri (traps, t[0].y, t[2].y, &lines[1], &lines[2]); + } else if (abs(t[1].y - t[0].y) < abs(t[2].y - t[0].y)) { + add_tri (traps, t[0].y, t[1].y, &lines[0], &lines[1]); + add_tri (traps, t[1].y, t[2].y, &lines[2], &lines[1]); + } else { + add_tri (traps, t[0].y, t[2].y, &lines[1], &lines[0]); + add_tri (traps, t[1].y, t[2].y, &lines[2], &lines[0]); + } +} /** * _cairo_traps_init_boxes: -- 1.9.3