diff --git a/legacy/eina/src/include/Eina.h b/legacy/eina/src/include/Eina.h index 41d4d46232..96ac93dff4 100644 --- a/legacy/eina/src/include/Eina.h +++ b/legacy/eina/src/include/Eina.h @@ -158,6 +158,8 @@ extern "C" { #include "eina_iterator.h" #include "eina_benchmark.h" #include "eina_convert.h" +#include "eina_cpu.h" +#include "eina_tiler.h" #ifdef __cplusplus } diff --git a/legacy/eina/src/include/Makefile.am b/legacy/eina/src/include/Makefile.am index 059daaad59..701b49b267 100644 --- a/legacy/eina/src/include/Makefile.am +++ b/legacy/eina/src/include/Makefile.am @@ -28,7 +28,9 @@ eina_inline_rbtree.x \ eina_inline_mempool.x \ eina_inline_rectangle.x \ eina_iterator.h \ -eina_main.h +eina_main.h \ +eina_cpu.h \ +eina_tiler.h installed_mainheaderdir = $(includedir)/eina-@VMAJ@ installed_mainheader_DATA = Eina.h eina_config.h diff --git a/legacy/eina/src/include/eina_cpu.h b/legacy/eina/src/include/eina_cpu.h new file mode 100644 index 0000000000..ad8361d184 --- /dev/null +++ b/legacy/eina/src/include/eina_cpu.h @@ -0,0 +1,37 @@ +/* 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 . + */ +#ifndef EINA_CPU_H_ +#define EINA_CPU_H_ + +#include "eina_types.h" + +typedef enum _Eina_Cpu_Features +{ + EINA_CPU_MMX = 0x00000001, + EINA_CPU_SSE = 0x00000002, + EINA_CPU_SSE2 = 0x00000004, + EINA_CPU_SSE3 = 0x00000008, + /* TODO 3DNow! */ + EINA_CPU_ALTIVEC = 0x00000010, + EINA_CPU_VIS = 0x00000020, + EINA_CPU_NEON = 0x00000040, +} Eina_Cpu_Features; + +EAPI Eina_Cpu_Features eina_cpu_features_get(void); + +#endif /* EINA_CPU_H_ */ diff --git a/legacy/eina/src/include/eina_private.h b/legacy/eina/src/include/eina_private.h index e612190b0c..ebb07a27c9 100644 --- a/legacy/eina/src/include/eina_private.h +++ b/legacy/eina/src/include/eina_private.h @@ -68,6 +68,9 @@ #define EINA_MAGIC_HASH 0x9876123e #define EINA_MAGIC_HASH_ITERATOR 0x9876123f +#define EINA_MAGIC_TILER 0x98761240 +#define EINA_MAGIC_TILER_ITERATOR 0x98761241 + /* undef the following, we want out version */ #undef FREE #define FREE(ptr) \ diff --git a/legacy/eina/src/include/eina_tiler.h b/legacy/eina/src/include/eina_tiler.h new file mode 100644 index 0000000000..c7748cb523 --- /dev/null +++ b/legacy/eina/src/include/eina_tiler.h @@ -0,0 +1,35 @@ +/* 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 . + */ +#ifndef EINA_TILER_H_ +#define EINA_TILER_H_ + +#include "eina_types.h" +#include "eina_iterator.h" +#include "eina_rectangle.h" + +typedef struct _Eina_Tiler Eina_Tiler; + +EAPI Eina_Tiler *eina_tiler_new(int w, int h); +EAPI void eina_tiler_del(Eina_Tiler *t); +EAPI void eina_tiler_tile_size_set(Eina_Tiler *t, int w, int h); +EAPI Eina_Bool eina_tiler_rect_add(Eina_Tiler *t, Eina_Rectangle *r); +EAPI void eina_tiler_rect_del(Eina_Tiler *t, Eina_Rectangle *r); +EAPI void eina_tiler_clear(Eina_Tiler *t); +EAPI Eina_Iterator * eina_tiler_iterator_new(const Eina_Tiler *t); + +#endif /* EINA_TILER_H_ */ diff --git a/legacy/eina/src/lib/Makefile.am b/legacy/eina/src/lib/Makefile.am index da9b4a8a43..2f98a6cbc5 100644 --- a/legacy/eina/src/lib/Makefile.am +++ b/legacy/eina/src/lib/Makefile.am @@ -31,7 +31,9 @@ eina_convert.c \ eina_rbtree.c \ eina_benchmark.c \ eina_rectangle.c \ -eina_stringshare.c +eina_stringshare.c \ +eina_cpu.c \ +eina_tiler.c if EINA_STATIC_BUILD_CHAINED_POOL diff --git a/legacy/eina/src/lib/eina_cpu.c b/legacy/eina/src/lib/eina_cpu.c new file mode 100644 index 0000000000..13674b0b4e --- /dev/null +++ b/legacy/eina/src/lib/eina_cpu.c @@ -0,0 +1,83 @@ +/* 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 . + */ +#include "eina_cpu.h" +/*============================================================================* + * Local * + *============================================================================*/ +/* FIXME this ifdefs should be replaced */ +#if defined(__i386__) || defined(__x86_64__) +/* We save ebx and restore it to be PIC compatible */ +static inline void _x86_cpuid(int op, int *a, int *b, int *c, int *d) +{ + asm volatile( + "pushl %%ebx \n\t" /* save %ebx */ + "cpuid \n\t" + "movl %%ebx, %1 \n\t" /* save what cpuid just put in %ebx */ + "popl %%ebx \n\t" /* restore the old %ebx */ + : "=a"(*a), "=r"(*b), "=c"(*c), "=d"(*d) + : "a"(op) + : "cc"); +} + +void _x86_simd(Eina_Cpu_Features *features) +{ + int a, b, c, d; + + _x86_cpuid(1, &a, &b, &c, &d); + /* + * edx + * 18 = PN (Processor Number) + * 19 = CLFlush (Cache Line Flush) + * 23 = MMX + * 25 = SSE + * 26 = SSE2 + * 28 = HTT (Hyper Threading) + * ecx + * 0 = SSE3 + */ + if ((d >> 23) & 1) + *features |= EINA_CPU_MMX; + if ((d >> 25) & 1) + *features |= EINA_CPU_SSE; + if ((d >> 26) & 1) + *features |= EINA_CPU_SSE2; + if (c & 1) + *features |= EINA_CPU_SSE3; +} +#endif +/*============================================================================* + * Global * + *============================================================================*/ +/*============================================================================* + * API * + *============================================================================*/ +/* FIXME the features checks should be called when this function is called? + * or make it static by doing eina_cpu_init() and return a local var + */ +/** + * + * @return + */ +EAPI Eina_Cpu_Features eina_cpu_features_get(void) +{ + Eina_Cpu_Features ecf = 0; +#if defined(__i386__) || defined(__x86_64__) + _x86_simd(&ecf); +#endif + return ecf; +} diff --git a/legacy/eina/src/lib/eina_tiler.c b/legacy/eina/src/lib/eina_tiler.c new file mode 100644 index 0000000000..bec28341bf --- /dev/null +++ b/legacy/eina/src/lib/eina_tiler.c @@ -0,0 +1,1200 @@ +/* EINA - EFL data type library + * Copyright (C) 2007-2008 Gustavo Sverzut Barbieri, 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 . + */ + +/* TODO + * it is possible to have more than one tiler algorithm, but for now the + * version Gustavo did is hardcoded here + * http://blog.gustavobarbieri.com.br/2007/06/03/evas-now-using-rectangle-split-and-merge/ + */ +#include +#include + +#include "eina_tiler.h" +#include "eina_private.h" +#include "eina_types.h" +/*============================================================================* + * Local * + *============================================================================*/ +/* The splitter data types */ +typedef struct list_node list_node_t; +typedef struct list list_t; +typedef struct rect rect_t; +typedef struct rect_node rect_node_t; + +struct list_node +{ + struct list_node *next; +}; + +struct list +{ + struct list_node *head; + struct list_node *tail; +}; + +struct rect +{ + short right; + short bottom; + short left; + short top; + short width; + short height; + int area; +}; + +struct rect_node +{ + struct list_node _lst; + struct rect rect; +}; + +typedef struct splitter +{ + Eina_Bool need_merge; + list_t rects; +} splitter_t; + +typedef struct list_node_pool +{ + list_node_t *node; + int len; + int max; +} list_node_pool_t; + + +static const list_node_t list_node_zeroed = { NULL }; +static const list_t list_zeroed = { NULL, NULL }; +static list_node_pool_t list_node_pool = { NULL, 0, 1024 }; + + +typedef struct _Eina_Iterator_Tiler +{ + Eina_Iterator iterator; + const Eina_Tiler *tiler; + list_node_t *curr; + EINA_MAGIC; +} Eina_Iterator_Tiler; + +struct _Eina_Tiler +{ + struct + { + int w, h; + } tile; + Eina_Rectangle area; + EINA_MAGIC; + splitter_t splitter; +}; +#define EINA_MAGIC_CHECK_TILER(d) \ + do { \ + if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_TILER)) \ + EINA_MAGIC_FAIL(d, EINA_MAGIC_TILER); \ + } while(0) + + +#define EINA_MAGIC_CHECK_TILER_ITERATOR(d) \ + do { \ + if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_TILER_ITERATOR)) \ + EINA_MAGIC_FAIL(d, EINA_MAGIC_TILER_ITERATOR); \ + } while(0) + +/* The Splitter algorithm */ +static inline void rect_init(rect_t *r, int x, int y, int w, int h) +{ + r->area = w * h; + + r->left = x; + r->top = y; + + r->right = x + w; + r->bottom = y + h; + + r->width = w; + r->height = h; +} + +static inline list_node_t * +rect_list_node_pool_get(void) +{ + if (list_node_pool.node) + { + list_node_t *node; + + node = list_node_pool.node; + list_node_pool.node = node->next; + list_node_pool.len--; + + return node; + } + else + return malloc(sizeof(rect_node_t)); +} + + +static inline void rect_list_concat(list_t *rects, list_t *other) +{ + if (!other->head) + return; + + if (rects->tail) + { + rects->tail->next = other->head; + rects->tail = other->tail; + } + else + { + rects->head = other->head; + rects->tail = other->tail; + } + *other = list_zeroed; +} + +static inline void rect_list_append_node(list_t *rects, list_node_t *node) +{ + if (rects->tail) + { + rects->tail->next = node; + rects->tail = node; + } + else + { + rects->head = node; + rects->tail = node; + } +} + +static inline void rect_list_append(list_t *rects, const rect_t r) +{ + rect_node_t *rect_node; + + rect_node = (rect_node_t *) rect_list_node_pool_get(); + rect_node->rect = r; + rect_node->_lst = list_node_zeroed; + + rect_list_append_node(rects, (list_node_t *) rect_node); +} + +static inline void rect_list_append_xywh(list_t *rects, int x, int y, int w, int h) +{ + rect_t r; + + rect_init(&r, x, y, w, h); + rect_list_append(rects, r); +} + +static inline void _calc_intra_rect_area(const rect_t a, const rect_t b, + int *width, int *height) +{ + int max_left, min_right, max_top, min_bottom; + + if (a.left < b.left) + max_left = b.left; + else + max_left = a.left; + + if (a.right < b.right) + min_right = a.right; + else + min_right = b.right; + + *width = min_right - max_left; + + if (a.top < b.top) + max_top = b.top; + else + max_top = a.top; + + if (a.bottom < b.bottom) + min_bottom = a.bottom; + else + min_bottom = b.bottom; + + *height = min_bottom - max_top; +} + +static inline void _split_strict(list_t *dirty, const rect_t current, rect_t r) +{ + int h_1, h_2, w_1, w_2; + + h_1 = current.top - r.top; + h_2 = r.bottom - current.bottom; + w_1 = current.left - r.left; + w_2 = r.right - current.right; + + if (h_1 > 0) + { + /* .--.r (b) .---.r2 + * | | | | + * .-------.cur (a) .---.r '---' + * | | | | -> | | + + * | `--' | `---' + * `-------' + */ + rect_list_append_xywh(dirty, r.left, r.top, r.width, h_1); + r.height -= h_1; + r.top = current.top; + } + + if (h_2 > 0) + { + /* .-------.cur (a) + * | .---. | .---.r + * | | | | -> | | + * `-------' `---' + .---.r2 + * | | | | + * `---'r (b) `---' + */ + rect_list_append_xywh(dirty, r.left, current.bottom, r.width, + h_2); + r.height -= h_2; + } + + if (w_1 > 0) + { + /* (b) r .----.cur (a) + * .--|-. | .--.r2 .-.r + * | | | | -> | | + | | + * `--|-' | `--' `-' + * `----' + */ + rect_list_append_xywh(dirty, r.left, r.top, w_1, r.height); + /* not necessary to keep these, r (b) will be destroyed */ + /* r.width -= w_1; */ + /* r.left = current.left; */ + } + + if (w_2 > 0) + { + /* .----.cur (a) + * | | + * | .-|--.r (b) .-.r .--.r2 + * | | | | -> | | + | | + * | `-|--' `-' `--' + * `----' + */ + rect_list_append_xywh(dirty, current.right, r.top, w_2, + r.height); + /* not necessary to keep this, r (b) will be destroyed */ + /* r.width -= w_2; */ + } +} + +static inline void _calc_intra_outer_rect_area(const rect_t a, const rect_t b, + rect_t *intra, rect_t *outer) +{ + int min_left, max_left, min_right, max_right; + int min_top, max_top, min_bottom, max_bottom; + + if (a.left < b.left) + { + max_left = b.left; + min_left = a.left; + } + else + { + max_left = a.left; + min_left = b.left; + } + + if (a.right < b.right) + { + min_right = a.right; + max_right = b.right; + } + else + { + min_right = b.right; + max_right = a.right; + } + + intra->left = max_left; + intra->right = min_right; + intra->width = min_right - max_left; + + outer->left = min_left; + outer->right = max_right; + outer->width = max_right - min_left; + + if (a.top < b.top) + { + max_top = b.top; + min_top = a.top; + } + else + { + max_top = a.top; + min_top = b.top; + } + + if (a.bottom < b.bottom) + { + min_bottom = a.bottom; + max_bottom = b.bottom; + } + else + { + min_bottom = b.bottom; + max_bottom = a.bottom; + } + + intra->top = max_top; + intra->bottom = min_bottom; + intra->height = min_bottom - max_top; + if ((intra->width > 0) && (intra->height > 0)) + intra->area = intra->width * intra->height; + else + intra->area = 0; + + outer->top = min_top; + outer->bottom = max_bottom; + outer->height = max_bottom - min_top; + outer->area = outer->width * outer->height; +} + +enum +{ + SPLIT_FUZZY_ACTION_NONE, + SPLIT_FUZZY_ACTION_SPLIT, + SPLIT_FUZZY_ACTION_MERGE +}; + +static inline int _split_fuzzy(list_t *dirty, const rect_t a, rect_t *b) +{ + int h_1, h_2, w_1, w_2, action; + + h_1 = a.top - b->top; + h_2 = b->bottom - a.bottom; + w_1 = a.left - b->left; + w_2 = b->right - a.right; + + action = SPLIT_FUZZY_ACTION_NONE; + + if (h_1 > 0) + { + /* .--.r (b) .---.r2 + * | | | | + * .-------.cur (a) .---.r '---' + * | | | | -> | | + + * | `--' | `---' + * `-------' + */ + rect_list_append_xywh(dirty, b->left, b->top, b->width, h_1); + b->height -= h_1; + b->top = a.top; + action = SPLIT_FUZZY_ACTION_SPLIT; + } + + if (h_2 > 0) + { + /* .-------.cur (a) + * | .---. | .---.r + * | | | | -> | | + * `-------' `---' + .---.r2 + * | | | | + * `---'r (b) `---' + */ + rect_list_append_xywh(dirty, b->left, a.bottom, b->width, h_2); + b->height -= h_2; + action = SPLIT_FUZZY_ACTION_SPLIT; + } + + if (((w_1 > 0) || (w_2 > 0)) && (a.height == b->height)) + return SPLIT_FUZZY_ACTION_MERGE; + + if (w_1 > 0) + { + /* (b) r .----.cur (a) + * .--|-. | .--.r2 .-.r + * | | | | -> | | + | | + * `--|-' | `--' `-' + * `----' + */ + rect_list_append_xywh(dirty, b->left, b->top, w_1, b->height); + /* not necessary to keep these, r (b) will be destroyed */ + /* b->width -= w_1; */ + /* b->left = a.left; */ + action = SPLIT_FUZZY_ACTION_SPLIT; + } + + if (w_2 > 0) + { + /* .----.cur (a) + * | | + * | .-|--.r (b) .-.r .--.r2 + * | | | | -> | | + | | + * | `-|--' `-' `--' + * `----' + */ + rect_list_append_xywh(dirty, a.right, b->top, w_2, b->height); + /* not necessary to keep these, r (b) will be destroyed */ + /* b->width -= w_2; */ + action = SPLIT_FUZZY_ACTION_SPLIT; + } + + return action; +} + +void rect_list_node_pool_set_max(int max) +{ + int diff; + + diff = list_node_pool.len - max; + for (; diff > 0 && list_node_pool.node != NULL; diff--) + { + list_node_t *node; + + node = list_node_pool.node; + list_node_pool.node = node->next; + list_node_pool.len--; + + free(node); + } + + list_node_pool.max = max; +} + +void rect_list_node_pool_flush(void) +{ + while (list_node_pool.node) + { + list_node_t *node; + + node = list_node_pool.node; + list_node_pool.node = node->next; + list_node_pool.len--; + + free(node); + } +} + + + +static inline void rect_list_node_pool_put(list_node_t *node) +{ + if (list_node_pool.len < list_node_pool.max) + { + node->next = list_node_pool.node; + list_node_pool.node = node; + list_node_pool.len++; + } + else + free(node); +} + +void rect_print(const rect_t r) +{ + printf("", r.left, r.top, r.width, r.height); +} + +void rect_list_print(const list_t rects) +{ + list_node_t *node; + int len; + + len = 0; + for (node = rects.head; node != NULL; node = node->next) + len++; + + printf("["); + for (node = rects.head; node != NULL; node = node->next) + { + rect_print(((rect_node_t *) node)->rect); + if (node->next) + { + putchar(','); + if (len < 4) + putchar(' '); + else + { + putchar('\n'); + putchar(' '); + } + } + } + printf("]\n"); +} + + +static inline list_node_t * +rect_list_unlink_next(list_t *rects, list_node_t *parent_node) +{ + list_node_t *node; + + if (parent_node) + { + node = parent_node->next; + parent_node->next = node->next; + } + else + { + node = rects->head; + rects->head = node->next; + } + + if (rects->tail == node) + rects->tail = parent_node; + *node = list_node_zeroed; + return node; +} + +static inline void rect_list_del_next(list_t *rects, list_node_t *parent_node) +{ + list_node_t *node; + + node = rect_list_unlink_next(rects, parent_node); + rect_list_node_pool_put(node); +} + +void rect_list_clear(list_t *rects) +{ + list_node_t *node; + + node = rects->head; + while (node) + { + list_node_t *aux; + + aux = node->next; + rect_list_node_pool_put(node); + node = aux; + } + *rects = list_zeroed; +} + +void rect_list_del_split_strict(list_t *rects, const rect_t del_r) +{ + list_t modified = list_zeroed; + list_node_t *cur_node, *prev_node; + + prev_node = NULL; + cur_node = rects->head; + while (cur_node) + { + int intra_width, intra_height; + rect_t current; + + current = ((rect_node_t*) cur_node)->rect; + + _calc_intra_rect_area(del_r, current, &intra_width, + &intra_height); + if ((intra_width <= 0) || (intra_height <= 0)) + { + /* .---.current .---.del_r + * | | | | + * `---+---.del_r `---+---.current + * | | | | + * `---' `---' + * no intersection, nothing to do + */ + prev_node = cur_node; + cur_node = cur_node->next; + } + else if ((intra_width == current.width) && (intra_height + == current.height)) + { + /* .-------.del_r + * | .---. | + * | | | | + * | `---'current + * `-------' + * current is contained, remove from rects + */ + cur_node = cur_node->next; + rect_list_del_next(rects, prev_node); + } + else + { + _split_strict(&modified, del_r, current); + cur_node = cur_node->next; + rect_list_del_next(rects, prev_node); + } + } + + rect_list_concat(rects, &modified); +} + +void rect_list_add_split_strict(list_t *rects, list_node_t *node) +{ + list_t dirty = list_zeroed; + list_t new_dirty = list_zeroed; + list_node_t *cur_node; + + if (!rects->head) + { + rect_list_append_node(rects, node); + return; + } + + rect_list_append_node(&dirty, node); + + cur_node = rects->head; + while (dirty.head) + { + rect_t current; + + if (!cur_node) + { + rect_list_concat(rects, &dirty); + break; + } + + current = ((rect_node_t*) cur_node)->rect; + + while (dirty.head) + { + int intra_width, intra_height; + rect_t r; + + r = ((rect_node_t *) dirty.head)->rect; + _calc_intra_rect_area(r, current, &intra_width, + &intra_height); + if ((intra_width == r.width) && (intra_height + == r.height)) + /* .-------.cur + * | .---.r| + * | | | | + * | `---' | + * `-------' + */ + rect_list_del_next(&dirty, NULL); + else if ((intra_width <= 0) || (intra_height <= 0)) + { + /* .---.cur .---.r + * | | | | + * `---+---.r `---+---.cur + * | | | | + * `---' `---' + */ + list_node_t *tmp; + tmp = rect_list_unlink_next(&dirty, NULL); + rect_list_append_node(&new_dirty, tmp); + } + else + { + _split_strict(&new_dirty, current, r); + rect_list_del_next(&dirty, NULL); + } + } + dirty = new_dirty; + new_dirty = list_zeroed; + + cur_node = cur_node->next; + } +} + +list_node_t * +rect_list_add_split_fuzzy(list_t *rects, list_node_t *node, int accepted_error) +{ + list_t dirty = list_zeroed; + list_node_t *old_last; + + old_last = rects->tail; + + if (!rects->head) + { + rect_list_append_node(rects, node); + return old_last; + } + + rect_list_append_node(&dirty, node); + while (dirty.head) + { + list_node_t *d_node, *cur_node, *prev_cur_node; + int keep_dirty; + rect_t r; + + d_node = rect_list_unlink_next(&dirty, NULL); + r = ((rect_node_t *) d_node)->rect; + + prev_cur_node = NULL; + cur_node = rects->head; + keep_dirty = 1; + while (cur_node) + { + int area, action; + rect_t current, intra, outer; + + current = ((rect_node_t *) cur_node)->rect; + + _calc_intra_outer_rect_area(r, current, &intra, &outer); + area = current.area + r.area - intra.area; + + if ((intra.width == r.width) && (intra.height + == r.height)) + { + /* .-------.cur + * | .---.r| + * | | | | + * | `---' | + * `-------' + */ + keep_dirty = 0; + break; + } + else if ((intra.width == current.width) + && (intra.height == current.height)) + { + /* .-------.r + * | .---.cur + * | | | | + * | `---' | + * `-------' + */ + if (old_last == cur_node) + old_last = prev_cur_node; + cur_node = cur_node->next; + rect_list_del_next(rects, prev_cur_node); + } + else if ((outer.area - area) <= accepted_error) + { + /* .-----------. bounding box (outer) + * |.---. .---.| + * ||cur| |r || + * || | | || + * |`---' `---'| + * `-----------' + * merge them, remove both and add merged + */ + rect_node_t *n; + + if (old_last == cur_node) + old_last = prev_cur_node; + + n = (rect_node_t *) rect_list_unlink_next( + rects, prev_cur_node); + n->rect = outer; + rect_list_append_node(&dirty, (list_node_t *) n); + + keep_dirty = 0; + break; + } + else if (intra.area <= accepted_error) + { + /* .---.cur .---.r + * | | | | + * `---+---.r `---+---.cur + * | | | | + * `---' `---' + * no split, no merge + */ + prev_cur_node = cur_node; + cur_node = cur_node->next; + } + else + { + /* split is required */ + action = _split_fuzzy(&dirty, current, &r); + if (action == SPLIT_FUZZY_ACTION_MERGE) + { + /* horizontal merge is possible: remove both, add merged */ + rect_node_t *n; + + if (old_last == cur_node) + old_last = prev_cur_node; + + n + = (rect_node_t *) rect_list_unlink_next( + rects, + prev_cur_node); + + n->rect.left = outer.left; + n->rect.width = outer.width; + n->rect.right = outer.right; + n->rect.area = outer.width * r.height; + rect_list_append_node(&dirty, + (list_node_t *) n); + } + else if (action == SPLIT_FUZZY_ACTION_NONE) + { + /* + * this rect check was totally useless, + * should never happen + */ + /* prev_cur_node = cur_node; */ + /* cur_node = cur_node->next; */ + printf("Should not get here!\n"); + abort(); + } + + keep_dirty = 0; + break; + } + } + if (__builtin_expect((keep_dirty), 0)) + { + printf("ok\n"); + } + if (EINA_UNLIKELY(keep_dirty)) + { + rect_list_append_node(rects, d_node); + } + else + rect_list_node_pool_put(d_node); + } + + return old_last; +} + +static inline void _calc_outer_rect_area(const rect_t a, const rect_t b, + rect_t *outer) +{ + int min_left, max_right; + int min_top, max_bottom; + + if (a.left < b.left) + min_left = a.left; + else + min_left = b.left; + + if (a.right < b.right) + max_right = b.right; + else + max_right = a.right; + + outer->left = min_left; + outer->right = max_right; + outer->width = max_right - min_left; + + if (a.top < b.top) + min_top = a.top; + else + min_top = b.top; + + if (a.bottom < b.bottom) + max_bottom = b.bottom; + else + max_bottom = a.bottom; + + outer->top = min_top; + outer->bottom = max_bottom; + outer->height = max_bottom - min_top; + + outer->area = outer->width * outer->height; +} + +void rect_list_merge_rects(list_t *rects, list_t *to_merge, int accepted_error) +{ + while (to_merge->head) + { + list_node_t *node, *parent_node; + rect_t r1; + int merged; + + r1 = ((rect_node_t *) to_merge->head)->rect; + + merged = 0; + parent_node = NULL; + node = rects->head; + while (node != NULL) + { + rect_t r2, outer; + int area; + + r2 = ((rect_node_t *) node)->rect; + + _calc_outer_rect_area(r1, r2, &outer); + area = r1.area + r2.area; /* intra area is taken as 0 */ + if (outer.area - area <= accepted_error) + { + /* + * remove both r1 and r2, create r3 + * actually r3 uses r2 instance, saves memory + */ + rect_node_t *n; + + n = (rect_node_t *) rect_list_unlink_next( + rects, parent_node); + n->rect = outer; + rect_list_append_node(to_merge, + (list_node_t *) n); + merged = 1; + break; + } + + parent_node = node; + node = node->next; + } + + if (!merged) + { + list_node_t *n; + n = rect_list_unlink_next(to_merge, NULL); + rect_list_append_node(rects, n); + } + else + rect_list_del_next(to_merge, NULL); + } +} + +void rect_list_add_split_fuzzy_and_merge(list_t *rects, list_node_t *node, + int split_accepted_error, int merge_accepted_error) +{ + list_node_t *n; + + n = rect_list_add_split_fuzzy(rects, node, split_accepted_error); + if (n && n->next) + { + list_t to_merge; + + /* split list into 2 segments, already merged and to merge */ + to_merge.head = n->next; + to_merge.tail = rects->tail; + rects->tail = n; + n->next = NULL; + + rect_list_merge_rects(rects, &to_merge, merge_accepted_error); + } +} + +static inline void _splitter_new(Eina_Tiler *t) +{ + t->splitter.rects = list_zeroed; + t->splitter.need_merge = EINA_FALSE; +} + +static inline void _splitter_del(Eina_Tiler *t) +{ + rect_list_clear(&t->splitter.rects); + rect_list_node_pool_flush(); +} + +static inline void _splitter_tile_size_set(Eina_Tiler *t, int w, int h) +{ + /* TODO are w and h used for something? */ + t->splitter.rects = list_zeroed; +} + +static inline Eina_Bool _splitter_rect_add(Eina_Tiler *t, Eina_Rectangle *rect) +{ + rect_node_t *rn; + + //printf("ACCOUNTING[1]: add_redraw: %4d,%4d %3dx%3d\n", x, y, w, h); + rect->x >>= 1; + rect->y >>= 1; + rect->w += 2; + rect->w >>= 1; + rect->h += 2; + rect->h >>= 1; + + rn = (rect_node_t *) rect_list_node_pool_get(); + rn->_lst = list_node_zeroed; + rect_init(&rn->rect, rect->x, rect->y, rect->w, rect->h); + //printf("ACCOUNTING[2]: add_redraw: %4d,%4d %3dx%3d\n", x, y, w, h); + //testing on my core2 duo desktop - fuzz of 32 or 48 is best. +#define FUZZ 32 + rect_list_add_split_fuzzy_and_merge(&t->splitter.rects, + (list_node_t *) rn, FUZZ * FUZZ, FUZZ * FUZZ); + return EINA_TRUE; +} + +static inline void _splitter_rect_del(Eina_Tiler *t, Eina_Rectangle *rect) +{ + rect_t r; + + if (!t->splitter.rects.head) + return; + rect->x += 1; + rect->y += 1; + rect->x >>= 1; + rect->y >>= 1; + rect->w -= 1; + rect->w >>= 1; + rect->h -= 1; + rect->h >>= 1; + + if ((rect->w <= 0) || (rect->h <= 0)) + return; + + rect_init(&r, rect->x, rect->y, rect->w, rect->h); + //fprintf(stderr, "ACCOUNTING: del_redraw: %4d,%4d %3dx%3d\n", x, y, w, h); + + rect_list_del_split_strict(&t->splitter.rects, r); + t->splitter.need_merge = EINA_TRUE; + return; +} + +static inline void _splitter_clear(Eina_Tiler *t) +{ + rect_list_clear(&t->splitter.rects); + t->splitter.need_merge = EINA_FALSE; +} +/* end of splitter algorithm */ + +static Eina_Bool _iterator_next(Eina_Iterator_Tiler *it, void **data) +{ + Eina_Rectangle *rect = (Eina_Rectangle *)data; + list_node_t *n; + + for (n = it->curr; n != NULL; n = n->next) + { + rect_t cur; + + cur = ((rect_node_t *) n)->rect; + + rect->x = cur.left << 1; + rect->y = cur.top << 1; + rect->w = cur.width << 1; + rect->h = cur.height << 1; + + if (eina_rectangle_intersection(rect, &it->tiler->area) == EINA_FALSE) + continue; + if ((rect->w <= 0) || (rect->h <= 0)) + continue; + return EINA_TRUE; + } + return EINA_FALSE; +} + +static void * _iterator_get_container(Eina_Iterator_Tiler *it) +{ + EINA_MAGIC_CHECK_TILER_ITERATOR(it); + return (void *)it->tiler; +} + +static void _iterator_free(Eina_Iterator_Tiler *it) +{ + EINA_MAGIC_CHECK_TILER_ITERATOR(it); + free(it); +} + +/*============================================================================* + * Global * + *============================================================================*/ +/*============================================================================* + * API * + *============================================================================*/ +/** + * To be documented + * FIXME: To be fixed + */ +EAPI Eina_Tiler *eina_tiler_new(int w, int h) +{ + Eina_Tiler *t; + + t = calloc(1, sizeof(Eina_Tiler)); + t->area.w = w; + t->area.h = h; + t->tile.w = w; + t->tile.h = h; + EINA_MAGIC_SET(t, EINA_MAGIC_TILER); + _splitter_new(t); + return t; +} +/** + * To be documented + * FIXME: To be fixed + */ +EAPI void eina_tiler_del(Eina_Tiler *t) +{ + EINA_MAGIC_CHECK_TILER(t); + _splitter_del(t); + free(t); +} +/** + * To be documented + * FIXME: To be fixed + */ +EAPI void eina_tiler_tile_size_set(Eina_Tiler *t, int w, int h) +{ + EINA_MAGIC_CHECK_TILER(t); + if ((w <= 0) || (h <= 0)) return; + + t->tile.w = w; + t->tile.h = h; + _splitter_tile_size_set(t, w, h); +} +/** + * To be documented + * FIXME: To be fixed + */ +EAPI Eina_Bool eina_tiler_rect_add(Eina_Tiler *t, Eina_Rectangle *r) +{ + Eina_Rectangle tmp; + + EINA_MAGIC_CHECK_TILER(t); + if ((r->w <= 0) || (r->h <= 0)) + return EINA_FALSE; + tmp = *r; + if (eina_rectangle_intersection(&tmp, &t->area) == EINA_FALSE) + return EINA_FALSE; + if ((tmp.w <= 0) || (tmp.h <= 0)) + return EINA_FALSE; + return _splitter_rect_add(t, &tmp); +} +/** + * To be documented + * FIXME: To be fixed + */ +EAPI void eina_tiler_rect_del(Eina_Tiler *t, Eina_Rectangle *r) +{ + Eina_Rectangle tmp; + + EINA_MAGIC_CHECK_TILER(t); + if ((r->w <= 0) || (r->h <= 0)) + return; + tmp = *r; + if (eina_rectangle_intersection(&tmp, &t->area) == EINA_FALSE) + return; + if ((tmp.w <= 0) || (tmp.h <= 0)) + return; + _splitter_rect_del(t, &tmp); +} +/** + * To be documented + * FIXME: To be fixed + */ +EAPI void eina_tiler_clear(Eina_Tiler *t) +{ + EINA_MAGIC_CHECK_TILER(t); + _splitter_clear(t); +} + + +EAPI Eina_Iterator * eina_tiler_iterator_new(const Eina_Tiler *t) +{ + Eina_Iterator_Tiler *it; + + EINA_MAGIC_CHECK_TILER(t); + it = calloc(1, sizeof (Eina_Iterator_Tiler)); + if (!it) return NULL; + + it->tiler = t; + + if (t->splitter.need_merge == EINA_TRUE) + { + list_t to_merge; + splitter_t *sp; + + sp = (splitter_t *)&(t->splitter); + to_merge = t->splitter.rects; + sp->rects = list_zeroed; + rect_list_merge_rects(&sp->rects, &to_merge, FUZZ * FUZZ); + sp->need_merge = 0; + } + + it->curr = it->tiler->splitter.rects.head; + it->iterator.next = FUNC_ITERATOR_NEXT(_iterator_next); + it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_iterator_get_container); + it->iterator.free = FUNC_ITERATOR_FREE(_iterator_free); + + EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); + EINA_MAGIC_SET(it, EINA_MAGIC_TILER_ITERATOR); + + return &it->iterator; +}