summaryrefslogtreecommitdiff
path: root/components/gui/src/image_container.c
diff options
context:
space:
mode:
authorbernard <[email protected]>2017-10-10 00:17:58 +0800
committerbernard <[email protected]>2017-10-10 00:17:58 +0800
commit01108b525294e1019fcab893dc991e8e17d1fa86 (patch)
treef52214cb4f76cffaeb8f4f5cf3c22f5c90604684 /components/gui/src/image_container.c
parentf8a1bf6fd809be4ce53d17bde1a367aa6bae8187 (diff)
[GUI] Update GUI engine code and add Kconfig file.
Diffstat (limited to 'components/gui/src/image_container.c')
-rw-r--r--components/gui/src/image_container.c440
1 files changed, 440 insertions, 0 deletions
diff --git a/components/gui/src/image_container.c b/components/gui/src/image_container.c
new file mode 100644
index 0000000000..66b7191271
--- /dev/null
+++ b/components/gui/src/image_container.c
@@ -0,0 +1,440 @@
+/*
+ * File : image_container.c
+ * This file is part of RT-Thread GUI Engine
+ * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2010-09-15 Bernard first version
+ */
+#include <rtgui/rtgui_system.h>
+#include <rtgui/image_container.h>
+
+/*
+ * ImageContainer is a Image pool to manage image resource in the system.
+ *
+ * All of image in the ImageContainer should be loaded in the memory.
+ * All of image are identified by image file name.
+ *
+ * Applications can use rtgui_image_container_get/put to refer or derefer
+ * a image resource.
+ */
+
+#if defined(RTGUI_IMAGE_CONTAINER) && defined(RTGUI_USING_DFS_FILERW)
+typedef unsigned int (*rtgui_hash_func_t)(const void *key);
+typedef struct _rtgui_hash_table rtgui_hash_table_t;
+typedef rt_bool_t (*rtgui_equal_func_t)(const void *a, const void *b);
+typedef void (*rtgui_user_func_t)(const void *value, const void *data);
+
+/*
+ *Hash tables
+ */
+rtgui_hash_table_t *hash_table_create(rtgui_hash_func_t hash_func, rtgui_equal_func_t key_equal_func);
+void hash_table_destroy(rtgui_hash_table_t *hash_table);
+
+void *hash_table_find(rtgui_hash_table_t *hash_table, const void *key);
+void hash_table_insert(rtgui_hash_table_t *hash_table, const void *key, void *value);
+rt_bool_t hash_table_remove(rtgui_hash_table_t *hash_table, const void *key);
+
+void hash_table_foreach(rtgui_hash_table_t *hash_table, rtgui_user_func_t user_func, void *data);
+unsigned int hash_table_get_size(rtgui_hash_table_t *hash_table);
+
+/* Hash Functions
+ */
+unsigned int direct_hash(const void *v);
+
+#define HASH_TABLE_MIN_SIZE 11
+#define HASH_TABLE_MAX_SIZE 6247
+
+typedef struct _gui_hash_node rtgui_hash_node_t;
+struct _gui_hash_node
+{
+ const void *key;
+ void *value;
+ rtgui_hash_node_t *next;
+};
+
+struct _rtgui_hash_table
+{
+ rt_uint16_t size;
+ rt_uint16_t nnodes;
+
+ rtgui_hash_node_t **nodes;
+ rtgui_hash_func_t hash_func;
+ rtgui_equal_func_t key_equal_func;
+};
+
+static const unsigned int primes[] =
+{
+ 11,
+ 19,
+ 37,
+ 73,
+ 109,
+ 163,
+ 251,
+ 367,
+ 557,
+ 823,
+ 1237,
+ 1861,
+ 2777,
+ 4177,
+ 6247,
+};
+
+static const unsigned int nprimes = sizeof(primes) / sizeof(primes[0]);
+
+static void hash_table_resize(rtgui_hash_table_t *hash_table);
+static rtgui_hash_node_t **hash_table_find_node(rtgui_hash_table_t *hash_table, const void *key);
+static rtgui_hash_node_t *hash_node_create(const void *key, void *value);
+static void hash_node_destroy(rtgui_hash_node_t *hash_node);
+static void hash_nodes_destroy(rtgui_hash_node_t *hash_node);
+static unsigned int primes_closest(unsigned int num);
+static void hash_table_needresize(rtgui_hash_table_t *hash_table);
+
+rt_inline unsigned int primes_closest(unsigned int num)
+{
+ unsigned int i;
+
+ for (i = 0; i < nprimes; i++)
+ if (primes[i] > num)
+ return primes[i];
+
+ return primes[nprimes - 1];
+}
+
+/* directly hash */
+unsigned int direct_hash(const void *v)
+{
+ return (unsigned int)v;
+}
+
+rtgui_hash_table_t *hash_table_create(rtgui_hash_func_t hash_func, rtgui_equal_func_t key_equal_func)
+{
+ rtgui_hash_table_t *hash_table;
+
+ hash_table = (rtgui_hash_table_t *) rtgui_malloc(sizeof(rtgui_hash_table_t));
+ if (hash_table != RT_NULL)
+ {
+ hash_table->size = HASH_TABLE_MIN_SIZE;
+ hash_table->nnodes = 0;
+ hash_table->hash_func = hash_func ? hash_func : direct_hash;
+ hash_table->key_equal_func = key_equal_func;
+ hash_table->nodes = (rtgui_hash_node_t **)rtgui_malloc(sizeof(rtgui_hash_node_t *) * hash_table->size);
+ if (hash_table->nodes == RT_NULL)
+ {
+ /* no memory yet */
+ rtgui_free(hash_table);
+ return RT_NULL;
+ }
+
+ rt_memset(hash_table->nodes, 0, sizeof(rtgui_hash_node_t *) * hash_table->size);
+ }
+
+ return hash_table;
+}
+
+void hash_table_destroy(rtgui_hash_table_t *hash_table)
+{
+ unsigned int i;
+
+ RT_ASSERT(hash_table != RT_NULL);
+
+ for (i = 0; i < hash_table->size; i++)
+ hash_nodes_destroy(hash_table->nodes[i]);
+
+ rtgui_free(hash_table->nodes);
+ rtgui_free(hash_table);
+}
+
+static rtgui_hash_node_t **hash_table_find_node(rtgui_hash_table_t *hash_table, const void *key)
+{
+ rtgui_hash_node_t **node;
+
+ node = &hash_table->nodes [(* hash_table->hash_func)(key) % hash_table->size];
+
+ if (hash_table->key_equal_func)
+ while (*node && !(*hash_table->key_equal_func)((*node)->key, key))
+ node = &(*node)->next;
+ else
+ while (*node && (*node)->key != key)
+ node = &(*node)->next;
+
+ return node;
+}
+
+void *hash_table_find(rtgui_hash_table_t *hash_table, const void *key)
+{
+ rtgui_hash_node_t *node;
+
+ RT_ASSERT(hash_table != RT_NULL);
+ RT_ASSERT(key != RT_NULL);
+
+ node = *hash_table_find_node(hash_table, key);
+
+ if (node) return node->value;
+ else return RT_NULL;
+}
+
+void hash_table_insert(rtgui_hash_table_t *hash_table, const void *key, void *value)
+{
+ rtgui_hash_node_t **node;
+
+ if (hash_table == RT_NULL)return;
+
+ node = hash_table_find_node(hash_table, key);
+ if (*node)
+ {
+ (*node)->value = value;
+ }
+ else
+ {
+ *node = hash_node_create(key, value);
+ hash_table->nnodes++;
+ hash_table_needresize(hash_table);
+ }
+}
+
+rt_bool_t hash_table_remove(rtgui_hash_table_t *hash_table, const void *key)
+{
+ rtgui_hash_node_t **node, *dest;
+
+ if (hash_table == RT_NULL) return RT_FALSE;
+
+ node = hash_table_find_node(hash_table, key);
+ if (*node)
+ {
+ rt_enter_critical();
+ dest = *node;
+ (*node) = dest->next;
+ hash_node_destroy(dest);
+ hash_table->nnodes--;
+
+ hash_table_needresize(hash_table);
+ rt_exit_critical();
+
+ return RT_TRUE;
+ }
+
+ return RT_FALSE;
+}
+
+void hash_table_foreach(rtgui_hash_table_t *hash_table, rtgui_user_func_t user_func, void *data)
+{
+ rtgui_hash_node_t *node;
+ int i;
+
+ RT_ASSERT(hash_table != RT_NULL);
+ RT_ASSERT(user_func != RT_NULL);
+
+ for (i = 0; i < hash_table->size; i++)
+ for (node = hash_table->nodes[i]; node; node = node->next)
+ (* user_func)(node->value, data);
+}
+
+unsigned int hash_table_get_size(rtgui_hash_table_t *hash_table)
+{
+ if (hash_table == NULL) return 0;
+
+ return hash_table->nnodes;
+}
+
+static void hash_table_needresize(rtgui_hash_table_t *hash_table)
+{
+ if ((hash_table->size >= 3 * hash_table->nnodes && hash_table->size > HASH_TABLE_MIN_SIZE) ||
+ (3 * hash_table->size <= hash_table->nnodes && hash_table->size < HASH_TABLE_MAX_SIZE))
+ hash_table_resize(hash_table);
+}
+
+static void hash_table_resize(rtgui_hash_table_t *hash_table)
+{
+ rtgui_hash_node_t **new_nodes;
+ rtgui_hash_node_t *node;
+ rtgui_hash_node_t *next;
+ unsigned int hash_val;
+ int new_size;
+ int i;
+
+ i = primes_closest(hash_table->nnodes);
+ new_size = i > HASH_TABLE_MAX_SIZE ? HASH_TABLE_MAX_SIZE : i < HASH_TABLE_MIN_SIZE ? HASH_TABLE_MIN_SIZE : i ;
+
+ new_nodes = (rtgui_hash_node_t **)rtgui_malloc(sizeof(rtgui_hash_node_t *) * new_size);
+ if (new_nodes == RT_NULL) return; /* no memory yet */
+ rt_memset(new_nodes, 0, sizeof(rtgui_hash_node_t *) * new_size);
+
+ for (i = 0; i < hash_table->size; i++)
+ {
+ for (node = hash_table->nodes[i]; node; node = next)
+ {
+ next = node->next;
+
+ hash_val = (* hash_table->hash_func)(node->key) % new_size;
+
+ node->next = new_nodes[hash_val];
+ new_nodes[hash_val] = node;
+ }
+ }
+
+ rtgui_free(hash_table->nodes);
+ hash_table->nodes = new_nodes;
+ hash_table->size = new_size;
+}
+
+static rtgui_hash_node_t *hash_node_create(const void *key, void *value)
+{
+ rtgui_hash_node_t *hash_node;
+
+ hash_node = (rtgui_hash_node_t *) rtgui_malloc(sizeof(rtgui_hash_node_t));
+ if (hash_node != RT_NULL)
+ {
+ /* set value and key */
+ hash_node->key = key;
+ hash_node->value = value;;
+
+ hash_node->next = RT_NULL;
+ }
+
+ return hash_node;
+}
+
+static void hash_node_destroy(rtgui_hash_node_t *hash_node)
+{
+ rtgui_free(hash_node);
+}
+
+static void hash_nodes_destroy(rtgui_hash_node_t *hash_node)
+{
+ if (hash_node)
+ {
+ rtgui_hash_node_t *node = hash_node;
+ rtgui_hash_node_t *temp;
+
+ while (node->next)
+ {
+ node->key = NULL;
+ node->value = NULL;
+
+ temp = node;
+ node = node->next;
+ rtgui_free(temp);
+ }
+
+ node->key = NULL;
+ node->value = NULL;
+ rtgui_free(node);
+ }
+}
+
+unsigned int string_hash_func(const void *self)
+{
+ const char *p;
+ int h = 0, g;
+
+ for (p = self; *p != '\0'; p += 1)
+ {
+ h = (h << 4) + *p;
+ g = h;
+
+ if (g & 0xf0000000)
+ {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+
+ return h ;
+}
+
+rt_bool_t string_equal_func(const void *a, const void *b)
+{
+ const char *str1, *str2;
+
+ str1 = (const char *)a;
+ str2 = (const char *)b;
+
+ if (strcmp(str1, str2) == 0) return RT_TRUE;
+ return RT_FALSE;
+}
+
+static rtgui_hash_table_t *image_hash_table;
+static struct rt_mutex _image_hash_lock;
+
+void rtgui_system_image_container_init(void)
+{
+ rt_mutex_init(&_image_hash_lock, "image", RT_IPC_FLAG_FIFO);
+
+ /* create image hash table */
+ image_hash_table = hash_table_create(string_hash_func, string_equal_func);
+ RT_ASSERT(image_hash_table != RT_NULL);
+}
+
+rtgui_image_item_t *rtgui_image_container_get(const char *filename)
+{
+ struct rtgui_image_item *item = RT_NULL;
+
+ if (rt_mutex_take(&_image_hash_lock, RT_WAITING_FOREVER) == RT_EOK)
+ {
+ item = hash_table_find(image_hash_table, filename);
+ if (item == RT_NULL)
+ {
+ item = (struct rtgui_image_item *) rtgui_malloc(sizeof(struct rtgui_image_item));
+ if (item == RT_NULL) return RT_NULL;
+
+ /* create a image object */
+ item->image = rtgui_image_create(filename, RT_TRUE);
+ if (item->image == RT_NULL)
+ {
+ rtgui_free(item);
+ return RT_NULL; /* create image failed */
+ }
+ item->refcount = 1;
+ item->filename = rt_strdup(filename);
+ hash_table_insert(image_hash_table, item->filename, item);
+ }
+ else
+ {
+ item->refcount ++; /* increase refcount */
+ }
+
+ rt_mutex_release(&_image_hash_lock);
+ }
+
+ return item;
+}
+RTM_EXPORT(rtgui_image_container_get);
+
+void rtgui_image_container_put(rtgui_image_item_t *item)
+{
+ rt_mutex_take(&_image_hash_lock, RT_WAITING_FOREVER);
+ item->refcount --;
+ if (item->refcount == 0)
+ {
+ /* remove item from container */
+ hash_table_remove(image_hash_table, item->filename);
+
+ /* destroy image and image item */
+ rt_free(item->filename);
+ rtgui_image_destroy(item->image);
+ rtgui_free(item);
+ }
+ rt_mutex_release(&_image_hash_lock);
+}
+RTM_EXPORT(rtgui_image_container_put);
+
+#endif
+