Rev 1892 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1892 | serge | 1 | /* cairo - a vector graphics library with display and print output |
2 | * |
||
3 | * Copyright © 2009 Chris Wilson |
||
4 | * |
||
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. |
||
12 | * |
||
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 |
||
18 | * |
||
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/ |
||
23 | * |
||
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. |
||
27 | * |
||
28 | * The Original Code is the cairo graphics library. |
||
29 | * |
||
30 | * The Initial Developer of the Original Code is Chris Wilson. |
||
31 | * |
||
32 | * Contributor(s): |
||
33 | * Chris Wilson |
||
34 | * |
||
35 | */ |
||
36 | |||
37 | #include "cairoint.h" |
||
38 | |||
39 | #include "cairo-error-private.h" |
||
40 | #include "cairo-rtree-private.h" |
||
41 | |||
42 | cairo_rtree_node_t * |
||
43 | _cairo_rtree_node_create (cairo_rtree_t *rtree, |
||
44 | cairo_rtree_node_t *parent, |
||
45 | int x, |
||
46 | int y, |
||
47 | int width, |
||
48 | int height) |
||
49 | { |
||
50 | cairo_rtree_node_t *node; |
||
51 | |||
52 | node = _cairo_freepool_alloc (&rtree->node_freepool); |
||
53 | if (node == NULL) { |
||
54 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
||
55 | return NULL; |
||
56 | } |
||
57 | |||
58 | node->children[0] = NULL; |
||
59 | node->parent = parent; |
||
60 | node->state = CAIRO_RTREE_NODE_AVAILABLE; |
||
61 | node->pinned = FALSE; |
||
62 | node->x = x; |
||
63 | node->y = y; |
||
64 | node->width = width; |
||
65 | node->height = height; |
||
66 | |||
67 | cairo_list_add (&node->link, &rtree->available); |
||
68 | |||
69 | return node; |
||
70 | } |
||
71 | |||
72 | void |
||
73 | _cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node) |
||
74 | { |
||
75 | int i; |
||
76 | |||
77 | cairo_list_del (&node->link); |
||
78 | |||
79 | if (node->state == CAIRO_RTREE_NODE_OCCUPIED) { |
||
3959 | Serge | 80 | rtree->destroy (node); |
1892 | serge | 81 | } else { |
82 | for (i = 0; i < 4 && node->children[i] != NULL; i++) |
||
83 | _cairo_rtree_node_destroy (rtree, node->children[i]); |
||
84 | } |
||
85 | |||
86 | _cairo_freepool_free (&rtree->node_freepool, node); |
||
87 | } |
||
88 | |||
89 | void |
||
90 | _cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node) |
||
91 | { |
||
92 | int i; |
||
93 | |||
94 | do { |
||
95 | assert (node->state == CAIRO_RTREE_NODE_DIVIDED); |
||
96 | |||
97 | for (i = 0; i < 4 && node->children[i] != NULL; i++) |
||
98 | if (node->children[i]->state != CAIRO_RTREE_NODE_AVAILABLE) |
||
99 | return; |
||
100 | |||
101 | for (i = 0; i < 4 && node->children[i] != NULL; i++) |
||
102 | _cairo_rtree_node_destroy (rtree, node->children[i]); |
||
103 | |||
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); |
||
108 | } |
||
109 | |||
110 | cairo_status_t |
||
111 | _cairo_rtree_node_insert (cairo_rtree_t *rtree, |
||
112 | cairo_rtree_node_t *node, |
||
113 | int width, |
||
114 | int height, |
||
115 | cairo_rtree_node_t **out) |
||
116 | { |
||
117 | int w, h, i; |
||
118 | |||
119 | assert (node->state == CAIRO_RTREE_NODE_AVAILABLE); |
||
120 | assert (node->pinned == FALSE); |
||
121 | |||
122 | if (node->width - width > rtree->min_size || |
||
123 | node->height - height > rtree->min_size) |
||
124 | { |
||
125 | w = node->width - width; |
||
126 | h = node->height - height; |
||
127 | |||
128 | i = 0; |
||
129 | node->children[i] = _cairo_rtree_node_create (rtree, node, |
||
130 | node->x, node->y, |
||
131 | width, height); |
||
132 | if (unlikely (node->children[i] == NULL)) |
||
133 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
||
134 | i++; |
||
135 | |||
136 | if (w > rtree->min_size) { |
||
137 | node->children[i] = _cairo_rtree_node_create (rtree, node, |
||
138 | node->x + width, |
||
139 | node->y, |
||
140 | w, height); |
||
141 | if (unlikely (node->children[i] == NULL)) |
||
142 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
||
143 | i++; |
||
144 | } |
||
145 | |||
146 | if (h > rtree->min_size) { |
||
147 | node->children[i] = _cairo_rtree_node_create (rtree, node, |
||
148 | node->x, |
||
149 | node->y + height, |
||
150 | width, h); |
||
151 | if (unlikely (node->children[i] == NULL)) |
||
152 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
||
153 | i++; |
||
154 | |||
155 | if (w > rtree->min_size) { |
||
156 | node->children[i] = _cairo_rtree_node_create (rtree, node, |
||
157 | node->x + width, |
||
158 | node->y + height, |
||
159 | w, h); |
||
160 | if (unlikely (node->children[i] == NULL)) |
||
161 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
||
162 | i++; |
||
163 | } |
||
164 | } |
||
165 | |||
166 | if (i < 4) |
||
167 | node->children[i] = NULL; |
||
168 | |||
169 | node->state = CAIRO_RTREE_NODE_DIVIDED; |
||
170 | cairo_list_move (&node->link, &rtree->evictable); |
||
171 | node = node->children[0]; |
||
172 | } |
||
173 | |||
174 | node->state = CAIRO_RTREE_NODE_OCCUPIED; |
||
175 | cairo_list_move (&node->link, &rtree->evictable); |
||
176 | *out = node; |
||
177 | |||
178 | return CAIRO_STATUS_SUCCESS; |
||
179 | } |
||
180 | |||
181 | void |
||
182 | _cairo_rtree_node_remove (cairo_rtree_t *rtree, cairo_rtree_node_t *node) |
||
183 | { |
||
184 | assert (node->state == CAIRO_RTREE_NODE_OCCUPIED); |
||
185 | assert (node->pinned == FALSE); |
||
186 | |||
3959 | Serge | 187 | rtree->destroy (node); |
188 | |||
1892 | serge | 189 | node->state = CAIRO_RTREE_NODE_AVAILABLE; |
190 | cairo_list_move (&node->link, &rtree->available); |
||
191 | |||
192 | _cairo_rtree_node_collapse (rtree, node->parent); |
||
193 | } |
||
194 | |||
195 | cairo_int_status_t |
||
196 | _cairo_rtree_insert (cairo_rtree_t *rtree, |
||
197 | int width, |
||
198 | int height, |
||
199 | cairo_rtree_node_t **out) |
||
200 | { |
||
201 | cairo_rtree_node_t *node; |
||
202 | |||
203 | cairo_list_foreach_entry (node, cairo_rtree_node_t, |
||
204 | &rtree->available, link) |
||
205 | { |
||
206 | if (node->width >= width && node->height >= height) |
||
207 | return _cairo_rtree_node_insert (rtree, node, width, height, out); |
||
208 | } |
||
209 | |||
210 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
211 | } |
||
212 | |||
213 | static uint32_t |
||
214 | hars_petruska_f54_1_random (void) |
||
215 | { |
||
216 | #define rol(x,k) ((x << k) | (x >> (32-k))) |
||
217 | static uint32_t x; |
||
218 | return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849; |
||
219 | #undef rol |
||
220 | } |
||
221 | |||
222 | cairo_int_status_t |
||
223 | _cairo_rtree_evict_random (cairo_rtree_t *rtree, |
||
224 | int width, |
||
225 | int height, |
||
226 | cairo_rtree_node_t **out) |
||
227 | { |
||
3959 | Serge | 228 | cairo_int_status_t ret = CAIRO_INT_STATUS_UNSUPPORTED; |
1892 | serge | 229 | cairo_rtree_node_t *node, *next; |
3959 | Serge | 230 | cairo_list_t tmp_pinned; |
1892 | serge | 231 | int i, cnt; |
232 | |||
3959 | Serge | 233 | cairo_list_init (&tmp_pinned); |
234 | |||
1892 | serge | 235 | /* propagate pinned from children to root */ |
3959 | Serge | 236 | cairo_list_foreach_entry_safe (node, next, |
237 | cairo_rtree_node_t, &rtree->pinned, link) { |
||
238 | node = node->parent; |
||
239 | while (node && ! node->pinned) { |
||
240 | node->pinned = 1; |
||
241 | cairo_list_move (&node->link, &tmp_pinned); |
||
242 | node = node->parent; |
||
243 | } |
||
1892 | serge | 244 | } |
245 | |||
246 | cnt = 0; |
||
247 | cairo_list_foreach_entry (node, cairo_rtree_node_t, |
||
248 | &rtree->evictable, link) |
||
249 | { |
||
250 | if (node->width >= width && node->height >= height) |
||
251 | cnt++; |
||
252 | } |
||
253 | |||
254 | if (cnt == 0) |
||
3959 | Serge | 255 | goto out; |
1892 | serge | 256 | |
257 | cnt = hars_petruska_f54_1_random () % cnt; |
||
258 | cairo_list_foreach_entry (node, cairo_rtree_node_t, |
||
259 | &rtree->evictable, link) |
||
260 | { |
||
261 | if (node->width >= width && node->height >= height && cnt-- == 0) { |
||
262 | if (node->state == CAIRO_RTREE_NODE_OCCUPIED) { |
||
3959 | Serge | 263 | rtree->destroy (node); |
1892 | serge | 264 | } else { |
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; |
||
268 | } |
||
269 | |||
270 | node->state = CAIRO_RTREE_NODE_AVAILABLE; |
||
271 | cairo_list_move (&node->link, &rtree->available); |
||
272 | |||
273 | *out = node; |
||
3959 | Serge | 274 | ret = CAIRO_STATUS_SUCCESS; |
275 | break; |
||
1892 | serge | 276 | } |
277 | } |
||
278 | |||
3959 | Serge | 279 | out: |
280 | while (! cairo_list_is_empty (&tmp_pinned)) { |
||
281 | node = cairo_list_first_entry (&tmp_pinned, cairo_rtree_node_t, link); |
||
282 | node->pinned = 0; |
||
283 | cairo_list_move (&node->link, &rtree->evictable); |
||
284 | } |
||
285 | return ret; |
||
1892 | serge | 286 | } |
287 | |||
288 | void |
||
289 | _cairo_rtree_unpin (cairo_rtree_t *rtree) |
||
290 | { |
||
3959 | Serge | 291 | while (! cairo_list_is_empty (&rtree->pinned)) { |
292 | cairo_rtree_node_t *node = cairo_list_first_entry (&rtree->pinned, |
||
293 | cairo_rtree_node_t, |
||
294 | link); |
||
295 | node->pinned = 0; |
||
296 | cairo_list_move (&node->link, &rtree->evictable); |
||
1892 | serge | 297 | } |
298 | } |
||
299 | |||
300 | void |
||
301 | _cairo_rtree_init (cairo_rtree_t *rtree, |
||
302 | int width, |
||
303 | int height, |
||
304 | int min_size, |
||
3959 | Serge | 305 | int node_size, |
306 | void (*destroy) (cairo_rtree_node_t *)) |
||
1892 | serge | 307 | { |
308 | assert (node_size >= (int) sizeof (cairo_rtree_node_t)); |
||
309 | _cairo_freepool_init (&rtree->node_freepool, node_size); |
||
310 | |||
311 | cairo_list_init (&rtree->available); |
||
312 | cairo_list_init (&rtree->pinned); |
||
313 | cairo_list_init (&rtree->evictable); |
||
314 | |||
315 | rtree->min_size = min_size; |
||
3959 | Serge | 316 | rtree->destroy = destroy; |
1892 | serge | 317 | |
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); |
||
323 | } |
||
324 | |||
325 | void |
||
326 | _cairo_rtree_reset (cairo_rtree_t *rtree) |
||
327 | { |
||
328 | int i; |
||
329 | |||
330 | if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) { |
||
3959 | Serge | 331 | rtree->destroy (&rtree->root); |
1892 | serge | 332 | } else { |
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; |
||
336 | } |
||
337 | |||
338 | cairo_list_init (&rtree->available); |
||
339 | cairo_list_init (&rtree->evictable); |
||
340 | cairo_list_init (&rtree->pinned); |
||
341 | |||
342 | rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE; |
||
343 | rtree->root.pinned = FALSE; |
||
344 | cairo_list_add (&rtree->root.link, &rtree->available); |
||
345 | } |
||
346 | |||
3959 | Serge | 347 | static void |
348 | _cairo_rtree_node_foreach (cairo_rtree_node_t *node, |
||
349 | void (*func)(cairo_rtree_node_t *, void *data), |
||
350 | void *data) |
||
351 | { |
||
352 | int i; |
||
353 | |||
354 | for (i = 0; i < 4 && node->children[i] != NULL; i++) |
||
355 | _cairo_rtree_node_foreach(node->children[i], func, data); |
||
356 | |||
357 | func(node, data); |
||
358 | } |
||
359 | |||
1892 | serge | 360 | void |
3959 | Serge | 361 | _cairo_rtree_foreach (cairo_rtree_t *rtree, |
362 | void (*func)(cairo_rtree_node_t *, void *data), |
||
363 | void *data) |
||
364 | { |
||
365 | int i; |
||
366 | |||
367 | if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) { |
||
368 | func(&rtree->root, data); |
||
369 | } else { |
||
370 | for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++) |
||
371 | _cairo_rtree_node_foreach (rtree->root.children[i], func, data); |
||
372 | } |
||
373 | } |
||
374 | |||
375 | void |
||
1892 | serge | 376 | _cairo_rtree_fini (cairo_rtree_t *rtree) |
377 | { |
||
378 | int i; |
||
379 | |||
380 | if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) { |
||
3959 | Serge | 381 | rtree->destroy (&rtree->root); |
1892 | serge | 382 | } else { |
383 | for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++) |
||
384 | _cairo_rtree_node_destroy (rtree, rtree->root.children[i]); |
||
385 | } |
||
386 | |||
387 | _cairo_freepool_fini (&rtree->node_freepool); |
||
388 | }>>>>>><>>>>> |