diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c index b22731df9..eca28d5ba 100644 --- a/src/cairo-bentley-ottmann.c +++ b/src/cairo-bentley-ottmann.c @@ -87,7 +87,7 @@ struct _cairo_bo_edge { cairo_bo_point32_t top; cairo_bo_point32_t middle; cairo_bo_point32_t bottom; - cairo_bool_t reversed; + int dir; cairo_bo_edge_t *prev; cairo_bo_edge_t *next; cairo_bo_trap_t *deferred_trap; @@ -1439,10 +1439,7 @@ _active_edges_to_traps (cairo_bo_edge_t *head, for (edge = head; edge; edge = edge->next) { if (fill_rule == CAIRO_FILL_RULE_WINDING) { - if (edge->reversed) - in_out++; - else - in_out--; + in_out += edge->dir; if (in_out == 0) { status = _cairo_bo_edge_end_trap (edge, top, bo_traps); if (status) @@ -1734,10 +1731,7 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps, edge->top.y = top.y; edge->bottom.x = bot.x; edge->bottom.y = bot.y; - /* XXX: The 'clockWise' name that cairo_polygon_t uses is - * totally bogus. It's really a (negated!) description of - * whether the edge is reversed. */ - edge->reversed = (! polygon->edges[i].clockWise); + edge->dir = polygon->edges[i].dir; edge->deferred_trap = NULL; edge->prev = NULL; edge->next = NULL; diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c index 1cef20e4a..46046bb9b 100644 --- a/src/cairo-path-fill.c +++ b/src/cairo-path-fill.c @@ -118,30 +118,23 @@ _cairo_filler_curve_to (void *closure, cairo_point_t *c, cairo_point_t *d) { - int i; - cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_filler_t *filler = closure; - cairo_polygon_t *polygon = &filler->polygon; cairo_spline_t spline; - status = _cairo_spline_init (&spline, &filler->current_point, b, c, d); - - if (status == CAIRO_INT_STATUS_DEGENERATE) + if (! _cairo_spline_init (&spline, + (cairo_add_point_func_t) _cairo_polygon_line_to, + &filler->polygon, + &filler->current_point, b, c, d)) + { return CAIRO_STATUS_SUCCESS; + } - status = _cairo_spline_decompose (&spline, filler->tolerance); - if (status) - goto CLEANUP_SPLINE; - - for (i = 1; i < spline.num_points; i++) - _cairo_polygon_line_to (polygon, &spline.points[i]); - - CLEANUP_SPLINE: + _cairo_spline_decompose (&spline, filler->tolerance); _cairo_spline_fini (&spline); filler->current_point = *d; - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index 027ebedf8..b36f4d8ef 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -890,33 +890,24 @@ _cpf_curve_to (void *closure, cairo_point_t *p3) { cpf_t *cpf = closure; - cairo_status_t status; cairo_spline_t spline; - int i; cairo_point_t *p0 = &cpf->current_point; - status = _cairo_spline_init (&spline, p0, p1, p2, p3); - if (status == CAIRO_INT_STATUS_DEGENERATE) + if (! _cairo_spline_init (&spline, + (cairo_add_point_func_t) cpf->line_to, + cpf->closure, + p0, p1, p2, p3)) + { return CAIRO_STATUS_SUCCESS; - - status = _cairo_spline_decompose (&spline, cpf->tolerance); - if (status) - goto out; - - for (i=1; i < spline.num_points; i++) { - status = cpf->line_to (cpf->closure, &spline.points[i]); - if (status) - goto out; } - cpf->current_point = *p3; + _cairo_spline_decompose (&spline, cpf->tolerance); + _cairo_spline_fini (&spline); - status = CAIRO_STATUS_SUCCESS; + cpf->current_point = *p3; - out: - _cairo_spline_fini (&spline); - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t diff --git a/src/cairo-path-in-fill.c b/src/cairo-path-in-fill.c index fcac9b134..2b9b057dc 100644 --- a/src/cairo-path-in-fill.c +++ b/src/cairo-path-in-fill.c @@ -165,8 +165,6 @@ _cairo_in_fill_curve_to (void *closure, cairo_in_fill_t *in_fill = closure; cairo_spline_t spline; cairo_fixed_t top, bot, left; - cairo_status_t status; - int i; /* first reject based on bbox */ bot = top = in_fill->current_point.y; @@ -187,21 +185,18 @@ _cairo_in_fill_curve_to (void *closure, return CAIRO_STATUS_SUCCESS; /* XXX Investigate direct inspection of the inflections? */ - status = _cairo_spline_init (&spline, &in_fill->current_point, b, c, d); - if (status == CAIRO_INT_STATUS_DEGENERATE) + if (! _cairo_spline_init (&spline, + (cairo_add_point_func_t) _cairo_in_fill_line_to, + in_fill, + &in_fill->current_point, b, c, d)) + { return CAIRO_STATUS_SUCCESS; + } - status = _cairo_spline_decompose (&spline, in_fill->tolerance); - if (status) - goto CLEANUP_SPLINE; - - for (i = 1; i < spline.num_points; i++) - _cairo_in_fill_line_to (in_fill, &spline.points[i]); - - CLEANUP_SPLINE: + _cairo_spline_decompose (&spline, in_fill->tolerance); _cairo_spline_fini (&spline); - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c index efccbcfea..3c02a94c2 100644 --- a/src/cairo-path-stroke.c +++ b/src/cairo-path-stroke.c @@ -283,13 +283,17 @@ _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_st tri[0] = in->point; if (clockwise) { - _cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector, &start); + start = + _cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector); + stop = + _cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector); 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); + start = + _cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector); + stop = + _cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector); step = +1; - _cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector, &stop); } i = start; @@ -494,10 +498,10 @@ _cairo_stroker_add_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f) cairo_pen_t *pen = &stroker->pen; slope = f->dev_vector; - _cairo_pen_find_active_cw_vertex_index (pen, &slope, &start); + start = _cairo_pen_find_active_cw_vertex_index (pen, &slope); slope.dx = -slope.dx; slope.dy = -slope.dy; - _cairo_pen_find_active_cw_vertex_index (pen, &slope, &stop); + stop = _cairo_pen_find_active_cw_vertex_index (pen, &slope); tri[0] = f->point; tri[1] = f->cw; @@ -968,40 +972,51 @@ _cairo_stroker_curve_to (void *closure, cairo_point_t *c, cairo_point_t *d) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_stroker_t *stroker = closure; - cairo_spline_t spline; - cairo_pen_t pen; + cairo_pen_stroke_spline_t spline_pen; cairo_stroke_face_t start, end; cairo_point_t extra_points[4]; cairo_point_t *a = &stroker->current_point; double initial_slope_dx, initial_slope_dy; double final_slope_dx, final_slope_dy; + cairo_status_t status; - status = _cairo_spline_init (&spline, a, b, c, d); + status = _cairo_pen_stroke_spline_init (&spline_pen, + &stroker->pen, + a, b, c, d); if (status == CAIRO_INT_STATUS_DEGENERATE) return _cairo_stroker_line_to (closure, d); + else if (status) + return status; - status = _cairo_pen_init_copy (&pen, &stroker->pen); - if (status) - goto CLEANUP_SPLINE; - - initial_slope_dx = _cairo_fixed_to_double (spline.initial_slope.dx); - initial_slope_dy = _cairo_fixed_to_double (spline.initial_slope.dy); - final_slope_dx = _cairo_fixed_to_double (spline.final_slope.dx); - final_slope_dy = _cairo_fixed_to_double (spline.final_slope.dy); + initial_slope_dx = _cairo_fixed_to_double (spline_pen.spline.initial_slope.dx); + initial_slope_dy = _cairo_fixed_to_double (spline_pen.spline.initial_slope.dy); + final_slope_dx = _cairo_fixed_to_double (spline_pen.spline.final_slope.dx); + final_slope_dy = _cairo_fixed_to_double (spline_pen.spline.final_slope.dy); - if (_compute_normalized_device_slope (&initial_slope_dx, &initial_slope_dy, stroker->ctm_inverse, NULL)) - _compute_face (a, &spline.initial_slope, initial_slope_dx, initial_slope_dy, stroker, &start); + if (_compute_normalized_device_slope (&initial_slope_dx, &initial_slope_dy, + stroker->ctm_inverse, NULL)) + { + _compute_face (a, + &spline_pen.spline.initial_slope, + initial_slope_dx, initial_slope_dy, + stroker, &start); + } - if (_compute_normalized_device_slope (&final_slope_dx, &final_slope_dy, stroker->ctm_inverse, NULL)) - _compute_face (d, &spline.final_slope, final_slope_dx, final_slope_dy, stroker, &end); + if (_compute_normalized_device_slope (&final_slope_dx, &final_slope_dy, + stroker->ctm_inverse, NULL)) + { + _compute_face (d, + &spline_pen.spline.final_slope, + final_slope_dx, final_slope_dy, + stroker, &end); + } if (stroker->has_current_face) { status = _cairo_stroker_join (stroker, &stroker->current_face, &start); if (status) goto CLEANUP_PEN; - } else if (!stroker->has_first_face) { + } else if (! stroker->has_first_face) { stroker->first_face = start; stroker->has_first_face = TRUE; } @@ -1021,18 +1036,16 @@ _cairo_stroker_curve_to (void *closure, extra_points[3].x -= end.point.x; extra_points[3].y -= end.point.y; - status = _cairo_pen_add_points (&pen, extra_points, 4); + status = _cairo_pen_add_points (&spline_pen.pen, extra_points, 4); if (status) goto CLEANUP_PEN; - status = _cairo_pen_stroke_spline (&pen, &spline, stroker->tolerance, stroker->traps); - if (status) - goto CLEANUP_PEN; + status = _cairo_pen_stroke_spline (&spline_pen, + stroker->tolerance, + stroker->traps); CLEANUP_PEN: - _cairo_pen_fini (&pen); - CLEANUP_SPLINE: - _cairo_spline_fini (&spline); + _cairo_pen_stroke_spline_fini (&spline_pen); stroker->current_point = *d; @@ -1063,16 +1076,20 @@ _cairo_stroker_curve_to_dashed (void *closure, cairo_point_t *c, cairo_point_t *d) { - cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_stroker_t *stroker = closure; cairo_spline_t spline; cairo_point_t *a = &stroker->current_point; cairo_line_join_t line_join_save; - int i; - status = _cairo_spline_init (&spline, a, b, c, d); - if (status == CAIRO_INT_STATUS_DEGENERATE) + if (! _cairo_spline_init (&spline, + stroker->dashed ? + (cairo_add_point_func_t) _cairo_stroker_line_to_dashed : + (cairo_add_point_func_t) _cairo_stroker_line_to, + stroker, + a, b, c, d)) + { return _cairo_stroker_line_to_dashed (closure, d); + } /* If the line width is so small that the pen is reduced to a single point, then we have nothing to do. */ @@ -1084,26 +1101,14 @@ _cairo_stroker_curve_to_dashed (void *closure, line_join_save = stroker->style->line_join; stroker->style->line_join = CAIRO_LINE_JOIN_ROUND; - status = _cairo_spline_decompose (&spline, stroker->tolerance); - if (status) - goto CLEANUP_GSTATE; - - for (i = 1; i < spline.num_points; i++) { - if (stroker->dashed) - status = _cairo_stroker_line_to_dashed (stroker, &spline.points[i]); - else - status = _cairo_stroker_line_to (stroker, &spline.points[i]); - if (status) - break; - } + _cairo_spline_decompose (&spline, stroker->tolerance); - CLEANUP_GSTATE: stroker->style->line_join = line_join_save; CLEANUP_SPLINE: _cairo_spline_fini (&spline); - return status; + return CAIRO_STATUS_SUCCESS; } static cairo_status_t diff --git a/src/cairo-pen.c b/src/cairo-pen.c index 425b3b965..43d344a19 100644 --- a/src/cairo-pen.c +++ b/src/cairo-pen.c @@ -1,6 +1,7 @@ /* cairo - a vector graphics library with display and print output * * Copyright © 2002 University of Southern California + * Copyright © 2008 Chris Wilson * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -32,6 +33,7 @@ * * Contributor(s): * Carl D. Worth + * Chris Wilson */ #include "cairoint.h" @@ -42,9 +44,6 @@ _cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *mat static void _cairo_pen_compute_slopes (cairo_pen_t *pen); -static void -_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_direction_t dir, cairo_polygon_t *polygon); - cairo_status_t _cairo_pen_init (cairo_pen_t *pen, double radius, @@ -104,7 +103,7 @@ _cairo_pen_fini (cairo_pen_t *pen) } cairo_status_t -_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other) +_cairo_pen_init_copy (cairo_pen_t *pen, const cairo_pen_t *other) { *pen = *other; @@ -323,10 +322,9 @@ _cairo_pen_compute_slopes (cairo_pen_t *pen) * pen's "extra points" from the spline's initial and final slopes are * properly found when beginning the spline stroking.] */ -void -_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen, - cairo_slope_t *slope, - int *active) +int +_cairo_pen_find_active_cw_vertex_index (const cairo_pen_t *pen, + const cairo_slope_t *slope) { int i; @@ -344,7 +342,7 @@ _cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen, if (i == pen->num_vertices) i = 0; - *active = i; + return i; } /* Find active pen vertex for counterclockwise edge of stroke at the given slope. @@ -352,13 +350,12 @@ _cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen, * Note: See the comments for _cairo_pen_find_active_cw_vertex_index * for some details about the strictness of the inequalities here. */ -void -_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen, - cairo_slope_t *slope, - int *active) +int +_cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen, + const cairo_slope_t *slope) { - int i; cairo_slope_t slope_reverse; + int i; slope_reverse = *slope; slope_reverse.dx = -slope_reverse.dx; @@ -378,56 +375,26 @@ _cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen, if (i < 0) i = pen->num_vertices - 1; - *active = i; + return i; } -static void -_cairo_pen_stroke_spline_half (cairo_pen_t *pen, - cairo_spline_t *spline, - cairo_direction_t dir, - cairo_polygon_t *polygon) +static int +_cairo_pen_stroke_spline_add_convolved_point (cairo_pen_stroke_spline_t *stroker, + const cairo_point_t *last_point, + const cairo_slope_t *slope, + cairo_point_t *last_hull_point, + int active, + int step) { - int i; - int start, stop, step; - int active = 0; - cairo_point_t hull_point; - cairo_slope_t slope, initial_slope, final_slope; - cairo_point_t *point = spline->points; - int num_points = spline->num_points; - - if (dir == CAIRO_DIRECTION_FORWARD) { - start = 0; - stop = num_points; - step = 1; - initial_slope = spline->initial_slope; - final_slope = spline->final_slope; - } else { - start = num_points - 1; - stop = -1; - step = -1; - initial_slope = spline->final_slope; - initial_slope.dx = -initial_slope.dx; - initial_slope.dy = -initial_slope.dy; - final_slope = spline->initial_slope; - final_slope.dx = -final_slope.dx; - final_slope.dy = -final_slope.dy; - } - - _cairo_pen_find_active_cw_vertex_index (pen, - &initial_slope, - &active); + do { + cairo_point_t hull_point; - i = start; - while (i != stop) { - hull_point.x = point[i].x + pen->vertices[active].point.x; - hull_point.y = point[i].y + pen->vertices[active].point.y; - - _cairo_polygon_line_to (polygon, &hull_point); - - if (i + step == stop) - slope = final_slope; - else - _cairo_slope_init (&slope, &point[i], &point[i+step]); + hull_point.x = last_point->x + stroker->pen.vertices[active].point.x; + hull_point.y = last_point->y + stroker->pen.vertices[active].point.y; + _cairo_polygon_add_edge (&stroker->polygon, + last_hull_point, &hull_point, + step); + *last_hull_point = hull_point; /* The strict inequalities here ensure that if a spline slope * compares identically with either of the slopes of the @@ -439,53 +406,164 @@ _cairo_pen_stroke_spline_half (cairo_pen_t *pen, * consider it unequal and reject. This is due to the inherent * ambiguity when comparing slopes that differ by exactly * pi. */ - if (_cairo_slope_compare (&slope, &pen->vertices[active].slope_ccw) > 0) { - if (++active == pen->num_vertices) + if (_cairo_slope_compare (slope, + &stroker->pen.vertices[active].slope_ccw) > 0) + { + if (++active == stroker->pen.num_vertices) active = 0; - } else if (_cairo_slope_compare (&slope, &pen->vertices[active].slope_cw) < 0) { + } + else if (_cairo_slope_compare (slope, + &stroker->pen.vertices[active].slope_cw) < 0) + { if (--active == -1) - active = pen->num_vertices - 1; - } else { - i += step; + active = stroker->pen.num_vertices - 1; } - } + else + { + return active; + } + } while (TRUE); } + /* Compute outline of a given spline using the pen. - The trapezoids needed to fill that outline will be added to traps -*/ + * The trapezoids needed to fill that outline will be added to traps + */ cairo_status_t -_cairo_pen_stroke_spline (cairo_pen_t *pen, - cairo_spline_t *spline, - double tolerance, - cairo_traps_t *traps) +_cairo_pen_stroke_spline (cairo_pen_stroke_spline_t *stroker, + double tolerance, + cairo_traps_t *traps) { cairo_status_t status; - cairo_polygon_t polygon; + cairo_slope_t slope; /* If the line width is so small that the pen is reduced to a single point, then we have nothing to do. */ - if (pen->num_vertices <= 1) + if (stroker->pen.num_vertices <= 1) return CAIRO_STATUS_SUCCESS; - _cairo_polygon_init (&polygon); - - status = _cairo_spline_decompose (spline, tolerance); + /* open the polygon */ + slope = stroker->spline.initial_slope; + stroker->forward_vertex = + _cairo_pen_find_active_cw_vertex_index (&stroker->pen, &slope); + stroker->forward_hull_point.x = stroker->last_point.x + + stroker->pen.vertices[stroker->forward_vertex].point.x; + stroker->forward_hull_point.y = stroker->last_point.y + + stroker->pen.vertices[stroker->forward_vertex].point.y; + + slope.dx = -slope.dx; + slope.dy = -slope.dy; + stroker->backward_vertex = + _cairo_pen_find_active_cw_vertex_index (&stroker->pen, &slope); + stroker->backward_hull_point.x = stroker->last_point.x + + stroker->pen.vertices[stroker->backward_vertex].point.x; + stroker->backward_hull_point.y = stroker->last_point.y + + stroker->pen.vertices[stroker->backward_vertex].point.y; + + _cairo_polygon_add_edge (&stroker->polygon, + &stroker->backward_hull_point, + &stroker->forward_hull_point, + 1); + + _cairo_spline_decompose (&stroker->spline, tolerance); + + /* close the polygon */ + slope = stroker->spline.final_slope; + _cairo_pen_stroke_spline_add_convolved_point (stroker, + &stroker->last_point, + &slope, + &stroker->forward_hull_point, + stroker->forward_vertex, + 1); + + slope.dx = -slope.dx; + slope.dy = -slope.dy; + _cairo_pen_stroke_spline_add_convolved_point (stroker, + &stroker->last_point, + &slope, + &stroker->backward_hull_point, + stroker->backward_vertex, + -1); + + _cairo_polygon_add_edge (&stroker->polygon, + &stroker->forward_hull_point, + &stroker->backward_hull_point, + 1); + + status = _cairo_polygon_status (&stroker->polygon); if (status) goto BAIL; - _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_FORWARD, &polygon); + status = _cairo_bentley_ottmann_tessellate_polygon (traps, + &stroker->polygon, + CAIRO_FILL_RULE_WINDING); +BAIL: - _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_REVERSE, &polygon); + return status; +} - _cairo_polygon_close (&polygon); - status = _cairo_polygon_status (&polygon); - if (status) - goto BAIL; +static void +_cairo_pen_stroke_spline_add_point (cairo_pen_stroke_spline_t *stroker, + const cairo_point_t *point) +{ + cairo_slope_t slope; + + _cairo_slope_init (&slope, &stroker->last_point, point); + stroker->forward_vertex = + _cairo_pen_stroke_spline_add_convolved_point (stroker, + &stroker->last_point, + &slope, + &stroker->forward_hull_point, + stroker->forward_vertex, + 1); + + slope.dx = -slope.dx; + slope.dy = -slope.dy; + stroker->backward_vertex = + _cairo_pen_stroke_spline_add_convolved_point (stroker, + &stroker->last_point, + &slope, + &stroker->backward_hull_point, + stroker->backward_vertex, + -1); + stroker->last_point = *point; +} - status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING); -BAIL: - _cairo_polygon_fini (&polygon); +cairo_int_status_t +_cairo_pen_stroke_spline_init (cairo_pen_stroke_spline_t *stroker, + const cairo_pen_t *pen, + const cairo_point_t *a, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d) +{ + cairo_int_status_t status; - return status; + if (! _cairo_spline_init (&stroker->spline, + (cairo_add_point_func_t) _cairo_pen_stroke_spline_add_point, + stroker, + a, b, c, d)) + { + return CAIRO_INT_STATUS_DEGENERATE; + } + + status = _cairo_pen_init_copy (&stroker->pen, pen); + if (status) { + _cairo_spline_fini (&stroker->spline); + return status; + } + + _cairo_polygon_init (&stroker->polygon); + + stroker->last_point = *a; + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_pen_stroke_spline_fini (cairo_pen_stroke_spline_t *stroker) +{ + _cairo_polygon_fini (&stroker->polygon); + _cairo_spline_fini (&stroker->spline); + _cairo_pen_fini (&stroker->pen); } diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c index 1392bfa18..95cadc9cc 100644 --- a/src/cairo-polygon.c +++ b/src/cairo-polygon.c @@ -84,16 +84,17 @@ _cairo_polygon_grow (cairo_polygon_t *polygon) return TRUE; } -static void +void _cairo_polygon_add_edge (cairo_polygon_t *polygon, const cairo_point_t *p1, - const cairo_point_t *p2) + const cairo_point_t *p2, + int dir) { cairo_edge_t *edge; /* drop horizontal edges */ if (p1->y == p2->y) - goto DONE; + return; if (polygon->num_edges == polygon->edges_size) { if (! _cairo_polygon_grow (polygon)) @@ -104,15 +105,12 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon, if (p1->y < p2->y) { edge->edge.p1 = *p1; edge->edge.p2 = *p2; - edge->clockWise = 1; + edge->dir = dir; } else { edge->edge.p1 = *p2; edge->edge.p2 = *p1; - edge->clockWise = 0; + edge->dir = -dir; } - - DONE: - _cairo_polygon_move_to (polygon, p2); } void @@ -131,9 +129,9 @@ _cairo_polygon_line_to (cairo_polygon_t *polygon, const cairo_point_t *point) { if (polygon->has_current_point) - _cairo_polygon_add_edge (polygon, &polygon->current_point, point); - else - _cairo_polygon_move_to (polygon, point); + _cairo_polygon_add_edge (polygon, &polygon->current_point, point, 1); + + _cairo_polygon_move_to (polygon, point); } void @@ -142,7 +140,8 @@ _cairo_polygon_close (cairo_polygon_t *polygon) if (polygon->has_current_point) { _cairo_polygon_add_edge (polygon, &polygon->current_point, - &polygon->first_point); + &polygon->first_point, + 1); polygon->has_current_point = FALSE; } diff --git a/src/cairo-spline.c b/src/cairo-spline.c index b39257e25..7ec1c56c1 100644 --- a/src/cairo-spline.c +++ b/src/cairo-spline.c @@ -36,29 +36,16 @@ #include "cairoint.h" -static cairo_status_t -_cairo_spline_grow (cairo_spline_t *spline); - -static cairo_status_t -_cairo_spline_add_point (cairo_spline_t *spline, const cairo_point_t *point); - -static void -_lerp_half (const cairo_point_t *a, const cairo_point_t *b, cairo_point_t *result); - -static void -_de_casteljau (cairo_spline_knots_t *s1, cairo_spline_knots_t *s2); - -static double -_cairo_spline_error_squared (const cairo_spline_knots_t *spline); - -static cairo_status_t -_cairo_spline_decompose_into (cairo_spline_knots_t *spline, double tolerance_squared, cairo_spline_t *result); - -cairo_int_status_t +cairo_bool_t _cairo_spline_init (cairo_spline_t *spline, + void (*add_point_func) (void*, const cairo_point_t *), + void *closure, const cairo_point_t *a, const cairo_point_t *b, const cairo_point_t *c, const cairo_point_t *d) { + spline->add_point_func = add_point_func; + spline->closure = closure; + spline->knots.a = *a; spline->knots.b = *b; spline->knots.c = *c; @@ -71,7 +58,7 @@ _cairo_spline_init (cairo_spline_t *spline, else if (a->x != d->x || a->y != d->y) _cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.d); else - return CAIRO_INT_STATUS_DEGENERATE; + return FALSE; if (c->x != d->x || c->y != d->y) _cairo_slope_init (&spline->final_slope, &spline->knots.c, &spline->knots.d); @@ -80,74 +67,25 @@ _cairo_spline_init (cairo_spline_t *spline, else _cairo_slope_init (&spline->final_slope, &spline->knots.a, &spline->knots.d); - spline->points = spline->points_embedded; - spline->points_size = ARRAY_LENGTH (spline->points_embedded); - spline->num_points = 0; - - return CAIRO_STATUS_SUCCESS; + return TRUE; } void _cairo_spline_fini (cairo_spline_t *spline) { - if (spline->points != spline->points_embedded) - free (spline->points); - - spline->points = spline->points_embedded; - spline->points_size = ARRAY_LENGTH (spline->points_embedded); - spline->num_points = 0; -} - -/* make room for at least one more point */ -static cairo_status_t -_cairo_spline_grow (cairo_spline_t *spline) -{ - cairo_point_t *new_points; - int old_size = spline->points_size; - int new_size = 2 * MAX (old_size, 16); - - assert (spline->num_points <= spline->points_size); - - if (spline->points == spline->points_embedded) { - new_points = _cairo_malloc_ab (new_size, sizeof (cairo_point_t)); - if (new_points) - memcpy (new_points, spline->points, old_size * sizeof (cairo_point_t)); - } else { - new_points = _cairo_realloc_ab (spline->points, - new_size, sizeof (cairo_point_t)); - } - - if (new_points == NULL) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - spline->points = new_points; - spline->points_size = new_size; - - return CAIRO_STATUS_SUCCESS; } -static cairo_status_t +static void _cairo_spline_add_point (cairo_spline_t *spline, const cairo_point_t *point) { - cairo_status_t status; cairo_point_t *prev; - if (spline->num_points) { - prev = &spline->points[spline->num_points - 1]; - if (prev->x == point->x && prev->y == point->y) - return CAIRO_STATUS_SUCCESS; - } - - if (spline->num_points >= spline->points_size) { - status = _cairo_spline_grow (spline); - if (status) - return status; - } - - spline->points[spline->num_points] = *point; - spline->num_points++; + prev = &spline->last_point; + if (prev->x == point->x && prev->y == point->y) + return; - return CAIRO_STATUS_SUCCESS; + spline->add_point_func (spline->closure, point); + spline->last_point = *point; } static void @@ -243,45 +181,28 @@ _cairo_spline_error_squared (const cairo_spline_knots_t *knots) return cerr; } -static cairo_status_t +static void _cairo_spline_decompose_into (cairo_spline_knots_t *s1, double tolerance_squared, cairo_spline_t *result) { cairo_spline_knots_t s2; - cairo_status_t status; if (_cairo_spline_error_squared (s1) < tolerance_squared) return _cairo_spline_add_point (result, &s1->a); _de_casteljau (s1, &s2); - status = _cairo_spline_decompose_into (s1, tolerance_squared, result); - if (status) - return status; - - status = _cairo_spline_decompose_into (&s2, tolerance_squared, result); - if (status) - return status; - - return CAIRO_STATUS_SUCCESS; + _cairo_spline_decompose_into (s1, tolerance_squared, result); + _cairo_spline_decompose_into (&s2, tolerance_squared, result); } -cairo_status_t +void _cairo_spline_decompose (cairo_spline_t *spline, double tolerance) { - cairo_status_t status; cairo_spline_knots_t s1; - /* reset the spline, but keep the buffer */ - spline->num_points = 0; - s1 = spline->knots; - status = _cairo_spline_decompose_into (&s1, tolerance * tolerance, spline); - if (status) - return status; - - status = _cairo_spline_add_point (spline, &spline->knots.d); - if (status) - return status; + spline->last_point = s1.a; + _cairo_spline_decompose_into (&s1, tolerance * tolerance, spline); - return CAIRO_STATUS_SUCCESS; + _cairo_spline_add_point (spline, &spline->knots.d); } diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h index 905bc401b..6f1354d65 100644 --- a/src/cairo-types-private.h +++ b/src/cairo-types-private.h @@ -265,9 +265,7 @@ typedef enum _cairo_clip_mode { typedef struct _cairo_edge { cairo_line_t edge; - int clockWise; - - cairo_fixed_t current_x; + int dir; } cairo_edge_t; typedef struct _cairo_polygon { @@ -287,15 +285,16 @@ typedef struct _cairo_spline_knots { cairo_point_t a, b, c, d; } cairo_spline_knots_t; typedef struct _cairo_spline { + void (*add_point_func) (void *, const cairo_point_t *); + void *closure; + cairo_spline_knots_t knots; cairo_slope_t initial_slope; cairo_slope_t final_slope; - int num_points; - int points_size; - cairo_point_t *points; - cairo_point_t points_embedded[64]; + cairo_bool_t has_point; + cairo_point_t last_point; } cairo_spline_t; typedef struct _cairo_pen_vertex { diff --git a/src/cairoint.h b/src/cairoint.h index 940e33c50..c0e9b2174 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -2114,7 +2114,7 @@ cairo_private void _cairo_pen_init_empty (cairo_pen_t *pen); cairo_private cairo_status_t -_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other); +_cairo_pen_init_copy (cairo_pen_t *pen, const cairo_pen_t *other); cairo_private void _cairo_pen_fini (cairo_pen_t *pen); @@ -2129,21 +2129,40 @@ _cairo_pen_add_points_for_slopes (cairo_pen_t *pen, cairo_point_t *c, cairo_point_t *d); -cairo_private void -_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen, - cairo_slope_t *slope, - int *active); +cairo_private int +_cairo_pen_find_active_cw_vertex_index (const cairo_pen_t *pen, + const cairo_slope_t *slope); -cairo_private void -_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen, - cairo_slope_t *slope, - int *active); +cairo_private int +_cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen, + const cairo_slope_t *slope); + +typedef struct _cairo_pen_stroke_spline { + cairo_pen_t pen; + cairo_spline_t spline; + cairo_polygon_t polygon; + cairo_point_t last_point; + cairo_point_t forward_hull_point; + cairo_point_t backward_hull_point; + int forward_vertex; + int backward_vertex; +} cairo_pen_stroke_spline_t; + +cairo_private cairo_int_status_t +_cairo_pen_stroke_spline_init (cairo_pen_stroke_spline_t *stroker, + const cairo_pen_t *pen, + const cairo_point_t *a, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d); cairo_private cairo_status_t -_cairo_pen_stroke_spline (cairo_pen_t *pen, - cairo_spline_t *spline, - double tolerance, - cairo_traps_t *traps); +_cairo_pen_stroke_spline (cairo_pen_stroke_spline_t *pen, + double tolerance, + cairo_traps_t *traps); + +cairo_private void +_cairo_pen_stroke_spline_fini (cairo_pen_stroke_spline_t *stroker); /* cairo-polygon.c */ cairo_private void @@ -2152,6 +2171,12 @@ _cairo_polygon_init (cairo_polygon_t *polygon); cairo_private void _cairo_polygon_fini (cairo_polygon_t *polygon); +cairo_private void +_cairo_polygon_add_edge (cairo_polygon_t *polygon, + const cairo_point_t *p1, + const cairo_point_t *p2, + int dir); + cairo_private void _cairo_polygon_move_to (cairo_polygon_t *polygon, const cairo_point_t *point); @@ -2166,14 +2191,16 @@ _cairo_polygon_close (cairo_polygon_t *polygon); #define _cairo_polygon_status(P) (P)->status /* cairo-spline.c */ -cairo_private cairo_int_status_t +typedef void (*cairo_add_point_func_t) (void*, const cairo_point_t *); + +cairo_private cairo_bool_t _cairo_spline_init (cairo_spline_t *spline, - const cairo_point_t *a, - const cairo_point_t *b, - const cairo_point_t *c, - const cairo_point_t *d); + cairo_add_point_func_t add_point_func, + void *closure, + const cairo_point_t *a, const cairo_point_t *b, + const cairo_point_t *c, const cairo_point_t *d); -cairo_private cairo_status_t +cairo_private void _cairo_spline_decompose (cairo_spline_t *spline, double tolerance); cairo_private void