mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-01-10 15:10:14 +01:00
[fill] Emit rectangles for GdkRegion
Scan the path for a series of consistently wound rectangles.
This commit is contained in:
parent
23df74e5ff
commit
4ac38f7c2b
3 changed files with 200 additions and 24 deletions
|
|
@ -150,6 +150,7 @@ _cairo_filler_close_path (void *closure)
|
|||
|
||||
static cairo_int_status_t
|
||||
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
cairo_traps_t *traps);
|
||||
|
||||
cairo_status_t
|
||||
|
|
@ -163,7 +164,7 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
|
|||
|
||||
/* Before we do anything else, we use a special-case filler for
|
||||
* a device-axis aligned rectangle if possible. */
|
||||
status = _cairo_path_fixed_fill_rectangle (path, traps);
|
||||
status = _cairo_path_fixed_fill_rectangle (path, fill_rule, traps);
|
||||
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
return status;
|
||||
|
||||
|
|
@ -205,27 +206,77 @@ BAIL:
|
|||
*/
|
||||
static cairo_int_status_t
|
||||
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
cairo_traps_t *traps)
|
||||
{
|
||||
if (_cairo_path_fixed_is_box (path, NULL)) {
|
||||
cairo_point_t *p = path->buf_head.base.points;
|
||||
cairo_point_t *top_left, *bot_right;
|
||||
cairo_box_t box;
|
||||
|
||||
top_left = &p[0];
|
||||
bot_right = &p[2];
|
||||
if (top_left->x > bot_right->x || top_left->y > bot_right->y) {
|
||||
int n;
|
||||
if (_cairo_path_fixed_is_box (path, &box)) {
|
||||
if (box.p1.x > box.p2.x) {
|
||||
cairo_fixed_t t;
|
||||
|
||||
/* not a simple cairo_rectangle() */
|
||||
for (n = 0; n < 4; n++) {
|
||||
if (p[n].x <= top_left->x && p[n].y <= top_left->y)
|
||||
top_left = &p[n];
|
||||
if (p[n].x >= bot_right->x && p[n].y >= bot_right->y)
|
||||
bot_right = &p[n];
|
||||
}
|
||||
t = box.p1.x;
|
||||
box.p1.x = box.p2.x;
|
||||
box.p2.x = t;
|
||||
}
|
||||
|
||||
return _cairo_traps_tessellate_rectangle (traps, top_left, bot_right);
|
||||
if (box.p1.y > box.p2.y) {
|
||||
cairo_fixed_t t;
|
||||
|
||||
t = box.p1.y;
|
||||
box.p1.y = box.p2.y;
|
||||
box.p2.y = t;
|
||||
}
|
||||
|
||||
return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
|
||||
} else if (fill_rule == CAIRO_FILL_RULE_WINDING) {
|
||||
cairo_path_fixed_iter_t iter;
|
||||
int last_cw = -1;
|
||||
|
||||
/* Support a series of rectangles as can be expected to describe a
|
||||
* GdkRegion clip region during exposes.
|
||||
*/
|
||||
_cairo_path_fixed_iter_init (&iter, path);
|
||||
while (_cairo_path_fixed_iter_is_box (&iter, &box)) {
|
||||
cairo_status_t status;
|
||||
int cw = 0;
|
||||
|
||||
if (box.p1.x > box.p2.x) {
|
||||
cairo_fixed_t t;
|
||||
|
||||
t = box.p1.x;
|
||||
box.p1.x = box.p2.x;
|
||||
box.p2.x = t;
|
||||
|
||||
cw = ! cw;
|
||||
}
|
||||
|
||||
if (box.p1.y > box.p2.y) {
|
||||
cairo_fixed_t t;
|
||||
|
||||
t = box.p1.y;
|
||||
box.p1.y = box.p2.y;
|
||||
box.p2.y = t;
|
||||
|
||||
cw = ! cw;
|
||||
}
|
||||
|
||||
if (last_cw < 0) {
|
||||
last_cw = cw;
|
||||
} else if (last_cw != cw) {
|
||||
_cairo_traps_clear (traps);
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
status = _cairo_traps_tessellate_rectangle (traps,
|
||||
&box.p1, &box.p2);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
}
|
||||
if (_cairo_path_fixed_iter_at_end (&iter))
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
_cairo_traps_clear (traps);
|
||||
}
|
||||
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
|
|
|||
|
|
@ -88,4 +88,21 @@ cairo_private cairo_bool_t
|
|||
_cairo_path_fixed_equal (const cairo_path_fixed_t *a,
|
||||
const cairo_path_fixed_t *b);
|
||||
|
||||
typedef struct _cairo_path_fixed_iter {
|
||||
cairo_path_buf_t *buf;
|
||||
int n_op;
|
||||
int n_point;
|
||||
} cairo_path_fixed_iter_t;
|
||||
|
||||
cairo_private void
|
||||
_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
|
||||
cairo_path_fixed_t *path);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_path_fixed_iter_is_box (cairo_path_fixed_iter_t *_iter,
|
||||
cairo_box_t *box);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter);
|
||||
|
||||
#endif /* CAIRO_PATH_FIXED_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -1002,10 +1002,8 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
|
|||
buf->points[2].y == buf->points[3].y &&
|
||||
buf->points[3].x == buf->points[0].x)
|
||||
{
|
||||
if (box) {
|
||||
box->p1 = buf->points[0];
|
||||
box->p2 = buf->points[2];
|
||||
}
|
||||
box->p1 = buf->points[0];
|
||||
box->p2 = buf->points[2];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -1014,10 +1012,8 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
|
|||
buf->points[2].x == buf->points[3].x &&
|
||||
buf->points[3].y == buf->points[0].y)
|
||||
{
|
||||
if (box) {
|
||||
box->p1 = buf->points[0];
|
||||
box->p2 = buf->points[2];
|
||||
}
|
||||
box->p1 = buf->points[0];
|
||||
box->p2 = buf->points[2];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -1049,3 +1045,115 @@ _cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
|
|||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
|
||||
cairo_path_fixed_t *path)
|
||||
{
|
||||
iter->buf = &path->buf_head.base;
|
||||
iter->n_op = 0;
|
||||
iter->n_point = 0;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_cairo_path_fixed_iter_next_op (cairo_path_fixed_iter_t *iter)
|
||||
{
|
||||
if (++iter->n_op == iter->buf->num_ops) {
|
||||
iter->buf = iter->buf->next;
|
||||
iter->n_op = 0;
|
||||
iter->n_point = 0;
|
||||
}
|
||||
|
||||
return iter->buf != NULL;
|
||||
}
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_path_fixed_iter_is_box (cairo_path_fixed_iter_t *_iter,
|
||||
cairo_box_t *box)
|
||||
{
|
||||
cairo_point_t points[5];
|
||||
cairo_path_fixed_iter_t iter;
|
||||
|
||||
if (_iter->buf == NULL)
|
||||
return FALSE;
|
||||
|
||||
iter = *_iter;
|
||||
|
||||
/* 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;
|
||||
points[0] = iter.buf->points[iter.n_point++];
|
||||
if (! _cairo_path_fixed_iter_next_op (&iter))
|
||||
return FALSE;
|
||||
|
||||
if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
|
||||
return FALSE;
|
||||
points[1] = iter.buf->points[iter.n_point++];
|
||||
if (! _cairo_path_fixed_iter_next_op (&iter))
|
||||
return FALSE;
|
||||
|
||||
if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
|
||||
return FALSE;
|
||||
points[2] = iter.buf->points[iter.n_point++];
|
||||
if (! _cairo_path_fixed_iter_next_op (&iter))
|
||||
return FALSE;
|
||||
|
||||
if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
|
||||
return FALSE;
|
||||
points[3] = iter.buf->points[iter.n_point++];
|
||||
if (! _cairo_path_fixed_iter_next_op (&iter))
|
||||
return FALSE;
|
||||
|
||||
/* 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) {
|
||||
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) {
|
||||
return FALSE;
|
||||
}
|
||||
if (! _cairo_path_fixed_iter_next_op (&iter))
|
||||
return FALSE;
|
||||
|
||||
/* Ok, we may have a box, if the points line up */
|
||||
if (points[0].y == points[1].y &&
|
||||
points[1].x == points[2].x &&
|
||||
points[2].y == points[3].y &&
|
||||
points[3].x == points[0].x)
|
||||
{
|
||||
box->p1 = points[0];
|
||||
box->p2 = points[2];
|
||||
*_iter = iter;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (points[0].x == points[1].x &&
|
||||
points[1].y == points[2].y &&
|
||||
points[2].x == points[3].x &&
|
||||
points[3].y == points[0].y)
|
||||
{
|
||||
box->p1 = points[0];
|
||||
box->p2 = points[2];
|
||||
*_iter = iter;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter)
|
||||
{
|
||||
if (iter->buf == NULL)
|
||||
return TRUE;
|
||||
|
||||
if (iter->buf->op[iter->n_op] == CAIRO_PATH_OP_MOVE_TO &&
|
||||
iter->buf->num_ops == iter->n_op + 1)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue