Skip to content

Commit

Permalink
path-bounder: Simplify code
Browse files Browse the repository at this point in the history
If the path extents are tight, all the extents computations and
approximations become trivial except for the stroke extents.
  • Loading branch information
Andrea Canciani committed Oct 29, 2010
1 parent 958c56e commit 89e1261
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 193 deletions.
249 changes: 56 additions & 193 deletions src/cairo-path-bounds.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
Expand Down Expand Up @@ -35,56 +36,30 @@
*/

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

typedef struct cairo_path_bounder {
cairo_point_t current_point;
cairo_bool_t has_initial_point;
cairo_bool_t has_point;

typedef struct _cairo_path_bounder {
cairo_point_t current_point;
cairo_bool_t has_extents;
cairo_box_t extents;
} cairo_path_bounder_t;

static void
_cairo_path_bounder_init (cairo_path_bounder_t *bounder)
{
bounder->has_initial_point = FALSE;
bounder->has_point = FALSE;
}

static void
_cairo_path_bounder_add_point (cairo_path_bounder_t *bounder,
const cairo_point_t *point)
{
if (bounder->has_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;
} else {
bounder->extents.p1.x = point->x;
bounder->extents.p1.y = point->y;
bounder->extents.p2.x = point->x;
bounder->extents.p2.y = point->y;
bounder->has_point = TRUE;
}
}

static cairo_status_t
_cairo_path_bounder_move_to (void *closure,
const cairo_point_t *point)
{
cairo_path_bounder_t *bounder = closure;

bounder->current_point = *point;
bounder->has_initial_point = TRUE;

if (likely (bounder->has_extents)) {
_cairo_box_add_point (&bounder->extents, point);
} else {
bounder->has_extents = TRUE;
_cairo_box_set (&bounder->extents, point, point);
}

return CAIRO_STATUS_SUCCESS;
}
Expand All @@ -95,13 +70,8 @@ _cairo_path_bounder_line_to (void *closure,
{
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, point);
bounder->current_point = *point;
_cairo_box_add_point (&bounder->extents, point);

return CAIRO_STATUS_SUCCESS;
}
Expand All @@ -114,25 +84,12 @@ _cairo_path_bounder_curve_to (void *closure,
{
cairo_path_bounder_t *bounder = closure;

/* If the bbox of the control points is entirely inside, then we
* do not need to further evaluate the spline.
*/
if (! bounder->has_point ||
b->x < bounder->extents.p1.x || b->x > bounder->extents.p2.x ||
b->y < bounder->extents.p1.y || b->y > bounder->extents.p2.y ||
c->x < bounder->extents.p1.x || c->x > bounder->extents.p2.x ||
c->y < bounder->extents.p1.y || c->y > bounder->extents.p2.y ||
d->x < bounder->extents.p1.x || d->x > bounder->extents.p2.x ||
d->y < bounder->extents.p1.y || d->y > bounder->extents.p2.y)
{
return _cairo_spline_bound (_cairo_path_bounder_line_to, bounder,
&bounder->current_point, b, c, d);
}
else
{
/* All control points are within the current extents. */
return CAIRO_STATUS_SUCCESS;
}
_cairo_box_add_curve_to (&bounder->extents,
&bounder->current_point,
b, c, d);
bounder->current_point = *d;

return CAIRO_STATUS_SUCCESS;
}

static cairo_status_t
Expand All @@ -141,53 +98,40 @@ _cairo_path_bounder_close_path (void *closure)
return CAIRO_STATUS_SUCCESS;
}

/* This computes the extents of all the points in the path, not those of
* the damage area (i.e it does not consider winding and it only inspects
* the control points of the curves, not the flattened path).
*/
cairo_bool_t
_cairo_path_bounder_extents (const cairo_path_fixed_t *path,
cairo_box_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;

bounder.has_extents = FALSE;
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);

if (bounder.has_extents)
*extents = bounder.extents;

return bounder.has_extents;
}

void
_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *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;
}
_cairo_path_fixed_approximate_fill_extents (path, extents);
}

/* A slightly better approximation than above - we actually decompose the
* Bezier, but we continue to ignore winding.
*/
void
_cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;

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);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
}
_cairo_path_fixed_fill_extents (path, CAIRO_FILL_RULE_WINDING, 0, extents);
}

void
Expand All @@ -196,25 +140,9 @@ _cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
double tolerance,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;

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);
if (path->extents.p1.x < path->extents.p2.x &&
path->extents.p1.y < path->extents.p2.y) {
_cairo_box_round_to_rectangle (&path->extents, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
Expand All @@ -228,65 +156,18 @@ _cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
const cairo_matrix_t *ctm,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;

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

/* include trailing move-to for degenerate segments */
if (path->needs_move_to) {
const cairo_point_t *point = &path->current_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;

_cairo_stroke_style_max_distance_from_path (style, ctm, &dx, &dy);

bounder.extents.p1.x -= _cairo_fixed_from_double (dx);
bounder.extents.p2.x += _cairo_fixed_from_double (dx);
bounder.extents.p1.y -= _cairo_fixed_from_double (dy);
bounder.extents.p2.y += _cairo_fixed_from_double (dy);

_cairo_box_round_to_rectangle (&bounder.extents, extents);
} else if (bounder.has_initial_point) {
if (path->has_extents) {
cairo_box_t box_extents;
double dx, dy;

/* accommodate capping of degenerate paths */

box_extents = path->extents;
_cairo_stroke_style_max_distance_from_path (style, ctm, &dx, &dy);
box_extents.p1.x -= _cairo_fixed_from_double (dx);
box_extents.p1.y -= _cairo_fixed_from_double (dy);
box_extents.p2.x += _cairo_fixed_from_double (dx);
box_extents.p2.y += _cairo_fixed_from_double (dy);

bounder.extents.p1.x = bounder.current_point.x - _cairo_fixed_from_double (dx);
bounder.extents.p2.x = bounder.current_point.x + _cairo_fixed_from_double (dx);
bounder.extents.p1.y = bounder.current_point.y - _cairo_fixed_from_double (dy);
bounder.extents.p2.y = bounder.current_point.y + _cairo_fixed_from_double (dy);

_cairo_box_round_to_rectangle (&bounder.extents, extents);
_cairo_box_round_to_rectangle (&box_extents, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
Expand Down Expand Up @@ -326,24 +207,6 @@ 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->has_extents;
}

_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);

*box = bounder.extents;
return bounder.has_point;
*box = path->extents;
return path->has_extents;
}
5 changes: 5 additions & 0 deletions src/cairoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -1217,6 +1217,11 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path,
void *closure,
double tolerance);


cairo_private cairo_bool_t
_cairo_path_bounder_extents (const cairo_path_fixed_t *path,
cairo_box_t *box);

cairo_private cairo_bool_t
_cairo_path_fixed_extents (const cairo_path_fixed_t *path,
cairo_box_t *box);
Expand Down

0 comments on commit 89e1261

Please sign in to comment.