Skip to content

Commit

Permalink
[spline] Eliminate intermediate allocations during spline decomposition.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Chris Wilson committed Nov 16, 2008
1 parent 3bf8379 commit d7873ee
Show file tree
Hide file tree
Showing 10 changed files with 331 additions and 329 deletions.
12 changes: 3 additions & 9 deletions src/cairo-bentley-ottmann.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
23 changes: 8 additions & 15 deletions src/cairo-path-fill.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 9 additions & 18 deletions src/cairo-path-fixed.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 8 additions & 13 deletions src/cairo-path-in-fill.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down
101 changes: 53 additions & 48 deletions src/cairo-path-stroke.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;

Expand Down Expand Up @@ -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. */
Expand All @@ -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
Expand Down
Loading

0 comments on commit d7873ee

Please sign in to comment.