/* cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Chris Wilson
*
* This library is free software ; you can redistribute it and / or
* modify it either under the terms of the GNU Lesser General Public
* License version 2 . 1 as published by the Free Software Foundation
* ( the " LGPL " ) or , at your option , under the terms of the Mozilla
* Public License Version 1 . 1 ( the " MPL " ) . If you do not alter this
* notice , a recipient may use your version of this file under either
* the MPL or the LGPL .
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING - LGPL - 2 . 1 ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Suite 500 , Boston , MA 02110 - 1335 , USA
* You should have received a copy of the MPL along with this library
* in the file COPYING - MPL - 1 . 1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1 . 1 ( the " License " ) ; you may not use this file except in
* compliance with the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* This software is distributed on an " AS IS " basis , WITHOUT WARRANTY
* OF ANY KIND , either express or implied . See the LGPL or the MPL for
* the specific language governing rights and limitations .
*
* The Original Code is the cairo graphics library .
*
* The Initial Developer of the Original Code is Chris Wilson .
*
* Contributor ( s ) :
* Chris Wilson < chris @ chris - wilson . co . uk >
*
*/
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-rtree-private.h"
cairo_rtree_node_t *
_cairo_rtree_node_create (cairo_rtree_t *rtree,
cairo_rtree_node_t *parent,
int x,
int y,
int width,
int height)
{
cairo_rtree_node_t *node;
node = _cairo_freepool_alloc (&rtree->node_freepool);
if (node == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
node->children[0 ] = NULL;
node->parent = parent;
node->state = CAIRO_RTREE_NODE_AVAILABLE;
node->pinned = FALSE ;
node->x = x;
node->y = y;
node->width = width;
node->height = height;
cairo_list_add (&node->link, &rtree->available);
return node;
}
void
_cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
{
int i;
cairo_list_del (&node->link);
if (node->state == CAIRO_RTREE_NODE_OCCUPIED) {
rtree->destroy (node);
} else {
for (i = 0 ; i < 4 && node->children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, node->children[i]);
}
_cairo_freepool_free (&rtree->node_freepool, node);
}
void
_cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
{
int i;
do {
assert (node->state == CAIRO_RTREE_NODE_DIVIDED);
for (i = 0 ; i < 4 && node->children[i] != NULL; i++)
if (node->children[i]->state != CAIRO_RTREE_NODE_AVAILABLE)
return ;
for (i = 0 ; i < 4 && node->children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, node->children[i]);
node->children[0 ] = NULL;
node->state = CAIRO_RTREE_NODE_AVAILABLE;
cairo_list_move (&node->link, &rtree->available);
} while ((node = node->parent) != NULL);
}
cairo_status_t
_cairo_rtree_node_insert (cairo_rtree_t *rtree,
cairo_rtree_node_t *node,
int width,
int height,
cairo_rtree_node_t **out)
{
int w, h, i;
assert (node->state == CAIRO_RTREE_NODE_AVAILABLE);
assert (node->pinned == FALSE );
if (node->width - width > rtree->min_size ||
node->height - height > rtree->min_size)
{
w = node->width - width;
h = node->height - height;
i = 0 ;
node->children[i] = _cairo_rtree_node_create (rtree, node,
node->x, node->y,
width, height);
if (unlikely (node->children[i] == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
i++;
if (w > rtree->min_size) {
node->children[i] = _cairo_rtree_node_create (rtree, node,
node->x + width,
node->y,
w, height);
if (unlikely (node->children[i] == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
i++;
}
if (h > rtree->min_size) {
node->children[i] = _cairo_rtree_node_create (rtree, node,
node->x,
node->y + height,
width, h);
if (unlikely (node->children[i] == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
i++;
if (w > rtree->min_size) {
node->children[i] = _cairo_rtree_node_create (rtree, node,
node->x + width,
node->y + height,
w, h);
if (unlikely (node->children[i] == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
i++;
}
}
if (i < 4 )
node->children[i] = NULL;
node->state = CAIRO_RTREE_NODE_DIVIDED;
cairo_list_move (&node->link, &rtree->evictable);
node = node->children[0 ];
}
node->state = CAIRO_RTREE_NODE_OCCUPIED;
cairo_list_move (&node->link, &rtree->evictable);
*out = node;
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_rtree_node_remove (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
{
assert (node->state == CAIRO_RTREE_NODE_OCCUPIED);
assert (node->pinned == FALSE );
rtree->destroy (node);
node->state = CAIRO_RTREE_NODE_AVAILABLE;
cairo_list_move (&node->link, &rtree->available);
_cairo_rtree_node_collapse (rtree, node->parent);
}
cairo_int_status_t
_cairo_rtree_insert (cairo_rtree_t *rtree,
int width,
int height,
cairo_rtree_node_t **out)
{
cairo_rtree_node_t *node;
cairo_list_foreach_entry (node, cairo_rtree_node_t,
&rtree->available, link)
{
if (node->width >= width && node->height >= height)
return _cairo_rtree_node_insert (rtree, node, width, height, out);
}
return CAIRO_INT_STATUS_UNSUPPORTED;
}
static uint32_t
hars_petruska_f54_1_random (void )
{
#define rol(x,k) ((x << k) | (x >> (32 -k)))
static uint32_t x;
return x = (x ^ rol (x, 5 ) ^ rol (x, 24 )) + 0 x37798849;
#undef rol
}
cairo_int_status_t
_cairo_rtree_evict_random (cairo_rtree_t *rtree,
int width,
int height,
cairo_rtree_node_t **out)
{
cairo_int_status_t ret = CAIRO_INT_STATUS_UNSUPPORTED;
cairo_rtree_node_t *node, *next;
cairo_list_t tmp_pinned;
int i, cnt;
cairo_list_init (&tmp_pinned);
/* propagate pinned from children to root */
cairo_list_foreach_entry_safe (node, next,
cairo_rtree_node_t, &rtree->pinned, link) {
node = node->parent;
while (node && ! node->pinned) {
node->pinned = 1 ;
cairo_list_move (&node->link, &tmp_pinned);
node = node->parent;
}
}
cnt = 0 ;
cairo_list_foreach_entry (node, cairo_rtree_node_t,
&rtree->evictable, link)
{
if (node->width >= width && node->height >= height)
cnt++;
}
if (cnt == 0 )
goto out;
cnt = hars_petruska_f54_1_random () % cnt;
cairo_list_foreach_entry (node, cairo_rtree_node_t,
&rtree->evictable, link)
{
if (node->width >= width && node->height >= height && cnt-- == 0 ) {
if (node->state == CAIRO_RTREE_NODE_OCCUPIED) {
rtree->destroy (node);
} else {
for (i = 0 ; i < 4 && node->children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, node->children[i]);
node->children[0 ] = NULL;
}
node->state = CAIRO_RTREE_NODE_AVAILABLE;
cairo_list_move (&node->link, &rtree->available);
*out = node;
ret = CAIRO_STATUS_SUCCESS;
break ;
}
}
out:
while (! cairo_list_is_empty (&tmp_pinned)) {
node = cairo_list_first_entry (&tmp_pinned, cairo_rtree_node_t, link);
node->pinned = 0 ;
cairo_list_move (&node->link, &rtree->evictable);
}
return ret;
}
void
_cairo_rtree_unpin (cairo_rtree_t *rtree)
{
while (! cairo_list_is_empty (&rtree->pinned)) {
cairo_rtree_node_t *node = cairo_list_first_entry (&rtree->pinned,
cairo_rtree_node_t,
link);
node->pinned = 0 ;
cairo_list_move (&node->link, &rtree->evictable);
}
}
void
_cairo_rtree_init (cairo_rtree_t *rtree,
int width,
int height,
int min_size,
int node_size,
void (*destroy) (cairo_rtree_node_t *))
{
assert (node_size >= (int ) sizeof (cairo_rtree_node_t));
_cairo_freepool_init (&rtree->node_freepool, node_size);
cairo_list_init (&rtree->available);
cairo_list_init (&rtree->pinned);
cairo_list_init (&rtree->evictable);
rtree->min_size = min_size;
rtree->destroy = destroy;
memset (&rtree->root, 0 , sizeof (rtree->root));
rtree->root.width = width;
rtree->root.height = height;
rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE;
cairo_list_add (&rtree->root.link, &rtree->available);
}
void
_cairo_rtree_reset (cairo_rtree_t *rtree)
{
int i;
if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) {
rtree->destroy (&rtree->root);
} else {
for (i = 0 ; i < 4 && rtree->root.children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, rtree->root.children[i]);
rtree->root.children[0 ] = NULL;
}
cairo_list_init (&rtree->available);
cairo_list_init (&rtree->evictable);
cairo_list_init (&rtree->pinned);
rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE;
rtree->root.pinned = FALSE ;
cairo_list_add (&rtree->root.link, &rtree->available);
}
static void
_cairo_rtree_node_foreach (cairo_rtree_node_t *node,
void (*func)(cairo_rtree_node_t *, void *data),
void *data)
{
int i;
for (i = 0 ; i < 4 && node->children[i] != NULL; i++)
_cairo_rtree_node_foreach(node->children[i], func, data);
func(node, data);
}
void
_cairo_rtree_foreach (cairo_rtree_t *rtree,
void (*func)(cairo_rtree_node_t *, void *data),
void *data)
{
int i;
if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) {
func(&rtree->root, data);
} else {
for (i = 0 ; i < 4 && rtree->root.children[i] != NULL; i++)
_cairo_rtree_node_foreach (rtree->root.children[i], func, data);
}
}
void
_cairo_rtree_fini (cairo_rtree_t *rtree)
{
int i;
if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) {
rtree->destroy (&rtree->root);
} else {
for (i = 0 ; i < 4 && rtree->root.children[i] != NULL; i++)
_cairo_rtree_node_destroy (rtree, rtree->root.children[i]);
}
_cairo_freepool_fini (&rtree->node_freepool);
}
Messung V0.5 in Prozent C=94 H=91 G=92
¤ Dauer der Verarbeitung: 0.4 Sekunden
¤
*© Formatika GbR, Deutschland