From 1645352bfb69cc6d43fcbf3c77b4da5693af322a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Jul 2009 09:09:42 +0100 Subject: [PATCH] [path] Evaluate is_box && is_region during construction Whilst constructing the path, if the operations continue to be axis-aligned lines, allow the is_box and is_region flags to persist. These are set to false as soon as a curve-to is added, a diagonal or in the case of is_region a non-integer point. --- src/cairo-path-fixed-private.h | 8 + src/cairo-path-fixed.c | 288 ++++++++++++--------------------- src/cairo.c | 2 + src/cairoint.h | 3 - 4 files changed, 116 insertions(+), 185 deletions(-) diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h index 0ade98806..5df184938 100644 --- a/src/cairo-path-fixed-private.h +++ b/src/cairo-path-fixed-private.h @@ -73,6 +73,8 @@ struct _cairo_path_fixed { cairo_point_t current_point; unsigned int has_current_point : 1; unsigned int has_curve_to : 1; + unsigned int is_box : 1; + unsigned int is_region : 1; cairo_path_buf_t *buf_tail; cairo_path_buf_fixed_t buf_head; @@ -105,4 +107,10 @@ _cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter, cairo_private cairo_bool_t _cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter); +static inline cairo_bool_t +_cairo_path_fixed_is_region (cairo_path_fixed_t *path) +{ + return path->is_region; +} + #endif /* CAIRO_PATH_FIXED_PRIVATE_H */ diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index f95c64ac8..5574e2d1e 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -42,10 +42,10 @@ /* private functions */ static cairo_status_t -_cairo_path_fixed_add (cairo_path_fixed_t *path, - cairo_path_op_t op, - cairo_point_t *points, - int num_points); +_cairo_path_fixed_add (cairo_path_fixed_t *path, + cairo_path_op_t op, + const cairo_point_t *points, + int num_points); static void _cairo_path_fixed_add_buf (cairo_path_fixed_t *path, @@ -62,9 +62,9 @@ _cairo_path_buf_add_op (cairo_path_buf_t *buf, cairo_path_op_t op); static void -_cairo_path_buf_add_points (cairo_path_buf_t *buf, - cairo_point_t *points, - int num_points); +_cairo_path_buf_add_points (cairo_path_buf_t *buf, + const cairo_point_t *points, + int num_points); void _cairo_path_fixed_init (cairo_path_fixed_t *path) @@ -85,6 +85,8 @@ _cairo_path_fixed_init (cairo_path_fixed_t *path) path->current_point.y = 0; path->has_current_point = FALSE; path->has_curve_to = FALSE; + path->is_region = TRUE; + path->is_box = TRUE; path->last_move_point = path->current_point; } @@ -99,8 +101,10 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path, path->current_point = other->current_point; path->has_current_point = other->has_current_point; - path->has_curve_to = other->has_curve_to; path->last_move_point = other->last_move_point; + path->has_curve_to = other->has_curve_to; + path->is_box = other->is_box; + path->is_region = other->is_region; path->buf_head.base.num_ops = other->buf_head.base.num_ops; path->buf_head.base.num_points = other->buf_head.base.num_points; @@ -370,6 +374,17 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path, status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1); if (unlikely (status)) return status; + + if (path->has_current_point && path->is_box) { + /* a move-to is first an implicit close */ + path->is_box = path->current_point.x == path->last_move_point.x || + path->current_point.y == path->last_move_point.y; + path->is_region &= path->is_box; + } + if (path->is_region) { + path->is_region = _cairo_fixed_is_integer (x) && + _cairo_fixed_is_integer (y); + } } path->current_point = point; @@ -390,15 +405,13 @@ _cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path, cairo_fixed_t dx, cairo_fixed_t dy) { - cairo_fixed_t x, y; - - if (! path->has_current_point) + if (unlikely (! path->has_current_point)) return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT); - x = path->current_point.x + dx; - y = path->current_point.y + dy; + return _cairo_path_fixed_move_to (path, + path->current_point.x + dx, + path->current_point.y + dy); - return _cairo_path_fixed_move_to (path, x, y); } cairo_status_t @@ -417,18 +430,25 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path, * explicitly calling into _cairo_path_fixed_move_to to ensure * that the last_move_point state is updated properly. */ - if (! path->has_current_point) + if (! path->has_current_point) { status = _cairo_path_fixed_move_to (path, point.x, point.y); - else + } else { status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1); - - if (unlikely (status)) - return status; + if (path->is_box) { + path->is_box = path->current_point.x == x || + path->current_point.y == y; + path->is_region &= path->is_box; + } + if (path->is_region) { + path->is_region = _cairo_fixed_is_integer (x) && + _cairo_fixed_is_integer (y); + } + } path->current_point = point; path->has_current_point = TRUE; - return CAIRO_STATUS_SUCCESS; + return status; } cairo_status_t @@ -436,15 +456,12 @@ _cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path, cairo_fixed_t dx, cairo_fixed_t dy) { - cairo_fixed_t x, y; - - if (! path->has_current_point) + if (unlikely (! path->has_current_point)) return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT); - x = path->current_point.x + dx; - y = path->current_point.y + dy; - - return _cairo_path_fixed_line_to (path, x, y); + return _cairo_path_fixed_line_to (path, + path->current_point.x + dx, + path->current_point.y + dy); } cairo_status_t @@ -456,17 +473,19 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path, cairo_status_t status; cairo_point_t point[3]; - point[0].x = x0; point[0].y = y0; - point[1].x = x1; point[1].y = y1; - point[2].x = x2; point[2].y = y2; - /* make sure subpaths are started properly */ if (! path->has_current_point) { - status = _cairo_path_fixed_move_to (path, point[0].x, point[0].y); + status = _cairo_path_fixed_move_to (path, x0, y0); if (unlikely (status)) return status; } + if (x2 == path->current_point.x && y2 == path->current_point.y) + return _cairo_path_fixed_line_to (path, x2, y2); + + point[0].x = x0; point[0].y = y0; + point[1].x = x1; point[1].y = y1; + point[2].x = x2; point[2].y = y2; status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3); if (unlikely (status)) return status; @@ -474,6 +493,8 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path, path->current_point = point[2]; path->has_current_point = TRUE; path->has_curve_to = TRUE; + path->is_box = FALSE; + path->is_region = FALSE; return CAIRO_STATUS_SUCCESS; } @@ -484,26 +505,24 @@ _cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path, cairo_fixed_t dx1, cairo_fixed_t dy1, cairo_fixed_t dx2, cairo_fixed_t dy2) { - cairo_fixed_t x0, y0; - cairo_fixed_t x1, y1; - cairo_fixed_t x2, y2; - - if (! path->has_current_point) + if (unlikely (! path->has_current_point)) return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT); - x0 = path->current_point.x + dx0; - y0 = path->current_point.y + dy0; - - x1 = path->current_point.x + dx1; - y1 = path->current_point.y + dy1; - - x2 = path->current_point.x + dx2; - y2 = path->current_point.y + dy2; + if (dx2 == 0 && dy2 == 0) { + return _cairo_path_fixed_line_to (path, + path->current_point.x, + path->current_point.y); + } return _cairo_path_fixed_curve_to (path, - x0, y0, - x1, y1, - x2, y2); + path->current_point.x + dx0, + path->current_point.y + dy0, + + path->current_point.x + dx1, + path->current_point.y + dy1, + + path->current_point.x + dx2, + path->current_point.y + dy2); } cairo_status_t @@ -518,13 +537,9 @@ _cairo_path_fixed_close_path (cairo_path_fixed_t *path) if (unlikely (status)) return status; - status = _cairo_path_fixed_move_to (path, - path->last_move_point.x, - path->last_move_point.y); - if (unlikely (status)) - return status; - - return CAIRO_STATUS_SUCCESS; + return _cairo_path_fixed_move_to (path, + path->last_move_point.x, + path->last_move_point.y); } cairo_bool_t @@ -542,10 +557,10 @@ _cairo_path_fixed_get_current_point (cairo_path_fixed_t *path, } static cairo_status_t -_cairo_path_fixed_add (cairo_path_fixed_t *path, - cairo_path_op_t op, - cairo_point_t *points, - int num_points) +_cairo_path_fixed_add (cairo_path_fixed_t *path, + cairo_path_op_t op, + const cairo_point_t *points, + int num_points) { cairo_path_buf_t *buf = path->buf_tail; @@ -616,25 +631,16 @@ _cairo_path_buf_add_op (cairo_path_buf_t *buf, } static void -_cairo_path_buf_add_points (cairo_path_buf_t *buf, - cairo_point_t *points, - int num_points) +_cairo_path_buf_add_points (cairo_path_buf_t *buf, + const cairo_point_t *points, + int num_points) { - int i; - - for (i=0; i < num_points; i++) { - buf->points[buf->num_points++] = points[i]; - } + memcpy (buf->points + buf->num_points, + points, + sizeof (points[0]) * num_points); + buf->num_points += num_points; } -static int const num_args[] = -{ - 1, /* cairo_path_move_to */ - 1, /* cairo_path_op_line_to */ - 3, /* cairo_path_op_curve_to */ - 0, /* cairo_path_op_close_path */ -}; - cairo_status_t _cairo_path_fixed_interpret (const cairo_path_fixed_t *path, cairo_direction_t dir, @@ -644,9 +650,14 @@ _cairo_path_fixed_interpret (const cairo_path_fixed_t *path, cairo_path_fixed_close_path_func_t *close_path, void *closure) { + const uint8_t num_args[] = { + 1, /* cairo_path_move_to */ + 1, /* cairo_path_op_line_to */ + 3, /* cairo_path_op_curve_to */ + 0, /* cairo_path_op_close_path */ + }; cairo_status_t status; const cairo_path_buf_t *buf; - cairo_path_op_t op; cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD); int step = forward ? 1 : -1; @@ -666,12 +677,11 @@ _cairo_path_fixed_interpret (const cairo_path_fixed_t *path, points = buf->points + buf->num_points; } - for (i=start; i != stop; i += step) { - op = buf->op[i]; + for (i = start; i != stop; i += step) { + cairo_path_op_t op = buf->op[i]; - if (! forward) { + if (! forward) points -= num_args[(int) op]; - } switch (op) { case CAIRO_PATH_OP_MOVE_TO: @@ -683,18 +693,17 @@ _cairo_path_fixed_interpret (const cairo_path_fixed_t *path, case CAIRO_PATH_OP_CURVE_TO: status = (*curve_to) (closure, &points[0], &points[1], &points[2]); break; - case CAIRO_PATH_OP_CLOSE_PATH: default: + ASSERT_NOT_REACHED; + case CAIRO_PATH_OP_CLOSE_PATH: status = (*close_path) (closure); break; } if (unlikely (status)) return status; - if (forward) { + if (forward) points += num_args[(int) op]; - } - } } @@ -705,16 +714,14 @@ static cairo_status_t _append_move_to (void *closure, const cairo_point_t *point) { - cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure; - return _cairo_path_fixed_move_to (path, point->x, point->y); + return _cairo_path_fixed_move_to (closure, point->x, point->y); } static cairo_status_t _append_line_to (void *closure, const cairo_point_t *point) { - cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure; - return _cairo_path_fixed_line_to (path, point->x, point->y); + return _cairo_path_fixed_line_to (closure, point->x, point->y); } static cairo_status_t @@ -723,15 +730,16 @@ _append_curve_to (void *closure, const cairo_point_t *p1, const cairo_point_t *p2) { - cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure; - return _cairo_path_fixed_curve_to (path, p0->x, p0->y, p1->x, p1->y, p2->x, p2->y); + return _cairo_path_fixed_curve_to (closure, + p0->x, p0->y, + p1->x, p1->y, + p2->x, p2->y); } static cairo_status_t _append_close_path (void *closure) { - cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure; - return _cairo_path_fixed_close_path (path); + return _cairo_path_fixed_close_path (closure); } cairo_status_t @@ -825,6 +833,8 @@ _cairo_path_fixed_is_equal (cairo_path_fixed_t *path, path->current_point.y != other->current_point.y || path->has_current_point != other->has_current_point || path->has_curve_to != other->has_curve_to || + path->is_box != other->is_box || + path->is_region != other->is_region || path->last_move_point.x != other->last_move_point.x || path->last_move_point.y != other->last_move_point.y) return FALSE; @@ -913,7 +923,6 @@ _cpf_close_path (void *closure) return cpf->close_path (cpf->closure); } - cairo_status_t _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path, cairo_direction_t dir, @@ -925,7 +934,7 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path, { cpf_t flattener; - if (!path->has_curve_to) { + if (! path->has_curve_to) { return _cairo_path_fixed_interpret (path, dir, move_to, line_to, @@ -965,6 +974,9 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path, { cairo_path_buf_t *buf = &path->buf_head.base; + if (! path->is_box) + return FALSE; + /* We can't have more than one buf for this check */ if (buf->next != NULL) return FALSE; @@ -1174,91 +1186,3 @@ _cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter) return FALSE; } - -/* Closure for path region testing. Every move_to must be to integer - * coordinates, there must be no curves, and every line_to or - * close_path must represent an axis aligned line to an integer point. - * We're relying on the path interpreter always sending a single - * move_to at the start of any subpath, not receiving having any - * superfluous move_tos, and the path intepreter bailing with our - * first non-successful error. */ -typedef struct cairo_path_region_tester { - cairo_point_t last_move_point; - cairo_point_t current_point; -} cprt_t; - -static cairo_status_t -_cprt_line_to (void *closure, - const cairo_point_t *p2) -{ - cprt_t *self = closure; - cairo_point_t *p1 = &self->current_point; - - if (p2->x == p1->x) { - if (_cairo_fixed_is_integer (p2->y)) { - p1->y = p2->y; - return CAIRO_STATUS_SUCCESS; - } - } else if (p2->y == p1->y) { - if (_cairo_fixed_is_integer (p2->x)) { - p1->x = p2->x; - return CAIRO_STATUS_SUCCESS; - } - } - - return CAIRO_INT_STATUS_UNSUPPORTED; -} - -static cairo_status_t -_cprt_close_path (void *closure) -{ - cprt_t *self = closure; - return _cprt_line_to (closure, &self->last_move_point); -} - -static cairo_status_t -_cprt_move_to (void *closure, - const cairo_point_t *p) -{ - cprt_t *self = closure; - cairo_status_t status; - - status = _cprt_close_path (closure); - if (status) - return status; - - if (_cairo_fixed_is_integer (p->x) && _cairo_fixed_is_integer (p->y)) { - self->current_point = *p; - self->last_move_point = *p; - return CAIRO_STATUS_SUCCESS; - } - - return CAIRO_INT_STATUS_UNSUPPORTED; -} - -/* - * Check whether the given path is representable as a region. - * That is, if the path contains only axis aligned lines between - * integer coordinates in device space. - */ -cairo_bool_t -_cairo_path_fixed_is_region (cairo_path_fixed_t *path) -{ - cprt_t cprt; - - if (path->has_curve_to) - return FALSE; - - cprt.current_point.x = 0; - cprt.current_point.y = 0; - cprt.last_move_point.x = 0; - cprt.last_move_point.y = 0; - - return _cairo_path_fixed_interpret (path, - CAIRO_DIRECTION_FORWARD, - _cprt_move_to, - _cprt_line_to, - NULL, - _cprt_close_path, - &cprt) == CAIRO_STATUS_SUCCESS; -} diff --git a/src/cairo.c b/src/cairo.c index 4324af7c1..eb78b7baf 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -56,6 +56,8 @@ static const cairo_t _cairo_nil = { { 0, 0 }, /* current point */ FALSE, /* has_current_point */ FALSE, /* has_curve_to */ + FALSE, /* is_box */ + FALSE, /* is_region */ NULL, {{NULL}} /* buf_tail, buf_head */ }} }; diff --git a/src/cairoint.h b/src/cairoint.h index fed81a5f8..cb30f6dee 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1617,9 +1617,6 @@ cairo_private cairo_bool_t _cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path, cairo_box_t *box); -cairo_private cairo_bool_t -_cairo_path_fixed_is_region (cairo_path_fixed_t *path); - /* cairo-path-in-fill.c */ cairo_private void _cairo_path_fixed_in_fill (cairo_path_fixed_t *path,