[spline] Eliminate intermediate allocations during spline decomposition.

The spline decomposition code allocates and stores points in a temporary
buffer which is immediately consumed by the caller. If the caller supplies
a callback that handles each point computed along the spline, then we can
use the point immediately and avoid the allocation.
This commit is contained in:
Chris Wilson 2008-11-14 17:18:47 +00:00
parent 3bf8379408
commit d7873eecc5
10 changed files with 333 additions and 331 deletions

View file

@ -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;

View file

@ -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

View file

@ -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;
}
_cairo_spline_decompose (&spline, cpf->tolerance);
_cairo_spline_fini (&spline);
cpf->current_point = *p3;
status = CAIRO_STATUS_SUCCESS;
out:
_cairo_spline_fini (&spline);
return status;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t

View file

@ -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

View file

@ -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_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);
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);
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 (&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 (&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;
_cairo_spline_decompose (&spline, stroker->tolerance);
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;
}
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

View file

@ -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 <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#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;
do {
cairo_point_t hull_point;
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);
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) {
if (--active == -1)
active = pen->num_vertices - 1;
} else {
i += step;
}
}
else if (_cairo_slope_compare (slope,
&stroker->pen.vertices[active].slope_cw) < 0)
{
if (--active == -1)
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);
/* 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;
status = _cairo_spline_decompose (spline, tolerance);
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);
_cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_REVERSE, &polygon);
_cairo_polygon_close (&polygon);
status = _cairo_polygon_status (&polygon);
if (status)
goto BAIL;
status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING);
status = _cairo_bentley_ottmann_tessellate_polygon (traps,
&stroker->polygon,
CAIRO_FILL_RULE_WINDING);
BAIL:
_cairo_polygon_fini (&polygon);
return status;
}
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;
}
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;
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);
}

View file

@ -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;
}

View file

@ -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;
}
prev = &spline->last_point;
if (prev->x == point->x && prev->y == point->y)
return;
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++;
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;
spline->last_point = s1.a;
_cairo_spline_decompose_into (&s1, tolerance * tolerance, spline);
status = _cairo_spline_add_point (spline, &spline->knots.d);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
_cairo_spline_add_point (spline, &spline->knots.d);
}

View file

@ -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 {

View file

@ -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
_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);
typedef void (*cairo_add_point_func_t) (void*, const cairo_point_t *);
cairo_private cairo_status_t
cairo_private cairo_bool_t
_cairo_spline_init (cairo_spline_t *spline,
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 void
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance);
cairo_private void