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;
+}