diff options
Diffstat (limited to 'src/cairo-path-fixed.c')
-rw-r--r-- | src/cairo-path-fixed.c | 152 |
1 files changed, 135 insertions, 17 deletions
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c index ffaf58c1..dd25bb88 100644 --- a/src/cairo-path-fixed.c +++ b/src/cairo-path-fixed.c @@ -120,7 +120,7 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path, buf_size = MAX (num_ops, (num_points + 1) / 2); if (buf_size) { buf = _cairo_path_buf_create (buf_size); - if (buf == NULL) { + if (unlikely (buf == NULL)) { _cairo_path_fixed_fini (path); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -372,7 +372,7 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path, *last_move_to_point = point; } else { status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1); - if (status) + if (unlikely (status)) return status; } @@ -426,7 +426,7 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path, else status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1); - if (status) + if (unlikely (status)) return status; path->current_point = point; @@ -467,12 +467,12 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path, if (! path->has_current_point) { status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point[0], 1); - if (status) + if (unlikely (status)) return status; } status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3); - if (status) + if (unlikely (status)) return status; path->current_point = point[2]; @@ -519,13 +519,13 @@ _cairo_path_fixed_close_path (cairo_path_fixed_t *path) return CAIRO_STATUS_SUCCESS; status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0); - if (status) + if (unlikely (status)) return status; status = _cairo_path_fixed_move_to (path, path->last_move_point.x, path->last_move_point.y); - if (status) + if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; @@ -557,7 +557,7 @@ _cairo_path_fixed_add (cairo_path_fixed_t *path, buf->num_points + num_points > 2 * buf->buf_size) { buf = _cairo_path_buf_create (buf->buf_size * 2); - if (buf == NULL) + if (unlikely (buf == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_path_fixed_add_buf (path, buf); @@ -692,7 +692,7 @@ _cairo_path_fixed_interpret (const cairo_path_fixed_t *path, status = (*close_path) (closure); break; } - if (status) + if (unlikely (status)) return status; if (forward) { @@ -759,7 +759,7 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path, cairo_fixed_t scaley) { cairo_path_buf_t *buf = &path->buf_head.base; - int i; + unsigned int i; while (buf) { for (i = 0; i < buf->num_points; i++) { @@ -790,7 +790,7 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path, cairo_matrix_t *matrix) { cairo_path_buf_t *buf; - int i; + unsigned int i; double dx, dy; if (matrix->yx == 0.0 && matrix->xy == 0.0) { @@ -930,6 +930,15 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path, { cpf_t flattener; + if (!path->has_curve_to) { + return _cairo_path_fixed_interpret (path, dir, + move_to, + line_to, + NULL, + close_path, + closure); + } + flattener.tolerance = tolerance; flattener.move_to = move_to; flattener.line_to = line_to; @@ -1058,7 +1067,7 @@ _cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter, static cairo_bool_t _cairo_path_fixed_iter_next_op (cairo_path_fixed_iter_t *iter) { - if (++iter->n_op == iter->buf->num_ops) { + if (++iter->n_op >= iter->buf->num_ops) { iter->buf = iter->buf->next; iter->n_op = 0; iter->n_point = 0; @@ -1068,8 +1077,8 @@ _cairo_path_fixed_iter_next_op (cairo_path_fixed_iter_t *iter) } cairo_bool_t -_cairo_path_fixed_iter_is_box (cairo_path_fixed_iter_t *_iter, - cairo_box_t *box) +_cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter, + cairo_box_t *box) { cairo_point_t points[5]; cairo_path_fixed_iter_t iter; @@ -1079,6 +1088,12 @@ _cairo_path_fixed_iter_is_box (cairo_path_fixed_iter_t *_iter, iter = *_iter; + if (iter.n_op == iter.buf->num_ops && + ! _cairo_path_fixed_iter_next_op (&iter)) + { + return FALSE; + } + /* Check whether the ops are those that would be used for a rectangle */ if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_MOVE_TO) return FALSE; @@ -1106,12 +1121,16 @@ _cairo_path_fixed_iter_is_box (cairo_path_fixed_iter_t *_iter, /* Now, there are choices. The rectangle might end with a LINE_TO * (to the original point), but this isn't required. If it - * doesn't, then it must end with a CLOSE_PATH. */ - if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_LINE_TO) { + * doesn't, then it must end with a CLOSE_PATH (which may be implicit). */ + if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_LINE_TO) + { points[4] = iter.buf->points[iter.n_point++]; if (points[4].x != points[0].x || points[4].y != points[0].y) return FALSE; - } else if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_CLOSE_PATH) { + } + else if (! (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_CLOSE_PATH || + iter.buf->op[iter.n_op] == CAIRO_PATH_OP_MOVE_TO)) + { return FALSE; } if (! _cairo_path_fixed_iter_next_op (&iter)) @@ -1149,6 +1168,9 @@ _cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter) if (iter->buf == NULL) return TRUE; + if (iter->n_op == iter->buf->num_ops) + return TRUE; + if (iter->buf->op[iter->n_op] == CAIRO_PATH_OP_MOVE_TO && iter->buf->num_ops == iter->n_op + 1) { @@ -1157,3 +1179,99 @@ _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, + 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 = *p2; + return CAIRO_STATUS_SUCCESS; + } + } + else if (p2->y == p1->y) { + if (_cairo_fixed_is_integer(p2->x)) { + *p1 = *p2; + 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, + cairo_point_t *p) +{ + cprt_t *self = closure; + cairo_status_t 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; +} + +static cairo_status_t +_cprt_curve_to (void *closure, + cairo_point_t *p0, + cairo_point_t *p1, + cairo_point_t *p2) +{ + (void)closure; + (void)p0; + (void)p1; + (void)p2; + 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; + cairo_status_t status; + 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; + status = _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + _cprt_move_to, + _cprt_line_to, + _cprt_curve_to, + _cprt_close_path, + &cprt); + return status == CAIRO_STATUS_SUCCESS; +} |