1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2009 Chris Wilson
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is Chris Wilson.
33 * Chris Wilson <chris@chris-wilson.co.uk>
39 #include "cairo-error-private.h"
40 #include "cairo-rtree-private.h"
43 _cairo_rtree_node_create (cairo_rtree_t *rtree,
44 cairo_rtree_node_t *parent,
50 cairo_rtree_node_t *node;
52 node = _cairo_freepool_alloc (&rtree->node_freepool);
54 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
58 node->children[0] = NULL;
59 node->parent = parent;
60 node->state = CAIRO_RTREE_NODE_AVAILABLE;
65 node->height = height;
67 cairo_list_add (&node->link, &rtree->available);
73 _cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
77 cairo_list_del (&node->link);
79 if (node->state == CAIRO_RTREE_NODE_OCCUPIED) {
80 rtree->destroy (node);
82 for (i = 0; i < 4 && node->children[i] != NULL; i++)
83 _cairo_rtree_node_destroy (rtree, node->children[i]);
86 _cairo_freepool_free (&rtree->node_freepool, node);
90 _cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
95 assert (node->state == CAIRO_RTREE_NODE_DIVIDED);
97 for (i = 0; i < 4 && node->children[i] != NULL; i++)
98 if (node->children[i]->state != CAIRO_RTREE_NODE_AVAILABLE)
101 for (i = 0; i < 4 && node->children[i] != NULL; i++)
102 _cairo_rtree_node_destroy (rtree, node->children[i]);
104 node->children[0] = NULL;
105 node->state = CAIRO_RTREE_NODE_AVAILABLE;
106 cairo_list_move (&node->link, &rtree->available);
107 } while ((node = node->parent) != NULL);
111 _cairo_rtree_node_insert (cairo_rtree_t *rtree,
112 cairo_rtree_node_t *node,
115 cairo_rtree_node_t **out)
119 assert (node->state == CAIRO_RTREE_NODE_AVAILABLE);
120 assert (node->pinned == FALSE);
122 if (node->width - width > rtree->min_size ||
123 node->height - height > rtree->min_size)
125 w = node->width - width;
126 h = node->height - height;
129 node->children[i] = _cairo_rtree_node_create (rtree, node,
132 if (unlikely (node->children[i] == NULL))
133 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
136 if (w > rtree->min_size) {
137 node->children[i] = _cairo_rtree_node_create (rtree, node,
141 if (unlikely (node->children[i] == NULL))
142 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
146 if (h > rtree->min_size) {
147 node->children[i] = _cairo_rtree_node_create (rtree, node,
151 if (unlikely (node->children[i] == NULL))
152 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
155 if (w > rtree->min_size) {
156 node->children[i] = _cairo_rtree_node_create (rtree, node,
160 if (unlikely (node->children[i] == NULL))
161 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
167 node->children[i] = NULL;
169 node->state = CAIRO_RTREE_NODE_DIVIDED;
170 cairo_list_move (&node->link, &rtree->evictable);
171 node = node->children[0];
174 node->state = CAIRO_RTREE_NODE_OCCUPIED;
175 cairo_list_move (&node->link, &rtree->evictable);
178 return CAIRO_STATUS_SUCCESS;
182 _cairo_rtree_node_remove (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
184 assert (node->state == CAIRO_RTREE_NODE_OCCUPIED);
185 assert (node->pinned == FALSE);
187 rtree->destroy (node);
189 node->state = CAIRO_RTREE_NODE_AVAILABLE;
190 cairo_list_move (&node->link, &rtree->available);
192 _cairo_rtree_node_collapse (rtree, node->parent);
196 _cairo_rtree_insert (cairo_rtree_t *rtree,
199 cairo_rtree_node_t **out)
201 cairo_rtree_node_t *node;
203 cairo_list_foreach_entry (node, cairo_rtree_node_t,
204 &rtree->available, link)
206 if (node->width >= width && node->height >= height)
207 return _cairo_rtree_node_insert (rtree, node, width, height, out);
210 return CAIRO_INT_STATUS_UNSUPPORTED;
214 hars_petruska_f54_1_random (void)
216 #define rol(x,k) ((x << k) | (x >> (32-k)))
218 return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
223 _cairo_rtree_evict_random (cairo_rtree_t *rtree,
226 cairo_rtree_node_t **out)
228 cairo_int_status_t ret = CAIRO_INT_STATUS_UNSUPPORTED;
229 cairo_rtree_node_t *node, *next;
230 cairo_list_t tmp_pinned;
233 cairo_list_init (&tmp_pinned);
235 /* propagate pinned from children to root */
236 cairo_list_foreach_entry_safe (node, next,
237 cairo_rtree_node_t, &rtree->pinned, link) {
239 while (node && ! node->pinned) {
241 cairo_list_move (&node->link, &tmp_pinned);
247 cairo_list_foreach_entry (node, cairo_rtree_node_t,
248 &rtree->evictable, link)
250 if (node->width >= width && node->height >= height)
257 cnt = hars_petruska_f54_1_random () % cnt;
258 cairo_list_foreach_entry (node, cairo_rtree_node_t,
259 &rtree->evictable, link)
261 if (node->width >= width && node->height >= height && cnt-- == 0) {
262 if (node->state == CAIRO_RTREE_NODE_OCCUPIED) {
263 rtree->destroy (node);
265 for (i = 0; i < 4 && node->children[i] != NULL; i++)
266 _cairo_rtree_node_destroy (rtree, node->children[i]);
267 node->children[0] = NULL;
270 node->state = CAIRO_RTREE_NODE_AVAILABLE;
271 cairo_list_move (&node->link, &rtree->available);
274 ret = CAIRO_STATUS_SUCCESS;
280 while (! cairo_list_is_empty (&tmp_pinned)) {
281 node = cairo_list_first_entry (&tmp_pinned, cairo_rtree_node_t, link);
283 cairo_list_move (&node->link, &rtree->evictable);
289 _cairo_rtree_unpin (cairo_rtree_t *rtree)
291 while (! cairo_list_is_empty (&rtree->pinned)) {
292 cairo_rtree_node_t *node = cairo_list_first_entry (&rtree->pinned,
296 cairo_list_move (&node->link, &rtree->evictable);
301 _cairo_rtree_init (cairo_rtree_t *rtree,
306 void (*destroy) (cairo_rtree_node_t *))
308 assert (node_size >= (int) sizeof (cairo_rtree_node_t));
309 _cairo_freepool_init (&rtree->node_freepool, node_size);
311 cairo_list_init (&rtree->available);
312 cairo_list_init (&rtree->pinned);
313 cairo_list_init (&rtree->evictable);
315 rtree->min_size = min_size;
316 rtree->destroy = destroy;
318 memset (&rtree->root, 0, sizeof (rtree->root));
319 rtree->root.width = width;
320 rtree->root.height = height;
321 rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE;
322 cairo_list_add (&rtree->root.link, &rtree->available);
326 _cairo_rtree_reset (cairo_rtree_t *rtree)
330 if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) {
331 rtree->destroy (&rtree->root);
333 for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++)
334 _cairo_rtree_node_destroy (rtree, rtree->root.children[i]);
335 rtree->root.children[0] = NULL;
338 cairo_list_init (&rtree->available);
339 cairo_list_init (&rtree->evictable);
340 cairo_list_init (&rtree->pinned);
342 rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE;
343 rtree->root.pinned = FALSE;
344 cairo_list_add (&rtree->root.link, &rtree->available);
348 _cairo_rtree_node_foreach (cairo_rtree_node_t *node,
349 void (*func)(cairo_rtree_node_t *, void *data),
354 for (i = 0; i < 4 && node->children[i] != NULL; i++)
355 _cairo_rtree_node_foreach(node->children[i], func, data);
361 _cairo_rtree_foreach (cairo_rtree_t *rtree,
362 void (*func)(cairo_rtree_node_t *, void *data),
367 if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) {
368 func(&rtree->root, data);
370 for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++)
371 _cairo_rtree_node_foreach (rtree->root.children[i], func, data);
376 _cairo_rtree_fini (cairo_rtree_t *rtree)
380 if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) {
381 rtree->destroy (&rtree->root);
383 for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++)
384 _cairo_rtree_node_destroy (rtree, rtree->root.children[i]);
387 _cairo_freepool_fini (&rtree->node_freepool);