mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-03 06:38:06 +02:00
[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:
parent
3bf8379408
commit
d7873eecc5
10 changed files with 333 additions and 331 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
256
src/cairo-pen.c
256
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 <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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue