Skip to content

Commit

Permalink
path: Compute coarse bounds upon construction.
Browse files Browse the repository at this point in the history
Frequently we only need the coarse path bounds, so avoid walking over
the list of points once more as we can cheaply track the extents during
construction.
  • Loading branch information
Chris Wilson committed Jan 22, 2010
1 parent 6bfcf3e commit 6b77567
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 100 deletions.
6 changes: 6 additions & 0 deletions src/cairo-debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,12 @@ _cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path)
{
cairo_status_t status;

printf ("path: extents=(%f, %f), (%f, %f)\n",
_cairo_fixed_to_double (path->extents.p1.x),
_cairo_fixed_to_double (path->extents.p1.y),
_cairo_fixed_to_double (path->extents.p2.x),
_cairo_fixed_to_double (path->extents.p2.y));

status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_print_move_to,
Expand Down
21 changes: 16 additions & 5 deletions src/cairo-gstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -806,14 +806,25 @@ _cairo_gstate_path_extents (cairo_gstate_t *gstate,
double *x1, double *y1,
double *x2, double *y2)
{
cairo_box_t box;
double px1, py1, px2, py2;

_cairo_path_fixed_bounds (path,
&px1, &py1, &px2, &py2);
if (_cairo_path_fixed_extents (path, &box)) {
px1 = _cairo_fixed_to_double (box.p1.x);
py1 = _cairo_fixed_to_double (box.p1.y);
px2 = _cairo_fixed_to_double (box.p2.x);
py2 = _cairo_fixed_to_double (box.p2.y);

_cairo_gstate_backend_to_user_rectangle (gstate,
&px1, &py1, &px2, &py2,
NULL);
} else {
px1 = 0.0;
py1 = 0.0;
px2 = 0.0;
py2 = 0.0;
}

_cairo_gstate_backend_to_user_rectangle (gstate,
&px1, &py1, &px2, &py2,
NULL);
if (x1)
*x1 = px1;
if (y1)
Expand Down
159 changes: 77 additions & 82 deletions src/cairo-path-bounds.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
*/

#include "cairoint.h"
#include "cairo-path-fixed-private.h"

typedef struct cairo_path_bounder {
cairo_point_t current_point;
Expand Down Expand Up @@ -134,26 +135,6 @@ _cairo_path_bounder_curve_to (void *closure,
}
}

static cairo_status_t
_cairo_path_bounder_curve_to_cp (void *closure,
const cairo_point_t *b,
const cairo_point_t *c,
const cairo_point_t *d)
{
cairo_path_bounder_t *bounder = closure;

if (bounder->has_initial_point) {
_cairo_path_bounder_add_point (bounder, &bounder->current_point);
bounder->has_initial_point = FALSE;
}

_cairo_path_bounder_add_point (bounder, b);
_cairo_path_bounder_add_point (bounder, c);
_cairo_path_bounder_add_point (bounder, d);

return CAIRO_STATUS_SUCCESS;
}

static cairo_status_t
_cairo_path_bounder_close_path (void *closure)
{
Expand All @@ -168,21 +149,8 @@ void
_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;

_cairo_path_bounder_init (&bounder);

status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_curve_to_cp,
_cairo_path_bounder_close_path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);

if (bounder.has_point) {
_cairo_box_round_to_rectangle (&bounder.extents, extents);
if (path->extents.p1.x < path->extents.p2.x) {
_cairo_box_round_to_rectangle (&path->extents, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
Expand All @@ -199,15 +167,20 @@ _cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path,
cairo_path_bounder_t bounder;
cairo_status_t status;

_cairo_path_bounder_init (&bounder);

status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_curve_to,
_cairo_path_bounder_close_path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);
if (! path->has_curve_to) {
bounder.extents = path->extents;
bounder.has_point = path->extents.p1.x < path->extents.p2.x;
} else {
_cairo_path_bounder_init (&bounder);

status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_curve_to,
_cairo_path_bounder_close_path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);
}

if (bounder.has_point) {
_cairo_box_round_to_rectangle (&bounder.extents, extents);
Expand All @@ -226,14 +199,19 @@ _cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
cairo_path_bounder_t bounder;
cairo_status_t status;

_cairo_path_bounder_init (&bounder);

status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_close_path,
&bounder, tolerance);
assert (status == CAIRO_STATUS_SUCCESS);
if (! path->has_curve_to) {
bounder.extents = path->extents;
bounder.has_point = path->extents.p1.x < path->extents.p2.x;
} else {
_cairo_path_bounder_init (&bounder);

status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_close_path,
&bounder, tolerance);
assert (status == CAIRO_STATUS_SUCCESS);
}

if (bounder.has_point) {
_cairo_box_round_to_rectangle (&bounder.extents, extents);
Expand All @@ -247,21 +225,43 @@ _cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
void
_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
const const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;

_cairo_path_bounder_init (&bounder);
if (! path->has_curve_to) {
bounder.extents = path->extents;

status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_curve_to,
_cairo_path_bounder_close_path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);
/* include trailing move-to for degenerate segments */
if (path->has_last_move_point) {
const cairo_point_t *point = &path->last_move_point;

if (point->x < bounder.extents.p1.x)
bounder.extents.p1.x = point->x;
if (point->y < bounder.extents.p1.y)
bounder.extents.p1.y = point->y;

if (point->x > bounder.extents.p2.x)
bounder.extents.p2.x = point->x;
if (point->y > bounder.extents.p2.y)
bounder.extents.p2.y = point->y;
}

bounder.has_point = bounder.extents.p1.x <= bounder.extents.p2.x;
bounder.has_initial_point = FALSE;
} else {
_cairo_path_bounder_init (&bounder);

status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_curve_to,
_cairo_path_bounder_close_path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);
}

if (bounder.has_point) {
double dx, dy;
Expand Down Expand Up @@ -294,12 +294,12 @@ _cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
}

cairo_status_t
_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_rectangle_int_t *extents)
_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_rectangle_int_t *extents)
{
cairo_traps_t traps;
cairo_box_t bbox;
Expand All @@ -322,14 +322,18 @@ _cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
return status;
}

void
_cairo_path_fixed_bounds (const cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
cairo_bool_t
_cairo_path_fixed_extents (const cairo_path_fixed_t *path,
cairo_box_t *box)
{
cairo_path_bounder_t bounder;
cairo_status_t status;

if (! path->has_curve_to) {
*box = path->extents;
return path->extents.p1.x < path->extents.p2.x;
}

_cairo_path_bounder_init (&bounder);

status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
Expand All @@ -340,15 +344,6 @@ _cairo_path_fixed_bounds (const cairo_path_fixed_t *path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);

if (bounder.has_point) {
*x1 = _cairo_fixed_to_double (bounder.extents.p1.x);
*y1 = _cairo_fixed_to_double (bounder.extents.p1.y);
*x2 = _cairo_fixed_to_double (bounder.extents.p2.x);
*y2 = _cairo_fixed_to_double (bounder.extents.p2.y);
} else {
*x1 = 0.0;
*y1 = 0.0;
*x2 = 0.0;
*y2 = 0.0;
}
*box = bounder.extents;
return bounder.has_point;
}
4 changes: 3 additions & 1 deletion src/cairo-path-fixed-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,17 @@ struct _cairo_path_fixed {
cairo_point_t last_move_point;
cairo_point_t current_point;
unsigned int has_current_point : 1;
unsigned int has_last_move_point : 1;
unsigned int has_curve_to : 1;
unsigned int is_rectilinear : 1;
unsigned int maybe_fill_region : 1;
unsigned int is_empty_fill : 1;

cairo_box_t extents;

cairo_path_buf_fixed_t buf;
};


cairo_private void
_cairo_path_fixed_translate (cairo_path_fixed_t *path,
cairo_fixed_t offx,
Expand Down
Loading

0 comments on commit 6b77567

Please sign in to comment.