summaryrefslogtreecommitdiff
path: root/src/cairo-path-fixed.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-path-fixed.c')
-rw-r--r--[-rwxr-xr-x]src/cairo-path-fixed.c90
1 files changed, 78 insertions, 12 deletions
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index 2c198815d..5d57a61ec 100755..100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -86,6 +86,7 @@ _cairo_path_fixed_init (cairo_path_fixed_t *path)
path->current_point.x = 0;
path->current_point.y = 0;
path->last_move_point = path->current_point;
+ path->start_point = path->current_point;
path->has_current_point = FALSE;
path->needs_move_to = TRUE;
@@ -95,6 +96,7 @@ _cairo_path_fixed_init (cairo_path_fixed_t *path)
path->fill_is_rectilinear = TRUE;
path->fill_maybe_region = TRUE;
path->fill_is_empty = TRUE;
+ path->is_convex = TRUE;
path->extents.p1.x = path->extents.p1.y = 0;
path->extents.p2.x = path->extents.p2.y = 0;
@@ -132,6 +134,9 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
path->buf.base.num_ops = other->buf.base.num_ops;
path->buf.base.num_points = other->buf.base.num_points;
+
+ path->is_convex = other->is_convex;
+
memcpy (path->buf.op, other->buf.base.op,
other->buf.base.num_ops * sizeof (other->buf.op[0]));
memcpy (path->buf.points, other->buf.points,
@@ -408,6 +413,11 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path,
path->current_point.y = y;
path->last_move_point = path->current_point;
+ if (_cairo_path_fixed_is_empty (path))
+ path->is_convex = TRUE;
+ else
+ path->is_convex = FALSE;
+
return CAIRO_STATUS_SUCCESS;
}
@@ -450,6 +460,11 @@ _cairo_path_fixed_new_sub_path (cairo_path_fixed_t *path)
path->needs_move_to = TRUE;
}
+ if (_cairo_path_fixed_is_empty (path))
+ path->is_convex = TRUE;
+ else
+ path->is_convex = FALSE;
+
path->has_current_point = FALSE;
}
@@ -548,6 +563,13 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
_cairo_box_add_point (&path->extents, &point);
+ /* if line to point does not match start point, is_convex false */
+ if (path->is_convex) {
+ if (path->start_point.x != x &&
+ path->start_point.y != y)
+ path->is_convex = FALSE;
+ }
+
return _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
}
@@ -620,6 +642,8 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
path->fill_maybe_region = FALSE;
path->fill_is_empty = FALSE;
+ path->is_convex = FALSE;
+
return _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
}
@@ -847,6 +871,9 @@ _cairo_path_fixed_interpret (const cairo_path_fixed_t *path,
}
} cairo_path_foreach_buf_end (buf, path);
+ if (path->needs_move_to && path->has_current_point)
+ return (*move_to) (closure, &path->current_point);
+
return CAIRO_STATUS_SUCCESS;
}
@@ -965,8 +992,19 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
path->extents.p1.x = _cairo_fixed_mul (scalex, path->extents.p1.x) + offx;
path->extents.p2.x = _cairo_fixed_mul (scalex, path->extents.p2.x) + offx;
+ if (scalex < 0) {
+ cairo_fixed_t t = path->extents.p1.x;
+ path->extents.p1.x = path->extents.p2.x;
+ path->extents.p2.x = t;
+ }
+
path->extents.p1.y = _cairo_fixed_mul (scaley, path->extents.p1.y) + offy;
path->extents.p2.y = _cairo_fixed_mul (scaley, path->extents.p2.y) + offy;
+ if (scaley < 0) {
+ cairo_fixed_t t = path->extents.p1.y;
+ path->extents.p1.y = path->extents.p2.y;
+ path->extents.p2.y = t;
+ }
}
void
@@ -1289,7 +1327,7 @@ _cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
}
/* Determine whether two lines A->B and C->D intersect based on the
- * algorithm described here: http://paulbourke.net/geometry/lineline2d/ */
+ * algorithm described here: http://paulbourke.net/geometry/pointlineplane/ */
static inline cairo_bool_t
_lines_intersect_or_are_coincident (cairo_point_t a,
cairo_point_t b,
@@ -1297,6 +1335,7 @@ _lines_intersect_or_are_coincident (cairo_point_t a,
cairo_point_t d)
{
cairo_int64_t numerator_a, numerator_b, denominator;
+ cairo_bool_t denominator_negative;
denominator = _cairo_int64_sub (_cairo_int32x32_64_mul (d.y - c.y, b.x - a.x),
_cairo_int32x32_64_mul (d.x - c.x, b.y - a.y));
@@ -1316,20 +1355,34 @@ _lines_intersect_or_are_coincident (cairo_point_t a,
return FALSE;
}
- /* If either division would produce a number between 0 and 1, i.e.
- * the numerator is smaller than the denominator and their signs are
- * the same, then the lines intersect. */
- if (_cairo_int64_lt (numerator_a, denominator) &&
- ! (_cairo_int64_negative (numerator_a) ^ _cairo_int64_negative(denominator))) {
- return TRUE;
- }
+ /* The lines intersect if both quotients are between 0 and 1 (exclusive). */
- if (_cairo_int64_lt (numerator_b, denominator) &&
- ! (_cairo_int64_negative (numerator_b) ^ _cairo_int64_negative(denominator))) {
- return TRUE;
+ /* We first test whether either quotient is a negative number. */
+ denominator_negative = _cairo_int64_negative (denominator);
+ if (_cairo_int64_negative (numerator_a) ^ denominator_negative)
+ return FALSE;
+ if (_cairo_int64_negative (numerator_b) ^ denominator_negative)
+ return FALSE;
+
+ /* A zero quotient indicates an "intersection" at an endpoint, which
+ * we aren't considering a true intersection. */
+ if (_cairo_int64_is_zero (numerator_a) || _cairo_int64_is_zero (numerator_b))
+ return FALSE;
+
+ /* If the absolute value of the numerator is larger than or equal to the
+ * denominator the result of the division would be greater than or equal
+ * to one. */
+ if (! denominator_negative) {
+ if (! _cairo_int64_lt (numerator_a, denominator) ||
+ ! _cairo_int64_lt (numerator_b, denominator))
+ return FALSE;
+ } else {
+ if (! _cairo_int64_lt (denominator, numerator_a) ||
+ ! _cairo_int64_lt (denominator, numerator_b))
+ return FALSE;
}
- return FALSE;
+ return TRUE;
}
cairo_bool_t
@@ -1454,6 +1507,19 @@ _cairo_path_fixed_is_single_line (const cairo_path_fixed_t *path)
}
cairo_bool_t
+_cairo_path_fixed_is_empty (const cairo_path_fixed_t *path)
+{
+ unsigned int i;
+ const cairo_path_buf_t *buf = cairo_path_head (path);
+ for (i = 0; i < buf->num_ops; i++) {
+ if (buf->op[i] != CAIRO_PATH_OP_MOVE_TO)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+cairo_bool_t
_cairo_path_fixed_is_single_arc (const cairo_path_fixed_t *path)
{
const cairo_path_buf_t *buf = cairo_path_head (path);