diff options
-rw-r--r-- | src/cairo-rtree-private.h | 1 | ||||
-rw-r--r-- | src/cairo-rtree.c | 50 |
2 files changed, 49 insertions, 2 deletions
diff --git a/src/cairo-rtree-private.h b/src/cairo-rtree-private.h index 72dc8ce73..33c6bc80d 100644 --- a/src/cairo-rtree-private.h +++ b/src/cairo-rtree-private.h @@ -51,6 +51,7 @@ enum { typedef struct _cairo_rtree_node { struct _cairo_rtree_node *children[4], *parent; + void **owner; cairo_list_t link; uint16_t pinned; uint16_t state; diff --git a/src/cairo-rtree.c b/src/cairo-rtree.c index c0dfe3130..ba142b7ac 100644 --- a/src/cairo-rtree.c +++ b/src/cairo-rtree.c @@ -56,6 +56,7 @@ _cairo_rtree_node_create (cairo_rtree_t *rtree, node->children[0] = NULL; node->parent = parent; + node->owner = NULL; node->state = CAIRO_RTREE_NODE_AVAILABLE; node->pinned = FALSE; node->x = x; @@ -76,6 +77,8 @@ _cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node) cairo_list_del (&node->link); if (node->state == CAIRO_RTREE_NODE_OCCUPIED) { + if (node->owner != NULL) + *node->owner = NULL; if (rtree->evict != NULL) rtree->evict (node); } else { @@ -235,6 +238,8 @@ _cairo_rtree_evict_random (cairo_rtree_t *rtree, { if (node->width >= width && node->height >= height && cnt-- == 0) { if (node->state == CAIRO_RTREE_NODE_OCCUPIED) { + if (node->owner != NULL) + *node->owner = NULL; if (rtree->evict != NULL) rtree->evict (node); } else { @@ -274,12 +279,49 @@ void _cairo_rtree_unpin (cairo_rtree_t *rtree) { cairo_rtree_node_t *node, *next; + cairo_list_t can_collapse; + + if (cairo_list_is_empty (&rtree->pinned)) + return; + + cairo_list_init (&can_collapse); cairo_list_foreach_entry_safe (node, next, - cairo_rtree_node_t, &rtree->pinned, link) + cairo_rtree_node_t, + &rtree->pinned, + link) { node->pinned = FALSE; - cairo_list_move (&node->link, &rtree->evictable); + if (node->state == CAIRO_RTREE_NODE_OCCUPIED && node->owner == NULL) { + cairo_bool_t all_available; + int i; + + node->state = CAIRO_RTREE_NODE_AVAILABLE; + cairo_list_move (&node->link, &rtree->available); + + all_available = TRUE; + node = node->parent; + for (i = 0; i < 4 && node->children[i] != NULL && all_available; i++) + all_available &= node->children[i]->state == CAIRO_RTREE_NODE_AVAILABLE; + + if (all_available) { + cairo_list_move (&node->link, &can_collapse); + for (i = 0; i < 4 && node->children[i] != NULL; i++) + cairo_list_del (&node->children[i]->link); + } + } + else + { + cairo_list_move (&node->link, &rtree->evictable); + } + } + + cairo_list_foreach_entry_safe (node, next, + cairo_rtree_node_t, + &can_collapse, + link) + { + _cairo_rtree_node_collapse (rtree, node); } } @@ -315,6 +357,8 @@ _cairo_rtree_reset (cairo_rtree_t *rtree) int i; if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) { + if (rtree->root.owner != NULL) + *rtree->root.owner = NULL; if (rtree->evict != NULL) rtree->evict (&rtree->root); } else { @@ -338,6 +382,8 @@ _cairo_rtree_fini (cairo_rtree_t *rtree) int i; if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) { + if (rtree->root.owner != NULL) + *rtree->root.owner = NULL; if (rtree->evict != NULL) rtree->evict (&rtree->root); } else { |