mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-01-08 22:20:22 +01:00
[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.
This commit is contained in:
parent
4bb157672e
commit
1645352bfb
4 changed files with 116 additions and 185 deletions
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
}}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue