summaryrefslogtreecommitdiff
path: root/src/cairo-path-fixed.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-path-fixed.c')
-rw-r--r--src/cairo-path-fixed.c152
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;
+}