Add Eina_Rectangle_Pool support. Typically help for font handling in OpenGL or

any case where you need to split a rectangle in many differents small rectangle.


SVN revision: 37252
This commit is contained in:
Cedric BAIL 2008-10-27 20:24:12 +00:00
parent db296d3d3c
commit 72e45419ec
11 changed files with 535 additions and 162 deletions

View File

@ -25,6 +25,7 @@ eina_rbtree.h \
eina_benchmark.h \
eina_inline_rbtree.x \
eina_inline_mempool.x \
eina_inline_rectangle.x \
eina_iterator.h
installed_mainheaderdir = $(prefix)/include/eina-@VMAJ@

View File

@ -0,0 +1,140 @@
/* EINA - EFL data type library
* Copyright (C) 2007-2008 Jorge Luis Zapata Muga
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library;
* if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EINA_INLINE_RECTANGLE_H__
#define EINA_INLINE_RECTANGLE_H__
static inline int
eina_spans_intersect(int c1, int l1, int c2, int l2)
{
return (!(((c2 + l2) <= c1) || (c2 >= (c1 + l1))));
}
static inline Eina_Bool
eina_rectangle_is_empty(Eina_Rectangle *r)
{
return ((r->w < 1) || (r->h < 1)) ? EINA_TRUE : EINA_FALSE;
}
static inline void
eina_rectangle_coords_from(Eina_Rectangle *r, int x, int y, int w, int h)
{
r->x = x;
r->y = y;
r->w = w;
r->h = h;
}
static inline Eina_Bool
eina_rectangles_intersect(Eina_Rectangle *r1, Eina_Rectangle *r2)
{
return (eina_spans_intersect(r1->x, r1->w, r2->x, r2->w) && eina_spans_intersect(r1->y, r1->h, r2->y, r2->h)) ? EINA_TRUE : EINA_FALSE;
}
static inline Eina_Bool
eina_rectangle_xcoord_inside(Eina_Rectangle *r, int x)
{
return ((x >= r->x) && (x < (r->x + r->w))) ? EINA_TRUE : EINA_FALSE;
}
static inline Eina_Bool
eina_rectangle_ycoord_inside(Eina_Rectangle *r, int y)
{
return ((y >= r->y) && (y < (r->y + r->h))) ? EINA_TRUE : EINA_FALSE;
}
static inline Eina_Bool
eina_rectangle_coords_inside(Eina_Rectangle *r, int x, int y)
{
return (eina_rectangle_xcoord_inside(r, x) && eina_rectangle_ycoord_inside(r, y)) ? EINA_TRUE : EINA_FALSE;
}
static inline void
eina_rectangle_union(Eina_Rectangle *dst, Eina_Rectangle *src)
{
/* left */
if (dst->x > src->x)
{
dst->w += dst->x - src->x;
dst->x = src->x;
}
/* right */
if ((dst->x + dst->w) < (src->x + src->w))
dst->w = src->x + src->w;
/* top */
if (dst->y > src->y)
{
dst->h += dst->y - src->y;
dst->y = src->y;
}
/* bottom */
if ((dst->y + dst->h) < (src->y + src->h))
dst->h = src->y + src->h;
}
static inline Eina_Bool
eina_rectangle_intersection(Eina_Rectangle *dst, Eina_Rectangle *src)
{
if (!(eina_rectangles_intersect(dst, src)))
return EINA_FALSE;
/* left */
if (dst->x < src->x)
{
dst->w += dst->x - src->x;
dst->x = src->x;
if (dst->w < 0)
dst->w = 0;
}
/* right */
if ((dst->x + dst->w) > (src->x + src->w))
dst->w = src->x + src->w - dst->x;
/* top */
if (dst->y < src->y)
{
dst->h += dst->y - src->y;
dst->y = src->y;
if (dst->h < 0)
dst->h = 0;
}
/* bottom */
if ((dst->y + dst->h) > (src->y + src->h))
dst->h = src->y + src->h - dst->y;
return EINA_TRUE;
}
static inline void
eina_rectangle_rescale_in(Eina_Rectangle *out, Eina_Rectangle *in, Eina_Rectangle *res)
{
res->x = in->x - out->x;
res->y = in->y - out->y;
res->w = in->w;
res->h = in->h;
}
static inline void
eina_rectangle_rescale_out(Eina_Rectangle *out, Eina_Rectangle *in, Eina_Rectangle *res)
{
res->x = out->x + in->x;
res->y = out->y + in->y;
res->w = out->w;
res->h = out->h;
}
#endif

View File

@ -24,6 +24,8 @@
* @{
*/
#include "eina_types.h"
/**
* To be documented
* FIXME: To be fixed
@ -36,161 +38,28 @@ typedef struct _Eina_Rectangle
int h;
} Eina_Rectangle;
/**
* To be documented
* FIXME: To be fixed
* Is it needed??
*/
static inline int
eina_spans_intersect(int c1, int l1, int c2, int l2)
{
return (!(((c2 + l2) <= c1) || (c2 >= (c1 + l1))));
}
/**
* To be documented
* FIXME: To be fixed
*/
static inline Eina_Bool
eina_rectangle_is_empty(Eina_Rectangle *r)
{
return ((r->w < 1) || (r->h < 1)) ? EINA_TRUE : EINA_FALSE;
}
typedef struct _Eina_Rectangle_Pool Eina_Rectangle_Pool;
/**
* To be documented
* FIXME: To be fixed
*/
static inline void
eina_rectangle_coords_from(Eina_Rectangle *r, int x, int y, int w, int h)
{
r->x = x;
r->y = y;
r->w = w;
r->h = h;
}
static inline int eina_spans_intersect(int c1, int l1, int c2, int l2);
static inline Eina_Bool eina_rectangle_is_empty(Eina_Rectangle *r);
static inline void eina_rectangle_coords_from(Eina_Rectangle *r, int x, int y, int w, int h);
static inline Eina_Bool eina_rectangles_intersect(Eina_Rectangle *r1, Eina_Rectangle *r2);
static inline Eina_Bool eina_rectangle_xcoord_inside(Eina_Rectangle *r, int x);
static inline Eina_Bool eina_rectangle_ycoord_inside(Eina_Rectangle *r, int y);
static inline Eina_Bool eina_rectangle_coords_inside(Eina_Rectangle *r, int x, int y);
static inline void eina_rectangle_union(Eina_Rectangle *dst, Eina_Rectangle *src);
static inline Eina_Bool eina_rectangle_intersection(Eina_Rectangle *dst, Eina_Rectangle *src);
static inline void eina_rectangle_rescale_in(Eina_Rectangle *out, Eina_Rectangle *in, Eina_Rectangle *res);
static inline void eina_rectangle_rescale_out(Eina_Rectangle *out, Eina_Rectangle *in, Eina_Rectangle *res);
/**
* To be documented
* FIXME: To be fixed
*/
static inline Eina_Bool
eina_rectangles_intersect(Eina_Rectangle *r1, Eina_Rectangle *r2)
{
return (eina_spans_intersect(r1->x, r1->w, r2->x, r2->w) && eina_spans_intersect(r1->y, r1->h, r2->y, r2->h)) ? EINA_TRUE : EINA_FALSE;
}
/**
* To be documented
* FIXME: To be fixed
*/
static inline Eina_Bool
eina_rectangle_xcoord_inside(Eina_Rectangle *r, int x)
{
return ((x >= r->x) && (x < (r->x + r->w))) ? EINA_TRUE : EINA_FALSE;
}
/**
* To be documented
* FIXME: To be fixed
*/
static inline Eina_Bool
eina_rectangle_ycoord_inside(Eina_Rectangle *r, int y)
{
return ((y >= r->y) && (y < (r->y + r->h))) ? EINA_TRUE : EINA_FALSE;
}
/**
* To be documented
* FIXME: To be fixed
*/
static inline Eina_Bool
eina_rectangle_coords_inside(Eina_Rectangle *r, int x, int y)
{
return (eina_rectangle_xcoord_inside(r, x) && eina_rectangle_ycoord_inside(r, y)) ? EINA_TRUE : EINA_FALSE;
}
/**
* To be documented
* FIXME: To be fixed
*/
static inline void
eina_rectangle_union(Eina_Rectangle *dst, Eina_Rectangle *src)
{
/* left */
if (dst->x > src->x)
{
dst->w += dst->x - src->x;
dst->x = src->x;
}
/* right */
if ((dst->x + dst->w) < (src->x + src->w))
dst->w = src->x + src->w;
/* top */
if (dst->y > src->y)
{
dst->h += dst->y - src->y;
dst->y = src->y;
}
/* bottom */
if ((dst->y + dst->h) < (src->y + src->h))
dst->h = src->y + src->h;
}
/**
* To be documented
* FIXME: To be fixed
*/
static inline Eina_Bool
eina_rectangle_intersection(Eina_Rectangle *dst, Eina_Rectangle *src)
{
if (!(eina_rectangles_intersect(dst, src)))
return EINA_FALSE;
EAPI Eina_Rectangle_Pool *eina_rectangle_pool_add(int w, int h);
EAPI void eina_rectangle_pool_delete(Eina_Rectangle_Pool *pool);
EAPI int eina_rectangle_pool_count(Eina_Rectangle_Pool *pool);
EAPI Eina_Rectangle *eina_rectangle_pool_request(Eina_Rectangle_Pool *pool, int w, int h);
EAPI void eina_rectangle_pool_release(Eina_Rectangle *rect);
/* left */
if (dst->x < src->x)
{
dst->w += dst->x - src->x;
dst->x = src->x;
if (dst->w < 0)
dst->w = 0;
}
/* right */
if ((dst->x + dst->w) > (src->x + src->w))
dst->w = src->x + src->w - dst->x;
/* top */
if (dst->y < src->y)
{
dst->h += dst->y - src->y;
dst->y = src->y;
if (dst->h < 0)
dst->h = 0;
}
/* bottom */
if ((dst->y + dst->h) > (src->y + src->h))
dst->h = src->y + src->h - dst->y;
return EINA_TRUE;
}
/**
* Rescale the coordinates from @in as if it where relative to @out
*/
static inline void
eina_rectangle_rescale_in(Eina_Rectangle *out, Eina_Rectangle *in, Eina_Rectangle *res)
{
res->x = in->x - out->x;
res->y = in->y - out->y;
res->w = in->w;
res->h = in->h;
}
/**
* To be documented
* FIXME: To be fixed
*/
static inline void
eina_rectangle_rescale_out(Eina_Rectangle *out, Eina_Rectangle *in, Eina_Rectangle *res)
{
res->x = out->x + in->x;
res->y = out->y + in->y;
res->w = out->w;
res->h = out->h;
}
#include "eina_inline_rectangle.x"
/** @} */
#endif /*_ENESIM_RECTANGLE_H_*/
#endif /*_EINA_RECTANGLE_H_*/

View File

@ -29,6 +29,7 @@ eina_accessor.c \
eina_convert.c \
eina_rbtree.c \
eina_benchmark.c \
eina_rectangle.c \
eina_stringshare.c
if EINA_STATIC_BUILD_CHAINED_POOL

View File

@ -30,12 +30,14 @@
* API *
*============================================================================*/
static int _eina_main_count = 0;
EAPI int
eina_init(void)
{
int r;
if (_eina_main_count) goto finish_init;
r = eina_error_init();
eina_error_init();
eina_hash_init();
eina_stringshare_init();
eina_list_init();
@ -44,13 +46,14 @@ eina_init(void)
eina_benchmark_init();
eina_magic_string_init();
return r;
finish_init:
return ++_eina_main_count;
}
EAPI int
eina_shutdown(void)
{
int r;
if (_eina_main_count != 1) goto finish_shutdown;
eina_magic_string_shutdown();
eina_benchmark_shutdown();
@ -59,8 +62,9 @@ eina_shutdown(void)
eina_list_shutdown();
eina_stringshare_shutdown();
eina_hash_shutdown();
r = eina_error_shutdown();
eina_error_shutdown();
return r;
finish_shutdown:
return --_eina_main_count;
}

View File

@ -0,0 +1,290 @@
/* EINA - EFL data type library
* Copyright (C) 2007-2008 Cedric BAIL, Carsten Haitzler
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library;
* if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include "eina_rectangle.h"
#include "eina_magic.h"
#include "eina_inlist.h"
#include "eina_private.h"
/*============================================================================*
* Local *
*============================================================================*/
/**
* @cond LOCAL
*/
#define EINA_RECTANGLE_POOL_MAGIC 0x1578FCB0
#define EINA_RECTANGLE_ALLOC_MAGIC 0x1578FCB1
typedef struct _Eina_Rectangle_Alloc Eina_Rectangle_Alloc;
struct _Eina_Rectangle_Pool
{
EINA_MAGIC;
Eina_Inlist *head;
unsigned int references;
int w;
int h;
};
struct _Eina_Rectangle_Alloc
{
EINA_INLIST;
EINA_MAGIC;
Eina_Rectangle_Pool *pool;
};
#define EINA_MAGIC_CHECK_RECTANGLE_POOL(d) \
do { \
if (!EINA_MAGIC_CHECK((d), EINA_RECTANGLE_POOL_MAGIC)) \
EINA_MAGIC_FAIL((d), EINA_RECTANGLE_POOL_MAGIC); \
} while (0);
#define EINA_MAGIC_CHECK_RECTANGLE_ALLOC(d) \
do { \
if (!EINA_MAGIC_CHECK((d), EINA_RECTANGLE_ALLOC_MAGIC)) \
EINA_MAGIC_FAIL((d), EINA_RECTANGLE_ALLOC_MAGIC); \
} while (0);
static inline Eina_Bool
_eina_rectangle_pool_collide(Eina_Rectangle_Alloc *head, Eina_Rectangle_Alloc *current, Eina_Rectangle *test)
{
Eina_Rectangle_Alloc *collide;
EINA_INLIST_FOREACH(head, collide)
{
Eina_Rectangle *colliding_rect = (Eina_Rectangle*) (collide + 1);
if (collide == current) continue;
if (eina_rectangles_intersect(colliding_rect, test))
return EINA_TRUE;
}
return EINA_FALSE;
}
static Eina_Bool
_eina_rectangle_pool_find(Eina_Rectangle_Alloc *head, int poolw, int poolh, int w, int h, int *x, int *y)
{
Eina_Rectangle_Alloc *item;
Eina_Rectangle tmp = { 0, 0, 0, 0 };
if (head == NULL) goto on_intersect;
EINA_INLIST_FOREACH(head, item)
{
Eina_Rectangle *rect = (Eina_Rectangle*) (item + 1);
Eina_Bool t1 = EINA_TRUE;
Eina_Bool t2 = EINA_TRUE;
Eina_Bool t3 = EINA_TRUE;
Eina_Bool t4 = EINA_TRUE;
Eina_Bool intersects;
if ((rect->x + rect->w + w) > poolw) t1 = EINA_FALSE;
if ((rect->y + h) > poolh) t1 = EINA_FALSE;
if ((rect->y + rect->h + h) > poolh) t2 = EINA_FALSE;
if ((rect->x + w) > poolw) t2 = EINA_FALSE;
if ((rect->x - w) < 0) t3 = EINA_FALSE;
if ((rect->y + h) > poolh) t3 = EINA_FALSE;
if ((rect->x + w) > poolw) t4 = EINA_FALSE;
if ((rect->y - h) < 0) t4 = EINA_FALSE;
intersects = EINA_FALSE;
if (t1)
{
/* 1. try here:
* +----++--+
* |AAAA||??|
* |AAAA|+--+
* |AAAA|
* +----+
*/
eina_rectangle_coords_from(&tmp, rect->x + rect->w, rect->y, w, h);
intersects = _eina_rectangle_pool_collide(head, item, &tmp);
if (!intersects) goto on_intersect;
}
intersects = EINA_FALSE;
if (t2)
{
/* 2. try here:
* +----+
* |AAAA|
* |AAAA|
* |AAAA|
* +----+
* +--+
* |??|
* +--+
*/
eina_rectangle_coords_from(&tmp, rect->x, rect->y + rect->h, w, h);
intersects = _eina_rectangle_pool_collide(head, item, &tmp);
if (!intersects) goto on_intersect;
}
intersects = EINA_FALSE;
if (t3)
{
/* 3. try here:
* +--++----+
* |??||AAAA|
* +--+|AAAA|
* |AAAA|
* +----+
*/
eina_rectangle_coords_from(&tmp, rect->x - w, rect->y, w, h);
intersects = _eina_rectangle_pool_collide(head, item, &tmp);
if (!intersects) goto on_intersect;
}
intersects = EINA_FALSE;
if (t4)
{
/* 2. try here:
* +--+
* |??|
* +--+
* +----+
* |AAAA|
* |AAAA|
* |AAAA|
* +----+
*/
eina_rectangle_coords_from(&tmp, rect->x, rect->y - h, w, h);
intersects = _eina_rectangle_pool_collide(head, item, &tmp);
if (!intersects) goto on_intersect;
}
}
return EINA_FALSE;
on_intersect:
*x = tmp.x;
*y = tmp.y;
return EINA_TRUE;
}
/**
* @endcond
*/
/*============================================================================*
* Global *
*============================================================================*/
/*============================================================================*
* API *
*============================================================================*/
EAPI Eina_Rectangle_Pool *
eina_rectangle_pool_add(int w, int h)
{
Eina_Rectangle_Pool *new;
new = malloc(sizeof (Eina_Rectangle_Pool));
if (!new) return NULL;
new->head = NULL;
new->references = 0;
new->w = w;
new->h = h;
EINA_MAGIC_SET(new, EINA_RECTANGLE_POOL_MAGIC);
return new;
}
EAPI void
eina_rectangle_pool_delete(Eina_Rectangle_Pool *pool)
{
Eina_Rectangle_Alloc *del;
while (pool->head)
{
del = (Eina_Rectangle_Alloc*) pool->head;
pool->head = (EINA_INLIST_GET(del))->next;
MAGIC_FREE(del);
}
MAGIC_FREE(pool);
}
EAPI int
eina_rectangle_pool_count(Eina_Rectangle_Pool *pool)
{
return pool->references;
}
EAPI Eina_Rectangle *
eina_rectangle_pool_request(Eina_Rectangle_Pool *pool, int w, int h)
{
Eina_Rectangle_Alloc *new;
Eina_Rectangle *rect;
Eina_Bool test;
int x;
int y;
if (w > pool->w || h > pool->h) return NULL;
test = _eina_rectangle_pool_find((Eina_Rectangle_Alloc*) pool->head, pool->w, pool->h, w, h, &x, &y);
if (!test) return NULL;
new = malloc(sizeof (Eina_Rectangle_Alloc) + sizeof (Eina_Rectangle));
if (!new) return NULL;
rect = (Eina_Rectangle*) (new + 1);
eina_rectangle_coords_from(rect, x, y, w, h);
pool->head = eina_inlist_prepend(pool->head, EINA_INLIST_GET(new));
pool->references++;
new->pool = pool;
EINA_MAGIC_SET(new, EINA_RECTANGLE_ALLOC_MAGIC);
return rect;
}
EAPI void
eina_rectangle_pool_release(Eina_Rectangle *rect)
{
Eina_Rectangle_Alloc *era = ((Eina_Rectangle_Alloc *) rect) - 1;
EINA_MAGIC_CHECK_RECTANGLE_ALLOC(era);
EINA_MAGIC_CHECK_RECTANGLE_POOL(era->pool);
era->pool->references--;
era->pool->head = eina_inlist_remove(era->pool->head, EINA_INLIST_GET(era));
MAGIC_FREE(era);
}

View File

@ -63,6 +63,7 @@ eina_test_rbtree.c \
eina_test_file.c \
eina_test_benchmark.c \
eina_test_mempool.c \
eina_test_rectangle.c \
eina_test_list.c
eina_suite_LDADD = @CHECK_LIBS@ $(top_builddir)/src/lib/libeina.la

View File

@ -45,6 +45,7 @@ static const Eina_Test_Case etc[] = {
{ "File", eina_test_file },
{ "Benchmark", eina_test_benchmark },
{ "Mempool", eina_test_mempool },
{ "Rectangle", eina_test_rectangle },
{ NULL, NULL }
};

View File

@ -43,5 +43,6 @@ void eina_test_rbtree(TCase *tc);
void eina_test_file(TCase *tc);
void eina_test_benchmark(TCase *tc);
void eina_test_mempool(TCase *tc);
void eina_test_rectangle(TCase *tc);
#endif /* EINA_SUITE_H_ */

View File

@ -27,10 +27,8 @@
START_TEST(eina_simple)
{
/* Eina_error as already been initialized by eina_hash
that was called by eina_mempool_init that's why we don't have 0 here */
fail_if(eina_init() != 2);
fail_if(eina_shutdown() != 1);
fail_if(eina_init() != 1);
fail_if(eina_shutdown() != 0);
}
END_TEST

View File

@ -0,0 +1,67 @@
/* EINA - EFL data type library
* Copyright (C) 2007-2008 Cedric BAIL, Carsten Haitzler
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library;
* if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include "eina_rectangle.h"
#include "eina_suite.h"
START_TEST(eina_rectangle_pool)
{
Eina_Rectangle_Pool *pool;
Eina_Rectangle *rects[8][8];
Eina_Rectangle *rct;
int x;
int y;
pool = eina_rectangle_pool_add(256, 256);
fail_if(pool == NULL);
fail_if(eina_rectangle_pool_request(pool, 1024, 1024) != NULL);
for (x = 0; x < 8; x++)
for (y = 0; y < 8; y++)
{
rects[x][y] = eina_rectangle_pool_request(pool, 32, 32);
fail_if(rects[x][y] == NULL);
}
fail_if(eina_rectangle_pool_count(pool) != 64);
fail_if(eina_rectangle_pool_request(pool, 32, 32) != NULL);
fail_if(eina_rectangle_pool_request(pool, 1024, 1024) != NULL);
for (x = 0; x < 8; x++)
eina_rectangle_pool_release(rects[0][x]);
fail_if(eina_rectangle_pool_request(pool, 16, 16) == NULL);
eina_rectangle_pool_delete(pool);
}
END_TEST
void
eina_test_rectangle(TCase *tc)
{
tcase_add_test(tc, eina_rectangle_pool);
}